mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Rewrite replay standings extrainfo
This commit is contained in:
parent
995af69eab
commit
32715fbe66
3 changed files with 200 additions and 62 deletions
201
src/g_demo.cpp
201
src/g_demo.cpp
|
|
@ -12,6 +12,10 @@
|
||||||
/// \brief Demo recording and playback
|
/// \brief Demo recording and playback
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <tcb/span.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "doomdef.h"
|
#include "doomdef.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
|
@ -158,6 +162,7 @@ static ticcmd_t oldcmd[MAXPLAYERS];
|
||||||
|
|
||||||
// Below consts are only used for demo extrainfo sections
|
// Below consts are only used for demo extrainfo sections
|
||||||
#define DW_STANDING 0x00
|
#define DW_STANDING 0x00
|
||||||
|
#define DW_STANDING2 0x01
|
||||||
|
|
||||||
// For time attack ghosts
|
// For time attack ghosts
|
||||||
#define GZT_XYZ 0x01
|
#define GZT_XYZ 0x01
|
||||||
|
|
@ -2326,36 +2331,26 @@ void G_BeginRecording(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT16 color, UINT32 val)
|
void srb2::write_current_demo_standings(const srb2::StandingsJson& standings)
|
||||||
{
|
{
|
||||||
char temp[16];
|
using namespace srb2;
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
if (demoinfo_p && *(UINT32 *)demoinfo_p == 0)
|
// TODO populate standings data
|
||||||
{
|
|
||||||
WRITEUINT8(demobuf.p, DEMOMARKER); // add the demo end marker
|
|
||||||
*(UINT32 *)demoinfo_p = demobuf.p - demobuf.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
WRITEUINT8(demobuf.p, DW_STANDING);
|
std::vector<uint8_t> ubjson = json::to_ubjson(standings);
|
||||||
WRITEUINT8(demobuf.p, ranking);
|
uint32_t bytes = ubjson.size();
|
||||||
|
|
||||||
// Name
|
WRITEUINT8(demobuf.p, DW_STANDING2);
|
||||||
memset(temp, 0, 16);
|
|
||||||
strncpy(temp, name, 16);
|
|
||||||
M_Memcpy(demobuf.p,temp,16);
|
|
||||||
demobuf.p += 16;
|
|
||||||
|
|
||||||
// Skin
|
WRITEUINT32(demobuf.p, bytes);
|
||||||
WRITEUINT8(demobuf.p, skinnum);
|
WRITEMEM(demobuf.p, ubjson.data(), bytes);
|
||||||
|
}
|
||||||
|
|
||||||
// Color
|
void srb2::write_current_demo_end_marker()
|
||||||
memset(temp, 0, 16);
|
{
|
||||||
strncpy(temp, skincolors[color].name, 16);
|
WRITEUINT8(demobuf.p, DEMOMARKER); // add the demo end marker
|
||||||
M_Memcpy(demobuf.p,temp,16);
|
*(UINT32 *)demoinfo_p = demobuf.p - demobuf.buffer;
|
||||||
demobuf.p += 16;
|
|
||||||
|
|
||||||
// Score/time/whatever
|
|
||||||
WRITEUINT32(demobuf.p, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void G_SetDemoTime(UINT32 ptime, UINT32 plap)
|
void G_SetDemoTime(UINT32 ptime, UINT32 plap)
|
||||||
|
|
@ -2510,6 +2505,52 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool load_ubjson_standing(menudemo_t* pdemo, tcb::span<std::byte> slice, tcb::span<democharlist_t> demoskins)
|
||||||
|
{
|
||||||
|
using namespace srb2;
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
StandingsJson js;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
js = json::from_ubjson(slice).template get<StandingsJson>();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t toread = std::min<size_t>(js.standings.size(), MAXPLAYERS);
|
||||||
|
for (size_t i = 0; i < toread; i++)
|
||||||
|
{
|
||||||
|
StandingJson& jsstanding = js.standings[i];
|
||||||
|
auto& memstanding = pdemo->standings[i];
|
||||||
|
memstanding.ranking = jsstanding.ranking;
|
||||||
|
strlcpy(memstanding.name, jsstanding.name.c_str(), 17);
|
||||||
|
if (jsstanding.demoskin >= demoskins.size())
|
||||||
|
{
|
||||||
|
memstanding.skin = demoskins[0].mapping;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memstanding.skin = demoskins[jsstanding.demoskin].mapping;
|
||||||
|
}
|
||||||
|
memstanding.color = SKINCOLOR_NONE;
|
||||||
|
for (size_t j = 0; j < numskincolors; j++)
|
||||||
|
{
|
||||||
|
skincolor_t& skincolor = skincolors[j];
|
||||||
|
if (jsstanding.skincolor == skincolor.name)
|
||||||
|
{
|
||||||
|
memstanding.color = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memstanding.timeorscore = jsstanding.timeorscore;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void G_LoadDemoInfo(menudemo_t *pdemo)
|
void G_LoadDemoInfo(menudemo_t *pdemo)
|
||||||
{
|
{
|
||||||
savebuffer_t info = {0};
|
savebuffer_t info = {0};
|
||||||
|
|
@ -2518,6 +2559,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
||||||
UINT16 pdemoflags;
|
UINT16 pdemoflags;
|
||||||
democharlist_t *skinlist = NULL;
|
democharlist_t *skinlist = NULL;
|
||||||
UINT16 pdemoversion, count;
|
UINT16 pdemoversion, count;
|
||||||
|
UINT16 legacystandingplayercount;
|
||||||
char mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
|
char mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
|
||||||
|
|
@ -2670,44 +2712,95 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
||||||
pdemo->gp = true;
|
pdemo->gp = true;
|
||||||
|
|
||||||
// Read standings!
|
// Read standings!
|
||||||
count = 0;
|
legacystandingplayercount = 0;
|
||||||
|
|
||||||
info.p = extrainfo_p;
|
info.p = extrainfo_p;
|
||||||
|
|
||||||
while (P_SaveBufferRemaining(&info) >= 1+1+16+1+16+4 &&
|
while (P_SaveBufferRemaining(&info) > 1)
|
||||||
READUINT8(info.p) == DW_STANDING) // Assume standings are always first in the extrainfo
|
|
||||||
{
|
{
|
||||||
char temp[16];
|
UINT8 extrainfotag = READUINT8(info.p);
|
||||||
|
|
||||||
pdemo->standings[count].ranking = READUINT8(info.p);
|
switch (extrainfotag)
|
||||||
|
{
|
||||||
// Name
|
case DW_STANDING:
|
||||||
M_Memcpy(pdemo->standings[count].name, info.p, 16);
|
|
||||||
info.p += 16;
|
|
||||||
|
|
||||||
// Skin
|
|
||||||
skinid = READUINT8(info.p);
|
|
||||||
if (skinid > worknumskins)
|
|
||||||
skinid = 0;
|
|
||||||
pdemo->standings[count].skin = skinlist[skinid].mapping;
|
|
||||||
|
|
||||||
// Color
|
|
||||||
M_Memcpy(temp,info.p,16);
|
|
||||||
info.p += 16;
|
|
||||||
for (i = 0; i < numskincolors; i++)
|
|
||||||
if (!stricmp(skincolors[i].name,temp)) // SRB2kart
|
|
||||||
{
|
{
|
||||||
pdemo->standings[count].color = i;
|
// This is the only extrainfo tag that is not length prefixed. All others must be.
|
||||||
|
constexpr size_t kLegacyStandingSize = 1+16+1+16+4;
|
||||||
|
if (P_SaveBufferRemaining(&info) < kLegacyStandingSize)
|
||||||
|
{
|
||||||
|
goto corrupt;
|
||||||
|
}
|
||||||
|
if (legacystandingplayercount >= MAXPLAYERS)
|
||||||
|
{
|
||||||
|
info.p += kLegacyStandingSize;
|
||||||
|
break; // switch
|
||||||
|
}
|
||||||
|
char temp[16];
|
||||||
|
|
||||||
|
pdemo->standings[legacystandingplayercount].ranking = READUINT8(info.p);
|
||||||
|
|
||||||
|
// Name
|
||||||
|
M_Memcpy(pdemo->standings[legacystandingplayercount].name, info.p, 16);
|
||||||
|
info.p += 16;
|
||||||
|
|
||||||
|
// Skin
|
||||||
|
skinid = READUINT8(info.p);
|
||||||
|
if (skinid > worknumskins)
|
||||||
|
skinid = 0;
|
||||||
|
pdemo->standings[legacystandingplayercount].skin = skinlist[skinid].mapping;
|
||||||
|
|
||||||
|
// Color
|
||||||
|
M_Memcpy(temp,info.p,16);
|
||||||
|
info.p += 16;
|
||||||
|
for (i = 0; i < numskincolors; i++)
|
||||||
|
if (!stricmp(skincolors[i].name,temp)) // SRB2kart
|
||||||
|
{
|
||||||
|
pdemo->standings[legacystandingplayercount].color = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Score/time/whatever
|
||||||
|
pdemo->standings[legacystandingplayercount].timeorscore = READUINT32(info.p);
|
||||||
|
|
||||||
|
legacystandingplayercount++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DW_STANDING2:
|
||||||
// Score/time/whatever
|
{
|
||||||
pdemo->standings[count].timeorscore = READUINT32(info.p);
|
if (P_SaveBufferRemaining(&info) < 4)
|
||||||
|
{
|
||||||
count++;
|
goto corrupt;
|
||||||
|
}
|
||||||
if (count >= MAXPLAYERS)
|
UINT32 size = READUINT32(info.p);
|
||||||
break; //@TODO still cycle through the rest of these if extra demo data is ever used
|
if (P_SaveBufferRemaining(&info) < size)
|
||||||
|
{
|
||||||
|
goto corrupt;
|
||||||
|
}
|
||||||
|
tcb::span<std::byte> slice = tcb::as_writable_bytes(tcb::span(info.p, size));
|
||||||
|
tcb::span<democharlist_t> demoskins {skinlist, worknumskins};
|
||||||
|
info.p += size;
|
||||||
|
if (!load_ubjson_standing(pdemo, slice, demoskins))
|
||||||
|
{
|
||||||
|
goto corrupt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Gracefully ignore other extrainfo tags by skipping their data
|
||||||
|
if (P_SaveBufferRemaining(&info) < 4)
|
||||||
|
{
|
||||||
|
goto corrupt;
|
||||||
|
}
|
||||||
|
UINT32 size = READUINT32(info.p);
|
||||||
|
if (P_SaveBufferRemaining(&info) < size)
|
||||||
|
{
|
||||||
|
goto corrupt;
|
||||||
|
}
|
||||||
|
info.p += size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (P_SaveBufferRemaining(&info) == 0)
|
if (P_SaveBufferRemaining(&info) == 0)
|
||||||
|
|
|
||||||
39
src/g_demo.h
39
src/g_demo.h
|
|
@ -19,6 +19,44 @@
|
||||||
#include "d_event.h"
|
#include "d_event.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// Modern json formats
|
||||||
|
namespace srb2
|
||||||
|
{
|
||||||
|
struct StandingJson
|
||||||
|
{
|
||||||
|
uint8_t ranking;
|
||||||
|
std::string name;
|
||||||
|
uint8_t demoskin;
|
||||||
|
std::string skincolor;
|
||||||
|
uint32_t timeorscore;
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||||
|
StandingJson,
|
||||||
|
ranking,
|
||||||
|
name,
|
||||||
|
demoskin,
|
||||||
|
skincolor,
|
||||||
|
timeorscore
|
||||||
|
)
|
||||||
|
};
|
||||||
|
struct StandingsJson
|
||||||
|
{
|
||||||
|
std::vector<StandingJson> standings;
|
||||||
|
|
||||||
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(StandingsJson, standings)
|
||||||
|
};
|
||||||
|
|
||||||
|
void write_current_demo_standings(const StandingsJson& standings);
|
||||||
|
void write_current_demo_end_marker();
|
||||||
|
|
||||||
|
} // namespace srb2
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -105,7 +143,6 @@ void G_RecordDemo(const char *name);
|
||||||
void G_BeginRecording(void);
|
void G_BeginRecording(void);
|
||||||
|
|
||||||
// Only called by shutdown code.
|
// Only called by shutdown code.
|
||||||
void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT16 color, UINT32 val);
|
|
||||||
void G_SetDemoTime(UINT32 ptime, UINT32 plap);
|
void G_SetDemoTime(UINT32 ptime, UINT32 plap);
|
||||||
UINT8 G_CmpDemoTime(char *oldname, char *newname);
|
UINT8 G_CmpDemoTime(char *oldname, char *newname);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,8 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
||||||
|
|
||||||
data.isduel = (numplayersingame <= 2);
|
data.isduel = (numplayersingame <= 2);
|
||||||
|
|
||||||
|
srb2::StandingsJson standings {};
|
||||||
|
|
||||||
for (j = 0; j < numplayersingame; j++)
|
for (j = 0; j < numplayersingame; j++)
|
||||||
{
|
{
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
|
@ -240,13 +242,13 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
||||||
|
|
||||||
if (demo.recording)
|
if (demo.recording)
|
||||||
{
|
{
|
||||||
G_WriteStanding(
|
srb2::StandingJson standing {};
|
||||||
data.pos[data.numplayers],
|
standing.ranking = data.pos[data.numplayers];
|
||||||
player_names[i],
|
standing.name = std::string(player_names[i]);
|
||||||
data.character[data.numplayers],
|
standing.demoskin = data.character[data.numplayers];
|
||||||
data.color[data.numplayers],
|
standing.skincolor = std::string(skincolors[data.color[data.numplayers]].name);
|
||||||
data.val[data.numplayers]
|
standing.timeorscore = data.val[data.numplayers];
|
||||||
);
|
standings.standings.emplace_back(std::move(standing));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.val[data.numplayers] == (UINT32_MAX-1))
|
if (data.val[data.numplayers] == (UINT32_MAX-1))
|
||||||
|
|
@ -284,6 +286,12 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
||||||
data.numplayers++;
|
data.numplayers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (demo.recording)
|
||||||
|
{
|
||||||
|
srb2::write_current_demo_end_marker();
|
||||||
|
srb2::write_current_demo_standings(standings);
|
||||||
|
}
|
||||||
|
|
||||||
if (getmainplayer == true)
|
if (getmainplayer == true)
|
||||||
{
|
{
|
||||||
// Okay, player scores have been set now - we can calculate GP-relevant material.
|
// Okay, player scores have been set now - we can calculate GP-relevant material.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue