fix all compile errors. no functionality yet (#77)

* fix all compile errors. can't link zlib

* fix oopsie

* nogui still has zlib error. need to unlink in public. dolphin-gui compiles and runs!

* fix cmakelists include
This commit is contained in:
David Liu 2023-05-17 03:29:01 -04:00 committed by GitHub
commit b3f0422234
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 827 additions and 744 deletions

View file

@ -699,8 +699,6 @@ endif()
add_subdirectory(Externals/imgui)
add_subdirectory(Externals/implot)
add_subdirectory(Externals/glslang)
add_subdirectory(Externals/SlippiLib)
include_directories(Externals/SlippiLib)
include_directories(Externals/nlohmann)
add_subdirectory(Externals/semver)
include_directories(Externals/semver/include)
@ -795,6 +793,8 @@ endif()
add_subdirectory(Externals/zlib-ng)
find_package(ZLIB REQUIRED)
pkg_check_modules(MINIZIP minizip>=3.0.0)
if(MINIZIP_FOUND)
message(STATUS "Using shared minizip")

View file

@ -1,19 +0,0 @@
project(SlippiLib
VERSION 1.0.0)
set(SRCS
SlippiGame.h
SlippiGame.cpp
)
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
set(CMAKE_CXX_STANDARD 17)
add_definitions(-std=c++17)
if(NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter")
endif()
add_library(SlippiLib STATIC ${SRCS})

View file

@ -2712,9 +2712,6 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T
return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min));
}
template float ImGui::SliderCalcRatioFromValueT<int, float>(ImGuiDataType, int, int, int, float, float);
// FIXME: Move some of the code into SliderBehavior(). Current responsability is larger than what the equivalent DragBehaviorT<> does, we also do some rendering, etc.
// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT)
template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)

View file

