Merge branch 'dedi-final' into 'master'

Final work for Dedicated Servers

See merge request KartKrew/Kart!2275
This commit is contained in:
toaster 2024-04-12 21:25:55 +00:00
commit 25e728fd33
8 changed files with 161 additions and 74 deletions

View file

@ -3382,8 +3382,7 @@ void SV_ResetServer(void)
// Copy our unlocks to a place where net material can grab at/overwrite them safely. // Copy our unlocks to a place where net material can grab at/overwrite them safely.
// (permits all unlocks in dedicated) // (permits all unlocks in dedicated)
for (i = 0; i < MAXUNLOCKABLES; i++) M_SetNetUnlocked();
netUnlocked[i] = (dedicated || gamedata->unlocked[i]);
expectChallenge = false; expectChallenge = false;

View file

@ -1538,6 +1538,19 @@ void D_SRB2Main(void)
// for dedicated server // for dedicated server
dedicated = M_CheckParm("-dedicated") != 0; dedicated = M_CheckParm("-dedicated") != 0;
if (dedicated)
{
p = M_CheckParm("-spoilers");
if (p && M_IsNextParm())
{
usedTourney = M_TryExactPassword(M_GetNextParm(), "XpsOixVTZSW0cwbiYAVgzokAmWfeYNq5mEckVsktheq4GOUWQecF5lWTkGNBJtoYX9vUMprFzraSovOSCeQ96Q==");
if (usedTourney)
{
CONS_Printf(M_GetText("Spoiler mode ON.\n"));
}
}
}
if (devparm) if (devparm)
CONS_Printf(M_GetText("Development mode ON.\n")); CONS_Printf(M_GetText("Development mode ON.\n"));
@ -1932,7 +1945,7 @@ void D_SRB2Main(void)
} }
{ {
if (!M_CheckParm("-server") && !M_CheckParm("-dedicated")) if (!M_CheckParm("-server") && !dedicated)
{ {
G_SetUsedCheats(); G_SetUsedCheats();

View file

@ -3640,12 +3640,12 @@ static INT32 TOLMaps(UINT8 pgametype)
// Not completed // Not completed
continue; continue;
} }
}
if (M_MapLocked(i + 1) == true) if (M_MapLocked(i + 1) == true)
{ {
// We haven't earned this one. // We haven't earned this one.
continue; continue;
}
} }
num++; num++;
@ -3753,12 +3753,12 @@ tryAgain:
// Not completed // Not completed
continue; continue;
} }
}
if (M_MapLocked(i + 1) == true) if (M_MapLocked(i + 1) == true)
{ {
// We haven't earned this one. // We haven't earned this one.
continue; continue;
}
} }
if (ignoreBuffers == false) if (ignoreBuffers == false)
@ -4331,12 +4331,12 @@ void G_GetNextMap(void)
// Not completed // Not completed
continue; continue;
} }
}
if (M_MapLocked(cm + 1) == true) if (M_MapLocked(cm + 1) == true)
{ {
// We haven't earned this one. // We haven't earned this one.
continue; continue;
}
} }
// If the map is in multiple cups, only consider the first one valid. // If the map is in multiple cups, only consider the first one valid.
@ -4416,12 +4416,12 @@ void G_GetNextMap(void)
// Not completed // Not completed
continue; continue;
} }
}
if (M_MapLocked(cm + 1) == true) if (M_MapLocked(cm + 1) == true)
{ {
// We haven't earned this one. // We haven't earned this one.
continue; continue;
}
} }
break; break;

View file

@ -734,8 +734,7 @@ void M_ClearSecrets(void)
memset(gamedata->collected, 0, sizeof(gamedata->collected)); memset(gamedata->collected, 0, sizeof(gamedata->collected));
memset(gamedata->unlocked, 0, sizeof(gamedata->unlocked)); memset(gamedata->unlocked, 0, sizeof(gamedata->unlocked));
memset(gamedata->unlockpending, 0, sizeof(gamedata->unlockpending)); memset(gamedata->unlockpending, 0, sizeof(gamedata->unlockpending));
if (!dedicated) memset(netUnlocked, 0, sizeof(netUnlocked));
memset(netUnlocked, 0, sizeof(netUnlocked));
memset(gamedata->achieved, 0, sizeof(gamedata->achieved)); memset(gamedata->achieved, 0, sizeof(gamedata->achieved));
Z_Free(gamedata->spraycans); Z_Free(gamedata->spraycans);
@ -1281,6 +1280,66 @@ void M_FinaliseGameData(void)
M_UpdateUnlockablesAndExtraEmblems(false, true); M_UpdateUnlockablesAndExtraEmblems(false, true);
} }
void M_SetNetUnlocked(void)
{
UINT16 i;
// Use your gamedata as baseline
for (i = 0; i < MAXUNLOCKABLES; i++)
{
netUnlocked[i] = gamedata->unlocked[i];
}
if (!dedicated)
{
return;
}
// Dedicated spoiler password - tournament mode equivalent.
if (usedTourney)
{
for (i = 0; i < MAXUNLOCKABLES; i++)
{
if (unlockables[i].conditionset == 55)
continue;
netUnlocked[i] = true;
}
return;
}
// Okay, now it's dedicated first-week spoilerless behaviour.
for (i = 0; i < MAXUNLOCKABLES; i++)
{
if (netUnlocked[i])
continue;
switch (unlockables[i].type)
{
case SECRET_CUP:
{
// Give the first seven Cups for free.
cupheader_t *cup = M_UnlockableCup(&unlockables[i]);
if (cup && cup->id < 7)
netUnlocked[i] = true;
break;
}
case SECRET_ADDONS:
{
netUnlocked[i] = true;
break;
}
default:
{
// Most stuff isn't given to dedis for free
break;
}
}
}
}
// ---------------------- // ----------------------
// Condition set checking // Condition set checking
// ---------------------- // ----------------------
@ -3404,11 +3463,6 @@ boolean M_SecretUnlocked(INT32 type, boolean local)
boolean M_CupLocked(cupheader_t *cup) boolean M_CupLocked(cupheader_t *cup)
{ {
// Don't lock maps in dedicated servers.
// That just makes hosts' lives hell.
if (dedicated)
return false;
// No skipping over any part of your marathon. // No skipping over any part of your marathon.
if (marathonmode) if (marathonmode)
return false; return false;
@ -3464,11 +3518,6 @@ boolean M_CupSecondRowLocked(void)
boolean M_MapLocked(UINT16 mapnum) boolean M_MapLocked(UINT16 mapnum)
{ {
// Don't lock maps in dedicated servers.
// That just makes hosts' lives hell.
if (dedicated)
return false;
// No skipping over any part of your marathon. // No skipping over any part of your marathon.
if (marathonmode) if (marathonmode)
return false; return false;

View file

@ -443,6 +443,7 @@ void M_ClearConditionSet(UINT16 set);
void M_ClearSecrets(void); void M_ClearSecrets(void);
void M_ClearStats(void); void M_ClearStats(void);
void M_FinaliseGameData(void); void M_FinaliseGameData(void);
void M_SetNetUnlocked(void);
boolean M_NotFreePlay(void); boolean M_NotFreePlay(void);
UINT16 M_CheckCupEmeralds(UINT8 difficulty); UINT16 M_CheckCupEmeralds(UINT8 difficulty);

View file

@ -43,22 +43,21 @@ namespace
constexpr const UINT8 kRRSalt[17] = "0L4rlK}{9ay6'VJS"; constexpr const UINT8 kRRSalt[17] = "0L4rlK}{9ay6'VJS";
std::array<UINT8, M_PW_BUF_SIZE> decode_hash(std::string encoded)
{
std::array<UINT8, M_PW_BUF_SIZE> decoded;
if (modp::b64_decode(encoded).size() != decoded.size())
throw std::invalid_argument("hash is incorrectly sized");
std::copy(encoded.begin(), encoded.end(), decoded.begin());
return decoded;
}
struct Pw struct Pw
{ {
Pw(void (*cb)(), const char *encoded_hash) : cb_(cb), hash_(decode_hash(encoded_hash)) {} Pw(void (*cb)(), const char *encoded_hash) : cb_(cb), hash_(decode_hash(encoded_hash)) {}
void (*cb_)(); void (*cb_)();
const std::array<UINT8, M_PW_BUF_SIZE> hash_; const std::array<UINT8, M_PW_BUF_SIZE> hash_;
private:
static std::array<UINT8, M_PW_BUF_SIZE> decode_hash(std::string encoded)
{
std::array<UINT8, M_PW_BUF_SIZE> decoded;
if (modp::b64_decode(encoded).size() != decoded.size())
throw std::invalid_argument("hash is incorrectly sized");
std::copy(encoded.begin(), encoded.end(), decoded.begin());
return decoded;
}
}; };
std::vector<Pw> passwords; std::vector<Pw> passwords;
@ -342,6 +341,20 @@ try_password_e M_TryPassword(const char *password, boolean conditions)
return return_code; return return_code;
} }
boolean M_TryExactPassword(const char *password, const char *encodedhash)
{
// Normalize input casing
std::string key = password;
strlwr(key.data());
UINT8 key_hash[M_PW_HASH_SIZE];
M_HashPassword(key_hash, key.c_str(), kRRSalt);
auto hash = decode_hash(encodedhash);
return (memcmp(key_hash, hash.data(), M_PW_HASH_SIZE) == 0);
}
#ifdef DEVELOP #ifdef DEVELOP
void Command_Crypt_f(void) void Command_Crypt_f(void)
{ {

View file

@ -27,6 +27,7 @@ try_password_e;
void M_PasswordInit(void); void M_PasswordInit(void);
try_password_e M_TryPassword(const char *password, boolean challenges); try_password_e M_TryPassword(const char *password, boolean challenges);
boolean M_TryExactPassword(const char *password, const char *encodedhash);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View file

@ -8373,30 +8373,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// will be set by player think. // will be set by player think.
players[consoleplayer].viewz = 1; players[consoleplayer].viewz = 1;
// Cancel all d_main.c fadeouts (keep fade in though). // (This define might be useful for other areas of code? Not sure)
if (reloadinggamestate) tic_t locstarttime, endtime, nowtime;
wipegamestate = gamestate; // Don't fade if reloading the gamestate
// Encore mode fade to pink to white
// This is handled BEFORE sounds are stopped.
else if (encoremode && !prevencoremode && modeattacking == ATTACKING_NONE && !demo.rewinding)
{
if (rendermode != render_none)
{
tic_t locstarttime, endtime, nowtime;
Music_StopAll(); // er, about that...
// Fade to an inverted screen, with a circle fade...
F_WipeStartScreen();
V_EncoreInvertScreen();
F_WipeEndScreen();
S_StartSound(NULL, sfx_ruby1);
F_RunWipe(wipe_encore_toinvert, wipedefs[wipe_encore_toinvert], false, NULL, false, false);
// Hold on invert for extra effect.
// (This define might be useful for other areas of code? Not sure)
#define WAIT(timetowait) \ #define WAIT(timetowait) \
locstarttime = nowtime = lastwipetic; \ locstarttime = nowtime = lastwipetic; \
endtime = locstarttime + timetowait; \ endtime = locstarttime + timetowait; \
@ -8415,6 +8394,28 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
NetKeepAlive(); \ NetKeepAlive(); \
} \ } \
// Cancel all d_main.c fadeouts (keep fade in though).
if (reloadinggamestate)
wipegamestate = gamestate; // Don't fade if reloading the gamestate
// Encore mode fade to pink to white
// This is handled BEFORE sounds are stopped.
else if (encoremode && !prevencoremode && modeattacking == ATTACKING_NONE && !demo.rewinding)
{
if (rendermode != render_none)
{
Music_StopAll(); // er, about that...
// Fade to an inverted screen, with a circle fade...
F_WipeStartScreen();
V_EncoreInvertScreen();
F_WipeEndScreen();
S_StartSound(NULL, sfx_ruby1);
F_RunWipe(wipe_encore_toinvert, wipedefs[wipe_encore_toinvert], false, NULL, false, false);
// Hold on invert for extra effect.
WAIT((3*TICRATE)/2); WAIT((3*TICRATE)/2);
S_StartSound(NULL, sfx_ruby2); S_StartSound(NULL, sfx_ruby2);
@ -8441,9 +8442,15 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
{ {
// dedicated servers can call this now, to wait the appropriate amount of time for clients to wipe // dedicated servers can call this now, to wait the appropriate amount of time for clients to wipe
F_RunWipe(wipe_encore_towhite, wipedefs[wipe_encore_towhite], false, "FADEMAP1", false, true); F_RunWipe(wipe_encore_towhite, wipedefs[wipe_encore_towhite], false, "FADEMAP1", false, true);
WAIT((3*TICRATE)/2);
F_RunWipe(wipe_level_toblack, wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false); F_RunWipe(wipe_level_toblack, wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
WAIT((3*TICRATE)/4);
} }
} }
#undef WAIT
// Special stage & record attack retry fade to white // Special stage & record attack retry fade to white
// This is handled BEFORE sounds are stopped. // This is handled BEFORE sounds are stopped.
@ -9135,15 +9142,19 @@ UINT8 P_InitMapData(void)
// Okay, it does... // Okay, it does...
{ {
ret |= MAPRET_ADDED; ret |= MAPRET_ADDED;
CONS_Printf("%s\n", name);
if (basenummapheaders && mapheaderinfo[i]->lumpnum != LUMPERROR) if (basenummapheaders)
{ {
G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you CONS_Printf("%s\n", name);
//If you replaced the map you're on, end the level when done. if (mapheaderinfo[i]->lumpnum != LUMPERROR)
if (i == gamemap - 1) {
ret |= MAPRET_CURRENTREPLACED; G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you
//If you replaced the map you're on, end the level when done.
if (i == gamemap - 1)
ret |= MAPRET_CURRENTREPLACED;
}
} }
mapheaderinfo[i]->lumpnum = maplump; mapheaderinfo[i]->lumpnum = maplump;