Merge branch 'rqdx' into 'master'

Roundqueue DX

Closes #1411

See merge request KartKrew/Kart!2473
This commit is contained in:
Oni 2024-10-20 18:52:35 +00:00
commit d9bf5d26dd
10 changed files with 797 additions and 302 deletions

View file

@ -4772,6 +4772,149 @@ static void PT_Say(int node)
DoSayCommand(say.message, say.target, say.flags, say.source); DoSayCommand(say.message, say.target, say.flags, say.source);
} }
static void PT_ReqMapQueue(int node)
{
if (client)
return; // Only sent to servers, why are we receiving this?
reqmapqueue_pak reqmapqueue = netbuffer->u.reqmapqueue;
// Check for a spoofed source.
if (reqmapqueue.source == serverplayer)
{
// Servers aren't guaranteed to have a playernode, dedis exist.
if (node != servernode)
return;
}
else
{
if (playernode[reqmapqueue.source] != node)
return;
if (!IsPlayerAdmin(reqmapqueue.source))
{
CONS_Debug(DBG_NETPLAY,"Received illegal request map queue cmd from Player %d (%s).\n", reqmapqueue.source+1, player_names[reqmapqueue.source]);
SendKick(reqmapqueue.source, KICK_MSG_CON_FAIL);
return;
}
}
const boolean doclear = (reqmapqueue.newgametype == ROUNDQUEUE_CMD_CLEAR);
// The following prints will only appear when multiple clients
// attempt to affect the round queue at similar time increments
if (doclear == true)
{
if (roundqueue.size == 0)
{
// therefore this one doesn't really need a error print
// because what both players wanted was done anyways
//CONS_Alert(CONS_ERROR, "queuemap: Queue is already empty!\n");
return;
}
}
else if (reqmapqueue.newgametype == ROUNDQUEUE_CMD_SHOW)
{
char maprevealmsg[256];
if (roundqueue.size == 0)
{
strlcpy(maprevealmsg, "There are no Rounds queued.", 256);
}
else if (roundqueue.position >= roundqueue.size)
{
strlcpy(maprevealmsg, "There are no more Rounds queued!", 256);
}
else
{
char *title = G_BuildMapTitle(roundqueue.entries[roundqueue.position].mapnum + 1);
strlcpy(
maprevealmsg,
va("The next Round will be on \"%s\".", title),
256
);
Z_Free(title);
}
DoSayCommand(maprevealmsg, 0, HU_SHOUT, servernode);
return;
}
else if (roundqueue.size >= ROUNDQUEUE_MAX)
{
CONS_Alert(CONS_ERROR, "Recieved REQMAPQUEUE, but unable to add map beyond %u\n", roundqueue.size);
// But this one does, because otherwise it's silent failure!
char rejectmsg[256];
strlcpy(rejectmsg, "The server couldn't queue your chosen map.", 256);
SendServerNotice(reqmapqueue.source, rejectmsg);
return;
}
if (reqmapqueue.newmapnum == NEXTMAP_VOTING)
{
UINT8 numPlayers = 0, i;
for (i = 0; i < MAXPLAYERS; ++i)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
extern consvar_t cv_forcebots; // debug
if (!(gametypes[reqmapqueue.newgametype]->rules & GTR_BOTS) && players[i].bot && !cv_forcebots.value)
{
// Gametype doesn't support bots
continue;
}
numPlayers++;
}
reqmapqueue.newmapnum = G_RandMapPerPlayerCount(G_TOLFlag(reqmapqueue.newgametype), UINT16_MAX, false, false, NULL, numPlayers);
}
if (reqmapqueue.newmapnum >= nummapheaders)
{
CONS_Alert(CONS_ERROR, "Recieved REQMAPQUEUE, but unable to add map of invalid ID (%u)\n", reqmapqueue.newmapnum);
char rejectmsg[256];
strlcpy(rejectmsg, "The server couldn't queue your chosen map.", 256);
SendServerNotice(reqmapqueue.source, rejectmsg);
return;
}
G_AddMapToBuffer(reqmapqueue.newmapnum);
UINT8 buf[1+2+1];
UINT8 *buf_p = buf;
WRITEUINT8(buf_p, reqmapqueue.flags);
WRITEUINT16(buf_p, reqmapqueue.newgametype);
WRITEUINT8(buf_p, roundqueue.size);
// Match Got_MapQueuecmd, but with the addition of reqmapqueue.newmapnum available to us
if (doclear == true)
{
memset(&roundqueue, 0, sizeof(struct roundqueue));
}
else
{
G_MapIntoRoundQueue(
reqmapqueue.newmapnum,
reqmapqueue.newgametype,
((reqmapqueue.flags & 1) != 0),
false
);
}
SendNetXCmd(XD_MAPQUEUE, buf, buf_p - buf);
}
static char NodeToSplitPlayer(int node, int split) static char NodeToSplitPlayer(int node, int split)
{ {
if (split == 0) if (split == 0)
@ -5117,6 +5260,9 @@ static void HandlePacketFromPlayer(SINT8 node)
case PT_SAY: case PT_SAY:
PT_Say(node); PT_Say(node);
break; break;
case PT_REQMAPQUEUE:
PT_ReqMapQueue(node);
break;
case PT_LOGIN: case PT_LOGIN:
if (client) if (client)
break; break;

View file

@ -135,6 +135,8 @@ typedef enum
PT_SAY, // "Hey server, please send this chat message to everyone via XD_SAY" PT_SAY, // "Hey server, please send this chat message to everyone via XD_SAY"
PT_REQMAPQUEUE, // Client requesting a roundqueue operation
NUMPACKETTYPE NUMPACKETTYPE
} packettype_t; } packettype_t;
@ -401,6 +403,14 @@ struct say_pak
UINT8 source; UINT8 source;
} ATTRPACK; } ATTRPACK;
struct reqmapqueue_pak
{
UINT16 newmapnum;
UINT16 newgametype;
UINT8 flags;
UINT8 source;
} ATTRPACK;
struct netinfo_pak struct netinfo_pak
{ {
UINT32 pingtable[MAXPLAYERS+1]; UINT32 pingtable[MAXPLAYERS+1];
@ -451,6 +461,7 @@ struct doomdata_t
responseall_pak responseall; // 256 bytes responseall_pak responseall; // 256 bytes
resultsall_pak resultsall; // 1024 bytes. Also, you really shouldn't trust anything here. resultsall_pak resultsall; // 1024 bytes. Also, you really shouldn't trust anything here.
say_pak say; // I don't care anymore. say_pak say; // I don't care anymore.
reqmapqueue_pak reqmapqueue; // Formerly XD_REQMAPQUEUE
} u; // This is needed to pack diff packet types data together } u; // This is needed to pack diff packet types data together
} ATTRPACK; } ATTRPACK;