@ -70,7 +70,7 @@ set (VCDCOM_SRC
"src/unique_ptr.h"
"src/varint_bigendian.h"
"src/vcdiff_defs.h"
"src/zlib/zlib.h"
"src/zlib/zlib_old.h"
"src/zlib/zconf.h"
"src/zlib/adler32.c"
"src/addrcache.cc"
@ -128,12 +128,17 @@ if (BUILD_STATIC_LIBS)
add_library (vcdcom ALIAS vcdcom_STATIC)
add_library (vcddec ALIAS vcddec_STATIC)
add_library (vcdenc ALIAS vcdenc_STATIC)
target_compile_options(vcdcom_STATIC PRIVATE -w)
target_compile_options(vcddec_STATIC PRIVATE -w)
target_compile_options(vcdenc_STATIC PRIVATE -w)
else ()
add_library (vcdcom ALIAS vcdcom_SHARED)
add_library (vcddec ALIAS vcddec_SHARED)
add_library (vcdenc ALIAS vcdenc_SHARED)
endif()
if (vcdiff_build_exec)
add_executable (vcdiff "src/vcdiff_main.cc")
target_link_libraries (vcdiff vcddec vcdenc gflags)

View file

@ -19,7 +19,7 @@
#define OPEN_VCDIFF_CHECKSUM_H_
#include "config.h"
#include "zlib/zlib.h"
#include "zlib/zlib_old.h"
#ifdef __MINGW32__
#include <stddef.h>
@ -33,7 +33,7 @@ const VCDChecksum kNoPartialChecksum = 0;
inline VCDChecksum ComputeAdler32(const char* buffer,
size_t size) {
return adler32(kNoPartialChecksum,
return adler32_old(kNoPartialChecksum,
reinterpret_cast<const Bytef*>(buffer),
static_cast<uInt>(size));
}
@ -41,7 +41,7 @@ inline VCDChecksum ComputeAdler32(const char* buffer,
inline VCDChecksum UpdateAdler32(VCDChecksum partial_checksum,
const char* buffer,
size_t size) {
return adler32(partial_checksum,
return adler32_old(partial_checksum,
reinterpret_cast<const Bytef*>(buffer),
static_cast<uInt>(size));
}

View file

@ -6,7 +6,7 @@
/* @(#) $Id$ */
#define ZLIB_INTERNAL
#include "zlib.h"
#include "zlib_old.h"
#define BASE 65521UL /* largest prime smaller than 65536 */
#define NMAX 5552
@ -94,7 +94,7 @@ void ZEXPORT adler32_range(min, max)
*max = ((BASE-1) << 16) | (BASE-1);
}
uLong ZEXPORT adler32(adler, buf, len)
uLong ZEXPORT adler32_old(adler, buf, len)
uLong adler;
const Bytef *buf;
uInt len;
@ -165,7 +165,7 @@ uLong ZEXPORT adler32(adler, buf, len)
}
/* ========================================================================= */
uLong ZEXPORT adler32_combine(adler1, adler2, len2)
uLong ZEXPORT adler32_combine_old(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off_t len2;

View file

@ -28,6 +28,8 @@
(zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
*/
#pragma once
#ifndef ZLIB_H
#define ZLIB_H
@ -1260,7 +1262,7 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
compression library.
*/
ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
ZEXTERN uLong ZEXPORT adler32_old OF((uLong adler, const Bytef *buf, uInt len));
/*
Update a running Adler-32 checksum with the bytes buf[0..len-1] and
return the updated checksum. If buf is NULL, this function returns
@ -1289,7 +1291,7 @@ ZEXTERN void ZEXPORT adler32_range OF((uLong* min, uLong* max));
software.
*/
ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
ZEXTERN uLong ZEXPORT adler32_combine_old OF((uLong adler1, uLong adler2,
z_off_t len2));
/*
Combine two Adler-32 checksums into one. For two sequences of bytes, seq1

View file

@ -78,7 +78,6 @@ SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
TabWidth: 2
UseTab: Never
---

View file

@ -924,7 +924,6 @@ static void RebuildUserDirectories(unsigned int dir_index)
s_user_paths[F_ARAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + ARAM_DUMP;
s_user_paths[F_FAKEVMEMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + FAKEVMEM_DUMP;
s_user_paths[F_GCSRAM_IDX] = s_user_paths[D_GCUSER_IDX] + GC_SRAM;
s_user_paths[F_WIISDCARD_IDX] = s_user_paths[D_WIIROOT_IDX] + DIR_SEP WII_SDCARD;
s_user_paths[F_USERJSON_IDX] = s_user_paths[D_SLIPPI_IDX] + USER_JSON;
s_user_paths[F_WIISDCARDIMAGE_IDX] = s_user_paths[D_LOAD_IDX] + WII_SD_CARD_IMAGE;

View file

@ -41,12 +41,6 @@ IOFile::IOFile(const std::string& filename, const char openmode[], SharedAccess
Open(filename, openmode, sh);
}
IOFile::IOFile(const std::string& filename, const char openmode[], int shflag)
: m_file(nullptr), m_good(true)
{
OpenShared(filename, openmode, shflag);
}
IOFile::~IOFile()
{
Close();
@ -98,19 +92,6 @@ bool IOFile::Open(const std::string& filename, const char openmode[],
return m_good;
}
bool IOFile::OpenShared(const std::string& filename, const char openmode[], int shflag)
{
Close();
#ifdef _WIN32
m_file = _fsopen(filename.c_str(), openmode, shflag);
#else
m_file = fopen(filename.c_str(), openmode);
#endif
m_good = IsOpen();
return m_good;
}
bool IOFile::Close()
{
if (!IsOpen() || 0 != std::fclose(m_file))

View file

@ -34,7 +34,6 @@ class IOFile
public:
IOFile();
IOFile(std::FILE* file);
IOFile(const std::string& filename, const char openmode[]);
IOFile(const std::string& filename, const char openmode[],
SharedAccess sh = SharedAccess::Default);
@ -48,8 +47,6 @@ public:
void Swap(IOFile& other) noexcept;
bool Open(const std::string& filename, const char openmode[]);
bool Open(const std::string& filename, const char openmode[],
SharedAccess sh = SharedAccess::Default);

View file

@ -18,13 +18,15 @@ namespace Common
#endif
#ifndef IS_PLAYBACK
#define SLIPPI_REV_STR "2.4.0" // netplay version
#define SLIPPI_REV_STR "2.4.0" // netplay version
#else
#define SLIPPI_REV_STR "2.4.1" // playback version
#define SLIPPI_REV_STR "2.4.1" // playback version
#endif
const std::string& GetSemVerStr() {
return SLIPPI_REV_STR;
const std::string& GetSemVerStr()
{
static const std::string sem_ver_str = SLIPPI_REV_STR;
return sem_ver_str;
}
const std::string& GetScmRevStr()
@ -32,7 +34,8 @@ const std::string& GetScmRevStr()
#ifndef IS_PLAYBACK
static const std::string scm_rev_str = "Mainline - Slippi (" SLIPPI_REV_STR ")" BUILD_TYPE_STR;
#else
static const std::string scm_rev_str = "Mainline - Slippi (" SLIPPI_REV_STR ") - Playback" BUILD_TYPE_STR;
static const std::string scm_rev_str =
"Mainline - Slippi (" SLIPPI_REV_STR ") - Playback" BUILD_TYPE_STR;
#endif
return scm_rev_str;
}

View file

@ -530,6 +530,8 @@ add_library(core
Slippi/SlippiSpectate.h
Slippi/SlippiUser.cpp
Slippi/SlippiUser.h
Slippi/SlippiGame.cpp
Slippi/SlippiGame.h
Slippi/SlippiGameReporter.cpp
Slippi/SlippiGameReporter.h
Slippi/SlippiDirectCodes.cpp
@ -644,11 +646,9 @@ PUBLIC
videoogl
videosoftware
semver
SlippiLib
vcdcom
vcddec
vcdenc
z
PRIVATE
FatFs

View file

@ -13,6 +13,7 @@
#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Slippi/SlippiConfig.h"
class IniFile;
@ -39,6 +40,9 @@ struct BootParameters;
struct SConfig
{
// Melee Version
Melee::Version m_melee_version;
// Settings
bool bAutomaticStart = false;
bool bBootToPause = false;
@ -51,8 +55,10 @@ struct SConfig
bool bWii = false;
bool m_is_mios = false;
// SLIPPITODO: MOVE THESE
// SLIPPITODO: MOVE SOME OF THESE TO Config/Config.h
// enable Slippi Networking output
bool m_OCEnable = true;
float m_OCFactor = 1.0f;
bool m_enableSpectator = true;
int m_spectatorPort = 51441;
std::string m_strSlippiInput = "";

View file

@ -189,7 +189,7 @@ static Installation InstallCodeHandlerLocked(const Core::CPUThreadGuard& guard)
// Install bootloader gct
for (size_t i = 0; i < bootloaderData.length(); ++i)
PowerPC::HostWrite_U8(bootloaderData[i], static_cast<u32>(codelist_base_address + i));
PowerPC::HostWrite_U8(guard, bootloaderData[i], static_cast<u32>(codelist_base_address + i));
}
else
{
@ -223,8 +223,8 @@ static Installation InstallCodeHandlerLocked(const Core::CPUThreadGuard& guard)
for (const GeckoCode::Code& code : active_code.codes)
{
PowerPC::HostWrite_U32(code.address, next_address);
PowerPC::HostWrite_U32(code.data, next_address + 4);
PowerPC::HostWrite_U32(guard, code.address, next_address);
PowerPC::HostWrite_U32(guard, code.data, next_address + 4);
next_address += CODE_SIZE;
}
}
@ -233,16 +233,13 @@ static Installation InstallCodeHandlerLocked(const Core::CPUThreadGuard& guard)
end_address - start_address);
// 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);
PowerPC::HostWrite_U32(guard, 0xF0000000, next_address);
PowerPC::HostWrite_U32(guard, 0x00000000, next_address + 4);
WARN_LOG_FMT(ACTIONREPLAY, "GeckoCodes: Using {} of {} bytes", next_address - start_address,
end_address - start_address);
}
WARN_LOG_FMT(ACTIONREPLAY, "GeckoCodes: Using {} of {} bytes", next_address - start_address,
end_address - start_address);
// Stop code. Tells the handler that this is the end of the list.
PowerPC::HostWrite_U32(guard, 0xF0000000, next_address);
PowerPC::HostWrite_U32(guard, 0x00000000, next_address + 4);
// Write 0 to trampoline address, not sure why this is necessary
PowerPC::HostWrite_U32(guard, 0, HLE_TRAMPOLINE_ADDRESS);
// Turn on codes

View file

@ -374,11 +374,12 @@ void DVDThread::ReadFile(std::string& fileName, std::vector<u8>& buf)
}
else
{
INFO_LOG_FMT(SLIPPI, "Failed to open file: %s", fileName.c_str());
INFO_LOG_FMT(SLIPPI, "Failed to open file: {}", fileName.c_str());
}
}
std::string DVDThread::GetFileName(const DiscIO::Partition &partition, u64 offset) {
std::string DVDThread::GetFileName(const DiscIO::Partition& partition, u64 offset)
{
return m_disc->GetFileSystem(partition)->FindFileInfo(offset)->GetName();
}
} // namespace DVD

View file

@ -6,10 +6,10 @@
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include <string>
#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Common/Flag.h"
@ -85,6 +85,8 @@ public:
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
const DiscIO::Partition& partition, DVD::ReplyType reply_type,
s64 ticks_until_completion);
// SLIPPINOTES: Used for checking if the MxDt.dat file exists
void ReadFile(std::string& fileName, std::vector<u8>& buf);
private:
void StartDVDThread();
@ -99,9 +101,6 @@ private:
void FinishRead(u64 id, s64 cycles_late);
void DVDThreadMain();
// SLIPPINOTES: Used for checking if the MxDt.dat file exists
void ReadFile(std::string& fileName, std::vector<u8>& buf);
std::string GetFileName(const DiscIO::Partition& partition, u64 offset);
struct ReadRequest

View file

@ -165,7 +165,7 @@ std::unique_ptr<IEXIDevice> EXIDevice_Create(Core::System& system, const EXIDevi
break;
case EXIDeviceType::Slippi:
result = std::make_unique<CEXISlippi>();
result = std::make_unique<CEXISlippi>(system);
break;
case EXIDeviceType::AMBaseboard:

View file

@ -8,7 +8,6 @@
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/MemoryUtil.h"
#include "Common/MsgHandler.h"
@ -16,6 +15,7 @@
#include "Common/Thread.h"
#include "Common/Version.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
@ -32,14 +32,15 @@
#include "Core/Slippi/SlippiPremadeText.h"
#include "Core/Slippi/SlippiReplayComm.h"
#include "Core/State.h"
#include "Core/System.h"
#include "VideoCommon/OnScreenDisplay.h"
#define FRAME_INTERVAL 900
#define SLEEP_TIME_MS 8
#define WRITE_FILE_SLEEP_TIME_MS 85
//#define LOCAL_TESTING
//#define CREATE_DIFF_FILES
// #define LOCAL_TESTING
// #define CREATE_DIFF_FILES
extern std::unique_ptr<SlippiPlaybackStatus> g_playbackStatus;
extern std::unique_ptr<SlippiReplayComm> g_replayComm;
extern bool g_needInputForFrame;
@ -112,9 +113,9 @@ std::string ConvertConnectCodeForGame(const std::string& input)
return connectCode;
}
CEXISlippi::CEXISlippi()
CEXISlippi::CEXISlippi(Core::System& system) : IEXIDevice(system)
{
INFO_LOG(SLIPPI, "EXI SLIPPI Constructor called.");
INFO_LOG_FMT(SLIPPI, "EXI SLIPPI Constructor called.");
user = std::make_unique<SlippiUser>();
g_playbackStatus = std::make_unique<SlippiPlaybackStatus>();
@ -125,7 +126,7 @@ CEXISlippi::CEXISlippi()
directCodes = std::make_unique<SlippiDirectCodes>("direct-codes.json");
teamsCodes = std::make_unique<SlippiDirectCodes>("teams-codes.json");
generator = std::default_random_engine(Common::Timer::GetTimeMs());
generator = std::default_random_engine(Common::Timer::NowMs());
// Loggers will check 5 bytes, make sure we own that memory
m_read_queue.reserve(5);
@ -405,7 +406,7 @@ void CEXISlippi::writeToFileAsync(u8* payload, u32 length, std::string fileOptio
if (fileOption == "create" && !writeThreadRunning)
{
WARN_LOG(SLIPPI, "Creating file write thread...");
WARN_LOG_FMT(SLIPPI, "Creating file write thread...");
writeThreadRunning = true;
m_fileWriteThread = std::thread(&CEXISlippi::FileWriteThread, this);
}
@ -446,7 +447,7 @@ void CEXISlippi::writeToFile(std::unique_ptr<WriteMessage> msg)
{
if (!msg)
{
ERROR_LOG(SLIPPI, "Unexpected error: write message is falsy.");
ERROR_LOG_FMT(SLIPPI, "Unexpected error: write message is falsy.");
return;
}
@ -518,7 +519,7 @@ void CEXISlippi::writeToFile(std::unique_ptr<WriteMessage> msg)
bool result = m_file.WriteBytes(&dataToWrite[0], dataToWrite.size());
if (!result)
{
ERROR_LOG(EXPANSIONINTERFACE, "Failed to write data to file.");
ERROR_LOG_FMT(EXPANSIONINTERFACE, "Failed to write data to file.");
}
// If file should be closed, close it
@ -526,7 +527,7 @@ void CEXISlippi::writeToFile(std::unique_ptr<WriteMessage> msg)
{
// Write the number of bytes for the raw output
std::vector<u8> sizeBytes = uint32ToVector(writtenByteCount);
m_file.Seek(11, 0);
m_file.Seek(11, File::SeekOrigin::Begin);
m_file.WriteBytes(&sizeBytes[0], sizeBytes.size());
// Close file
@ -579,22 +580,22 @@ void CEXISlippi::createNewFile()
}
std::string filepath = dirpath + DIR_SEP + generateFileName();
INFO_LOG(SLIPPI, "EXI_DeviceSlippi.cpp: Creating new replay file %s", filepath.c_str());
INFO_LOG_FMT(SLIPPI, "EXI_DeviceSlippi.cpp: Creating new replay file {}", filepath.c_str());
#ifdef _WIN32
m_file = File::IOFile(filepath, "wb", _SH_DENYWR);
m_file = File::IOFile(filepath, "wb", File::SharedAccess::Read);
#else
m_file = File::IOFile(filepath, "wb");
#endif
if (!m_file)
{
PanicAlertFmtT("Could not create .slp replay file [%s].\n\n"
"The replay folder's path might be invalid, or you might "
"not have permission to write to it.\n\n"
"You can change the replay folder in Config > Slippi > "
"Slippi Replay Settings.",
filepath.c_str());
PanicAlertFmtT("Could not create .slp replay file [{0}].\n\n"
"The replay folder's path might be invalid, or you might "
"not have permission to write to it.\n\n"
"You can change the replay folder in Config > Slippi > "
"Slippi Replay Settings.",
filepath);
}
}
@ -1152,7 +1153,7 @@ void CEXISlippi::prepareGeckoList()
}
std::vector<u8> source = settings->geckoCodes;
INFO_LOG(SLIPPI, "Booting codes with source size: %d", source.size());
INFO_LOG_FMT(SLIPPI, "Booting codes with source size: {}", source.size());
int idx = 0;
while (idx < source.size())
@ -1192,8 +1193,8 @@ void CEXISlippi::prepareGeckoList()
if (deny_list.count(address))
continue;
INFO_LOG(SLIPPI, "Codetype [%x] Inserting section: %d - %d (%x, %d)", codeType,
idx - codeOffset, idx, address, codeOffset);
INFO_LOG_FMT(SLIPPI, "Codetype [{:x}] Inserting section: {} - {} ({:x}, {})", 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);
@ -1226,7 +1227,7 @@ void CEXISlippi::prepareCharacterFrameData(Slippi::FrameData* frame, u8 port, u8
// << data.animation
// << "\n";
// WARN_LOG(EXPANSIONINTERFACE, "[Frame %d] [Player %d] Positions: %f | %f", frameIndex, port,
// WARN_LOG_FMT(EXPANSIONINTERFACE, "[Frame {}] [Player {}] Positions: %f | %f", frameIndex, port,
// data.locationX, data.locationY);
// Add all of the inputs in order
@ -1288,7 +1289,7 @@ void CEXISlippi::prepareFrameData(u8* payload)
auto watchSettings = g_replayComm->current;
if (frameIndex > watchSettings.endFrame)
{
INFO_LOG(SLIPPI, "Killing game because we are past endFrame");
INFO_LOG_FMT(SLIPPI, "Killing game because we are past endFrame");
m_read_queue.push_back(FRAME_RESP_TERMINATE);
return;
}
@ -1506,12 +1507,12 @@ void CEXISlippi::prepareIsFileReady()
{
// Do not start if replay file doesn't exist
// TODO: maybe display error message?
INFO_LOG(SLIPPI, "EXI_DeviceSlippi.cpp: Replay file does not exist?");
INFO_LOG_FMT(SLIPPI, "EXI_DeviceSlippi.cpp: Replay file does not exist?");
m_read_queue.push_back(0);
return;
}
INFO_LOG(SLIPPI, "EXI_DeviceSlippi.cpp: Replay file loaded successfully!?");
INFO_LOG_FMT(SLIPPI, "EXI_DeviceSlippi.cpp: Replay file loaded successfully!?");
// Clear playback control related vars
g_playbackStatus->resetPlayback();
@ -1735,11 +1736,12 @@ bool CEXISlippi::shouldAdvanceOnlineFrame(s32 frame)
}
auto dynamicEmulationSpeed = 1.0f + deviation;
SConfig::GetInstance().m_EmulationSpeed = dynamicEmulationSpeed;
// SConfig::GetInstance().m_EmulationSpeed = 0.97f; // used for testing
Config::SetCurrent(Config::MAIN_EMULATION_SPEED, dynamicEmulationSpeed);
// SConfig::GetInstance().m_EmulationSpeed = dynamicEmulationSpeed;
// SConfig::GetInstance().m_EmulationSpeed = 0.97f; // used for testing
INFO_LOG(SLIPPI_ONLINE, "[Frame %d] Offset for advance is: %d us. New speed: %.2f%%", frame,
offsetUs, dynamicEmulationSpeed * 100.0f);
INFO_LOG_FMT(SLIPPI_ONLINE, "[Frame {}] Offset for advance is: {} us. New speed: {.4}%", frame,
offsetUs, dynamicEmulationSpeed * 100.0f);
s32 frameTime = 16683;
s32 t1 = 10000;
@ -1869,7 +1871,7 @@ void CEXISlippi::prepareOpponentInputs(s32 frame, bool shouldSkip)
latestFrame = frame;
latestFrameRead[i] = latestFrame;
appendWordToBuffer(&m_read_queue, static_cast<u32>(latestFrame));
// INFO_LOG(SLIPPI_ONLINE, "Sending frame num %d for pIdx %d (offset: %d)", latestFrame, i,
// INFO_LOG_FMT(SLIPPI_ONLINE, "Sending frame num {} for pIdx {} (offset: {})", latestFrame, i,
// offset[i]);
}
// Send the current frame for any unused player slots.
@ -1900,7 +1902,7 @@ void CEXISlippi::prepareOpponentInputs(s32 frame, bool shouldSkip)
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],
// ERROR_LOG_FMT(SLIPPI_ONLINE, "EXI: [{}] %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]);
}
@ -1939,8 +1941,8 @@ void CEXISlippi::handleCaptureSavestate(u8* payload)
ss->Capture();
activeSavestates[frame] = std::move(ss);
// u32 timeDiff = (u32)(Common::Timer::GetTimeUs() - startTime);
// INFO_LOG(SLIPPI_ONLINE, "SLIPPI ONLINE: Captured savestate for frame %d in: %f ms", frame,
// u32 timeDiff = (u32)(Common::Timer::NowUs() - startTime);
// INFO_LOG_FMT(SLIPPI_ONLINE, "SLIPPI ONLINE: Captured savestate for frame {} in: %f ms", frame,
// ((double)timeDiff) / 1000);
}
@ -1980,8 +1982,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,
// u32 timeDiff = (u32)(Common::Timer::NowUs() - startTime);
// INFO_LOG_FMT(SLIPPI_ONLINE, "SLIPPI ONLINE: Loaded savestate for frame {} in: %f ms", frame,
// ((double)timeDiff) / 1000);
}
@ -2070,7 +2072,7 @@ bool CEXISlippi::doesTagMatchInput(u8* input, u8 inputLen, std::string tag)
bool isMatch = true;
for (int i = 0; i < inputLen; i++)
{
// ERROR_LOG(SLIPPI_ONLINE, "Entered: %X%X. History: %X%X", input[i * 3], input[i * 3 + 1],
// ERROR_LOG_FMT(SLIPPI_ONLINE, "Entered: %X%X. History: %X%X", input[i * 3], input[i * 3 + 1],
// (u8)jisTag[i * 2], (u8)jisTag[i * 2 + 1]);
if (input[i * 3] != (u8)jisTag[i * 2] || input[i * 3 + 1] != (u8)jisTag[i * 2 + 1])
{
@ -2421,7 +2423,7 @@ void CEXISlippi::prepareOnlineMatchState()
// Check if someone is picking dumb characters in non-direct
auto localCharOk = lps.characterId < 26;
auto remoteCharOk = true;
INFO_LOG(SLIPPI_ONLINE, "remotePlayerCount: %d", remotePlayerCount);
INFO_LOG_FMT(SLIPPI_ONLINE, "remotePlayerCount: {}", remotePlayerCount);
for (int i = 0; i < remotePlayerCount; i++)
{
if (rps[i].characterId >= 26)
@ -2497,7 +2499,7 @@ void CEXISlippi::prepareOnlineMatchState()
// Set rng offset
rngOffset = isDecider ? lps.rngOffset : rps[0].rngOffset;
INFO_LOG(SLIPPI_ONLINE, "Rng Offset: 0x%x", rngOffset);
INFO_LOG_FMT(SLIPPI_ONLINE, "Rng Offset: {:#x}", rngOffset);
// Check if everyone is the same color
auto color = orderedSelections[0].teamId;
@ -2726,8 +2728,8 @@ void CEXISlippi::setMatchSelections(u8* payload)
s.stageId = getRandomStage();
}
INFO_LOG(SLIPPI, "LPS set char: %d, iSS: %d, %d, stage: %d, team: %d", s.isCharacterSelected,
stageSelectOption, s.isStageSelected, s.stageId, s.teamId);
INFO_LOG_FMT(SLIPPI, "LPS set char: {}, iSS: {}, {}, stage: {}, team: {}", s.isCharacterSelected,
stageSelectOption, s.isStageSelected, s.stageId, s.teamId);
s.rngOffset = generator() % 0xFFFF;
@ -2749,7 +2751,7 @@ void CEXISlippi::prepareFileLength(u8* payload)
std::string contents;
u32 size = gameFileLoader->LoadFile(fileName, contents);
INFO_LOG(SLIPPI, "Getting file size for: %s -> %d", fileName.c_str(), size);
INFO_LOG_FMT(SLIPPI, "Getting file size for: {} -> {}", fileName.c_str(), size);
// Write size to output
appendWordToBuffer(&m_read_queue, size);
@ -2765,7 +2767,7 @@ void CEXISlippi::prepareFileLoad(u8* payload)
u32 size = gameFileLoader->LoadFile(fileName, contents);
std::vector<u8> buf(contents.begin(), contents.end());
INFO_LOG(SLIPPI, "Writing file contents: %s -> %d", fileName.c_str(), size);
INFO_LOG_FMT(SLIPPI, "Writing file contents: {} -> {}", fileName.c_str(), size);
// Write the contents to output
m_read_queue.insert(m_read_queue.end(), buf.begin(), buf.end());
@ -2777,7 +2779,7 @@ void CEXISlippi::prepareGctLength()
u32 size = Gecko::GetGctLength();
INFO_LOG(SLIPPI, "Getting gct size: %d", size);
INFO_LOG_FMT(SLIPPI, "Getting gct size: {}", size);
// Write size to output
appendWordToBuffer(&m_read_queue, size);
@ -2792,7 +2794,7 @@ void CEXISlippi::prepareGctLoad(u8* payload)
// 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);
INFO_LOG_FMT(SLIPPI, "Preparing to write gecko codes at: {:#x}", address);
m_read_queue.insert(m_read_queue.end(), gct.begin(), gct.end());
}
@ -2883,7 +2885,7 @@ void CEXISlippi::handleChatMessage(u8* payload)
return;
int messageId = payload[0];
INFO_LOG(SLIPPI, "SLIPPI CHAT INPUT: 0x%x", messageId);
INFO_LOG_FMT(SLIPPI, "SLIPPI CHAT INPUT: {:#x}", messageId);
#ifdef LOCAL_TESTING
localChatMessageId = 11;
@ -2902,15 +2904,16 @@ void CEXISlippi::handleChatMessage(u8* payload)
void CEXISlippi::logMessageFromGame(u8* payload)
{
// The first byte indicates whether to log the time or not
if (payload[0] == 0)
{
// The first byte indicates whether to log the time or not
GENERIC_LOG(Common::Log::SLIPPI, (Common::Log::LOG_LEVELS)payload[1], "%s", (char*)&payload[2]);
GENERIC_LOG_FMT(Common::Log::LogType::SLIPPI, (Common::Log::LogLevel)payload[1], "{}",
(char*)&payload[2]);
}
else
{
GENERIC_LOG(Common::Log::SLIPPI, (Common::Log::LOG_LEVELS)payload[1], "%s: %llu",
(char*)&payload[2], Common::Timer::GetTimeUs());
GENERIC_LOG_FMT(Common::Log::LogType::SLIPPI, (Common::Log::LogLevel)payload[1], "{}: {}",
(char*)&payload[2], Common::Timer::NowUs());
}
}
@ -2944,7 +2947,7 @@ void CEXISlippi::prepareOnlineStatus()
{
// Check if we have the latest version, and if not, indicate we need to update
version::Semver200_version latestVersion(userInfo.latest_version);
version::Semver200_version currentVersion(Common::scm_slippi_semver_str);
version::Semver200_version currentVersion(Common::GetSemVerStr());
appState = latestVersion > currentVersion ? 2 : 1;
}
@ -2976,7 +2979,7 @@ void doConnectionCleanup(std::unique_ptr<SlippiMatchmaking> mm,
void CEXISlippi::handleConnectionCleanup()
{
ERROR_LOG(SLIPPI_ONLINE, "Connection cleanup started...");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Connection cleanup started...");
// Handle destructors in a separate thread to not block the main thread
std::thread cleanup(doConnectionCleanup, std::move(matchmaking), std::move(slippi_netplay));
@ -3004,7 +3007,7 @@ void CEXISlippi::handleConnectionCleanup()
isLocalConnected = false;
#endif
ERROR_LOG(SLIPPI_ONLINE, "Connection cleanup completed...");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Connection cleanup completed...");
}
void CEXISlippi::prepareNewSeed()
@ -3022,7 +3025,7 @@ void CEXISlippi::handleReportGame(u8* payload)
SlippiGameReporter::GameReport r;
r.duration_frames = Common::swap32(&payload[0]);
// ERROR_LOG(SLIPPI_ONLINE, "Frames: %d", r.duration_frames);
// ERROR_LOG_FMT(SLIPPI_ONLINE, "Frames: {}", r.duration_frames);
for (auto i = 0; i < 2; ++i)
{
@ -3033,7 +3036,8 @@ void CEXISlippi::handleReportGame(u8* payload)
auto swappedDamageDone = Common::swap32(&payload[6 + offset]);
p.damage_done = *(float*)&swappedDamageDone;
// ERROR_LOG(SLIPPI_ONLINE, "Stocks: %d, DamageDone: %f", p.stocks_remaining, p.damage_done);
// ERROR_LOG_FMT(SLIPPI_ONLINE, "Stocks: {}, DamageDone: %f", p.stocks_remaining,
// p.damage_done);
r.players.push_back(p);
}
@ -3058,14 +3062,19 @@ void CEXISlippi::prepareDelayResponse()
void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
{
u8* memPtr = Memory::GetPointer(_uAddr);
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
u8* memPtr = memory.GetPointer(_uAddr);
u32 bufLoc = 0;
if (memPtr == nullptr)
{
NOTICE_LOG(SLIPPI, "DMA Write was passed an invalid address: %x", _uAddr);
Dolphin_Debugger::PrintCallstack(Common::Log::SLIPPI, Common::Log::LNOTICE);
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard(system);
NOTICE_LOG_FMT(SLIPPI, "DMA Write was passed an invalid address: {:x}", _uAddr);
Dolphin_Debugger::PrintCallstack(system, guard, Common::Log::LogType::SLIPPI,
Common::Log::LogLevel::LNOTICE);
m_read_queue.clear();
return;
}
@ -3089,10 +3098,10 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
g_needInputForFrame = true;
}
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]);
INFO_LOG_FMT(EXPANSIONINTERFACE,
"EXI SLIPPI DMAWrite: addr: {:#x} size: {}, bufLoc:[{} {} {} {} {}]", _uAddr, _uSize,
memPtr[bufLoc], memPtr[bufLoc + 1], memPtr[bufLoc + 2], memPtr[bufLoc + 3],
memPtr[bufLoc + 4]);
while (bufLoc < _uSize)
{
@ -3100,7 +3109,7 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
if (!payloadSizes.count(byte))
{
// This should never happen. Do something else if it does?
WARN_LOG(EXPANSIONINTERFACE, "EXI SLIPPI: Invalid command byte: 0x%x", byte);
WARN_LOG_FMT(EXPANSIONINTERFACE, "EXI SLIPPI: Invalid command byte: {:#x}", byte);
return;
}
@ -3217,19 +3226,21 @@ void CEXISlippi::DMARead(u32 addr, u32 size)
{
if (m_read_queue.empty())
{
ERROR_LOG(SLIPPI, "EXI SLIPPI DMARead: Empty");
ERROR_LOG_FMT(SLIPPI, "EXI SLIPPI DMARead: Empty");
return;
}
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_FMT(EXPANSIONINTERFACE,
"EXI SLIPPI DMARead: addr: {:#x} size: {}, startResp: [{} {} {} {} {}]", addr, size,
queueAddr[0], queueAddr[1], queueAddr[2], queueAddr[3], queueAddr[4]);
// Copy buffer data to memory
Memory::CopyToEmu(addr, queueAddr, size);
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
memory.CopyToEmu(addr, queueAddr, size);
}
bool CEXISlippi::IsPresent() const

View file

@ -4,12 +4,11 @@
#pragma once
#include <SlippiGame.h>
#include "Common/CommonTypes.h"
#include "Common/File.h"
#include "Common/FileUtil.h"
#include "Common/IOFile.h"
#include "Core/Slippi/SlippiDirectCodes.h"
#include "Core/Slippi/SlippiGame.h"
#include "Core/Slippi/SlippiGameFileLoader.h"
#include "Core/Slippi/SlippiGameReporter.h"
#include "Core/Slippi/SlippiMatchmaking.h"
@ -31,7 +30,7 @@ namespace ExpansionInterface
class CEXISlippi : public IEXIDevice
{
public:
CEXISlippi();
CEXISlippi(Core::System& system);
virtual ~CEXISlippi();
void DMAWrite(u32 _uAddr, u32 _uSize) override;

View file

@ -179,7 +179,7 @@ void CameraLogic::Update(const std::array<CameraPoint, NUM_POINTS>& camera_point
break;
default:
// This seems to be fairly common, 0xff data is sent in this case:
// WARN_LOG(WIIMOTE, "Game is requesting IR data before setting IR mode.");
// WARN_LOG_FMT(WIIMOTE, "Game is requesting IR data before setting IR mode.");
break;
}
}

View file

@ -15,8 +15,8 @@
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/Slippi/SlippiSavestate.h"
#include "Core/ConfigManager.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/HW/CPU.h"
#include "Core/HW/GPFifo.h"
#include "Core/HW/MMIO.h"
@ -25,7 +25,7 @@
#include "Core/PowerPC/GDBStub.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/Slippi/SlippiSavestate.h"
#include "Core/System.h"
#include "VideoCommon/VideoBackendBase.h"
@ -533,269 +533,268 @@ u32 HostRead_Instruction(const Core::CPUThreadGuard& guard, const u32 address)
}
// Taken from Ishii. SLIPPITODO: ask jas
//static void Memcheck(u32 address, u32 var, bool write, size_t size)
// static void Memcheck(u32 address, u32 var, bool write, size_t size)
//{
//*********************************************************************
//* How to test memory sections
//*********************************************************************
// 1. Uncomment once of the memory analysis blocks below
// 2. Start the application (release version is fine)
// 3. At a bp somewhere before where you want to start looking for mem access
// 4. Once hit, add a MBP in code section (something that will never get hit)
// and turn off JIT Core
// 5. Start the emulation again and memory accesses should get logged
// 6. Make sure you have logging enabled for MI memmap
//*********************************************************************
//* How to test memory sections
//*********************************************************************
// 1. Uncomment once of the memory analysis blocks below
// 2. Start the application (release version is fine)
// 3. At a bp somewhere before where you want to start looking for mem access
// 4. Once hit, add a MBP in code section (something that will never get hit)
// and turn off JIT Core
// 5. Start the emulation again and memory accesses should get logged
// 6. Make sure you have logging enabled for MI memmap
//*********************************************************************
//* Looking for heap writes?
//*********************************************************************
// if (!write || size != 4)
//{
// return;
// }
//*********************************************************************
//* Looking for heap writes?
//*********************************************************************
// if (!write || size != 4)
//{
// return;
// }
// static u32 heapStart = 0x80bd5c40;
// static u32 heapEnd = 0x811AD5A0;
// static u32 heapStart = 0x80bd5c40;
// static u32 heapEnd = 0x811AD5A0;
// static std::unordered_map<u32, bool> visited;
// static std::unordered_map<u32, bool> visited;
// // If we are writting to somewhere in heap, return
// if (address >= heapStart && address < heapEnd)
// return;
// // If we are writting to somewhere in heap, return
// if (address >= heapStart && address < heapEnd)
// return;
// // If we are not writting a pointer the somewhere in heap, return
// if (var < heapStart || var >= heapEnd)
// return;
// // If we are not writting a pointer the somewhere in heap, return
// if (var < heapStart || var >= heapEnd)
// return;
// if (visited.count(address))
// return;
// if (visited.count(address))
// return;
// visited[address] = true;
// ERROR_LOG(SLIPPI_ONLINE, "%x (%s) %x -> %x", PC, PowerPC::debug_interface.GetDescription(PC).c_str(), address,
// var);
// visited[address] = true;
// ERROR_LOG_FMT(SLIPPI_ONLINE, "%x (%s) %x -> %x", PC,
// PowerPC::debug_interface.GetDescription(PC).c_str(), address, var);
//*********************************************************************
//* Looking for camera player position memory
//*********************************************************************
// static std::unordered_map<u32, bool> visited = {};
// static std::unordered_map<std::string, bool> whitelist = {
// {"PlayerThink_CameraBehavior", true}, // Per-Player update camera position function
// {"CameraFunctionBlrl", true}, // Update camera position
//};
//*********************************************************************
//* Looking for camera player position memory
//*********************************************************************
// static std::unordered_map<u32, bool> visited = {};
// static std::unordered_map<std::string, bool> whitelist = {
// {"PlayerThink_CameraBehavior", true}, // Per-Player update camera position function
// {"CameraFunctionBlrl", true}, // Update camera position
//};
// static std::vector<SlippiSavestate::PreserveBlock> soundStuff = {
//
//};
// static std::vector<SlippiSavestate::PreserveBlock> soundStuff = {
//
//};
// auto sceneController = ReadFromHardware<FLAG_READ, u32>(0x80479d30);
// if ((sceneController & 0xFF0000FF) != 0x08000002)
//{
// return;
//}
// auto isLoading = ReadFromHardware<FLAG_READ, u32>(0x80479d64);
// if (isLoading)
//{
// return;
//}
// if (!write)
//{
// return;
//}
// if (address >= 0x804dec00 && address < 0x804eec00)
//{
// return;
//}
// if (visited.count(address))
//{
// return;
//}
// visited[address] = true;
// for (auto it = soundStuff.begin(); it != soundStuff.end(); ++it)
//{
// if (address >= it->address && address < it->address + it->length)
// {
// return;
// }
//}
// if ((address & 0xFF000000) == 0xcc000000)
//{
// return;
//}
// std::vector<Dolphin_Debugger::CallstackEntry> callstack;
// Dolphin_Debugger::GetCallstack(callstack);
// bool isFound = false;
// for (auto it = callstack.begin(); it != callstack.end(); ++it)
//{
// std::string func = PowerPC::debug_interface.GetDescription(it->vAddress).c_str();
// if (whitelist.count(func))
// {
// isFound = true;
// break;
// }
//}
// if (!isFound)
//{
// return;
//}
// NOTICE_LOG(MEMMAP, "(%s) %x (%s) | %x (%x) <-> %x", write ? "Write" : "Read", PC,
// PowerPC::debug_interface.GetDescription(PC).c_str(), var, size, address);
//*********************************************************************
//* Looking for sound memory
//*********************************************************************
// static std::unordered_map<u32, bool> visited = {};
// static std::unordered_map<std::string, bool> whitelist = {
// {"__AIDHandler", true}, // lol
// {"__AXOutAiCallback", true}, // lol
// {"__AXOutNewFrame", true}, // lol
// {"__AXSyncPBs", true}, // lol
// {"SFX_PlaySFX", true}, // lol
// {"__DSPHandler", true},
//};
// static std::vector<SlippiSavestate::PreserveBlock> soundStuff = {
// {0x804031A0, 0x24}, // [804031A0 - 804031C4)
// {0x80407FB4, 0x34C}, // [80407FB4 - 80408300)
// {0x80433C64, 0x1EE80}, // [80433C64 - 80452AE4)
// {0x804A8D78, 0x17A68}, // [804A8D78 - 804C07E0)
// {0x804C28E0, 0x399C}, // [804C28E0 - 804C627C)
// {0x804D7474, 0x8}, // [804D7474 - 804D747C)
// {0x804D74F0, 0x50}, // [804D74F0 - 804D7540)
// {0x804D7548, 0x4}, // [804D7548 - 804D754C)
// {0x804D7558, 0x24}, // [804D7558 - 804D757C)
// {0x804D7580, 0xC}, // [804D7580 - 804D758C)
// {0x804D759C, 0x4}, // [804D759C - 804D75A0)
// {0x804D7720, 0x4}, // [804D7720 - 804D7724)
// {0x804D7744, 0x4}, // [804D7744 - 804D7748)
// {0x804D774C, 0x8}, // [804D774C - 804D7754)
// {0x804D7758, 0x8}, // [804D7758 - 804D7760)
// {0x804D7788, 0x10}, // [804D7788 - 804D7798)
// {0x804D77C8, 0x4}, // [804D77C8 - 804D77CC)
// {0x804D77D0, 0x4}, // [804D77D0 - 804D77D4)
// {0x804D77E0, 0x4}, // [804D77E0 - 804D77E4)
// {0x804DE358, 0x80}, // [804DE358 - 804DE3D8)
// {0x804DE800, 0x70}, // [804DE800 - 804DE870)
//};
// auto sceneController = ReadFromHardware<FLAG_READ, u32>(0x80479d30);
// if ((sceneController & 0xFF0000FF) != 0x08000002)
//{
// return;
//}
// auto isLoading = ReadFromHardware<FLAG_READ, u32>(0x80479d64);
// if (isLoading)
//{
// return;
//}
// if (address >= 0x804dec00)
//{
// return;
//}
////if (!write)
////{
//// return;
////}
// if (visited.count(address))
//{
// return;
//}
// visited[address] = true;
// for (auto it = soundStuff.begin(); it != soundStuff.end(); ++it)
//{
// if (address >= it->address && address < it->address + it->length)
// {
// return;
// }
//}
// if ((address & 0xFF000000) == 0xcc000000)
//{
// return;
//}
// std::vector<Dolphin_Debugger::CallstackEntry> callstack;
// Dolphin_Debugger::GetCallstack(callstack);
// bool isFound = false;
// for (auto it = callstack.begin(); it != callstack.end(); ++it)
//{
// std::string func = PowerPC::debug_interface.GetDescription(it->vAddress).c_str();
// if (whitelist.count(func))
// {
// isFound = true;
// break;
// }
//}
// if (!isFound)
//{
// return;
//}
// NOTICE_LOG(MEMMAP, "(%s) %x (%s) | %x (%x) <-> %x", write ? "Write" : "Read", PC,
// PowerPC::debug_interface.GetDescription(PC).c_str(), var, size, address);
//*********************************************************************
//* Detect writes in unknown memory region
//*********************************************************************
//static std::unordered_map<u32, bool> visited = {};
//auto sceneController = ReadFromHardware<FLAG_READ, u32>(0x80479d30);
//if ((sceneController & 0xFF0000FF) != 0x08000002)
//{
// return;
//}
//auto isLoading = ReadFromHardware<FLAG_READ, u32>(0x80479d64);
//if (isLoading)
//{
// return;
//}
//if (!write)
//{
// return;
//}
//// [804fec00 - 80BD5C40)
//if (address < 0x8071b000 || address >= 0x80bb0000)
//{
// return;
//}
//if (visited.count(address))
//{
// return;
//}
//visited[address] = true;
//if ((address & 0xFF000000) == 0xcc000000)
//{
// return;
//}
//NOTICE_LOG(MEMMAP, "(%s) %x (%s) | %x (%x) <-> %x", write ? "Write" : "Read", PC,
// PowerPC::debug_interface.GetDescription(PC).c_str(), var, size, address);
// auto sceneController = ReadFromHardware<FLAG_READ, u32>(0x80479d30);
// if ((sceneController & 0xFF0000FF) != 0x08000002)
//{
// return;
//}
// auto isLoading = ReadFromHardware<FLAG_READ, u32>(0x80479d64);
// if (isLoading)
//{
// return;
//}
// if (!write)
//{
// return;
//}
// if (address >= 0x804dec00 && address < 0x804eec00)
//{
// return;
//}
// if (visited.count(address))
//{
// return;
//}
// visited[address] = true;
// for (auto it = soundStuff.begin(); it != soundStuff.end(); ++it)
//{
// if (address >= it->address && address < it->address + it->length)
// {
// return;
// }
//}
// if ((address & 0xFF000000) == 0xcc000000)
//{
// return;
//}
// std::vector<Dolphin_Debugger::CallstackEntry> callstack;
// Dolphin_Debugger::GetCallstack(callstack);
// bool isFound = false;
// for (auto it = callstack.begin(); it != callstack.end(); ++it)
//{
// std::string func = PowerPC::debug_interface.GetDescription(it->vAddress).c_str();
// if (whitelist.count(func))
// {
// isFound = true;
// break;
// }
//}
// if (!isFound)
//{
// return;
//}
// NOTICE_LOG(MEMMAP, "(%s) %x (%s) | %x (%x) <-> %x", write ? "Write" : "Read", PC,
// PowerPC::debug_interface.GetDescription(PC).c_str(), var, size, address);
//*********************************************************************
//* Looking for sound memory
//*********************************************************************
// static std::unordered_map<u32, bool> visited = {};
// static std::unordered_map<std::string, bool> whitelist = {
// {"__AIDHandler", true}, // lol
// {"__AXOutAiCallback", true}, // lol
// {"__AXOutNewFrame", true}, // lol
// {"__AXSyncPBs", true}, // lol
// {"SFX_PlaySFX", true}, // lol
// {"__DSPHandler", true},
//};
// static std::vector<SlippiSavestate::PreserveBlock> soundStuff = {
// {0x804031A0, 0x24}, // [804031A0 - 804031C4)
// {0x80407FB4, 0x34C}, // [80407FB4 - 80408300)
// {0x80433C64, 0x1EE80}, // [80433C64 - 80452AE4)
// {0x804A8D78, 0x17A68}, // [804A8D78 - 804C07E0)
// {0x804C28E0, 0x399C}, // [804C28E0 - 804C627C)
// {0x804D7474, 0x8}, // [804D7474 - 804D747C)
// {0x804D74F0, 0x50}, // [804D74F0 - 804D7540)
// {0x804D7548, 0x4}, // [804D7548 - 804D754C)
// {0x804D7558, 0x24}, // [804D7558 - 804D757C)
// {0x804D7580, 0xC}, // [804D7580 - 804D758C)
// {0x804D759C, 0x4}, // [804D759C - 804D75A0)
// {0x804D7720, 0x4}, // [804D7720 - 804D7724)
// {0x804D7744, 0x4}, // [804D7744 - 804D7748)
// {0x804D774C, 0x8}, // [804D774C - 804D7754)
// {0x804D7758, 0x8}, // [804D7758 - 804D7760)
// {0x804D7788, 0x10}, // [804D7788 - 804D7798)
// {0x804D77C8, 0x4}, // [804D77C8 - 804D77CC)
// {0x804D77D0, 0x4}, // [804D77D0 - 804D77D4)
// {0x804D77E0, 0x4}, // [804D77E0 - 804D77E4)
// {0x804DE358, 0x80}, // [804DE358 - 804DE3D8)
// {0x804DE800, 0x70}, // [804DE800 - 804DE870)
//};
// auto sceneController = ReadFromHardware<FLAG_READ, u32>(0x80479d30);
// if ((sceneController & 0xFF0000FF) != 0x08000002)
//{
// return;
//}
// auto isLoading = ReadFromHardware<FLAG_READ, u32>(0x80479d64);
// if (isLoading)
//{
// return;
//}
// if (address >= 0x804dec00)
//{
// return;
//}
////if (!write)
////{
//// return;
////}
// if (visited.count(address))
//{
// return;
//}
// visited[address] = true;
// for (auto it = soundStuff.begin(); it != soundStuff.end(); ++it)
//{
// if (address >= it->address && address < it->address + it->length)
// {
// return;
// }
//}
// if ((address & 0xFF000000) == 0xcc000000)
//{
// return;
//}
// std::vector<Dolphin_Debugger::CallstackEntry> callstack;
// Dolphin_Debugger::GetCallstack(callstack);
// bool isFound = false;
// for (auto it = callstack.begin(); it != callstack.end(); ++it)
//{
// std::string func = PowerPC::debug_interface.GetDescription(it->vAddress).c_str();
// if (whitelist.count(func))
// {
// isFound = true;
// break;
// }
//}
// if (!isFound)
//{
// return;
//}
// NOTICE_LOG(MEMMAP, "(%s) %x (%s) | %x (%x) <-> %x", write ? "Write" : "Read", PC,
// PowerPC::debug_interface.GetDescription(PC).c_str(), var, size, address);
//*********************************************************************
//* Detect writes in unknown memory region
//*********************************************************************
// static std::unordered_map<u32, bool> visited = {};
// auto sceneController = ReadFromHardware<FLAG_READ, u32>(0x80479d30);
// if ((sceneController & 0xFF0000FF) != 0x08000002)
//{
// return;
// }
// auto isLoading = ReadFromHardware<FLAG_READ, u32>(0x80479d64);
// if (isLoading)
//{
// return;
// }
// if (!write)
//{
// return;
// }
//// [804fec00 - 80BD5C40)
// if (address < 0x8071b000 || address >= 0x80bb0000)
//{
// return;
// }
// if (visited.count(address))
//{
// return;
// }
// visited[address] = true;
// if ((address & 0xFF000000) == 0xcc000000)
//{
// return;
// }
// NOTICE_LOG(MEMMAP, "(%s) %x (%s) | %x (%x) <-> %x", write ? "Write" : "Read", PC,
// PowerPC::debug_interface.GetDescription(PC).c_str(), var, size, address);
//}
static void Memcheck(u32 address, u32 var, bool write, size_t size)
std::optional<ReadResult<u32>> HostTryReadInstruction(const Core::CPUThreadGuard& guard,
const u32 address,
RequestedAddressSpace space)

View file

@ -0,0 +1,23 @@
#pragma once
namespace Melee
{
enum class Version
{
NTSC,
TwentyXX,
UPTM,
MEX,
OTHER,
};
}
namespace Slippi
{
enum class Chat
{
ON,
DIRECT_ONLY,
OFF
};
}

View file

@ -215,7 +215,7 @@ std::vector<SlippiDirectCodes::CodeInfo> SlippiDirectCodes::parseFile(std::strin
// Unlike the user.json, the encapsulating type should be an array.
if (res.is_discarded() || !res.is_array())
{
WARN_LOG(SLIPPI_ONLINE, "Malformed json in direct codes file.");
WARN_LOG_FMT(SLIPPI_ONLINE, "Malformed json in direct codes file.");
return directCodes;
}

View file

@ -4,14 +4,17 @@
#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) {
uint8_t readByte(uint8_t* a, int& idx, uint32_t maxSize, uint8_t defaultValue)
{
if (idx >= (int)maxSize)
{
idx += 1;
return defaultValue;
}
@ -19,9 +22,10 @@ uint8_t readByte(uint8_t *a, int &idx, uint32_t maxSize, uint8_t defaultValue) {
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;
}
@ -31,34 +35,38 @@ uint16_t readHalf(uint8_t *a, int &idx, uint32_t maxSize,
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;
}
uint32_t value =
a[idx] << 24 | a[idx + 1] << 16 | a[idx + 2] << 8 | a[idx + 3];
uint32_t value = a[idx] << 24 | a[idx + 1] << 16 | a[idx + 2] << 8 | a[idx + 3];
idx += 4;
return value;
}
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);
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);
}
@ -67,15 +75,18 @@ void handleGameInit(Game *game, uint32_t maxSize) {
// 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);
}
}
@ -94,32 +105,37 @@ void handleGameInit(Game *game, uint32_t maxSize) {
// Read display name for each player
std::array<std::array<uint8_t, DISPLAY_NAME_SIZE>, 4> playerDisplayNames;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < DISPLAY_NAME_SIZE; j++) {
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < DISPLAY_NAME_SIZE; j++)
{
playerDisplayNames[i][j] = readByte(data, idx, maxSize, 0);
}
}
// Read connectCodes
std::array<std::array<uint8_t, CONNECT_CODE_SIZE>, 4> playerConnectCodes;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < CONNECT_CODE_SIZE; j++) {
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < CONNECT_CODE_SIZE; j++)
{
playerConnectCodes[i][j] = readByte(data, idx, maxSize, 0);
}
}
// 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++) {
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
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;
}
@ -143,12 +159,15 @@ void handleGameInit(Game *game, uint32_t maxSize) {
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
@ -156,16 +175,17 @@ void handleGameInit(Game *game, uint32_t maxSize) {
}
}
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);
game->settings.geckoCodes.insert(game->settings.geckoCodes.end(), data, data + maxSize);
// File is good to load
game->areSettingsLoaded = true;
}
void handleFrameStart(Game *game, uint32_t maxSize) {
void handleFrameStart(Game* game, uint32_t maxSize)
{
int idx = 0;
// Check frame count
@ -173,7 +193,7 @@ void handleFrameStart(Game *game, uint32_t maxSize) {
game->frameCount = frameCount;
auto frameUniquePtr = std::make_unique<FrameData>();
FrameData *frame = frameUniquePtr.get();
FrameData* frame = frameUniquePtr.get();
frame->frame = frameCount;
frame->randomSeedExists = true;
@ -181,12 +201,13 @@ void handleFrameStart(Game *game, uint32_t maxSize) {
// Add frame to game. The frames are stored in multiple ways because
// for games with rollback, the same frame may be replayed multiple times
frame->numSinceStart = game->frames.size();
frame->numSinceStart = static_cast<uint32_t>(game->frames.size());
game->frames.push_back(std::move(frameUniquePtr));
game->framesByIndex[frameCount] = frame;
}
void handlePreFrameUpdate(Game *game, uint32_t maxSize) {
void handlePreFrameUpdate(Game* game, uint32_t maxSize)
{
int idx = 0;
// Check frame count
@ -194,10 +215,11 @@ void handlePreFrameUpdate(Game *game, uint32_t maxSize) {
game->frameCount = frameCount;
auto frameUniquePtr = std::make_unique<FrameData>();
FrameData *frame = frameUniquePtr.get();
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;
@ -232,36 +254,40 @@ void handlePreFrameUpdate(Game *game, uint32_t maxSize) {
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);
}
uint32_t noPercent = 0xFFFFFFFF;
p.percent = readFloat(data, idx, maxSize, *(float *)(&noPercent));
p.percent = readFloat(data, idx, maxSize, *(float*)(&noPercent));
// Add player data to frame
std::unordered_map<uint8_t, PlayerFrameData> *target;
std::unordered_map<uint8_t, PlayerFrameData>* target;
target = isFollower ? &frame->followers : &frame->players;
// Set the player data for the player or follower
target->operator[](playerSlot) = p;
// Add frame to game
if (isNewFrame) {
frame->numSinceStart = game->frames.size();
if (isNewFrame)
{
frame->numSinceStart = static_cast<uint32_t>(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)) {
FrameData* frame = nullptr;
if (game->framesByIndex.count(frameCount))
{
// If this frame already exists, get the current frame
frame = game->frames.back().get();
}
@ -274,35 +300,39 @@ void handlePostFrameUpdate(Game *game, uint32_t maxSize) {
uint8_t playerSlot = readByte(data, idx, maxSize, 0);
uint8_t isFollower = readByte(data, idx, maxSize, 0);
PlayerFrameData *p =
isFollower ? &frame->followers[playerSlot] : &frame->players[playerSlot];
PlayerFrameData* p = isFollower ? &frame->followers[playerSlot] : &frame->players[playerSlot];
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 handleFrameEnd(Game *game, uint32_t maxSize) {
void handleFrameEnd(Game* game, uint32_t maxSize)
{
int idx = 0;
int32_t frameCount = readWord(data, idx, maxSize, 0);
@ -311,23 +341,27 @@ void handleFrameEnd(Game *game, uint32_t maxSize) {
game->lastFinalizedFrame = lastFinalizedFrame;
}
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;
}
@ -338,8 +372,10 @@ int getRawDataPosition(std::ifstream *f) {
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;
}
@ -347,28 +383,28 @@ uint32_t getRawDataLength(std::ifstream *f, int position, int fileSize) {
f->seekg(position - 4, std::ios::beg);
f->read(buffer, 4);
uint8_t *byteBuf = (uint8_t *)&buffer[0];
uint32_t length =
byteBuf[0] << 24 | byteBuf[1] << 16 | byteBuf[2] << 8 | byteBuf[3];
uint8_t* byteBuf = (uint8_t*)&buffer[0];
uint32_t length = byteBuf[0] << 24 | byteBuf[1] << 16 | byteBuf[2] << 8 | byteBuf[3];
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
@ -382,8 +418,10 @@ std::unordered_map<uint8_t, uint32_t> getMessageSizes(std::ifstream *f,
return messageSizes;
}
void SlippiGame::processData() {
if (isProcessingComplete) {
void SlippiGame::processData()
{
if (isProcessingComplete)
{
// If we have finished processing this file, return
return;
}
@ -391,17 +429,20 @@ void SlippiGame::processData() {
// 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);
@ -415,7 +456,8 @@ void SlippiGame::processData() {
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);
@ -433,7 +475,8 @@ void SlippiGame::processData() {
// log << "Size to read: " << sizeToRead << "\n";
// log << "Start Pos: " << startPos << "\n";
// log << "End Pos: " << endPos << "\n\n";
if (sizeToRead <= 0) {
if (sizeToRead <= 0)
{
return;
}
@ -441,7 +484,8 @@ void SlippiGame::processData() {
file->read(&newData[0], sizeToRead);
int newDataPos = 0;
while (newDataPos < sizeToRead) {
while (newDataPos < sizeToRead)
{
auto command = newData[newDataPos];
auto payloadSize = asmEvents[command];
@ -450,32 +494,35 @@ void SlippiGame::processData() {
// 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);
return;
}
data = (uint8_t *)&newData[newDataPos + 1];
data = (uint8_t*)&newData[newDataPos + 1];
uint8_t isSplitComplete = false;
uint32_t outerPayloadSize = payloadSize;
// Handle a split message, combining in until we possess the entire message
if (command == EVENT_SPLIT_MESSAGE) {
if (shouldResetSplitMessageBuf) {
if (command == EVENT_SPLIT_MESSAGE)
{
if (shouldResetSplitMessageBuf)
{
splitMessageBuf.clear();
shouldResetSplitMessageBuf = false;
}
int _ = 0;
uint16_t blockSize =
readHalf(&data[SPLIT_MESSAGE_INTERNAL_DATA_LEN], _, payloadSize, 0);
uint16_t blockSize = readHalf(&data[SPLIT_MESSAGE_INTERNAL_DATA_LEN], _, payloadSize, 0);
splitMessageBuf.insert(splitMessageBuf.end(), data, data + blockSize);
isSplitComplete = data[SPLIT_MESSAGE_INTERNAL_DATA_LEN + 3];
if (isSplitComplete) {
if (isSplitComplete)
{
// Transform this message into a different message
command = data[SPLIT_MESSAGE_INTERNAL_DATA_LEN + 2];
data = &splitMessageBuf[0];
@ -484,7 +531,8 @@ void SlippiGame::processData() {
}
}
switch (command) {
switch (command)
{
case EVENT_GAME_INIT:
handleGameInit(game.get(), payloadSize);
break;
@ -523,24 +571,23 @@ void SlippiGame::processData() {
}
}
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;
#ifdef _WIN32
// On Windows, we need to convert paths to std::wstring to deal with UTF-8
std::wstring convertedPath =
std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(path);
result->file = std::make_unique<std::ifstream>(
convertedPath, std::ios::in | std::ios::binary);
std::wstring convertedPath = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(path);
result->file = std::make_unique<std::ifstream>(convertedPath, std::ios::in | std::ios::binary);
#else
result->file =
std::make_unique<std::ifstream>(path, std::ios::in | std::ios::binary);
result->file = std::make_unique<std::ifstream>(path, std::ios::in | std::ios::binary);
#endif
// result->log.open("log.txt");
if (!result->file->is_open()) {
if (!result->file->is_open())
{
return nullptr;
}
@ -558,59 +605,77 @@ std::unique_ptr<SlippiGame> SlippiGame::FromFile(std::string path) {
return std::move(result);
}
bool SlippiGame::IsProcessingComplete() { return 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 static_cast<bool>(game->framesByIndex.count(frame));
}
std::array<uint8_t, 4> SlippiGame::GetVersion() { return game->version; }
std::array<uint8_t, 4> SlippiGame::GetVersion()
{
return game->version;
}
std::string SlippiGame::GetVersionString() {
std::string SlippiGame::GetVersionString()
{
char version[30];
sprintf(version, "%d.%d.%d", game->version[0], game->version[1],
game->version[2]);
sprintf(version, "%d.%d.%d", game->version[0], game->version[1], game->version[2]);
return std::string(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;
}
// Get the frame we want
return game->frames[pos].get();
}
int32_t SlippiGame::GetLastFinalizedFrame() {
int32_t SlippiGame::GetLastFinalizedFrame()
{
processData();
return game->lastFinalizedFrame;
}
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();
}
uint8_t SlippiGame::GetGameEndMethod() { return game->winCondition; }
} // namespace Slippi
uint8_t SlippiGame::GetGameEndMethod()
{
return game->winCondition;
}
} // namespace Slippi

View file

@ -8,7 +8,8 @@
#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;
@ -31,9 +32,10 @@ const uint8_t GAME_SHEIK_EXTERNAL_ID = 0x13;
const uint32_t SPLIT_MESSAGE_INTERNAL_DATA_LEN = 512;
static uint8_t *data;
static uint8_t* data;
typedef struct {
typedef struct
{
// Every player update has its own rng seed because it might change in between
// players
uint32_t randomSeed;
@ -56,19 +58,20 @@ typedef struct {
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;
@ -78,7 +81,8 @@ typedef struct FrameData {
std::unordered_map<uint8_t, PlayerFrameData> followers;
} FrameData;
typedef struct {
typedef struct
{
// Static data
uint8_t characterId;
uint8_t characterColor;
@ -89,8 +93,9 @@ typedef struct {
std::array<uint8_t, CONNECT_CODE_SIZE> connectCode;
} PlayerSettings;
typedef struct {
uint16_t stage; // Stage ID
typedef struct
{
uint16_t stage; // Stage ID
uint32_t randomSeed;
std::array<uint32_t, GAME_INFO_HEADER_SIZE> header;
std::array<uint32_t, UCF_TOGGLE_SIZE> ucfToggles;
@ -102,14 +107,15 @@ typedef struct {
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::unordered_map<int32_t, FrameData*> framesByIndex;
std::vector<std::unique_ptr<FrameData>> frames;
GameSettings settings;
bool areSettingsLoaded = false;
int32_t frameCount; // Current/last frame count
int32_t frameCount; // Current/last frame count
int32_t lastFinalizedFrame = -124;
// From OnGameEnd event
@ -118,25 +124,25 @@ typedef struct Game {
// 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},
{EVENT_PRE_FRAME_UPDATE, 58},
{EVENT_POST_FRAME_UPDATE, 33},
{EVENT_GAME_END, 1},
{EVENT_FRAME_START, 8}};
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}};
class SlippiGame {
class SlippiGame
{
public:
static std::unique_ptr<SlippiGame> FromFile(std::string path);
bool AreSettingsLoaded();
bool DoesFrameExist(int32_t frame);
std::array<uint8_t, 4> GetVersion();
std::string GetVersionString();
FrameData *GetFrame(int32_t frame);
FrameData *GetFrameAt(uint32_t pos);
FrameData* GetFrame(int32_t frame);
FrameData* GetFrameAt(uint32_t pos);
int32_t GetLastFinalizedFrame();
int32_t GetLatestIndex();
GameSettings *GetSettings();
GameSettings* GetSettings();
uint8_t GetGameEndMethod();
bool DoesPlayerExist(int8_t port);
bool IsProcessingComplete();
@ -153,4 +159,4 @@ private:
bool isProcessingComplete = false;
void processData();
};
} // namespace Slippi
} // namespace Slippi

View file

@ -1,12 +1,13 @@
#include "SlippiGameFileLoader.h"
#include "Common/File.h"
#include "Common/FileUtil.h"
#include "Common/IOFile.h"
#include "Common/Logging/Log.h"
#include "Core/Boot/Boot.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/DVD/DVDThread.h"
#include "Core/System.h"
std::string getFilePath(std::string fileName)
{
@ -36,7 +37,7 @@ u32 SlippiGameFileLoader::LoadFile(std::string fileName, std::string& data)
return (u32)data.size();
}
INFO_LOG(SLIPPI, "Loading file: %s", fileName.c_str());
INFO_LOG_FMT(SLIPPI, "Loading file: {}", fileName.c_str());
std::string gameFilePath = getFilePath(fileName);
if (gameFilePath.empty())
@ -55,14 +56,14 @@ u32 SlippiGameFileLoader::LoadFile(std::string fileName, std::string& data)
Core::GetState() == Core::State::Running)
{
std::vector<u8> buf;
INFO_LOG(SLIPPI, "Will process diff");
DVDThread::ReadFile(fileName, buf);
INFO_LOG_FMT(SLIPPI, "Will process diff");
Core::System::GetInstance().GetDVDThread().ReadFile(fileName, buf);
std::string diffContents = fileContents;
decoder.Decode((char*)buf.data(), buf.size(), diffContents, &fileContents);
}
fileCache[fileName] = fileContents;
data = fileCache[fileName];
INFO_LOG(SLIPPI, "File size: %d", (u32)data.size());
INFO_LOG_FMT(SLIPPI, "File size: {}", (u32)data.size());
return (u32)data.size();
}

View file

@ -116,7 +116,8 @@ void SlippiGameReporter::ReportThreadHandler()
if (res != 0)
{
ERROR_LOG(SLIPPI_ONLINE, "[GameReport] Got error executing request. Err code: %d", res);
ERROR_LOG_FMT(SLIPPI_ONLINE, "[GameReport] Got error executing request. Err code : {}",
static_cast<u8>(res));
}
gameIndex++;

View file

@ -36,10 +36,9 @@ 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::GetSemVerStr().find("dev") == std::string::npos ? MM_HOST_PROD : MM_HOST_DEV;
generator = std::default_random_engine(Common::Timer::GetTimeMs());
generator = std::default_random_engine(Common::Timer::NowMs());
}
SlippiMatchmaking::~SlippiMatchmaking()
@ -367,7 +366,7 @@ void SlippiMatchmaking::startMatchmaking()
if (SConfig::GetInstance().m_slippiForceLanIp)
{
WARN_LOG(SLIPPI_ONLINE, "[Matchmaking] Overwriting LAN IP sent with configured address");
WARN_LOG_FMT(SLIPPI_ONLINE, "[Matchmaking] Overwriting LAN IP sent with configured address");
sprintf(lan_addr, "%s:%d", SConfig::GetInstance().m_slippiLanIp.c_str(), m_hostPort);
}
@ -382,7 +381,7 @@ void SlippiMatchmaking::startMatchmaking()
request["type"] = MmMessageType::CREATE_TICKET;
request["user"] = {{"uid", userInfo.uid}, {"playKey", userInfo.play_key}};
request["search"] = {{"mode", m_searchSettings.mode}, {"connectCode", connectCodeBuf}};
request["appVersion"] = Common::scm_slippi_semver_str;
request["appVersion"] = Common::GetSemVerStr();
request["ipAddressLan"] = lan_addr;
sendMessage(request);

View file

@ -13,11 +13,11 @@
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/NetPlayProto.h"
#include "SlippiGame.h"
#include "SlippiPremadeText.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/VideoConfig.h"
#include <SlippiGame.h>
#include <algorithm>
#include <fstream>
#include <memory>
@ -52,7 +52,7 @@ SlippiNetplayClient::~SlippiNetplayClient()
SLIPPI_NETPLAY = nullptr;
WARN_LOG(SLIPPI_ONLINE, "Netplay client cleanup complete");
WARN_LOG_FMT(SLIPPI_ONLINE, "Netplay client cleanup complete");
}
// called from ---SLIPPI EXI--- thread
@ -98,7 +98,7 @@ SlippiNetplayClient::SlippiNetplayClient(std::vector<std::string> addrs, std::ve
// the NAT on some routers
if (localPort > 0)
{
INFO_LOG(SLIPPI_ONLINE, "Setting up local address");
INFO_LOG_FMT(SLIPPI_ONLINE, "Setting up local address");
localAddrDef.host = ENET_HOST_ANY;
localAddrDef.port = localPort;
@ -129,7 +129,7 @@ SlippiNetplayClient::SlippiNetplayClient(std::vector<std::string> addrs, std::ve
std::stringstream keyStrm;
keyStrm << addr.host << "-" << addr.port;
activeConnections[keyStrm.str()][peer] = true;
INFO_LOG_FMT(SLIPPI_ONLINE, "New connection (constr): {}", keyStrm.str().c_str());
INFO_LOG_FMT(SLIPPI_ONLINE, "New connection (constr): {}", keyStrm.str());
if (peer == nullptr)
{
@ -173,31 +173,32 @@ u8 SlippiNetplayClient::LocalPlayerPort()
// called from ---NETPLAY--- thread
unsigned int SlippiNetplayClient::OnData(sf::Packet& packet, ENetPeer* peer)
{
Netplay::MessageID mid = 0;
if (!(packet >> mid))
u8 message_value = 0;
if (!(packet >> message_value))
{
ERROR_LOG(SLIPPI_ONLINE, "Received empty netplay packet");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received empty netplay packet");
return 0;
}
NetPlay::MessageID mid{message_value};
switch (mid)
{
case Netplay::MessageID::SLIPPI_PAD:
case NetPlay::MessageID::SLIPPI_PAD:
{
// Fetch current time immediately for the most accurate timing calculations
u64 curTime = Common::Timer::GetTimeUs();
u64 curTime = Common::Timer::NowUs();
int32_t frame;
if (!(packet >> frame))
{
ERROR_LOG(SLIPPI_ONLINE, "Netplay packet too small to read frame count");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Netplay packet too small to read frame count");
break;
}
u8 packetPlayerPort;
if (!(packet >> packetPlayerPort))
{
ERROR_LOG(SLIPPI_ONLINE, "Netplay packet too small to read player index");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Netplay packet too small to read player index");
break;
}
u8 pIdx = PlayerIdxFromPort(packetPlayerPort);
@ -318,7 +319,7 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet, ENetPeer* peer)
// Send Ack
sf::Packet spac;
spac << NetPlay::MessageID::SLIPPI_PAD_ACK;
spac << static_cast<u8>(NetPlay::MessageID::SLIPPI_PAD_ACK);
spac << frame;
spac << m_player_idx;
// INFO_LOG_FMT(SLIPPI_ONLINE, "Sending ack packet for frame {} (player {}) to peer at {}:{}",
@ -338,14 +339,14 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet, ENetPeer* peer)
int32_t frame;
if (!(packet >> frame))
{
ERROR_LOG(SLIPPI_ONLINE, "Ack packet too small to read frame");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Ack packet too small to read frame");
break;
}
u8 packetPlayerPort;
if (!(packet >> packetPlayerPort))
{
ERROR_LOG(SLIPPI_ONLINE, "Netplay ack packet too small to read player index");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Netplay ack packet too small to read player index");
break;
}
u8 pIdx = PlayerIdxFromPort(packetPlayerPort);
@ -376,7 +377,7 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet, ENetPeer* peer)
auto sendTime = ackTimers[pIdx].front().timeUs;
ackTimers[pIdx].pop();
pingUs[pIdx] = Common::Timer::GetTimeUs() - sendTime;
pingUs[pIdx] = Common::Timer::NowUs() - sendTime;
if (g_ActiveConfig.bShowNetPlayPing && frame % SLIPPI_PING_DISPLAY_INTERVAL == 0 && pIdx == 0)
{
std::stringstream pingDisplay;
@ -440,7 +441,7 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet, ENetPeer* peer)
break;
default:
WARN_LOG_FMT(SLIPPI_ONLINE, "Unknown message received with id : {}", mid);
WARN_LOG_FMT(SLIPPI_ONLINE, "Unknown message received with id : {}", static_cast<u8>(mid));
break;
}
@ -449,7 +450,7 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet& packet, ENetPeer* peer)
void SlippiNetplayClient::writeToPacket(sf::Packet& packet, SlippiPlayerSelections& s)
{
packet << static_cast<NetPlay::MessageId>(NetPlay::MessageID::SLIPPI_MATCH_SELECTIONS);
packet << static_cast<u8>(NetPlay::MessageID::SLIPPI_MATCH_SELECTIONS);
packet << s.characterId << s.characterColor << s.isCharacterSelected;
packet << s.playerIdx;
packet << s.stageId << s.isStageSelected;
@ -459,7 +460,7 @@ void SlippiNetplayClient::writeToPacket(sf::Packet& packet, SlippiPlayerSelectio
void SlippiNetplayClient::WriteChatMessageToPacket(sf::Packet& packet, int messageId, u8 player_id)
{
packet << static_cast<NetPlay::MessageId>(NetPlay::MessageID::SLIPPI_CHAT_MESSAGE);
packet << static_cast<u8>(NetPlay::MessageID::SLIPPI_CHAT_MESSAGE);
packet << messageId;
packet << player_id;
}
@ -471,13 +472,13 @@ SlippiNetplayClient::ReadChatMessageFromPacket(sf::Packet& packet)
if (!(packet >> s->messageId))
{
ERROR_LOG(SLIPPI_ONLINE, "Chat packet too small to read message ID");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Chat packet too small to read message ID");
s->error = true;
return std::move(s);
}
if (!(packet >> s->playerIdx))
{
ERROR_LOG(SLIPPI_ONLINE, "Chat packet too small to read player index");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Chat packet too small to read player index");
s->error = true;
return std::move(s);
}
@ -524,42 +525,42 @@ SlippiNetplayClient::readSelectionsFromPacket(sf::Packet& packet)
if (!(packet >> s->characterId))
{
ERROR_LOG(SLIPPI_ONLINE, "Received invalid player selection");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received invalid player selection");
s->error = true;
}
if (!(packet >> s->characterColor))
{
ERROR_LOG(SLIPPI_ONLINE, "Received invalid player selection");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received invalid player selection");
s->error = true;
}
if (!(packet >> s->isCharacterSelected))
{
ERROR_LOG(SLIPPI_ONLINE, "Received invalid player selection");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received invalid player selection");
s->error = true;
}
if (!(packet >> s->playerIdx))
{
ERROR_LOG(SLIPPI_ONLINE, "Received invalid player selection");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received invalid player selection");
s->error = true;
}
if (!(packet >> s->stageId))
{
ERROR_LOG(SLIPPI_ONLINE, "Received invalid player selection");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received invalid player selection");
s->error = true;
}
if (!(packet >> s->isStageSelected))
{
ERROR_LOG(SLIPPI_ONLINE, "Received invalid player selection");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received invalid player selection");
s->error = true;
}
if (!(packet >> s->rngOffset))
{
ERROR_LOG(SLIPPI_ONLINE, "Received invalid player selection");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received invalid player selection");
s->error = true;
}
if (!(packet >> s->teamId))
{
ERROR_LOG(SLIPPI_ONLINE, "Received invalid player selection");
ERROR_LOG_FMT(SLIPPI_ONLINE, "Received invalid player selection");
s->error = true;
}
@ -573,7 +574,7 @@ void SlippiNetplayClient::Send(sf::Packet& packet)
for (int i = 0; i < m_server.size(); i++)
{
NetPlay::MessageId mid = ((u8*)packet.getData())[0];
NetPlay::MessageID mid{((u8*)packet.getData())[0]};
if (mid == NetPlay::MessageID::SLIPPI_PAD || mid == NetPlay::MessageID::SLIPPI_PAD_ACK)
{
// Slippi communications do not need reliable connection and do not need to
@ -645,7 +646,7 @@ void SlippiNetplayClient::SendAsync(std::unique_ptr<sf::Packet> packet)
void SlippiNetplayClient::ThreadFunc()
{
// Let client die 1 second before host such that after a swap, the client won't be connected to
u64 startTime = Common::Timer::GetTimeMs();
u64 startTime = Common::Timer::NowMs();
u64 timeout = 8000;
std::vector<bool> connections;
@ -669,7 +670,7 @@ void SlippiNetplayClient::ThreadFunc()
case ENET_EVENT_TYPE_RECEIVE:
if (!netEvent.peer)
{
INFO_LOG(SLIPPI_ONLINE, "[Netplay] got receive event with nil peer");
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] got receive event with nil peer");
continue;
}
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] got receive event with peer addr {}:{}",
@ -684,7 +685,7 @@ void SlippiNetplayClient::ThreadFunc()
case ENET_EVENT_TYPE_DISCONNECT:
if (!netEvent.peer)
{
INFO_LOG(SLIPPI_ONLINE, "[Netplay] got disconnect event with nil peer");
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] got disconnect event with nil peer");
continue;
}
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] got disconnect event with peer addr {}:{}",
@ -695,7 +696,7 @@ void SlippiNetplayClient::ThreadFunc()
{
if (!netEvent.peer)
{
INFO_LOG(SLIPPI_ONLINE, "[Netplay] got connect event with nil peer");
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] got connect event with nil peer");
continue;
}
@ -724,7 +725,7 @@ void SlippiNetplayClient::ThreadFunc()
// Don't add this person again if they are already connected. Not doing this can cause
// one person to take up 2 or more spots, denying one or more players from connecting
// and thus getting stuck on the "Waiting" step
INFO_LOG(SLIPPI_ONLINE, "Already connected!");
INFO_LOG_FMT(SLIPPI_ONLINE, "Already connected!");
break; // Breaks out of case
}
@ -740,14 +741,17 @@ void SlippiNetplayClient::ThreadFunc()
// out of two that are on your LAN, it might report that you failed to connect to the
// wrong person. There might be more problems tho, not sure
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] Comparing connection address: {} - {}",
remoteAddrs[i].host, netEvent.peer->address.host);
static_cast<u32>(remoteAddrs[i].host),
static_cast<u32>(netEvent.peer->address.host));
if (remoteAddrs[i].host == netEvent.peer->address.host && !connections[i])
{
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] Overwriting ENetPeer for address: {}:{}",
netEvent.peer->address.host, netEvent.peer->address.port);
static_cast<u32>(netEvent.peer->address.host),
static_cast<u32>(netEvent.peer->address.port));
INFO_LOG_FMT(SLIPPI_ONLINE,
"[Netplay] Overwriting ENetPeer with id ({}) with new peer of id {}",
m_server[i]->connectID, netEvent.peer->connectID);
static_cast<u32>(m_server[i]->connectID),
static_cast<u32>(netEvent.peer->connectID));
m_server[i] = netEvent.peer;
connections[i] = true;
break;
@ -768,20 +772,21 @@ void SlippiNetplayClient::ThreadFunc()
if (allConnected)
{
m_client->intercept = ENetUtil::InterceptCallback;
INFO_LOG(SLIPPI_ONLINE, "Slippi online connection successful!");
INFO_LOG_FMT(SLIPPI_ONLINE, "Slippi online connection successful!");
slippiConnectStatus = SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED;
break;
}
for (int i = 0; i < m_remotePlayerCount; i++)
{
INFO_LOG_FMT(SLIPPI_ONLINE, "m_client peer {} state: {}", i, m_client->peers[i].state);
INFO_LOG_FMT(SLIPPI_ONLINE, "m_client peer {} state: {}", i,
static_cast<u8>(m_client->peers[i].state));
}
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] Not yet connected. Res: {}, Type: {}", net,
netEvent.type);
static_cast<u8>(netEvent.type));
// Time out after enough time has passed
u64 curTime = Common::Timer::GetTimeMs();
u64 curTime = Common::Timer::NowMs();
if ((curTime - startTime) >= timeout || !m_do_loop.IsSet())
{
for (int i = 0; i < m_remotePlayerCount; i++)
@ -793,7 +798,7 @@ void SlippiNetplayClient::ThreadFunc()
}
slippiConnectStatus = SlippiConnectStatus::NET_CONNECT_STATUS_FAILED;
INFO_LOG(SLIPPI_ONLINE, "Slippi online connection failed");
INFO_LOG_FMT(SLIPPI_ONLINE, "Slippi online connection failed");
return;
}
}
@ -801,8 +806,9 @@ void SlippiNetplayClient::ThreadFunc()
INFO_LOG_FMT(SLIPPI_ONLINE, "Successfully initialized {} connections", m_server.size());
for (int i = 0; i < m_server.size(); i++)
{
INFO_LOG_FMT(SLIPPI_ONLINE, "Connection {}: {}, {}", i, m_server[i]->address.host,
m_server[i]->address.port);
INFO_LOG_FMT(SLIPPI_ONLINE, "Connection {}: {}, {}", i,
static_cast<u32>(m_server[i]->address.host),
static_cast<u16>(m_server[i]->address.port));
}
bool qos_success = false;
@ -906,7 +912,7 @@ void SlippiNetplayClient::ThreadFunc()
// it can be safely ignored
if (isConnectedClient && activeConnections[keyStrm.str()].empty())
{
INFO_LOG(SLIPPI_ONLINE, "[Netplay] Final disconnect received for a client.");
INFO_LOG_FMT(SLIPPI_ONLINE, "[Netplay] Final disconnect received for a client.");
m_do_loop.Clear(); // Stop the loop, will trigger a disconnect
}
break;
@ -974,7 +980,7 @@ void SlippiNetplayClient::StartSlippiGame()
{
FrameTiming timing;
timing.frame = 0;
timing.timeUs = Common::Timer::GetTimeUs();
timing.timeUs = Common::Timer::NowUs();
lastFrameTiming[i] = timing;
lastFrameAcked[i] = 0;
@ -991,7 +997,7 @@ void SlippiNetplayClient::SendConnectionSelected()
{
isConnectionSelected = true;
auto spac = std::make_unique<sf::Packet>();
*spac << static_cast<NetPlay::MessageId>(NetPlay::MessageID::SLIPPI_CONN_SELECTED);
*spac << static_cast<u8>(NetPlay::MessageID::SLIPPI_CONN_SELECTED);
SendAsync(std::move(spac));
}
void SlippiNetplayClient::SendSlippiPad(std::unique_ptr<SlippiPad> pad)
@ -1037,7 +1043,7 @@ void SlippiNetplayClient::SendSlippiPad(std::unique_ptr<SlippiPad> pad)
}
auto frame = localPadQueue.front()->frame;
auto spac = std::make_unique<sf::Packet>();
*spac << static_cast<NetPlay::MessageId>(NetPlay::MessageID::SLIPPI_PAD);
*spac << static_cast<u8>(NetPlay::MessageID::SLIPPI_PAD);
*spac << frame;
*spac << this->m_player_idx;
@ -1045,7 +1051,7 @@ void SlippiNetplayClient::SendSlippiPad(std::unique_ptr<SlippiPad> pad)
spac->append((*it)->padBuf, SLIPPI_PAD_DATA_SIZE); // only transfer 8 bytes per pad
SendAsync(std::move(spac));
u64 time = Common::Timer::GetTimeUs();
u64 time = Common::Timer::NowUs();
hasGameStarted = true;

View file

@ -5,7 +5,9 @@
#include <share.h>
#endif
#include "Common/Config/Config.h"
#include "Common/Logging/Log.h"
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/HW/EXI/EXI_DeviceSlippi.h"
#include "Core/NetPlayClient.h"
@ -37,14 +39,14 @@ s32 emod(s32 a, s32 b)
std::string processDiff(std::vector<u8> iState, std::vector<u8> cState)
{
INFO_LOG(SLIPPI, "Processing diff");
INFO_LOG_FMT(SLIPPI, "Processing diff");
numDiffsProcessing += 1;
cv_processingDiff.notify_one();
std::string diff = std::string();
open_vcdiff::VCDiffEncoder encoder((char*)iState.data(), iState.size());
encoder.Encode((char*)cState.data(), cState.size(), &diff);
INFO_LOG(SLIPPI, "done processing");
INFO_LOG_FMT(SLIPPI, "done processing");
numDiffsProcessing -= 1;
cv_processingDiff.notify_one();
return diff;
@ -75,7 +77,7 @@ void SlippiPlaybackStatus::prepareSlippiPlayback(s32& frameIndex)
// block if there's too many diffs being processed
while (shouldRunThreads && numDiffsProcessing > 2)
{
INFO_LOG(SLIPPI, "Processing too many diffs, blocking main process");
INFO_LOG_FMT(SLIPPI, "Processing too many diffs, blocking main process");
cv_processingDiff.wait(processingLock);
}
@ -86,7 +88,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_FMT(SLIPPI, "Reached frame {}. Target was {}. Unblocking", frameIndex, targetFrameNum);
cv_waitingForTargetFrame.notify_one();
}
}
@ -115,7 +117,7 @@ void SlippiPlaybackStatus::resetPlayback()
void SlippiPlaybackStatus::processInitialState()
{
INFO_LOG(SLIPPI, "saving iState");
INFO_LOG_FMT(SLIPPI, "saving iState");
State::SaveToBuffer(iState);
// The initial save to cState causes a stutter of about 5-10 frames
// Doing it here to get it out of the way and prevent stutters later
@ -123,7 +125,7 @@ void SlippiPlaybackStatus::processInitialState()
State::SaveToBuffer(cState);
if (SConfig::GetInstance().m_slippiEnableSeek)
{
SConfig::GetInstance().bHideCursor = false;
Config::SetCurrent(Config::MAIN_SHOW_CURSOR, Config::ShowCursor::Constantly);
}
};
@ -132,7 +134,7 @@ void SlippiPlaybackStatus::SavestateThread()
Common::SetCurrentThreadName("Savestate thread");
std::unique_lock<std::mutex> intervalLock(mtx);
INFO_LOG(SLIPPI, "Entering savestate thread");
INFO_LOG_FMT(SLIPPI, "Entering savestate thread");
while (shouldRunThreads)
{
@ -159,7 +161,7 @@ void SlippiPlaybackStatus::SavestateThread()
}
else if (SConfig::GetInstance().m_slippiEnableSeek && !hasStateBeenProcessed && !isStartFrame)
{
INFO_LOG(SLIPPI, "saving diff at frame: %d", fixedFrameNumber);
INFO_LOG_FMT(SLIPPI, "saving diff at frame: {}", fixedFrameNumber);
State::SaveToBuffer(cState);
futureDiffs[fixedFrameNumber] = std::async(processDiff, iState, cState);
@ -167,7 +169,7 @@ void SlippiPlaybackStatus::SavestateThread()
Common::SleepCurrentThread(SLEEP_TIME_MS);
}
INFO_LOG(SLIPPI, "Exiting savestate thread");
INFO_LOG_FMT(SLIPPI, "Exiting savestate thread");
}
void SlippiPlaybackStatus::seekToFrame()
@ -251,7 +253,7 @@ void SlippiPlaybackStatus::seekToFrame()
}
else
{
INFO_LOG(SLIPPI, "Already seeking. Ignoring this call");
INFO_LOG_FMT(SLIPPI, "Already seeking. Ignoring this call");
}
}

View file

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

View file

@ -98,7 +98,7 @@ public:
va_start(args, textId);
vsprintf(str, format.c_str(), args);
va_end(args);
// INFO_LOG(SLIPPI, "%s", str);
// INFO_LOG_FMT(SLIPPI, "%s", str);
std::vector<u8> data = {};
std::vector<u8> empty = {};
@ -222,7 +222,7 @@ public:
u16 sht = static_cast<u16>((TEXT_OP_CODE::COMMON_CHARACTER << 8) | pos);
u8 r = static_cast<u8>(sht >> 8);
u8 r2 = static_cast<u8>(sht & 0xFF);
// INFO_LOG(SLIPPI, "%x %x %x %c", sht, r, r2, chr);
// INFO_LOG_FMT(SLIPPI, "%x %x %x %c", sht, r, r2, chr);
data.push_back(r);
data.push_back(r2);

View file

@ -31,8 +31,8 @@ static inline void trim(std::string& s)
SlippiReplayComm::SlippiReplayComm()
{
INFO_LOG(EXPANSIONINTERFACE, "SlippiReplayComm: Using playback config path: %s",
SConfig::GetInstance().m_strSlippiInput.c_str());
INFO_LOG_FMT(EXPANSIONINTERFACE, "SlippiReplayComm: Using playback config path: {}",
SConfig::GetInstance().m_strSlippiInput.c_str());
configFilePath = SConfig::GetInstance().m_strSlippiInput.c_str();
}
@ -96,7 +96,7 @@ void SlippiReplayComm::nextReplay()
std::unique_ptr<Slippi::SlippiGame> SlippiReplayComm::loadGame()
{
auto replayFilePath = getReplayPath();
INFO_LOG(EXPANSIONINTERFACE, "Attempting to load replay file %s", replayFilePath.c_str());
INFO_LOG_FMT(EXPANSIONINTERFACE, "Attempting to load replay file {}", replayFilePath.c_str());
auto result = Slippi::SlippiGame::FromFile(replayFilePath);
if (result)
{
@ -147,7 +147,7 @@ void SlippiReplayComm::loadFile()
return;
}
WARN_LOG(EXPANSIONINTERFACE, "File change detected in comm file: %s", configFilePath.c_str());
WARN_LOG_FMT(EXPANSIONINTERFACE, "File change detected in comm file: {}", configFilePath.c_str());
configLastLoadModTime = modTime;
// TODO: Maybe load file in a more intelligent way to save
@ -179,7 +179,7 @@ void SlippiReplayComm::loadFile()
}
else
{
WARN_LOG(EXPANSIONINTERFACE, "Comm file load error detected. Check file format");
WARN_LOG_FMT(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?

View file

@ -1,6 +1,5 @@
#pragma once
#include <SlippiGame.h>
#include <limits.h>
#include <nlohmann/json.hpp>
#include <queue>
@ -8,6 +7,8 @@
#include <Common/CommonTypes.h>
#include "SlippiGame.h"
using json = nlohmann::json;
class SlippiReplayComm

View file

@ -2,6 +2,7 @@
#include <vector>
#include "Common/CommonFuncs.h"
#include "Common/MemoryUtil.h"
#include "Core/Core.h"
#include "Core/HW/AudioInterface.h"
#include "Core/HW/DSP.h"
#include "Core/HW/DVD/DVDInterface.h"
@ -13,6 +14,7 @@
#include "Core/HW/SI/SI.h"
#include "Core/HW/VideoInterface.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
bool SlippiSavestate::shouldForceInit;
@ -108,11 +110,13 @@ void SlippiSavestate::initBackupLocs()
return;
}
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard(Core::System::GetInstance());
// Get Main Heap Boundaries
fullBackupRegions[3].startAddress = PowerPC::HostRead_U32(0x804d76b8);
fullBackupRegions[3].endAddress = PowerPC::HostRead_U32(0x804d76bc);
WARN_LOG(SLIPPI_ONLINE, "Heap start is: 0x%X", fullBackupRegions[3].startAddress);
WARN_LOG(SLIPPI_ONLINE, "Heap end is: 0x%X", fullBackupRegions[3].endAddress);
fullBackupRegions[3].startAddress = PowerPC::HostRead_U32(guard, 0x804d76b8);
fullBackupRegions[3].endAddress = PowerPC::HostRead_U32(guard, 0x804d76bc);
WARN_LOG_FMT(SLIPPI_ONLINE, "Heap start is: {:#x}", fullBackupRegions[3].startAddress);
WARN_LOG_FMT(SLIPPI_ONLINE, "Heap end is: {:#x}", fullBackupRegions[3].endAddress);
// Sort exclude sections
std::sort(excludeSections.begin(), excludeSections.end(), cmpFn);
@ -194,7 +198,7 @@ void SlippiSavestate::getDolphinState(PointerWrap& p)
// p.DoMarker("DVDInterface");
// GPFifo::DoState(p);
// p.DoMarker("GPFifo");
ExpansionInterface::DoState(p);
Core::System::GetInstance().GetExpansionInterface().DoState(p);
p.DoMarker("ExpansionInterface");
// AudioInterface::DoState(p);
// p.DoMarker("AudioInterface");
@ -206,7 +210,7 @@ void SlippiSavestate::Capture()
for (auto it = backupLocs.begin(); it != backupLocs.end(); ++it)
{
auto size = it->endAddress - it->startAddress;
Memory::CopyFromEmu(it->data, it->startAddress, size);
Core::System::GetInstance().GetMemory().CopyFromEmu(it->data, it->startAddress, size);
}
//// Second copy dolphin states
@ -228,6 +232,7 @@ void SlippiSavestate::Load(std::vector<PreserveBlock> blocks)
// {
// blocks.push_back(*it);
// }
auto& memory = Core::System::GetInstance().GetMemory();
// Back up
for (auto it = blocks.begin(); it != blocks.end(); ++it)
@ -238,14 +243,14 @@ void SlippiSavestate::Load(std::vector<PreserveBlock> blocks)
preservationMap[*it] = std::vector<u8>(it->length);
}
Memory::CopyFromEmu(&preservationMap[*it][0], it->address, it->length);
memory.CopyFromEmu(&preservationMap[*it][0], it->address, it->length);
}
// Restore memory blocks
for (auto it = backupLocs.begin(); it != backupLocs.end(); ++it)
{
auto size = it->endAddress - it->startAddress;
Memory::CopyToEmu(it->startAddress, it->data, size);
memory.CopyToEmu(it->startAddress, it->data, size);
}
//// Restore audio
@ -256,6 +261,6 @@ void SlippiSavestate::Load(std::vector<PreserveBlock> blocks)
// Restore
for (auto it = blocks.begin(); it != blocks.end(); ++it)
{
Memory::CopyToEmu(it->address, &preservationMap[*it][0], it->length);
memory.CopyToEmu(it->address, &preservationMap[*it][0], it->length);
}
}

View file

@ -253,7 +253,7 @@ void SlippiSpectateServer::handleMessage(u8* buffer, u32 length, u16 peer_id)
json reply;
reply["type"] = "connect_reply";
reply["nick"] = "Slippi Online";
reply["version"] = Common::scm_slippi_semver_str;
reply["version"] = Common::GetSemVerStr();
reply["cursor"] = sent_cursor;
std::string packet_buffer = reply.dump();
@ -273,7 +273,7 @@ void SlippiSpectateServer::SlippicommSocketThread(void)
{
if (enet_initialize() != 0)
{
WARN_LOG(SLIPPI, "An error occurred while initializing spectator server.");
WARN_LOG_FMT(SLIPPI, "An error occurred while initializing spectator server.");
return;
}
@ -297,7 +297,7 @@ void SlippiSpectateServer::SlippicommSocketThread(void)
if (server == nullptr)
{
WARN_LOG(SLIPPI, "Could not create spectator server");
WARN_LOG_FMT(SLIPPI, "Could not create spectator server");
enet_deinitialize();
return;
}
@ -332,8 +332,8 @@ void SlippiSpectateServer::SlippicommSocketThread(void)
{
case ENET_EVENT_TYPE_CONNECT:
{
INFO_LOG(SLIPPI, "A new spectator connected from %x:%u.\n", event.peer->address.host,
event.peer->address.port);
INFO_LOG_FMT(SLIPPI, "A new spectator connected from {:x}:{}.\n", event.peer->address.host,
event.peer->address.port);
std::shared_ptr<SlippiSocket> newSlippiSocket(new SlippiSocket());
newSlippiSocket->m_peer = event.peer;
@ -351,8 +351,8 @@ void SlippiSpectateServer::SlippicommSocketThread(void)
}
case ENET_EVENT_TYPE_DISCONNECT:
{
INFO_LOG(SLIPPI, "A spectator disconnected from %x:%u.\n", event.peer->address.host,
event.peer->address.port);
INFO_LOG_FMT(SLIPPI, "A spectator disconnected from {:x}:{}.\n", event.peer->address.host,
event.peer->address.port);
// Delete the item in the m_sockets map
m_sockets.erase(event.peer->incomingPeerID);
@ -362,7 +362,7 @@ void SlippiSpectateServer::SlippicommSocketThread(void)
}
default:
{
INFO_LOG(SLIPPI, "Spectator sent an unknown ENet event type");
INFO_LOG_FMT(SLIPPI, "Spectator sent an unknown ENet event type");
break;
}
}

View file

@ -7,7 +7,9 @@
#include <enet/enet.h>
#include "Common/SPSCQueue.h"
#pragma warning(push, 0)
#include "nlohmann/json.hpp"
#pragma warning(pop)
using json = nlohmann::json;
// Sockets in windows are unsigned

View file

@ -58,7 +58,7 @@ static void RunSystemCommand(const std::string& command)
static 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);
INFO_LOG_FMT(SLIPPI_ONLINE, "[User] Received data: {}", len);
std::string* buf = (std::string*)rcvBuf;
@ -106,7 +106,7 @@ bool SlippiUser::AttemptLogin()
{
std::string user_file_path = getUserFilePath();
// INFO_LOG(SLIPPI_ONLINE, "Looking for file at: %s", user_file_path.c_str());
// INFO_LOG_FMT(SLIPPI_ONLINE, "Looking for file at: {}", user_file_path);
{
// Put the filename here in its own scope because we don't really need it elsewhere
@ -116,14 +116,15 @@ bool SlippiUser::AttemptLogin()
// If both files exist we just log they exist and take no further action
if (File::Exists(user_file_path))
{
INFO_LOG(SLIPPI_ONLINE, "Found both .json.txt and .json file for user data. Using .json "
"and ignoring the .json.txt");
INFO_LOG_FMT(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(user_file_path_txt, user_file_path))
{
WARN_LOG(SLIPPI_ONLINE, "Could not move file %s to %s", user_file_path_txt.c_str(),
user_file_path.c_str());
WARN_LOG_FMT(SLIPPI_ONLINE, "Could not move file {} to {}", user_file_path_txt,
user_file_path);
}
}
}
@ -138,8 +139,7 @@ bool SlippiUser::AttemptLogin()
if (m_is_logged_in)
{
overwriteFromServer();
WARN_LOG(SLIPPI_ONLINE, "Found user %s (%s)", m_user_info.display_name.c_str(),
m_user_info.uid.c_str());
WARN_LOG_FMT(SLIPPI_ONLINE, "Found user {} ({})", m_user_info.display_name, m_user_info.uid);
}
return m_is_logged_in;
@ -158,14 +158,14 @@ void SlippiUser::OpenLogInPage()
#endif
#ifndef __APPLE__
char* escaped_path = curl_easy_escape(nullptr, path.c_str(), (int)path.length());
char* escaped_path = curl_easy_escape(nullptr, path.c_str(), static_cast<int>(path.length()));
path = std::string(escaped_path);
curl_free(escaped_path);
#endif
std::string full_url = url + "?path=" + path;
INFO_LOG(SLIPPI_ONLINE, "[User] Login at path: %s", full_url.c_str());
INFO_LOG_FMT(SLIPPI_ONLINE, "[User] Login at path: {}", full_url);
#ifdef _WIN32
std::string command = "explorer \"" + full_url + "\"";
@ -181,23 +181,24 @@ void SlippiUser::OpenLogInPage()
void SlippiUser::UpdateApp()
{
#if defined(__APPLE__) || defined(_WIN32)
CriticalAlertT("Dolphin auto updates are not available on standalone builds. Migrate to "
"the Slippi Launcher at your earliest convenience");
CriticalAlertFmtT("Dolphin auto updates are not available on standalone builds. Migrate to "
"the Slippi Launcher at your earliest convenience");
return;
#else
const char* appimage_path = getenv("APPIMAGE");
const char* appmount_path = getenv("APPDIR");
if (!appimage_path)
{
CriticalAlertT("Automatic updates are not available for non-AppImage Linux builds.");
CriticalAlertFmtT("Automatic updates are not available for non-AppImage Linux builds.");
return;
}
std::string path(appimage_path);
std::string mount_path(appmount_path);
std::string command = mount_path + "/usr/bin/appimageupdatetool " + path;
WARN_LOG(SLIPPI, "Executing app update command: %s", command.c_str());
WARN_LOG_FMT(SLIPPI, "Executing app update command: {}", command);
RunSystemCommand(command);
CriticalAlertT("Dolphin failed to update, please head over to the Slippi Discord for support.");
CriticalAlertFmtT(
"Dolphin failed to update, please head over to the Slippi Discord for support.");
return;
#endif
}
@ -317,7 +318,8 @@ void SlippiUser::overwriteFromServer()
if (res != 0)
{
ERROR_LOG(SLIPPI, "[User] Error fetching user info from server, code: %d", res);
ERROR_LOG_FMT(SLIPPI, "[User] Error fetching user info from server, code: {}",
static_cast<u8>(res));
return;
}
@ -325,7 +327,7 @@ void SlippiUser::overwriteFromServer()
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code != 200)
{
ERROR_LOG(SLIPPI, "[User] Server responded with non-success status: %d", response_code);
ERROR_LOG_FMT(SLIPPI, "[User] Server responded with non-success status: {}", response_code);
return;
}

View file

@ -20,10 +20,13 @@ endif()
set_target_properties(dolphin-nogui PROPERTIES OUTPUT_NAME dolphin-emu-nogui)
target_link_libraries(dolphin-nogui
PUBLIC
z
PRIVATE
core
uicommon
cpp-optparse
ZLIB::ZLIB
)
if(MSVC)

View file

@ -28,9 +28,9 @@
#include "Core/HotkeyManager.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/USB/Bluetooth/BTBase.h"
#include "Core/IOS/USB/Bluetooth/BTReal.h"
#include "Core/Slippi/SlippiNetplay.h"
#include "Core/Slippi/SlippiPlayback.h"
#include "Core/IOS/USB/Bluetooth/BTReal.h"
#include "Core/State.h"
#include "Core/System.h"
#include "Core/WiiUtils.h"
@ -560,7 +560,7 @@ void HotkeyScheduler::Run()
// Slippi Playback
if (IsHotkey(HK_SLIPPI_JUMP_BACK))
{
INFO_LOG(SLIPPI, "jump back");
INFO_LOG_FMT(SLIPPI, "jump back");
if (g_playbackStatus->targetFrameNum == INT_MAX)
{
g_playbackStatus->targetFrameNum = g_playbackStatus->currentPlaybackFrame - 1200;
@ -570,7 +570,7 @@ void HotkeyScheduler::Run()
if (IsHotkey(HK_SLIPPI_STEP_BACK))
{
INFO_LOG(SLIPPI, "step back");
INFO_LOG_FMT(SLIPPI, "step back");
if (g_playbackStatus->targetFrameNum == INT_MAX)
{
g_playbackStatus->targetFrameNum = g_playbackStatus->currentPlaybackFrame - 300;
@ -580,7 +580,7 @@ void HotkeyScheduler::Run()
if (IsHotkey(HK_SLIPPI_STEP_FORWARD))
{
INFO_LOG(SLIPPI, "step forward");
INFO_LOG_FMT(SLIPPI, "step forward");
if (g_playbackStatus->targetFrameNum == INT_MAX)
{
g_playbackStatus->targetFrameNum = g_playbackStatus->currentPlaybackFrame + 300;
@ -590,7 +590,7 @@ void HotkeyScheduler::Run()
if (IsHotkey(HK_SLIPPI_JUMP_FORWARD))
{
INFO_LOG(SLIPPI, "jump forward");
INFO_LOG_FMT(SLIPPI, "jump forward");
if (g_playbackStatus->targetFrameNum == INT_MAX)
{
g_playbackStatus->targetFrameNum = g_playbackStatus->currentPlaybackFrame + 1200;

View file

@ -27,8 +27,8 @@
#include "Core/Boot/Boot.h"
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/Slippi/SlippiSpectate.h"
#include "Core/DolphinAnalytics.h"
#include "Core/Slippi/SlippiSpectate.h"
#include "DolphinQt/Host.h"
#include "DolphinQt/MainWindow.h"
@ -261,10 +261,12 @@ int main(int argc, char* argv[])
else
{
#ifndef IS_PLAYBACK
if (Settings::Instance().IsBootDefaultISO() && !Settings::Instance().GetDefaultGame().isEmpty())
if (!Config::Get(Config::MAIN_DEFAULT_ISO).empty() &&
!Settings::Instance().GetDefaultGame().isEmpty())
{
boot = BootParameters::GenerateFromFile(Settings::Instance().GetDefaultGame().toStdString(),
save_state_path);
boot = BootParameters::GenerateFromFile(
Settings::Instance().GetDefaultGame().toStdString(),
BootSessionData(save_state_path, DeleteSavestateAfterBoot::No));
}
#endif

View file

@ -715,11 +715,6 @@ void Settings::SetSlippiSeekbarEnabled(bool enabled)
SConfig::GetInstance().m_slippiEnableSeek = enabled;
}
bool Settings::IsBootDefaultISO() const
{
return SConfig::GetInstance().bBootDefaultISO;
}
bool Settings::IsSDCardInserted() const
{
return Config::Get(Config::MAIN_WII_SD_CARD);

View file

@ -103,7 +103,6 @@ public:
void SetSDCardInserted(bool inserted);
bool IsUSBKeyboardConnected() const;
void SetUSBKeyboardConnected(bool connected);
bool IsBootDefaultISO() const;
// Graphics
void SetCursorVisibility(Config::ShowCursor hideCursor);

View file

@ -211,11 +211,13 @@ void GeneralPane::CreateAnalytics()
void GeneralPane::LoadConfig()
{
m_checkbox_dualcore->setChecked(SConfig::GetInstance().bCPUThread);
m_checkbox_cheats->setChecked(Settings::Instance().GetCheatsEnabled());
m_checkbox_default_boot_iso->setChecked(SConfig::GetInstance().bBootDefaultISO);
m_checkbox_override_region_settings->setChecked(SConfig::GetInstance().bOverrideRegionSettings);
m_checkbox_auto_disc_change->setChecked(Config::Get(Config::MAIN_AUTO_DISC_CHANGE));
const QSignalBlocker blocker(this);
SignalBlocking(m_checkbox_dualcore)->setChecked(Config::Get(Config::MAIN_CPU_THREAD));
SignalBlocking(m_checkbox_cheats)->setChecked(Settings::Instance().GetCheatsEnabled());
SignalBlocking(m_checkbox_override_region_settings)
->setChecked(Config::Get(Config::MAIN_OVERRIDE_REGION_SETTINGS));
SignalBlocking(m_checkbox_auto_disc_change)
->setChecked(Config::Get(Config::MAIN_AUTO_DISC_CHANGE));
#ifdef USE_DISCORD_PRESENCE
SignalBlocking(m_checkbox_discord_presence)
->setChecked(Config::Get(Config::MAIN_USE_DISCORD_PRESENCE));
@ -278,14 +280,10 @@ void GeneralPane::OnSaveConfig()
#endif
Config::SetBaseOrCurrent(Config::MAIN_CPU_THREAD, m_checkbox_dualcore->isChecked());
Settings::Instance().SetCheatsEnabled(m_checkbox_cheats->isChecked());
settings.bBootDefaultISO = m_checkbox_default_boot_iso->isChecked();
settings.bOverrideRegionSettings = m_checkbox_override_region_settings->isChecked();
Config::SetBaseOrCurrent(Config::MAIN_OVERRIDE_REGION_SETTINGS,
m_checkbox_override_region_settings->isChecked());
Config::SetBase(Config::MAIN_AUTO_DISC_CHANGE, m_checkbox_auto_disc_change->isChecked());
Config::SetBaseOrCurrent(Config::MAIN_ENABLE_CHEATS, m_checkbox_cheats->isChecked());
if (!IsOnline())
settings.m_EmulationSpeed = m_combobox_speedlimit->currentIndex() * 0.1f;
Settings::Instance().SetFallbackRegion(
UpdateFallbackRegionFromIndex(m_combobox_fallback_region->currentIndex()));

View file

@ -92,7 +92,8 @@ void SlippiPane::CreateLayout()
[](int index) {
SConfig::GetInstance().m_slippiEnableQuickChat = static_cast<Slippi::Chat>(index);
});
netplay_quick_chat_combo->setCurrentIndex(SConfig::GetInstance().m_slippiEnableQuickChat);
netplay_quick_chat_combo->setCurrentIndex(
static_cast<u32>(SConfig::GetInstance().m_slippiEnableQuickChat));
online_settings_layout->addRow(tr("Quick Chat:"), netplay_quick_chat_combo);

View file

@ -187,15 +187,13 @@ static std::string GetTimeForFrame(s32 currFrame)
bool show_help = false;
bool show_settings = false;
u32 idle_tick = Common::Timer::GetTimeMs();
u32 idle_tick = Common::Timer::NowMs();
ImVec2 prev_mouse(0, 0);
bool ButtonCustom(
const char* label,
const ImVec2& size_arg,
ImU32 fill = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImU32 hover_fill = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImGuiButtonFlags flags = 0)
bool ButtonCustom(const char* label, const ImVec2& size_arg,
ImU32 fill = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImU32 hover_fill = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImGuiButtonFlags flags = 0)
{
// ImGui::GetWindowDrawList()->AddRectFilled(
// ImGui::GetCurrentWindow()->DC.CursorPos,
@ -358,10 +356,10 @@ bool SeekBarBehavior(const ImRect& bb, ImGuiID id, int* v, int v_min, int v_max,
else
isHeld = hovered && isDown;
float new_grab_t = ImGui::SliderCalcRatioFromValueT<int, float>(
ImGuiDataType_S32, new_value, v_min, v_max, power, linear_zero_pos);
float curr_grab_t = ImGui::SliderCalcRatioFromValueT<int, float>(ImGuiDataType_S32, *v, v_min,
v_max, power, linear_zero_pos);
float new_grab_t = ImGui::ScaleRatioFromValueT<int, float>(ImGuiDataType_S32, new_value, v_min,
v_max, power, linear_zero_pos);
float curr_grab_t = ImGui::ScaleRatioFromValueT<int, float>(ImGuiDataType_S32, *v, v_min, v_max,
power, linear_zero_pos);
if (axis == ImGuiAxis_Y)
{
@ -513,8 +511,8 @@ bool VolumeBarBehavior(const ImRect& bb, ImGuiID id, int* v, int v_min, int v_ma
isHeld = isHeld ? isHeld && isDown : hovered && isDown;
float grab_t = ImGui::SliderCalcRatioFromValueT<int, float>(ImGuiDataType_S32, *v, v_min, v_max,
power, linear_zero_pos);
float grab_t = ImGui::ScaleRatioFromValueT<int, float>(ImGuiDataType_S32, *v, v_min, v_max, power,
linear_zero_pos);
if (axis == ImGuiAxis_Y)
{
grab_t = 1.0f - grab_t;
@ -595,7 +593,7 @@ void DrawSlippiPlaybackControls()
auto mousePos = ImGui::GetMousePos();
auto currTime = Common::Timer::GetTimeMs();
auto currTime = Common::Timer::NowMs();
if (!(mousePos[0] == prev_mouse[0] && mousePos[1] == prev_mouse[1]))
{
idle_tick = currTime;
@ -640,7 +638,7 @@ void DrawSlippiPlaybackControls()
ImGui::SetCursorPos(ImVec2(0.0f, height - scaled_height * 0.0265f));
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.5f, 0.45f));
// if (ButtonCustom(paused ? ICON_FA_PLAY : ICON_FA_PAUSE, ImVec2(40.0f, BUTTON_WIDTH))) {
// INFO_LOG(SLIPPI, "playing");
// INFO_LOG_FMT(SLIPPI, "playing");
//}
// ImGui::SameLine(0.0f, 5.0f);
if (ButtonCustom(ICON_FA_FAST_BACKWARD, ImVec2(BUTTON_WIDTH, BUTTON_WIDTH)))
@ -757,39 +755,39 @@ void DrawSlippiPlaybackControls()
if (show_help)
{
ImGui::GetWindowDrawList()->AddRectFilled(
ImVec2(width - BUTTON_WIDTH * 10.0f, height - scaled_height * 0.21f),
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.8f * style.Alpha)));
ImVec2(width - BUTTON_WIDTH * 10.0f, height - scaled_height * 0.21f),
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.8f * style.Alpha)));
auto divide =
(height - scaled_height * 0.2f - LABEL_BOX_BOTTOM - 0.01f * scaled_height) / 7.0f;
(height - scaled_height * 0.2f - LABEL_BOX_BOTTOM - 0.01f * scaled_height) / 7.0f;
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 10.0f + scaled_height * 0.005f,
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 7.0f));
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 7.0f));
ImGui::Text("Play/Pause: Spacebar");
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 10.0f + scaled_height * 0.005f,
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 6.0f));
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 6.0f));
ImGui::Text("Step Back (5s): Left Arrow");
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 10.0f + scaled_height * 0.005f,
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 5.0f));
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 5.0f));
ImGui::Text("Step Forward (5s): Right Arrow");
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 10.0f + scaled_height * 0.005f,
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 4.0f));
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 4.0f));
ImGui::Text("Jump Back (20s): Shift + Left Arrow");
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 10.0f + scaled_height * 0.005f,
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 3.0f));
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 3.0f));
ImGui::Text("Jump Forward (20s): Shift + Right Arrow");
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 10.0f + scaled_height * 0.005f,
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 2.0f));
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide * 2.0f));
ImGui::Text("Frame Advance: Period");
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 10.0f + scaled_height * 0.005f,
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide));
LABEL_BOX_BOTTOM + 0.005f * scaled_height + divide));
ImGui::Text("Big jumps may take several seconds.");
}
if (ImGui::IsItemHovered() && !show_help)
{
ImGui::GetWindowDrawList()->AddRectFilled(
ImVec2(width - scaled_height * 0.095f, LABEL_BOX_TOP),
ImVec2(width - (scaled_height * 0.005f + BUTTON_WIDTH), LABEL_BOX_BOTTOM),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.9f)));
ImVec2(width - scaled_height * 0.095f, LABEL_BOX_TOP),
ImVec2(width - (scaled_height * 0.005f + BUTTON_WIDTH), LABEL_BOX_BOTTOM),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.9f)));
ImGui::SetCursorPos(ImVec2(width - (scaled_height * 0.09f), LABEL_TEXT_HEIGHT));
ImGui::Text("View Help");
}
@ -803,7 +801,7 @@ void DrawSlippiPlaybackControls()
}
if (show_settings)
{
//bool show_speed_options = false;
// bool show_speed_options = false;
auto option_height = (scaled_height * 0.05f) / 2.0f;
ImGui::GetWindowDrawList()->AddRectFilled(
@ -811,47 +809,45 @@ void DrawSlippiPlaybackControls()
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.8f * style.Alpha)));
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 5.0f + 0.005 * scaled_height, LABEL_BOX_BOTTOM - option_height * 4.0f + 0.005 * scaled_height));
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 5.0f + 0.005 * scaled_height,
LABEL_BOX_BOTTOM - option_height * 4.0f + 0.005 * scaled_height));
ImGui::Text("Playback Speed");
auto quarter_speed = ImRect(
ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 3.0f),
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM - option_height * 2.0));
auto half_speed = ImRect(
ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 2.0f),
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM - option_height));
auto normal_speed = ImRect(
ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height),
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM));
auto quarter_speed =
ImRect(ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 3.0f),
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM - option_height * 2.0));
auto half_speed =
ImRect(ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 2.0f),
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM - option_height));
auto normal_speed =
ImRect(ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height),
ImVec2(width - BUTTON_WIDTH, LABEL_BOX_BOTTOM));
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 3.0f));
ImGui::SetCursorPos(
ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 3.0f));
if (ButtonCustom(
"0.25",
ImVec2(quarter_speed.GetWidth(), quarter_speed.GetHeight()),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImGui::ColorConvertFloat4ToU32(ImVec4(255.0f, 255.0f, 255.0f, 0.3f * style.Alpha))
))
"0.25", ImVec2(quarter_speed.GetWidth(), quarter_speed.GetHeight()),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImGui::ColorConvertFloat4ToU32(ImVec4(255.0f, 255.0f, 255.0f, 0.3f * style.Alpha))))
{
SConfig::GetInstance().m_EmulationSpeed = 0.25f;
}
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 2.0f));
ImGui::SetCursorPos(
ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 2.0f));
if (ButtonCustom(
"0.5",
ImVec2(half_speed.GetWidth(), half_speed.GetHeight()),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImGui::ColorConvertFloat4ToU32(ImVec4(255.0f, 255.0f, 255.0f, 0.3f * style.Alpha))
))
"0.5", ImVec2(half_speed.GetWidth(), half_speed.GetHeight()),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImGui::ColorConvertFloat4ToU32(ImVec4(255.0f, 255.0f, 255.0f, 0.3f * style.Alpha))))
{
SConfig::GetInstance().m_EmulationSpeed = 0.5f;
}
ImGui::SetCursorPos(ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 1.0f));
ImGui::SetCursorPos(
ImVec2(width - BUTTON_WIDTH * 5.0f, LABEL_BOX_BOTTOM - option_height * 1.0f));
if (ButtonCustom(
"Normal",
ImVec2(normal_speed.GetWidth(), normal_speed.GetHeight()),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImGui::ColorConvertFloat4ToU32(ImVec4(255.0f, 255.0f, 255.0f, 0.3f * style.Alpha))
))
"Normal", ImVec2(normal_speed.GetWidth(), normal_speed.GetHeight()),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.0f)),
ImGui::ColorConvertFloat4ToU32(ImVec4(255.0f, 255.0f, 255.0f, 0.3f * style.Alpha))))
{
SConfig::GetInstance().m_EmulationSpeed = 1.0f;
}
@ -859,9 +855,9 @@ void DrawSlippiPlaybackControls()
if (ImGui::IsItemHovered() && !show_settings)
{
ImGui::GetWindowDrawList()->AddRectFilled(
ImVec2(width - scaled_height * 0.087f, LABEL_BOX_TOP),
ImVec2(width - (scaled_height * 0.005f + BUTTON_WIDTH), LABEL_BOX_BOTTOM),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.9f)));
ImVec2(width - scaled_height * 0.087f, LABEL_BOX_TOP),
ImVec2(width - (scaled_height * 0.005f + BUTTON_WIDTH), LABEL_BOX_BOTTOM),
ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.9f)));
ImGui::SetCursorPos(ImVec2(width - (scaled_height * 0.082f), LABEL_TEXT_HEIGHT));
ImGui::Text("Settings");
}