mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Rewrite how Spray Cans are stored in gamedata
- For programmers:
- Deprecate GamedataSprayCanJson
- Previously stored colour name and map name together.
- Was swapped in place to move invalid entries to the back.
- If the old info exists, we convert it.
- Instead:
- Store list of colour names
- Index into that list in GamedataMapJson to write map ID
- Stable-sort the list as collected then uncollected
- Write only valid entries into gamedata_t
- Use the map ID reference to link map back to final order
- Sounds more complicated, and it kind of is - but the code is WAY more readable, elegant IMO, allows for expansions to be added later and takes advantage of CPP features it didn't originally
- For testers:
- Ideally, nothing should change. Just be careful and remember to keep backups of your gamedata
# Conflicts:
# src/g_gamedata.cpp
# src/g_gamedata.h
This commit is contained in:
parent
3f9c0685eb
commit
1fa1da9b4e
2 changed files with 124 additions and 81 deletions
|
|
@ -29,7 +29,9 @@
|
|||
namespace fs = std::filesystem;
|
||||
|
||||
#define GD_VERSION_MAJOR (0xBA5ED321)
|
||||
#define GD_VERSION_MINOR (1)
|
||||
#define GD_VERSION_MINOR (2)
|
||||
|
||||
#define GD_MINIMUM_SPRAYCANSV2 (2)
|
||||
|
||||
void srb2::save_ng_gamedata()
|
||||
{
|
||||
|
|
@ -146,6 +148,18 @@ void srb2::save_ng_gamedata()
|
|||
ng.skins[name] = std::move(skin);
|
||||
}
|
||||
|
||||
for (int i = 0; i < gamedata->numspraycans; i++)
|
||||
{
|
||||
uint16_t col = gamedata->spraycans[i].col;
|
||||
|
||||
if (col >= SKINCOLOR_FIRSTFREESLOT)
|
||||
{
|
||||
col = SKINCOLOR_NONE;
|
||||
}
|
||||
|
||||
ng.spraycans_v2.emplace_back(String(skincolors[col].name));
|
||||
}
|
||||
|
||||
auto maptojson = [](recorddata_t *records)
|
||||
{
|
||||
srb2::GamedataMapJson map {};
|
||||
|
|
@ -167,6 +181,7 @@ void srb2::save_ng_gamedata()
|
|||
map.stats.time.custom = records->modetimeplayed[GDGT_CUSTOM];
|
||||
map.stats.time.timeattack = records->timeattacktimeplayed;
|
||||
map.stats.time.spbattack = records->spbattacktimeplayed;
|
||||
map.spraycan = records->spraycan;
|
||||
|
||||
return map;
|
||||
};
|
||||
|
|
@ -183,38 +198,6 @@ void srb2::save_ng_gamedata()
|
|||
srb2::String lumpname { unloadedmap->lumpname };
|
||||
ng.maps[lumpname] = std::move(map);
|
||||
}
|
||||
for (int i = 0; i < gamedata->numspraycans; i++)
|
||||
{
|
||||
srb2::GamedataSprayCanJson spraycan {};
|
||||
|
||||
candata_t* can = &gamedata->spraycans[i];
|
||||
|
||||
if (can->col >= numskincolors)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
spraycan.color = String(skincolors[can->col].name);
|
||||
|
||||
if (can->map == NEXTMAP_INVALID)
|
||||
{
|
||||
spraycan.map = "";
|
||||
ng.spraycans.emplace_back(std::move(spraycan));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (can->map >= nummapheaders)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mapheader_t* mapheader = mapheaderinfo[can->map];
|
||||
if (!mapheader)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
spraycan.map = String(mapheader->lumpname);
|
||||
ng.spraycans.emplace_back(std::move(spraycan));
|
||||
}
|
||||
|
||||
auto cuptojson = [](cupwindata_t *windata)
|
||||
{
|
||||
|
|
@ -401,6 +384,7 @@ void srb2::load_ng_gamedata()
|
|||
uint32_t majorversion;
|
||||
uint8_t minorversion;
|
||||
uint8_t dirty;
|
||||
bool converted = false;
|
||||
try
|
||||
{
|
||||
majorversion = srb2::io::read_uint32(bis);
|
||||
|
|
@ -591,6 +575,29 @@ void srb2::load_ng_gamedata()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<candata_t> tempcans;
|
||||
|
||||
for (auto& cancolor : js.spraycans_v2)
|
||||
{
|
||||
// Version 2 behaviour - spraycans_v2, not spraycans!
|
||||
|
||||
candata_t tempcan;
|
||||
tempcan.col = SKINCOLOR_NONE;
|
||||
tempcan.map = NEXTMAP_INVALID;
|
||||
|
||||
// Find the skin color index for the name
|
||||
for (size_t i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++)
|
||||
{
|
||||
if (cancolor != skincolors[i].name)
|
||||
continue;
|
||||
|
||||
tempcan.col = i;
|
||||
break;
|
||||
}
|
||||
|
||||
tempcans.emplace_back(std::move(tempcan));
|
||||
}
|
||||
|
||||
for (auto& mappair : js.maps)
|
||||
{
|
||||
UINT16 mapnum = G_MapNumber(mappair.first.c_str());
|
||||
|
|
@ -614,10 +621,21 @@ void srb2::load_ng_gamedata()
|
|||
dummyrecord.timeattacktimeplayed = mappair.second.stats.time.timeattack;
|
||||
dummyrecord.spbattacktimeplayed = mappair.second.stats.time.spbattack;
|
||||
|
||||
dummyrecord.spraycan = (minorversion >= GD_MINIMUM_SPRAYCANSV2)
|
||||
? mappair.second.spraycan
|
||||
: UINT16_MAX;
|
||||
|
||||
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
|
||||
{
|
||||
// Valid mapheader, time to populate with record data.
|
||||
|
||||
// Infill Spray Can info
|
||||
if (dummyrecord.spraycan < tempcans.size())
|
||||
{
|
||||
tempcans[dummyrecord.spraycan].map = mapnum;
|
||||
}
|
||||
dummyrecord.spraycan = UINT16_MAX; // We repopulate this later.
|
||||
|
||||
mapheaderinfo[mapnum]->records = dummyrecord;
|
||||
}
|
||||
else if (dummyrecord.mapvisited & MV_BEATEN
|
||||
|
|
@ -641,73 +659,95 @@ void srb2::load_ng_gamedata()
|
|||
unloadedmap->next = unloadedmapheaders;
|
||||
unloadedmapheaders = unloadedmap;
|
||||
|
||||
// Invalidate can.
|
||||
dummyrecord.spraycan = UINT16_MAX;
|
||||
|
||||
// Finally, copy into.
|
||||
unloadedmap->records = dummyrecord;
|
||||
}
|
||||
}
|
||||
|
||||
gamedata->gotspraycans = 0;
|
||||
gamedata->numspraycans = js.spraycans.size();
|
||||
if ((minorversion < GD_MINIMUM_SPRAYCANSV2) && (js.spraycans.size() > 1))
|
||||
{
|
||||
// Deprecated behaviour! Look above for spraycans_v2 handling
|
||||
|
||||
converted = true;
|
||||
|
||||
for (auto& deprecatedcan : js.spraycans)
|
||||
{
|
||||
candata_t tempcan;
|
||||
tempcan.col = SKINCOLOR_NONE;
|
||||
|
||||
// Find the skin color index for the name
|
||||
for (size_t i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++)
|
||||
{
|
||||
if (deprecatedcan.color != skincolors[i].name)
|
||||
continue;
|
||||
|
||||
tempcan.col = i;
|
||||
break;
|
||||
}
|
||||
|
||||
UINT16 mapnum = NEXTMAP_INVALID;
|
||||
if (!deprecatedcan.map.empty())
|
||||
{
|
||||
mapnum = G_MapNumber(deprecatedcan.map.c_str());
|
||||
}
|
||||
tempcan.map = mapnum;
|
||||
|
||||
tempcans.emplace_back(std::move(tempcan));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Post-process of Spray Cans - a component of both v1 and v2 spraycans behaviour
|
||||
|
||||
// Determine sizes.
|
||||
for (auto& tempcan : tempcans)
|
||||
{
|
||||
if (tempcan.col == SKINCOLOR_NONE)
|
||||
continue;
|
||||
|
||||
gamedata->numspraycans++;
|
||||
|
||||
if (tempcan.map >= nummapheaders)
|
||||
continue;
|
||||
|
||||
gamedata->gotspraycans++;
|
||||
}
|
||||
|
||||
if (gamedata->numspraycans)
|
||||
{
|
||||
// Arrange with collected first
|
||||
std::stable_sort(tempcans.begin(), tempcans.end(), [ ]( auto& lhs, auto& rhs )
|
||||
{
|
||||
return (rhs.map >= basenummapheaders && lhs.map < basenummapheaders);
|
||||
});
|
||||
|
||||
gamedata->spraycans = static_cast<candata_t*>(Z_Malloc(
|
||||
(gamedata->numspraycans * sizeof(candata_t)),
|
||||
PU_STATIC, NULL));
|
||||
|
||||
for (size_t i = 0; i < gamedata->numspraycans; i++)
|
||||
// Finally, fill can data.
|
||||
size_t i = 0;
|
||||
for (auto& tempcan : tempcans)
|
||||
{
|
||||
auto& can = js.spraycans[i];
|
||||
if (tempcan.col == SKINCOLOR_NONE)
|
||||
continue;
|
||||
|
||||
skincolors[tempcan.col].cache_spraycan = i;
|
||||
|
||||
if (tempcan.map < nummapheaders)
|
||||
mapheaderinfo[tempcan.map]->records.spraycan = i;
|
||||
|
||||
gamedata->spraycans[i] = tempcan;
|
||||
|
||||
if (++i < gamedata->numspraycans)
|
||||
continue;
|
||||
|
||||
// Find the skin color index for the name
|
||||
bool foundcolor = false;
|
||||
for (size_t j = 0; j < numskincolors; j++)
|
||||
{
|
||||
if (can.color == skincolors[j].name)
|
||||
{
|
||||
gamedata->spraycans[i].col = j;
|
||||
skincolors[j].cache_spraycan = i;
|
||||
foundcolor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundcolor)
|
||||
{
|
||||
// Invalid color name? Ignore the spraycan
|
||||
gamedata->numspraycans -= 1;
|
||||
i -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
gamedata->spraycans[i].map = NEXTMAP_INVALID;
|
||||
|
||||
UINT16 mapnum = NEXTMAP_INVALID;
|
||||
if (!can.map.empty())
|
||||
{
|
||||
mapnum = G_MapNumber(can.map.c_str());
|
||||
}
|
||||
gamedata->spraycans[i].map = mapnum;
|
||||
if (mapnum >= nummapheaders)
|
||||
{
|
||||
// Can has not been grabbed on any map, this is intentional.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gamedata->gotspraycans != i)
|
||||
{
|
||||
//CONS_Printf("LOAD - Swapping gotten can %u, color %s with prior ungotten can %u\n", i, skincolors[col].name, gamedata->gotspraycans);
|
||||
|
||||
// All grabbed cans should be at the head of the list.
|
||||
// Let's swap with the can the disjoint occoured at.
|
||||
// This will prevent a gap from occouring on reload.
|
||||
candata_t copycan = gamedata->spraycans[gamedata->gotspraycans];
|
||||
gamedata->spraycans[gamedata->gotspraycans] = gamedata->spraycans[i];
|
||||
gamedata->spraycans[i] = copycan;
|
||||
|
||||
mapheaderinfo[copycan.map]->records.spraycan = i;
|
||||
}
|
||||
mapheaderinfo[mapnum]->records.spraycan = gamedata->gotspraycans;
|
||||
gamedata->gotspraycans++;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& cuppair : js.cups)
|
||||
|
|
@ -812,7 +852,6 @@ void srb2::load_ng_gamedata()
|
|||
}
|
||||
}
|
||||
|
||||
bool converted = false;
|
||||
UINT32 chao_key_rounds = GDCONVERT_ROUNDSTOKEY;
|
||||
UINT32 start_keys = GDINIT_CHAOKEYS;
|
||||
|
||||
|
|
|
|||
|
|
@ -243,10 +243,12 @@ struct GamedataMapJson final
|
|||
{
|
||||
GamedataMapVisitedJson visited;
|
||||
GamedataMapStatsJson stats;
|
||||
uint16_t spraycan;
|
||||
|
||||
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapJson, visited, stats)
|
||||
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapJson, visited, stats, spraycan)
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
struct GamedataSprayCanJson final
|
||||
{
|
||||
String map;
|
||||
|
|
@ -296,8 +298,9 @@ struct GamedataJson final
|
|||
GamedataChallengeGridJson challengegrid;
|
||||
uint32_t timesBeaten;
|
||||
HashMap<String, GamedataSkinJson> skins;
|
||||
Vector<String> spraycans_v2;
|
||||
HashMap<String, GamedataMapJson> maps;
|
||||
Vector<GamedataSprayCanJson> spraycans;
|
||||
Vector<GamedataSprayCanJson> spraycans; // Deprecated
|
||||
HashMap<String, GamedataCupJson> cups;
|
||||
Vector<GamedataSealedSwapJson> sealedswaps;
|
||||
|
||||
|
|
@ -317,6 +320,7 @@ struct GamedataJson final
|
|||
challengegrid,
|
||||
timesBeaten,
|
||||
skins,
|
||||
spraycans_v2,
|
||||
maps,
|
||||
spraycans,
|
||||
cups,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue