mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-10 18:12:46 +00:00
Immense 25-file diff, so spun off into its own branch.
- Improved appearance
- Not just a big block of text on a blue background
- Well, OK, the main part is, but some stuff has been spun out into its own fields
- Title text
- Text and button prompt for Yes/No or OK
- Slides with pow on and off the screen
- Disabled MM_EVENTHANDLER, which has always been dog but got considerably worse after newmenus to the point nothing's using it anymore
- Required in order to reduce the reliance on FUNCPTRCAST, which prevents Eidolon from compiling some stuff because it's not valid C++
496 lines
11 KiB
C
496 lines
11 KiB
C
/// \file menus/play-online-server-browser.c
|
|
/// \brief MULTIPLAYER ROOM FETCH / REFRESH THREADS
|
|
|
|
#include "../k_menu.h"
|
|
#include "../v_video.h"
|
|
#include "../i_system.h" // I_OsPolling
|
|
#include "../i_video.h" // I_UpdateNoBlit
|
|
|
|
#ifdef SERVERLISTDEBUG
|
|
#include "../m_random.h"
|
|
#endif
|
|
|
|
menuitem_t PLAY_MP_ServerBrowser[] =
|
|
{
|
|
|
|
{IT_STRING | IT_CVAR, "SORT BY", NULL, // tooltip MUST be null.
|
|
NULL, {.cvar = &cv_serversort}, 0, 0},
|
|
|
|
{IT_STRING, "REFRESH", NULL,
|
|
NULL, {NULL}, 0, 0},
|
|
|
|
{IT_NOTHING, NULL, NULL, NULL, {NULL}, 0, 0},
|
|
};
|
|
|
|
menu_t PLAY_MP_ServerBrowserDef = {
|
|
sizeof (PLAY_MP_ServerBrowser) / sizeof (menuitem_t),
|
|
&PLAY_MP_RoomSelectDef,
|
|
0,
|
|
PLAY_MP_ServerBrowser,
|
|
32, 36,
|
|
0, 0,
|
|
0,
|
|
"NETMD2",
|
|
0, 0,
|
|
M_DrawMPServerBrowser,
|
|
M_MPServerBrowserTick,
|
|
NULL,
|
|
NULL,
|
|
M_ServerBrowserInputs
|
|
};
|
|
|
|
static CV_PossibleValue_t serversort_cons_t[] = {
|
|
{0,"Ping"},
|
|
{1,"AVG. Power Level"},
|
|
{2,"Most Players"},
|
|
{3,"Least Players"},
|
|
{4,"Max Player Slots"},
|
|
{5,"Gametype"},
|
|
{0,NULL}
|
|
};
|
|
consvar_t cv_serversort = CVAR_INIT ("serversort", "Ping", CV_CALL, serversort_cons_t, M_SortServerList);
|
|
|
|
// for server fetch threads...
|
|
M_waiting_mode_t m_waiting_mode = M_NOT_WAITING;
|
|
|
|
// depending on mpmenu.room, either allows only unmodded servers or modded ones. Remove others from the list.
|
|
// we do this by iterating backwards.
|
|
static void M_CleanServerList(void)
|
|
{
|
|
UINT8 i = serverlistcount;
|
|
|
|
while (i)
|
|
{
|
|
|
|
if (serverlist[i].info.modifiedgame != mpmenu.room)
|
|
{
|
|
// move everything after this index 1 slot down...
|
|
if (i != serverlistcount)
|
|
memcpy(&serverlist[i], &serverlist[i+1], sizeof(serverelem_t)*(serverlistcount-i));
|
|
|
|
serverlistcount--;
|
|
}
|
|
|
|
i--;
|
|
}
|
|
}
|
|
|
|
void
|
|
M_SetWaitingMode (int mode)
|
|
{
|
|
#ifdef HAVE_THREADS
|
|
I_lock_mutex(&k_menu_mutex);
|
|
#endif
|
|
{
|
|
m_waiting_mode = mode;
|
|
}
|
|
#ifdef HAVE_THREADS
|
|
I_unlock_mutex(k_menu_mutex);
|
|
#endif
|
|
}
|
|
|
|
int
|
|
M_GetWaitingMode (void)
|
|
{
|
|
int mode;
|
|
|
|
#ifdef HAVE_THREADS
|
|
I_lock_mutex(&k_menu_mutex);
|
|
#endif
|
|
{
|
|
mode = m_waiting_mode;
|
|
}
|
|
#ifdef HAVE_THREADS
|
|
I_unlock_mutex(k_menu_mutex);
|
|
#endif
|
|
|
|
return mode;
|
|
}
|
|
|
|
#ifdef MASTERSERVER
|
|
#ifdef HAVE_THREADS
|
|
void
|
|
Spawn_masterserver_thread (const char *name, void (*thread)(int*))
|
|
{
|
|
int *id = malloc(sizeof *id);
|
|
|
|
I_lock_mutex(&ms_QueryId_mutex);
|
|
{
|
|
*id = ms_QueryId;
|
|
}
|
|
I_unlock_mutex(ms_QueryId_mutex);
|
|
|
|
I_spawn_thread(name, (I_thread_fn)thread, id);
|
|
}
|
|
|
|
int
|
|
Same_instance (int id)
|
|
{
|
|
int okay;
|
|
|
|
I_lock_mutex(&ms_QueryId_mutex);
|
|
{
|
|
okay = ( id == ms_QueryId );
|
|
}
|
|
I_unlock_mutex(ms_QueryId_mutex);
|
|
|
|
return okay;
|
|
}
|
|
#endif/*HAVE_THREADS*/
|
|
|
|
void
|
|
Fetch_servers_thread (int *id)
|
|
{
|
|
msg_server_t * server_list;
|
|
|
|
(void)id;
|
|
|
|
M_SetWaitingMode(M_WAITING_SERVERS);
|
|
|
|
#ifdef HAVE_THREADS
|
|
server_list = GetShortServersList(*id);
|
|
#else
|
|
server_list = GetShortServersList(0);
|
|
#endif
|
|
|
|
if (server_list)
|
|
{
|
|
#ifdef HAVE_THREADS
|
|
if (Same_instance(*id))
|
|
#endif
|
|
{
|
|
M_SetWaitingMode(M_NOT_WAITING);
|
|
|
|
#ifdef HAVE_THREADS
|
|
I_lock_mutex(&ms_ServerList_mutex);
|
|
{
|
|
ms_ServerList = server_list;
|
|
}
|
|
I_unlock_mutex(ms_ServerList_mutex);
|
|
#else
|
|
CL_QueryServerList(server_list);
|
|
free(server_list);
|
|
#endif
|
|
}
|
|
#ifdef HAVE_THREADS
|
|
else
|
|
{
|
|
free(server_list);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_THREADS
|
|
free(id);
|
|
#endif
|
|
}
|
|
#endif/*MASTERSERVER*/
|
|
|
|
// updates serverlist
|
|
void M_RefreshServers(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
|
|
// Display a little "please wait" message.
|
|
M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Searching for servers...");
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
|
|
I_OsPolling();
|
|
I_UpdateNoBlit();
|
|
if (rendermode == render_soft)
|
|
I_FinishUpdate(); // page flip or blit buffer
|
|
|
|
#ifdef MASTERSERVER
|
|
#ifdef HAVE_THREADS
|
|
Spawn_masterserver_thread("fetch-servers", Fetch_servers_thread);
|
|
#else/*HAVE_THREADS*/
|
|
Fetch_servers_thread(NULL);
|
|
#endif/*HAVE_THREADS*/
|
|
#else/*MASTERSERVER*/
|
|
CL_UpdateServerList();
|
|
#endif/*MASTERSERVER*/
|
|
|
|
#ifdef SERVERLISTDEBUG
|
|
M_ServerListFillDebug();
|
|
#endif
|
|
M_CleanServerList();
|
|
M_SortServerList();
|
|
|
|
}
|
|
|
|
#ifdef UPDATE_ALERT
|
|
static void M_CheckMODVersion(int id)
|
|
{
|
|
char updatestring[500];
|
|
const char *updatecheck = GetMODVersion(id);
|
|
if(updatecheck)
|
|
{
|
|
sprintf(updatestring, UPDATE_ALERT_STRING, VERSIONSTRING, updatecheck);
|
|
#ifdef HAVE_THREADS
|
|
I_lock_mutex(&k_menu_mutex);
|
|
#endif
|
|
M_StartMessage("Game Update", updatestring, NULL, MM_NOTHING, NULL, NULL);
|
|
#ifdef HAVE_THREADS
|
|
I_unlock_mutex(k_menu_mutex);
|
|
#endif
|
|
}
|
|
}
|
|
#endif/*UPDATE_ALERT*/
|
|
|
|
#if defined (UPDATE_ALERT) && defined (HAVE_THREADS)
|
|
static void
|
|
Check_new_version_thread (int *id)
|
|
{
|
|
M_SetWaitingMode(M_WAITING_VERSION);
|
|
|
|
M_CheckMODVersion(*id);
|
|
|
|
if (Same_instance(*id))
|
|
{
|
|
Fetch_servers_thread(id);
|
|
}
|
|
else
|
|
{
|
|
free(id);
|
|
}
|
|
}
|
|
#endif/*defined (UPDATE_ALERT) && defined (HAVE_THREADS)*/
|
|
|
|
|
|
// Initializes serverlist when entering the menu...
|
|
void M_ServersMenu(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
// modified game check: no longer handled
|
|
// we don't request a restart unless the filelist differs
|
|
|
|
mpmenu.servernum = 0;
|
|
mpmenu.scrolln = 0;
|
|
mpmenu.slide = 0;
|
|
|
|
M_SetupNextMenu(&PLAY_MP_ServerBrowserDef, false);
|
|
itemOn = 0;
|
|
|
|
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
|
|
I_lock_mutex(&ms_QueryId_mutex);
|
|
{
|
|
ms_QueryId++;
|
|
}
|
|
I_unlock_mutex(ms_QueryId_mutex);
|
|
|
|
I_lock_mutex(&ms_ServerList_mutex);
|
|
{
|
|
if (ms_ServerList)
|
|
{
|
|
free(ms_ServerList);
|
|
ms_ServerList = NULL;
|
|
}
|
|
}
|
|
I_unlock_mutex(ms_ServerList_mutex);
|
|
|
|
#ifdef UPDATE_ALERT
|
|
Spawn_masterserver_thread("check-new-version", Check_new_version_thread);
|
|
#else/*UPDATE_ALERT*/
|
|
Spawn_masterserver_thread("fetch-servers", Fetch_servers_thread);
|
|
#endif/*UPDATE_ALERT*/
|
|
#else/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/
|
|
#ifdef UPDATE_ALERT
|
|
M_CheckMODVersion(0);
|
|
#endif/*UPDATE_ALERT*/
|
|
M_RefreshServers(0);
|
|
#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/
|
|
|
|
#ifdef SERVERLISTDEBUG
|
|
M_ServerListFillDebug();
|
|
#endif
|
|
|
|
M_CleanServerList();
|
|
M_SortServerList();
|
|
}
|
|
|
|
#ifdef SERVERLISTDEBUG
|
|
|
|
// Fill serverlist with a bunch of garbage to make our life easier in debugging
|
|
void M_ServerListFillDebug(void)
|
|
{
|
|
UINT8 i = 0;
|
|
|
|
serverlistcount = 10;
|
|
memset(serverlist, 0, sizeof(serverlist)); // zero out the array for convenience...
|
|
|
|
for (i = 0; i < serverlistcount; i++)
|
|
{
|
|
// We don't really care about the server node for this, let's just fill in the info so that we have a visual...
|
|
serverlist[i].info.numberofplayer = min(i, 8);
|
|
serverlist[i].info.maxplayer = 8;
|
|
|
|
serverlist[i].info.avgpwrlv = P_RandomRange(PR_UNDEFINED, 500, 1500);
|
|
serverlist[i].info.time = P_RandomRange(PR_UNDEFINED, 1, 8); // ping
|
|
|
|
strcpy(serverlist[i].info.servername, va("Serv %d", i+1));
|
|
|
|
strcpy(serverlist[i].info.gametypename, i & 1 ? "Race" : "Battle");
|
|
|
|
P_RandomRange(PR_UNDEFINED, 0, 5); // change results...
|
|
serverlist[i].info.kartvars = P_RandomRange(PR_UNDEFINED, 0, 3) & SV_SPEEDMASK;
|
|
|
|
serverlist[i].info.modifiedgame = P_RandomRange(PR_UNDEFINED, 0, 1);
|
|
|
|
CONS_Printf("Serv %d | %d...\n", i, serverlist[i].info.modifiedgame);
|
|
}
|
|
}
|
|
|
|
#endif // SERVERLISTDEBUG
|
|
|
|
// Ascending order, not descending.
|
|
// The casts are safe as long as the caller doesn't do anything stupid.
|
|
#define SERVER_LIST_ENTRY_COMPARATOR(key) \
|
|
static int ServerListEntryComparator_##key(const void *entry1, const void *entry2) \
|
|
{ \
|
|
const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2; \
|
|
if (sa->info.key != sb->info.key) \
|
|
return sa->info.key - sb->info.key; \
|
|
return strcmp(sa->info.servername, sb->info.servername); \
|
|
}
|
|
|
|
// This does descending instead of ascending.
|
|
#define SERVER_LIST_ENTRY_COMPARATOR_REVERSE(key) \
|
|
static int ServerListEntryComparator_##key##_reverse(const void *entry1, const void *entry2) \
|
|
{ \
|
|
const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2; \
|
|
if (sb->info.key != sa->info.key) \
|
|
return sb->info.key - sa->info.key; \
|
|
return strcmp(sb->info.servername, sa->info.servername); \
|
|
}
|
|
|
|
SERVER_LIST_ENTRY_COMPARATOR(time)
|
|
SERVER_LIST_ENTRY_COMPARATOR(numberofplayer)
|
|
SERVER_LIST_ENTRY_COMPARATOR_REVERSE(numberofplayer)
|
|
SERVER_LIST_ENTRY_COMPARATOR_REVERSE(maxplayer)
|
|
SERVER_LIST_ENTRY_COMPARATOR(avgpwrlv)
|
|
|
|
|
|
static int ServerListEntryComparator_gametypename(const void *entry1, const void *entry2)
|
|
{
|
|
const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2;
|
|
int c;
|
|
if (( c = strcasecmp(sa->info.gametypename, sb->info.gametypename) ))
|
|
return c;
|
|
return strcmp(sa->info.servername, sb->info.servername); \
|
|
}
|
|
|
|
void M_SortServerList(void)
|
|
{
|
|
switch(cv_serversort.value)
|
|
{
|
|
case 0: // Ping.
|
|
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_time);
|
|
break;
|
|
case 1: // AVG. Power Level
|
|
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_avgpwrlv);
|
|
break;
|
|
case 2: // Most players.
|
|
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer_reverse);
|
|
break;
|
|
case 3: // Least players.
|
|
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer);
|
|
break;
|
|
case 4: // Max players.
|
|
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_maxplayer_reverse);
|
|
break;
|
|
case 5: // Gametype.
|
|
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Server browser inputs & ticker
|
|
void M_MPServerBrowserTick(void)
|
|
{
|
|
mpmenu.slide /= 2;
|
|
}
|
|
|
|
// Input handler for server browser.
|
|
boolean M_ServerBrowserInputs(INT32 ch)
|
|
{
|
|
UINT8 pid = 0;
|
|
UINT8 maxscroll = serverlistcount-(SERVERSPERPAGE/2);
|
|
(void) ch;
|
|
|
|
if (!itemOn && menucmd[pid].dpad_ud < 0)
|
|
{
|
|
M_PrevOpt(); // go to itemOn 2
|
|
if (serverlistcount)
|
|
{
|
|
UINT8 prevscroll = mpmenu.scrolln;
|
|
|
|
mpmenu.servernum = serverlistcount;
|
|
mpmenu.scrolln = maxscroll;
|
|
mpmenu.slide = SERVERSPACE * (prevscroll - mpmenu.scrolln);
|
|
}
|
|
else
|
|
{
|
|
itemOn = 1; // Sike! If there are no servers, go to refresh instead.
|
|
}
|
|
|
|
return true; // overwrite behaviour.
|
|
}
|
|
else if (itemOn == 2) // server browser itself...
|
|
{
|
|
// we have to manually do that here.
|
|
if (M_MenuBackPressed(pid))
|
|
{
|
|
M_GoBack(0);
|
|
M_SetMenuDelay(pid);
|
|
}
|
|
|
|
else if (menucmd[pid].dpad_ud > 0) // down
|
|
{
|
|
if (mpmenu.servernum >= serverlistcount-1)
|
|
{
|
|
UINT8 prevscroll = mpmenu.scrolln;
|
|
mpmenu.servernum = 0;
|
|
mpmenu.scrolln = 0;
|
|
mpmenu.slide = SERVERSPACE * (prevscroll - mpmenu.scrolln);
|
|
|
|
M_NextOpt(); // Go back to the top of the real menu.
|
|
}
|
|
else
|
|
{
|
|
mpmenu.servernum++;
|
|
if (mpmenu.scrolln < maxscroll && mpmenu.servernum > SERVERSPERPAGE/2)
|
|
{
|
|
mpmenu.scrolln++;
|
|
mpmenu.slide += SERVERSPACE;
|
|
}
|
|
}
|
|
S_StartSound(NULL, sfx_s3k5b);
|
|
M_SetMenuDelay(pid);
|
|
|
|
}
|
|
else if (menucmd[pid].dpad_ud < 0)
|
|
{
|
|
|
|
if (!mpmenu.servernum)
|
|
{
|
|
M_PrevOpt();
|
|
}
|
|
else
|
|
{
|
|
if (mpmenu.servernum <= serverlistcount-(SERVERSPERPAGE/2) && mpmenu.scrolln)
|
|
{
|
|
mpmenu.scrolln--;
|
|
mpmenu.slide -= SERVERSPACE;
|
|
}
|
|
|
|
mpmenu.servernum--;
|
|
}
|
|
S_StartSound(NULL, sfx_s3k5b);
|
|
M_SetMenuDelay(pid);
|
|
|
|
}
|
|
return true; // Overwrite behaviour.
|
|
}
|
|
return false; // use normal behaviour.
|
|
}
|