File diff suppressed because it is too large Load diff

View file

@ -153,7 +153,7 @@ typedef enum
XD_PAUSE, // 9 XD_PAUSE, // 9
XD_ADDPLAYER, // 10 XD_ADDPLAYER, // 10
XD_SPECTATE, // 11 XD_SPECTATE, // 11
XD_CLEARSCORES, // 12 XD_SETSCORE, // 12
XD_VERIFIED, // 13 XD_VERIFIED, // 13
XD_RANDOMSEED, // 14 XD_RANDOMSEED, // 14
XD_RUNSOC, // 15 XD_RUNSOC, // 15
@ -180,8 +180,8 @@ typedef enum
XD_SCHEDULETASK, // 34 XD_SCHEDULETASK, // 34
XD_SCHEDULECLEAR, // 35 XD_SCHEDULECLEAR, // 35
XD_AUTOMATE, // 36 XD_AUTOMATE, // 36
XD_REQMAPQUEUE, // 37 // 37 is free
XD_MAPQUEUE, // 38 XD_MAPQUEUE = XD_AUTOMATE+2, // 38
XD_CALLZVOTE, // 39 XD_CALLZVOTE, // 39
XD_SETZVOTE, // 40 XD_SETZVOTE, // 40
XD_TEAMCHANGE, // 41 XD_TEAMCHANGE, // 41

View file

@ -38,7 +38,9 @@ extern "C" {
// ============================= // =============================
#define ROUNDQUEUE_MAX 10 // sane max? maybe make dynamically allocated later #define ROUNDQUEUE_MAX 10 // sane max? maybe make dynamically allocated later
#define ROUNDQUEUE_CLEAR UINT16_MAX // lives in gametype field of packets // These two live in gametype field of packets
#define ROUNDQUEUE_CMD_CLEAR UINT16_MAX
#define ROUNDQUEUE_CMD_SHOW UINT16_MAX-1
// The roundqueue itself is resident in g_game.h // The roundqueue itself is resident in g_game.h
// Selected by user. // Selected by user.

View file

@ -4406,13 +4406,28 @@ void G_GetNextMap(void)
if (setalready == false) if (setalready == false)
{ {
UINT8 numPlayers = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
numPlayers++;
}
UINT32 tolflag = G_TOLFlag(gametype); UINT32 tolflag = G_TOLFlag(gametype);
register INT16 cm; register INT16 cm;
if (!(gametyperules & GTR_NOCUPSELECT)) const boolean cupmode = (!(gametyperules & GTR_NOCUPSELECT));
nextmap = NEXTMAP_TITLE;
if (cupmode)
{ {
cupheader_t *cup = mapheaderinfo[gamemap-1]->cup; cupheader_t *cup = mapheaderinfo[prevmap]->cup;
UINT8 gettingresult = 0; boolean gettingresult = false;
while (cup) while (cup)
{ {
@ -4420,7 +4435,7 @@ void G_GetNextMap(void)
if (!marathonmode && M_CupLocked(cup)) if (!marathonmode && M_CupLocked(cup))
{ {
cup = cup->next; cup = cup->next;
gettingresult = 1; gettingresult = true;
continue; continue;
} }
@ -4437,6 +4452,35 @@ void G_GetNextMap(void)
continue; continue;
} }
// If the map is in multiple cups, only consider the first one valid.
if (mapheaderinfo[cm]->cup != cup)
{
continue;
}
if (!gettingresult)
{
// Not the map you're on?
if (cm == prevmap)
{
// Ok, this is the current map, time to get the next valid
gettingresult = true;
}
continue;
}
if ((mapheaderinfo[cm]->menuflags & LF2_HIDEINMENU) == LF2_HIDEINMENU)
{
// Not intended to be accessed in multiplayer.
continue;
}
if (numPlayers > mapheaderinfo[cm]->playerLimit)
{
// Too many players for this map.
continue;
}
// Only care about restrictions if the host is a listen server. // Only care about restrictions if the host is a listen server.
if (!dedicated && !marathonmode) if (!dedicated && !marathonmode)
{ {
@ -4462,32 +4506,13 @@ void G_GetNextMap(void)
continue; continue;
} }
// If the map is in multiple cups, only consider the first one valid.
if (mapheaderinfo[cm]->cup != cup)
{
continue;
}
// Grab the first valid after the map you're on // Grab the first valid after the map you're on
if (gettingresult) nextmap = cm;
{ break;
nextmap = cm;
gettingresult = 2;
break;
}
// Not the map you're on?
if (cm != prevmap)
{
continue;
}
// Ok, this is the current map, time to get the next
gettingresult = 1;
} }
// We have a good nextmap? // We have a good nextmap?
if (gettingresult == 2) if (nextmap < NEXTMAP_SPECIAL)
{ {
break; break;
} }
@ -4495,22 +4520,25 @@ void G_GetNextMap(void)
// Ok, iterate to the next // Ok, iterate to the next
cup = cup->next; cup = cup->next;
} }
// Didn't get a nextmap before reaching the end?
if (gettingresult != 2)
{
nextmap = NEXTMAP_CEREMONY; // ceremonymap
}
} }
else
// Haven't grabbed a nextmap yet?
if (nextmap >= NEXTMAP_SPECIAL)
{ {
cm = prevmap; if (cupmode && mapheaderinfo[prevmap]->cup)
do
{ {
if (++cm >= nummapheaders) // Special case - looking for Lost & Found #1.
cm = 0; // Could be anywhere in mapheaderinfo.
cm = 0;
}
else
{
// All subsequent courses in load order.
cm = prevmap+1;
}
for (; cm < nummapheaders; cm++)
{
if (!mapheaderinfo[cm] if (!mapheaderinfo[cm]
|| mapheaderinfo[cm]->lumpnum == LUMPERROR || mapheaderinfo[cm]->lumpnum == LUMPERROR
|| !(mapheaderinfo[cm]->typeoflevel & tolflag) || !(mapheaderinfo[cm]->typeoflevel & tolflag)
@ -4519,6 +4547,24 @@ void G_GetNextMap(void)
continue; continue;
} }
if (cupmode && mapheaderinfo[cm]->cup)
{
// Only Lost & Found this loop around.
continue;
}
if ((mapheaderinfo[cm]->menuflags & LF2_HIDEINMENU) == LF2_HIDEINMENU)
{
// Not intended to be accessed in multiplayer.
continue;
}
if (numPlayers > mapheaderinfo[cm]->playerLimit)
{
// Too many players for this map.
continue;
}
// Only care about restrictions if the host is a listen server. // Only care about restrictions if the host is a listen server.
if (!dedicated && !marathonmode) if (!dedicated && !marathonmode)
{ {
@ -4547,10 +4593,9 @@ void G_GetNextMap(void)
continue; continue;
} }
nextmap = cm;
break; break;
} while (cm != prevmap); }
nextmap = cm;
} }
if (K_CanChangeRules(true)) if (K_CanChangeRules(true))
@ -4563,24 +4608,14 @@ void G_GetNextMap(void)
nextmap = prevmap; nextmap = prevmap;
break; break;
case 3: // Voting screen. case 3: // Voting screen.
if (numPlayers != 0)
{ {
for (i = 0; i < MAXPLAYERS; i++) nextmap = NEXTMAP_VOTING;
{ break;
if (!playeringame[i])
continue;
if (players[i].spectator)
continue;
break;
}
if (i != MAXPLAYERS)
{
nextmap = NEXTMAP_VOTING;
break;
}
} }
/* FALLTHRU */ /* FALLTHRU */
case 2: // Go to random map. case 2: // Go to random map.
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, false, NULL); nextmap = G_RandMapPerPlayerCount(G_TOLFlag(gametype), prevmap, false, false, NULL, numPlayers);
break; break;
default: default:
if (nextmap >= NEXTMAP_SPECIAL) // Loop back around if (nextmap >= NEXTMAP_SPECIAL) // Loop back around

View file

@ -372,7 +372,7 @@ void Command_Setlives_f(void)
D_Cheat(consoleplayer, CHEAT_LIVES, atoi(COM_Argv(1))); D_Cheat(consoleplayer, CHEAT_LIVES, atoi(COM_Argv(1)));
} }
void Command_Setscore_f(void) void Command_Setroundscore_f(void)
{ {
REQUIRE_CHEATS; REQUIRE_CHEATS;
REQUIRE_INLEVEL; REQUIRE_INLEVEL;

View file

@ -75,7 +75,7 @@ void Command_Savecheckpoint_f(void);
void Command_Setrings_f(void); void Command_Setrings_f(void);
void Command_Setspheres_f(void); void Command_Setspheres_f(void);
void Command_Setlives_f(void); void Command_Setlives_f(void);
void Command_Setscore_f(void); void Command_Setroundscore_f(void);
void Command_Devmode_f(void); void Command_Devmode_f(void);
void Command_Scale_f(void); void Command_Scale_f(void);
void Command_Gravflip_f(void); void Command_Gravflip_f(void);

View file

@ -353,7 +353,7 @@ void M_HandlePauseMenuGametype(INT32 choice)
} }
else // ideally for "random" only, but no sane fallback for "same" and "next" else // ideally for "random" only, but no sane fallback for "same" and "next"
{ {
COM_ImmedExecute(va("randommap -gt %s", gametypes[menugametype]->name)); COM_ImmedExecute(va("map -random -gt %s", gametypes[menugametype]->name));
} }
} }
return; return;

View file

@ -83,6 +83,7 @@ TYPEDEF (challengeall_pak);
TYPEDEF (responseall_pak); TYPEDEF (responseall_pak);
TYPEDEF (resultsall_pak); TYPEDEF (resultsall_pak);
TYPEDEF (say_pak); TYPEDEF (say_pak);
TYPEDEF (reqmapqueue_pak);
TYPEDEF (netinfo_pak); TYPEDEF (netinfo_pak);
// d_event.h // d_event.h