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.
// (permits all unlocks in dedicated)
for (i = 0; i < MAXUNLOCKABLES; i++)
netUnlocked[i] = (dedicated || gamedata->unlocked[i]);
M_SetNetUnlocked();
expectChallenge = false;

View file

@ -1538,6 +1538,19 @@ void D_SRB2Main(void)
// for dedicated server
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)
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();

View file

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

View file

@ -734,8 +734,7 @@ void M_ClearSecrets(void)
memset(gamedata->collected, 0, sizeof(gamedata->collected));
memset(gamedata->unlocked, 0, sizeof(gamedata->unlocked));
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));
Z_Free(gamedata->spraycans);
@ -1281,6 +1280,66 @@ void M_FinaliseGameData(void)
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
// ----------------------
@ -3404,11 +3463,6 @@ boolean M_SecretUnlocked(INT32 type, boolean local)
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.
if (marathonmode)
return false;
@ -3464,11 +3518,6 @@ boolean M_CupSecondRowLocked(void)
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.
if (marathonmode)
return false;

View file

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

View file

@ -43,22 +43,21 @@ namespace
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
{
Pw(void (*cb)(), const char *encoded_hash) : cb_(cb), hash_(decode_hash(encoded_hash)) {}
void (*cb_)();
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;
@ -342,6 +341,20 @@ try_password_e M_TryPassword(const char *password, boolean conditions)
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
void Command_Crypt_f(void)
{

View file

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

View file

@ -8373,30 +8373,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// will be set by player think.
players[consoleplayer].viewz = 1;
// 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)
{
tic_t locstarttime, endtime, nowtime;
// (This define might be useful for other areas of code? Not sure)
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) \
locstarttime = nowtime = lastwipetic; \
endtime = locstarttime + timetowait; \
@ -8415,6 +8394,28 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
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);
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
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);
WAIT((3*TICRATE)/4);
}
}
#undef WAIT
// Special stage & record attack retry fade to white
// This is handled BEFORE sounds are stopped.
@ -9135,15 +9142,19 @@ UINT8 P_InitMapData(void)
// Okay, it does...
{
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 (i == gamemap - 1)
ret |= MAPRET_CURRENTREPLACED;
if (mapheaderinfo[i]->lumpnum != LUMPERROR)
{
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;