mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-04-27 04:21:47 +00:00
Rewrite ringprofiles format
This commit is contained in:
parent
e3d0ec0a62
commit
7b40b4c8c6
2 changed files with 256 additions and 180 deletions
|
|
@ -10,6 +10,11 @@
|
||||||
/// \file k_profiles.c
|
/// \file k_profiles.c
|
||||||
/// \brief implements methods for profiles etc.
|
/// \brief implements methods for profiles etc.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include "io/streams.hpp"
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
#include "d_main.h" // pandf
|
#include "d_main.h" // pandf
|
||||||
#include "byteptr.h" // READ/WRITE macros
|
#include "byteptr.h" // READ/WRITE macros
|
||||||
|
|
@ -236,10 +241,10 @@ void PR_InitNewProfile(void)
|
||||||
|
|
||||||
void PR_SaveProfiles(void)
|
void PR_SaveProfiles(void)
|
||||||
{
|
{
|
||||||
size_t length = 0;
|
namespace fs = std::filesystem;
|
||||||
const size_t headerlen = strlen(PROFILEHEADER);
|
using json = nlohmann::json;
|
||||||
UINT8 i, j, k;
|
using namespace srb2;
|
||||||
savebuffer_t save = {0};
|
namespace io = srb2::io;
|
||||||
|
|
||||||
if (profilesList[PROFILE_GUEST] == NULL)
|
if (profilesList[PROFILE_GUEST] == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -247,65 +252,94 @@ void PR_SaveProfiles(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (P_SaveBufferAlloc(&save, sizeof(UINT32) + (numprofiles * sizeof(profile_t))) == false)
|
ProfilesJson ng{};
|
||||||
|
|
||||||
|
for (size_t i = 1; i < numprofiles; i++)
|
||||||
{
|
{
|
||||||
I_Error("No more free memory for saving profiles\n");
|
ProfileJson jsonprof;
|
||||||
return;
|
profile_t* cprof = profilesList[i];
|
||||||
}
|
|
||||||
|
|
||||||
// Add header.
|
jsonprof.version = PROFILEVER;
|
||||||
WRITESTRINGN(save.p, PROFILEHEADER, headerlen);
|
jsonprof.profilename = std::string(cprof->profilename);
|
||||||
WRITEUINT8(save.p, PROFILEVER);
|
std::copy(std::begin(cprof->public_key), std::end(cprof->public_key), std::begin(jsonprof.publickey));
|
||||||
WRITEUINT8(save.p, numprofiles);
|
std::copy(std::begin(cprof->secret_key), std::end(cprof->secret_key), std::begin(jsonprof.secretkey));
|
||||||
|
jsonprof.playername = std::string(cprof->playername);
|
||||||
for (i = 1; i < numprofiles; i++)
|
jsonprof.skinname = std::string(cprof->skinname);
|
||||||
{
|
jsonprof.colorname = std::string(skincolors[cprof->color].name);
|
||||||
// Names and keys, all the string data up front
|
jsonprof.followername = std::string(cprof->follower);
|
||||||
WRITESTRINGN(save.p, profilesList[i]->profilename, PROFILENAMELEN);
|
if (cprof->followercolor == FOLLOWERCOLOR_MATCH)
|
||||||
WRITEMEM(save.p, profilesList[i]->public_key, sizeof(((profile_t *)0)->public_key));
|
|
||||||
WRITEMEM(save.p, profilesList[i]->secret_key, sizeof(((profile_t *)0)->secret_key));
|
|
||||||
WRITESTRINGN(save.p, profilesList[i]->playername, MAXPLAYERNAME);
|
|
||||||
|
|
||||||
// Character and colour.
|
|
||||||
WRITESTRINGN(save.p, profilesList[i]->skinname, SKINNAMESIZE);
|
|
||||||
WRITEUINT16(save.p, profilesList[i]->color);
|
|
||||||
|
|
||||||
// Follower and colour.
|
|
||||||
WRITESTRINGN(save.p, profilesList[i]->follower, SKINNAMESIZE);
|
|
||||||
WRITEUINT16(save.p, profilesList[i]->followercolor);
|
|
||||||
|
|
||||||
WRITEUINT32(save.p, profilesList[i]->wins);
|
|
||||||
|
|
||||||
// Consvars.
|
|
||||||
WRITEUINT8(save.p, profilesList[i]->kickstartaccel);
|
|
||||||
WRITEUINT8(save.p, profilesList[i]->autoroulette);
|
|
||||||
WRITEUINT8(save.p, profilesList[i]->litesteer);
|
|
||||||
WRITEUINT8(save.p, profilesList[i]->rumble);
|
|
||||||
|
|
||||||
// Controls.
|
|
||||||
for (j = 0; j < num_gamecontrols; j++)
|
|
||||||
{
|
{
|
||||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
jsonprof.followercolorname = "Match";
|
||||||
|
}
|
||||||
|
else if (cprof->followercolor == FOLLOWERCOLOR_OPPOSITE)
|
||||||
|
{
|
||||||
|
jsonprof.followercolorname = "Opposite";
|
||||||
|
}
|
||||||
|
else if (cprof->followercolor == SKINCOLOR_NONE)
|
||||||
|
{
|
||||||
|
jsonprof.followercolorname = "Default";
|
||||||
|
}
|
||||||
|
else if (cprof->followercolor >= numskincolors)
|
||||||
|
{
|
||||||
|
jsonprof.followercolorname = std::string();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jsonprof.followercolorname = std::string(skincolors[cprof->followercolor].name);
|
||||||
|
}
|
||||||
|
jsonprof.records.wins = cprof->wins;
|
||||||
|
jsonprof.preferences.kickstartaccel = cprof->kickstartaccel;
|
||||||
|
jsonprof.preferences.autoroulette = cprof->autoroulette;
|
||||||
|
jsonprof.preferences.litesteer = cprof->litesteer;
|
||||||
|
jsonprof.preferences.rumble = cprof->rumble;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < num_gamecontrols; j++)
|
||||||
|
{
|
||||||
|
for (size_t k = 0; k < MAXINPUTMAPPING; k++)
|
||||||
{
|
{
|
||||||
WRITEINT32(save.p, profilesList[i]->controls[j][k]);
|
jsonprof.controls[j][k] = cprof->controls[j][k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ng.profiles.emplace_back(std::move(jsonprof));
|
||||||
}
|
}
|
||||||
|
|
||||||
length = save.p - save.buffer;
|
std::vector<uint8_t> ubjson = json::to_ubjson(ng);
|
||||||
|
|
||||||
if (!FIL_WriteFile(va(pandf, srb2home, PROFILESFILE), save.buffer, length))
|
std::string realpath = fmt::format("{}/{}", srb2home, PROFILESFILE);
|
||||||
|
std::string tmppath = fmt::format("{}.tmp", realpath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
io::FileStream file {tmppath, io::FileStreamMode::kWrite};
|
||||||
|
io::BufferedOutputStream<io::FileStream> bos {std::move(file)};
|
||||||
|
|
||||||
|
io::write(static_cast<uint32_t>(0x52494E47), bos, io::Endian::kBE); // "RING"
|
||||||
|
io::write(static_cast<uint32_t>(0x5052464C), bos, io::Endian::kBE); // "PRFL"
|
||||||
|
io::write(static_cast<uint8_t>(0), bos); // reserved1
|
||||||
|
io::write(static_cast<uint8_t>(0), bos); // reserved2
|
||||||
|
io::write(static_cast<uint8_t>(0), bos); // reserved3
|
||||||
|
io::write(static_cast<uint8_t>(0), bos); // reserved4
|
||||||
|
io::write_exact(bos, tcb::as_bytes(tcb::make_span(ubjson)));
|
||||||
|
bos.flush();
|
||||||
|
file = bos.stream();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
fs::rename(tmppath, realpath);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
{
|
{
|
||||||
P_SaveBufferFree(&save);
|
|
||||||
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?");
|
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?");
|
||||||
}
|
}
|
||||||
P_SaveBufferFree(&save);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PR_LoadProfiles(void)
|
void PR_LoadProfiles(void)
|
||||||
{
|
{
|
||||||
const size_t headerlen = strlen(PROFILEHEADER);
|
namespace fs = std::filesystem;
|
||||||
UINT8 i, j, k, version;
|
using namespace srb2;
|
||||||
|
namespace io = srb2::io;
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
profile_t *dprofile = PR_MakeProfile(
|
profile_t *dprofile = PR_MakeProfile(
|
||||||
PROFILEDEFAULTNAME,
|
PROFILEDEFAULTNAME,
|
||||||
PROFILEDEFAULTPNAME,
|
PROFILEDEFAULTPNAME,
|
||||||
|
|
@ -314,166 +348,132 @@ void PR_LoadProfiles(void)
|
||||||
gamecontroldefault,
|
gamecontroldefault,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
savebuffer_t save = {0};
|
|
||||||
|
|
||||||
if (P_SaveBufferFromFile(&save, va(pandf, srb2home, PROFILESFILE)) == false)
|
std::string datapath {fmt::format("{}/{}", srb2home, PROFILESFILE)};
|
||||||
|
|
||||||
|
io::BufferedInputStream<io::FileStream> bis;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
io::FileStream file {datapath, io::FileStreamMode::kRead};
|
||||||
|
bis = io::BufferedInputStream(std::move(file));
|
||||||
|
}
|
||||||
|
catch (const io::FileStreamException& ex)
|
||||||
{
|
{
|
||||||
// No profiles. Add the default one.
|
|
||||||
PR_AddProfile(dprofile);
|
PR_AddProfile(dprofile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(PROFILEHEADER, (const char *)save.buffer, headerlen))
|
ProfilesJson js;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
const char *gdfolder = "the Ring Racers folder";
|
uint32_t magic1;
|
||||||
if (strcmp(srb2home,"."))
|
uint32_t magic2;
|
||||||
gdfolder = srb2home;
|
uint8_t reserved1;
|
||||||
|
uint8_t reserved2;
|
||||||
|
uint8_t reserved3;
|
||||||
|
uint8_t reserved4;
|
||||||
|
magic1 = io::read_uint32(bis, io::Endian::kBE);
|
||||||
|
magic2 = io::read_uint32(bis, io::Endian::kBE);
|
||||||
|
reserved1 = io::read_uint8(bis);
|
||||||
|
reserved2 = io::read_uint8(bis);
|
||||||
|
reserved3 = io::read_uint8(bis);
|
||||||
|
reserved4 = io::read_uint8(bis);
|
||||||
|
|
||||||
P_SaveBufferFree(&save);
|
if (magic1 != 0x52494E47 || magic2 != 0x5052464C || reserved1 != 0 || reserved2 != 0 || reserved3 != 0 || reserved4 != 0)
|
||||||
I_Error("Not a valid Profile file.\nDelete %s (maybe in %s) and try again.", PROFILESFILE, gdfolder);
|
{
|
||||||
}
|
throw std::domain_error("Header is incompatible");
|
||||||
save.p += headerlen;
|
}
|
||||||
|
|
||||||
version = READUINT8(save.p);
|
std::vector<std::byte> remainder = io::read_to_vec(bis);
|
||||||
if (version > PROFILEVER)
|
// safety: std::byte repr is always uint8_t 1-byte aligned
|
||||||
{
|
tcb::span<uint8_t> remainder_as_u8 = tcb::span((uint8_t*)remainder.data(), remainder.size());
|
||||||
P_SaveBufferFree(&save);
|
json parsed = json::from_ubjson(remainder_as_u8);
|
||||||
I_Error("Existing %s is from the future! (expected %d, got %d)", PROFILESFILE, PROFILEVER, version);
|
js = parsed.template get<ProfilesJson>();
|
||||||
}
|
}
|
||||||
else if (version < PROFILEVER)
|
catch (...)
|
||||||
{
|
{
|
||||||
// We're converting - let'd create a backup.
|
I_Error("Profiles file is corrupt");
|
||||||
FIL_WriteFile(va("%s" PATHSEP "%s.bak", srb2home, PROFILESFILE), save.buffer, save.size);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
numprofiles = READUINT8(save.p);
|
numprofiles = js.profiles.size() + 1; // 1 for guest
|
||||||
if (numprofiles > MAXPROFILES)
|
if (numprofiles > MAXPROFILES+1)
|
||||||
numprofiles = MAXPROFILES;
|
|
||||||
|
|
||||||
for (i = 1; i < numprofiles; i++)
|
|
||||||
{
|
{
|
||||||
profilesList[i] = static_cast<profile_t*>(Z_Calloc(sizeof(profile_t), PU_STATIC, NULL));
|
numprofiles = MAXPROFILES+1;
|
||||||
|
}
|
||||||
|
|
||||||
// Version. (We always update this on successful forward step)
|
for (size_t i = 1; i < numprofiles; i++)
|
||||||
profilesList[i]->version = PROFILEVER;
|
{
|
||||||
|
auto& jsprof = js.profiles[i - 1];
|
||||||
|
profile_t* newprof = static_cast<profile_t*>(Z_Calloc(sizeof(profile_t), PU_STATIC, NULL));
|
||||||
|
profilesList[i] = newprof;
|
||||||
|
|
||||||
// Names and keys, all the identity stuff up front
|
newprof->version = jsprof.version;
|
||||||
READSTRINGN(save.p, profilesList[i]->profilename, PROFILENAMELEN);
|
strlcpy(newprof->profilename, jsprof.profilename.c_str(), sizeof(newprof->profilename));
|
||||||
|
memcpy(newprof->public_key, jsprof.publickey.data(), sizeof(newprof->public_key));
|
||||||
|
memcpy(newprof->secret_key, jsprof.secretkey.data(), sizeof(newprof->secret_key));
|
||||||
|
|
||||||
// Profile update 2-->3: Add profile keys.
|
strlcpy(newprof->playername, jsprof.playername.c_str(), sizeof(newprof->playername));
|
||||||
if (version < 3)
|
strlcpy(newprof->skinname, jsprof.skinname.c_str(), sizeof(newprof->skinname));
|
||||||
|
newprof->color = PROFILEDEFAULTCOLOR;
|
||||||
|
for (size_t c = 0; c < numskincolors; c++)
|
||||||
{
|
{
|
||||||
// Generate missing keys.
|
if (jsprof.colorname == skincolors[c].name && K_ColorUsable(static_cast<skincolornum_t>(c), false, false))
|
||||||
PR_GenerateProfileKeys(profilesList[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
READMEM(save.p, profilesList[i]->public_key, sizeof(((profile_t *)0)->public_key));
|
|
||||||
READMEM(save.p, profilesList[i]->secret_key, sizeof(((profile_t *)0)->secret_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
READSTRINGN(save.p, profilesList[i]->playername, MAXPLAYERNAME);
|
|
||||||
|
|
||||||
// Character and colour.
|
|
||||||
READSTRINGN(save.p, profilesList[i]->skinname, SKINNAMESIZE);
|
|
||||||
profilesList[i]->color = READUINT16(save.p);
|
|
||||||
|
|
||||||
if (profilesList[i]->color == SKINCOLOR_NONE)
|
|
||||||
{
|
|
||||||
; // Valid, even outside the bounds
|
|
||||||
}
|
|
||||||
else if (profilesList[i]->color >= numskincolors
|
|
||||||
|| K_ColorUsable(static_cast<skincolornum_t>(profilesList[i]->color), false, false) == false)
|
|
||||||
{
|
|
||||||
profilesList[i]->color = PROFILEDEFAULTCOLOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Follower and colour.
|
|
||||||
READSTRINGN(save.p, profilesList[i]->follower, SKINNAMESIZE);
|
|
||||||
profilesList[i]->followercolor = READUINT16(save.p);
|
|
||||||
|
|
||||||
if (profilesList[i]->followercolor == FOLLOWERCOLOR_MATCH
|
|
||||||
|| profilesList[i]->followercolor == FOLLOWERCOLOR_OPPOSITE
|
|
||||||
|| profilesList[i]->followercolor == SKINCOLOR_NONE)
|
|
||||||
{
|
|
||||||
; // Valid, even outside the bounds
|
|
||||||
}
|
|
||||||
else if (profilesList[i]->followercolor >= numskincolors
|
|
||||||
|| K_ColorUsable(static_cast<skincolornum_t>(profilesList[i]->followercolor), true, false) == false)
|
|
||||||
{
|
|
||||||
profilesList[i]->followercolor = PROFILEDEFAULTFOLLOWERCOLOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Profile update 5-->6: PWR isn't in profile data anymore.
|
|
||||||
if (version < 6)
|
|
||||||
{
|
|
||||||
save.p += PWRLV_NUMTYPES*2;
|
|
||||||
profilesList[i]->wins = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
profilesList[i]->wins = READUINT32(save.p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consvars.
|
|
||||||
profilesList[i]->kickstartaccel = (boolean)READUINT8(save.p);
|
|
||||||
|
|
||||||
// 6->7, add autoroulette
|
|
||||||
if (version < 7)
|
|
||||||
{
|
|
||||||
profilesList[i]->autoroulette = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
profilesList[i]->autoroulette = (boolean)READUINT8(save.p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7->8, add litesteer
|
|
||||||
if (version < 8)
|
|
||||||
{
|
|
||||||
profilesList[i]->litesteer = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
profilesList[i]->litesteer = (boolean)READUINT8(save.p);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 4)
|
|
||||||
{
|
|
||||||
profilesList[i]->rumble = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
profilesList[i]->rumble = (boolean)READUINT8(save.p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Controls.
|
|
||||||
for (j = 0; j < num_gamecontrols; j++)
|
|
||||||
{
|
|
||||||
#ifdef DEVELOP
|
|
||||||
// Profile update 1-->2: Add gc_rankings.
|
|
||||||
// Profile update 4-->5: Add gc_startlossless.
|
|
||||||
if ((j == gc_rankings && version < 2) ||
|
|
||||||
(j == gc_startlossless && version < 5))
|
|
||||||
{
|
{
|
||||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
newprof->color = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(newprof->follower, jsprof.followername.c_str(), sizeof(newprof->follower));
|
||||||
|
newprof->followercolor = PROFILEDEFAULTFOLLOWERCOLOR;
|
||||||
|
if (jsprof.followercolorname == "Match")
|
||||||
|
{
|
||||||
|
newprof->followercolor = FOLLOWERCOLOR_MATCH;
|
||||||
|
}
|
||||||
|
else if (jsprof.followercolorname == "Opposite")
|
||||||
|
{
|
||||||
|
newprof->followercolor = FOLLOWERCOLOR_OPPOSITE;
|
||||||
|
}
|
||||||
|
else if (jsprof.followercolorname == "Default")
|
||||||
|
{
|
||||||
|
newprof->followercolor = SKINCOLOR_NONE;
|
||||||
|
}
|
||||||
|
else if (!jsprof.followercolorname.empty())
|
||||||
|
{
|
||||||
|
for (size_t c = 0; c < numskincolors; c++)
|
||||||
|
{
|
||||||
|
if (jsprof.followercolorname == skincolors[c].name && K_ColorUsable(static_cast<skincolornum_t>(c), false, false))
|
||||||
{
|
{
|
||||||
profilesList[i]->controls[j][k] = gamecontroldefault[j][k];
|
newprof->followercolor = c;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
newprof->wins = jsprof.records.wins;
|
||||||
|
newprof->kickstartaccel = jsprof.preferences.kickstartaccel;
|
||||||
|
newprof->autoroulette = jsprof.preferences.autoroulette;
|
||||||
|
newprof->litesteer = jsprof.preferences.litesteer;
|
||||||
|
newprof->rumble = jsprof.preferences.rumble;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < num_gamecontrols; j++)
|
||||||
{
|
{
|
||||||
profilesList[i]->controls[j][k] = READINT32(save.p);
|
for (size_t k = 0; k < MAXINPUTMAPPING; k++)
|
||||||
|
{
|
||||||
|
newprof->controls[j][k] = jsprof.controls.at(j).at(k);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (const std::out_of_range& ex)
|
||||||
|
{
|
||||||
|
I_Error("Profile '%s' controls are corrupt", jsprof.playername.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the the default profile directly to avoid letting anyone tamper with it.
|
|
||||||
profilesList[PROFILE_GUEST] = dprofile;
|
profilesList[PROFILE_GUEST] = dprofile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,82 @@
|
||||||
#include "k_follower.h" // followers
|
#include "k_follower.h" // followers
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
namespace srb2
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ProfileRecordsJson
|
||||||
|
{
|
||||||
|
uint32_t wins;
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfileRecordsJson, wins)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProfilePreferencesJson
|
||||||
|
{
|
||||||
|
bool kickstartaccel;
|
||||||
|
bool autoroulette;
|
||||||
|
bool litesteer;
|
||||||
|
bool rumble;
|
||||||
|
tm test;
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||||
|
ProfilePreferencesJson,
|
||||||
|
kickstartaccel,
|
||||||
|
autoroulette,
|
||||||
|
litesteer,
|
||||||
|
rumble
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProfileJson
|
||||||
|
{
|
||||||
|
uint32_t version;
|
||||||
|
std::string profilename;
|
||||||
|
std::string playername;
|
||||||
|
std::array<uint8_t, 32> publickey = {{}};
|
||||||
|
std::array<uint8_t, 64> secretkey = {{}};
|
||||||
|
std::string skinname;
|
||||||
|
std::string colorname;
|
||||||
|
std::string followername;
|
||||||
|
std::string followercolorname;
|
||||||
|
ProfileRecordsJson records;
|
||||||
|
ProfilePreferencesJson preferences;
|
||||||
|
std::array<std::array<int32_t, MAXINPUTMAPPING>, gamecontrols_e::num_gamecontrols> controls = {{{{}}}};
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||||
|
ProfileJson,
|
||||||
|
version,
|
||||||
|
profilename,
|
||||||
|
playername,
|
||||||
|
publickey,
|
||||||
|
secretkey,
|
||||||
|
skinname,
|
||||||
|
colorname,
|
||||||
|
followername,
|
||||||
|
followercolorname,
|
||||||
|
records,
|
||||||
|
preferences,
|
||||||
|
controls
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProfilesJson
|
||||||
|
{
|
||||||
|
std::vector<ProfileJson> profiles;
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfilesJson, profiles)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace srb2
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -31,7 +107,7 @@ extern "C" {
|
||||||
#define SKINNAMESIZE 16
|
#define SKINNAMESIZE 16
|
||||||
|
|
||||||
#define PROFILENAMELEN 6
|
#define PROFILENAMELEN 6
|
||||||
#define PROFILEVER 8
|
#define PROFILEVER 1
|
||||||
#define MAXPROFILES 16
|
#define MAXPROFILES 16
|
||||||
#define PROFILESFILE "ringprofiles.prf"
|
#define PROFILESFILE "ringprofiles.prf"
|
||||||
#define PROFILE_GUEST 0
|
#define PROFILE_GUEST 0
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue