diff --git a/.travis.yml b/.travis.yml
index 4959e4d2..66349890 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -439,6 +439,30 @@ matrix:
# List Ubuntu LTS, newest to oldest
# Then list non-LTS, newest to oldest
################################
+ - os: linux
+ addons:
+ apt:
+ packages:
+ - libsdl2-mixer-dev
+ - libpng-dev
+ - libgl1-mesa-dev
+ - libgme-dev
+ - libcurl4-openssl-dev
+ - p7zip-full
+ - gcc-4.8
+ compiler: gcc-4.8
+ dist: xenial
+ if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+ AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+ AND env(DPL_TERMINATE_MAIN) != "1"
+ env:
+ - _DPL_JOB_ENABLED=1
+ - _DPL_JOB_NAME=focal
+ - _DPL_DPUT_TARGET=1
+ - _DPL_PACKAGE_SOURCE=1
+ - PACKAGE_DISTRO=focal
+ - PACKAGE_SUBVERSION=~20.04focal
+ #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
- os: linux
addons:
apt:
@@ -463,6 +487,30 @@ matrix:
- PACKAGE_DISTRO=bionic
- PACKAGE_SUBVERSION=~18.04bionic
#gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+ - os: linux
+ addons:
+ apt:
+ packages:
+ - libsdl2-mixer-dev
+ - libpng-dev
+ - libgl1-mesa-dev
+ - libgme-dev
+ - libcurl4-openssl-dev
+ - p7zip-full
+ - gcc-4.8
+ compiler: gcc-4.8
+ dist: xenial
+ if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+ AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+ AND env(DPL_TERMINATE_MAIN) != "1"
+ env:
+ - _DPL_JOB_ENABLED=1
+ - _DPL_JOB_NAME=xenial
+ - _DPL_DPUT_TARGET=1
+ - _DPL_PACKAGE_SOURCE=1
+ - PACKAGE_DISTRO=xenial
+ - PACKAGE_SUBVERSION=~16.04xenial
+ #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
- os: linux
addons:
apt:
@@ -505,59 +553,11 @@ matrix:
AND env(DPL_TERMINATE_MAIN) != "1"
env:
- _DPL_JOB_ENABLED=1
- - _DPL_JOB_NAME=disco
+ - _DPL_JOB_NAME=eoan
- _DPL_DPUT_TARGET=1
- _DPL_PACKAGE_SOURCE=1
- - PACKAGE_DISTRO=disco
- - PACKAGE_SUBVERSION=~19.04disco
- #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
- - os: linux
- addons:
- apt:
- packages:
- - libsdl2-mixer-dev
- - libpng-dev
- - libgl1-mesa-dev
- - libgme-dev
- - libcurl4-openssl-dev
- - p7zip-full
- - gcc-4.8
- compiler: gcc-4.8
- dist: xenial
- if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
- AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
- AND env(DPL_TERMINATE_MAIN) != "1"
- env:
- - _DPL_JOB_ENABLED=1
- - _DPL_JOB_NAME=cosmic
- - _DPL_DPUT_TARGET=1
- - _DPL_PACKAGE_SOURCE=1
- - PACKAGE_DISTRO=cosmic
- - PACKAGE_SUBVERSION=~18.10cosmic
- #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
- - os: linux
- addons:
- apt:
- packages:
- - libsdl2-mixer-dev
- - libpng-dev
- - libgl1-mesa-dev
- - libgme-dev
- - libcurl4-openssl-dev
- - p7zip-full
- - gcc-4.8
- compiler: gcc-4.8
- dist: xenial
- if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
- AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
- AND env(DPL_TERMINATE_MAIN) != "1"
- env:
- - _DPL_JOB_ENABLED=1
- - _DPL_JOB_NAME=xenial
- - _DPL_DPUT_TARGET=1
- - _DPL_PACKAGE_SOURCE=1
- - PACKAGE_DISTRO=xenial
- - PACKAGE_SUBVERSION=~16.04xenial
+ - PACKAGE_DISTRO=eoan
+ - PACKAGE_SUBVERSION=~19.10eoan
#gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
allow_failures:
- compiler: clang-3.5
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c0d673a6..cbb0fa20 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,6 +35,7 @@ set(SRB2_CORE_SOURCES
m_random.c
md5.c
mserv.c
+ http-mserv.c
s_sound.c
screen.c
sounds.c
diff --git a/src/Makefile b/src/Makefile
index 8eda8c40..dd678cb2 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -548,6 +548,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/w_wad.o \
$(OBJDIR)/filesrch.o \
$(OBJDIR)/mserv.o \
+ $(OBJDIR)/http-mserv.o\
$(OBJDIR)/i_tcp.o \
$(OBJDIR)/lzf.o \
$(OBJDIR)/vid_copy.o \
diff --git a/src/command.c b/src/command.c
index bd3a2243..95fd5ef4 100644
--- a/src/command.c
+++ b/src/command.c
@@ -543,10 +543,7 @@ static void COM_ExecuteString(char *ptext)
if (!stricmp(com_argv[0], a->name))
{
if (recursion > MAX_ALIAS_RECURSION)
- {
CONS_Alert(CONS_WARNING, M_GetText("Alias recursion cycle detected!\n"));
- recursion = 0;
- }
else
{
char buf[1024];
@@ -578,8 +575,10 @@ static void COM_ExecuteString(char *ptext)
}
WRITESTRING(write, read);
+ // Monster Iestyn: keep track of how many levels of recursion we're in
recursion++;
COM_BufInsertText(buf);
+ recursion--;
}
return;
}
diff --git a/src/console.c b/src/console.c
index 28958089..11a7961e 100644
--- a/src/console.c
+++ b/src/console.c
@@ -31,6 +31,7 @@
#include "i_video.h"
#include "z_zone.h"
#include "i_system.h"
+#include "i_threads.h"
#include "d_main.h"
#include "m_menu.h"
#include "filesrch.h"
@@ -45,6 +46,16 @@
#define MAXHUDLINES 20
+#ifdef HAVE_THREADS
+I_mutex con_mutex;
+
+# define Lock_state() I_lock_mutex(&con_mutex)
+# define Unlock_state() I_unlock_mutex(con_mutex)
+#else/*HAVE_THREADS*/
+# define Lock_state()
+# define Unlock_state()
+#endif/*HAVE_THREADS*/
+
static boolean con_started = false; // console has been initialised
boolean con_startup = false; // true at game startup, screen need refreshing
static boolean con_forcepic = true; // at startup toggle console translucency when first off
@@ -170,6 +181,8 @@ static void CONS_hudlines_Change(void)
{
INT32 i;
+ Lock_state();
+
// Clear the currently displayed lines
for (i = 0; i < con_hudlines; i++)
con_hudtime[i] = 0;
@@ -181,6 +194,8 @@ static void CONS_hudlines_Change(void)
con_hudlines = cons_hudlines.value;
+ Unlock_state();
+
CONS_Printf(M_GetText("Number of console HUD lines is now %d\n"), con_hudlines);
}
@@ -188,12 +203,16 @@ static void CONS_hudlines_Change(void)
//
static void CONS_Clear_f(void)
{
+ Lock_state();
+
memset(con_buffer, 0, CON_BUFFERSIZE);
con_cx = 0;
con_cy = con_totallines-1;
con_line = &con_buffer[con_cy*con_width];
con_scrollup = 0;
+
+ Unlock_state();
}
// Choose english keymap
@@ -369,20 +388,29 @@ void CON_Init(void)
for (i = 0; i < NUMINPUTS; i++)
bindtable[i] = NULL;
+ Lock_state();
+
// clear all lines
memset(con_buffer, 0, CON_BUFFERSIZE);
// make sure it is ready for the loading screen
con_width = 0;
+
+ Unlock_state();
+
CON_RecalcSize();
CON_SetupColormaps();
+ Lock_state();
+
//note: CON_Ticker should always execute at least once before D_Display()
con_clipviewtop = -1; // -1 does not clip
con_hudlines = atoi(cons_hudlines.defaultvalue);
+ Unlock_state();
+
// setup console input filtering
CON_InputInit();
@@ -391,15 +419,23 @@ void CON_Init(void)
COM_AddCommand("cls", CONS_Clear_f);
//COM_AddCommand("english", CONS_English_f);
// set console full screen for game startup MAKE SURE VID_Init() done !!!
+ Lock_state();
+
con_destlines = vid.height;
con_curlines = vid.height;
+ Unlock_state();
if (!dedicated)
{
+ Lock_state();
+
con_started = true;
con_startup = true; // need explicit screen refresh until we are in Doom loop
consoletoggle = false;
+
+ Unlock_state();
+
CV_RegisterVar(&cons_msgtimeout);
CV_RegisterVar(&cons_hudlines);
CV_RegisterVar(&cons_speed);
@@ -411,19 +447,27 @@ void CON_Init(void)
}
else
{
+ Lock_state();
+
con_started = true;
con_startup = false; // need explicit screen refresh until we are in Doom loop
consoletoggle = true;
+
+ Unlock_state();
}
}
// Console input initialization
//
static void CON_InputInit(void)
{
+ Lock_state();
+
// prepare the first prompt line
memset(inputlines, 0, sizeof (inputlines));
inputline = 0;
input_cur = input_sel = input_len = 0;
+
+ Unlock_state();
}
//======================================================================
@@ -439,6 +483,8 @@ static void CON_RecalcSize(void)
char *tmp_buffer;
char *string;
+ Lock_state();
+
switch (cv_constextsize.value)
{
case V_NOSCALEPATCH:
@@ -476,11 +522,18 @@ static void CON_RecalcSize(void)
// check for change of video width
if (conw == con_width)
+ {
+ Unlock_state();
return; // didn't change
+ }
+
+ Unlock_state();
tmp_buffer = Z_Malloc(CON_BUFFERSIZE, PU_STATIC, NULL);
string = Z_Malloc(CON_BUFFERSIZE, PU_STATIC, NULL); // BP: it is a line but who know
+ Lock_state();
+
oldcon_width = con_width;
oldnumlines = con_totallines;
oldcon_cy = con_cy;
@@ -501,6 +554,8 @@ static void CON_RecalcSize(void)
con_line = &con_buffer[con_cy*con_width];
con_scrollup = 0;
+ Unlock_state();
+
// re-arrange console text buffer to keep text
if (oldcon_width) // not the first time
{
@@ -525,7 +580,11 @@ static void CON_RecalcSize(void)
static void CON_ChangeHeight(void)
{
- INT32 minheight = 20 * con_scalefactor; // 20 = 8+8+4
+ INT32 minheight;
+
+ Lock_state();
+
+ minheight = 20 * con_scalefactor; // 20 = 8+8+4
// toggle console in
con_destlines = (cons_height.value*vid.height)/100;
@@ -535,13 +594,19 @@ static void CON_ChangeHeight(void)
con_destlines = vid.height;
con_destlines &= ~0x3; // multiple of text row height
+
+ Unlock_state();
}
// Handles Console moves in/out of screen (per frame)
//
static void CON_MoveConsole(void)
{
- const fixed_t conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT);
+ fixed_t conspeed;
+
+ Lock_state();
+
+ conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT);
// instant
if (!cons_speed.value)
@@ -563,6 +628,8 @@ static void CON_MoveConsole(void)
if (con_curlines < con_destlines)
con_curlines = con_destlines;
}
+
+ Unlock_state();
}
INT32 CON_ShiftChar(INT32 ch)
@@ -587,27 +654,44 @@ void CON_ClearHUD(void)
{
INT32 i;
+ Lock_state();
+
for (i = 0; i < con_hudlines; i++)
con_hudtime[i] = 0;
+
+ Unlock_state();
}
// Force console to move out immediately
// note: con_ticker will set consoleready false
void CON_ToggleOff(void)
{
+ Lock_state();
+
if (!con_destlines)
+ {
+ Unlock_state();
return;
+ }
con_destlines = 0;
con_curlines = 0;
CON_ClearHUD();
con_forcepic = 0;
con_clipviewtop = -1; // remove console clipping of view
+
+ Unlock_state();
}
boolean CON_Ready(void)
{
- return consoleready;
+ boolean ready;
+ Lock_state();
+ {
+ ready = consoleready;
+ }
+ Unlock_state();
+ return ready;
}
// Console ticker: handles console move in/out, cursor blinking
@@ -615,7 +699,11 @@ boolean CON_Ready(void)
void CON_Ticker(void)
{
INT32 i;
- INT32 minheight = 20 * con_scalefactor; // 20 = 8+8+4
+ INT32 minheight;
+
+ Lock_state();
+
+ minheight = 20 * con_scalefactor; // 20 = 8+8+4
// cursor blinking
con_tick++;
@@ -673,6 +761,8 @@ void CON_Ticker(void)
if (con_hudtime[i] < 0)
con_hudtime[i] = 0;
}
+
+ Unlock_state();
}
//
@@ -684,32 +774,51 @@ void CON_Ticker(void)
static void CON_InputClear(void)
{
+ Lock_state();
+
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
input_cur = input_sel = input_len = 0;
+
+ Unlock_state();
}
static void CON_InputSetString(const char *c)
{
+ Lock_state();
+
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
strcpy(inputlines[inputline], c);
input_cur = input_sel = input_len = strlen(c);
+
+ Unlock_state();
}
static void CON_InputAddString(const char *c)
{
size_t csize = strlen(c);
+
+ Lock_state();
+
if (input_len + csize > CON_MAXPROMPTCHARS-1)
+ {
+ Unlock_state();
return;
+ }
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur);
memcpy(&inputlines[inputline][input_cur], c, csize);
input_len += csize;
input_sel = (input_cur += csize);
+
+ Unlock_state();
}
static void CON_InputDelSelection(void)
{
size_t start, end, len;
+
+ Lock_state();
+
if (input_cur > input_sel)
{
start = input_sel;
@@ -728,27 +837,39 @@ static void CON_InputDelSelection(void)
input_len -= len;
input_sel = input_cur = start;
+
+ Unlock_state();
}
static void CON_InputAddChar(char c)
{
if (input_len >= CON_MAXPROMPTCHARS-1)
return;
+
+ Lock_state();
+
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur);
inputlines[inputline][input_cur++] = c;
inputlines[inputline][++input_len] = 0;
input_sel = input_cur;
+
+ Unlock_state();
}
static void CON_InputDelChar(void)
{
if (!input_cur)
return;
+
+ Lock_state();
+
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur);
inputlines[inputline][--input_len] = 0;
input_sel = --input_cur;
+
+ Unlock_state();
}
//
@@ -1174,6 +1295,8 @@ static void CON_Print(char *msg)
S_StartSound(NULL, sfx_radio);
}
+ Lock_state();
+
if (!(*msg & 0x80))
{
con_line[con_cx++] = '\x80';
@@ -1234,7 +1357,10 @@ static void CON_Print(char *msg)
}
if (*msg == '\0')
+ {
+ Unlock_state();
return;
+ }
// printable character
for (l = 0; l < (con_width-11) && msg[l] > ' '; l++)
@@ -1252,6 +1378,8 @@ static void CON_Print(char *msg)
for (; l > 0; l--)
con_line[con_cx++] = *(msg++);
}
+
+ Unlock_state();
}
void CON_LogMessage(const char *msg)
@@ -1283,6 +1411,7 @@ void CONS_Printf(const char *fmt, ...)
{
va_list argptr;
static char *txt = NULL;
+ boolean startup;
if (txt == NULL)
txt = malloc(8192);
@@ -1315,11 +1444,16 @@ void CONS_Printf(const char *fmt, ...)
CON_LogMessage(txt);
#endif
+ Lock_state();
+
// make sure new text is visible
con_scrollup = 0;
+ startup = con_startup;
+
+ Unlock_state();
// if not in display loop, force screen update
- if (con_startup)
+ if (startup)
{
#if (defined (_WINDOWS)) || (defined (__OS2__) && !defined (HAVE_SDL))
patch_t *con_backpic = W_CachePatchName("KARTKREW", PU_CACHE);
@@ -1633,8 +1767,13 @@ static void CON_DrawConsole(void)
//
void CON_Drawer(void)
{
+ Lock_state();
+
if (!con_started || !graphics_started)
+ {
+ Unlock_state();
return;
+ }
if (con_recalc)
CON_RecalcSize();
@@ -1644,4 +1783,6 @@ void CON_Drawer(void)
else if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS
|| gamestate == GS_VOTING || gamestate == GS_EVALUATION || gamestate == GS_WAITINGPLAYERS)
CON_DrawHudlines();
+
+ Unlock_state();
}
diff --git a/src/console.h b/src/console.h
index 11621746..ba0141a0 100644
--- a/src/console.h
+++ b/src/console.h
@@ -12,6 +12,7 @@
#include "d_event.h"
#include "command.h"
+#include "i_threads.h"
#ifdef _WII
void CON_InitWii(void);
@@ -21,6 +22,10 @@ void CON_Init(void);
boolean CON_Responder(event_t *ev);
+#ifdef HAVE_THREADS
+extern I_mutex con_mutex;
+#endif
+
// set true when screen size has changed, to adapt console
extern boolean con_recalc;
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 5b02fc5e..6b8c107b 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -76,7 +76,7 @@
boolean server = true; // true or false but !server == client
#define client (!server)
boolean nodownload = false;
-static boolean serverrunning = false;
+boolean serverrunning = false;
INT32 serverplayer = 0;
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
@@ -1351,7 +1351,7 @@ static boolean CL_AskFileList(INT32 firstfile)
netbuffer->packettype = PT_TELLFILESNEEDED;
netbuffer->u.filesneedednum = firstfile;
- return HSendPacket(servernode, true, 0, sizeof (INT32));
+ return HSendPacket(servernode, false, 0, sizeof (INT32));
}
/** Sends a special packet to declare how many players in local
@@ -1829,7 +1829,7 @@ static void CL_LoadReceivedSavegame(void)
#endif
#ifndef NONET
-static void SendAskInfo(INT32 node, boolean viams)
+static void SendAskInfo(INT32 node)
{
const tic_t asktime = I_GetTime();
netbuffer->packettype = PT_ASKINFO;
@@ -1840,10 +1840,6 @@ static void SendAskInfo(INT32 node, boolean viams)
// now allowed traffic from the host to us in, so once the MS relays
// our address to the host, it'll be able to speak to us.
HSendPacket(node, false, 0, sizeof (askinfo_pak));
-
- // Also speak to the MS.
- if (viams && node != 0 && node != BROADCASTADDR)
- SendAskInfoViaMS(node, asktime);
}
serverelem_t serverlist[MAXSERVERLIST];
@@ -1909,13 +1905,96 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
M_SortServerList();
}
+#ifdef HAVE_THREADS
+struct Fetch_servers_ctx
+{
+ int room;
+ int id;
+};
+
+static void
+Fetch_servers_thread (struct Fetch_servers_ctx *ctx)
+{
+ msg_server_t *server_list;
+
+ server_list = GetShortServersList(ctx->room, ctx->id);
+
+ if (server_list)
+ {
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ if (ctx->id != ms_QueryId)
+ {
+ free(server_list);
+ server_list = NULL;
+ }
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+
+ if (server_list)
+ {
+ I_lock_mutex(&m_menu_mutex);
+ {
+ if (m_waiting_mode == M_WAITING_SERVERS)
+ m_waiting_mode = M_NOT_WAITING;
+ }
+ I_unlock_mutex(m_menu_mutex);
+
+ I_lock_mutex(&ms_ServerList_mutex);
+ {
+ ms_ServerList = server_list;
+ }
+ I_unlock_mutex(ms_ServerList_mutex);
+ }
+ }
+
+ free(ctx);
+}
+#endif/*HAVE_THREADS*/
+
+void CL_QueryServerList (msg_server_t *server_list)
+{
+ INT32 i;
+
+ for (i = 0; server_list[i].header.buffer[0]; i++)
+ {
+ // Make sure MS version matches our own, to
+ // thwart nefarious servers who lie to the MS.
+
+ /* lol bruh, that version COMES from the servers */
+ //if (strcmp(version, server_list[i].version) == 0)
+ {
+ INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port);
+ if (node == -1)
+ break; // no more node free
+ SendAskInfo(node);
+ // Force close the connection so that servers can't eat
+ // up nodes forever if we never get a reply back from them
+ // (usually when they've not forwarded their ports).
+ //
+ // Don't worry, we'll get in contact with the working
+ // servers again when they send SERVERINFO to us later!
+ //
+ // (Note: as a side effect this probably means every
+ // server in the list will probably be using the same node (e.g. node 1),
+ // not that it matters which nodes they use when
+ // the connections are closed afterwards anyway)
+ // -- Monster Iestyn 12/11/18
+ Net_CloseConnection(node|FORCECLOSE);
+ }
+ }
+}
+
void CL_UpdateServerList(boolean internetsearch, INT32 room)
{
+#ifdef HAVE_THREADS
+ struct Fetch_servers_ctx *ctx;
+#endif
+
SL_ClearServerList(0);
if (!netgame && I_NetOpenSocket)
{
- MSCloseUDPSocket(); // Tidy up before wiping the slate.
if (I_NetOpenSocket())
{
netgame = true;
@@ -1925,56 +2004,36 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
// search for local servers
if (netgame)
- SendAskInfo(BROADCASTADDR, false);
+ SendAskInfo(BROADCASTADDR);
if (internetsearch)
{
- const msg_server_t *server_list;
- INT32 i = -1;
- server_list = GetShortServersList(room);
+#ifdef HAVE_THREADS
+ ctx = malloc(sizeof *ctx);
+
+ /* This called from M_Refresh so I don't use a mutex */
+ m_waiting_mode = M_WAITING_SERVERS;
+
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ ctx->id = ms_QueryId;
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+
+ ctx->room = room;
+
+ I_spawn_thread("fetch-servers", (I_thread_fn)Fetch_servers_thread, ctx);
+#else
+ msg_server_t *server_list;
+
+ server_list = GetShortServersList(room, 0);
+
if (server_list)
{
- char version[8] = "";
-#if VERSION > 0 || SUBVERSION > 0
- snprintf(version, sizeof (version), "%d.%d", VERSION, SUBVERSION);
-#else
- strcpy(version, GetRevisionString());
+ CL_QueryServerList(server_list);
+ free(server_list);
+ }
#endif
- version[sizeof (version) - 1] = '\0';
-
- for (i = 0; server_list[i].header.buffer[0]; i++)
- {
- // Make sure MS version matches our own, to
- // thwart nefarious servers who lie to the MS.
-
- if (strcmp(version, server_list[i].version) == 0)
- {
- INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port);
- if (node == -1)
- break; // no more node free
- SendAskInfo(node, true);
- // Force close the connection so that servers can't eat
- // up nodes forever if we never get a reply back from them
- // (usually when they've not forwarded their ports).
- //
- // Don't worry, we'll get in contact with the working
- // servers again when they send SERVERINFO to us later!
- //
- // (Note: as a side effect this probably means every
- // server in the list will probably be using the same node (e.g. node 1),
- // not that it matters which nodes they use when
- // the connections are closed afterwards anyway)
- // -- Monster Iestyn 12/11/18
- Net_CloseConnection(node|FORCECLOSE);
- }
- }
- }
-
- //no server list?(-1) or no servers?(0)
- if (!i)
- {
- ; /// TODO: display error or warning?
- }
}
}
@@ -2044,11 +2103,11 @@ static boolean CL_FinishedFileList(void)
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
- "You have WAD files loaded or have\n"
- "modified the game in some way, and\n"
- "your file list does not match\n"
- "the server's file list.\n"
- "Please restart SRB2Kart before connecting.\n\n"
+ "You have the wrong addons loaded.\n\n"
+ "To play on this server, restart\n"
+ "the game and don't load any addons.\n"
+ "SRB2Kart will automatically add\n"
+ "everything you need when you join.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
@@ -2083,11 +2142,12 @@ static boolean CL_FinishedFileList(void)
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
- "You cannot connect to this server\n"
- "because you cannot download the files\n"
- "that you are missing from the server.\n\n"
- "See the console or log file for\n"
- "more details.\n\n"
+ "An error occured when trying to\n"
+ "download missing addons.\n"
+ "(This is almost always a problem\n"
+ "with the server, not your game.)\n\n"
+ "See the console or log file\n"
+ "for additional details.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
@@ -2149,14 +2209,13 @@ static boolean CL_FinishedFileList(void)
/** Called by CL_ServerConnectionTicker
*
- * \param viams ???
* \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit.
* \return False if the connection was aborted
* \sa CL_ServerConnectionTicker
* \sa CL_ConnectToServer
*
*/
-static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
+static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
{
#ifndef NONET
INT32 i;
@@ -2214,7 +2273,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
// Ask the info to the server (askinfo packet)
if (*asksent + NEWTICRATE < I_GetTime())
{
- SendAskInfo(servernode, viams);
+ SendAskInfo(servernode);
*asksent = I_GetTime();
}
#else
@@ -2229,7 +2288,6 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
/** Called by CL_ConnectToServer
*
- * \param viams ???
* \param tmpsave The name of the gamestate file???
* \param oldtic Used for knowing when to poll events and redraw
* \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit.
@@ -2238,7 +2296,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
* \sa CL_ConnectToServer
*
*/
-static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic_t *oldtic, tic_t *asksent)
+static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic_t *asksent)
{
boolean waitmore;
INT32 i;
@@ -2250,7 +2308,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
switch (cl_mode)
{
case CL_SEARCHING:
- if (!CL_ServerConnectionSearchTicker(viams, asksent))
+ if (!CL_ServerConnectionSearchTicker(asksent))
return false;
break;
@@ -2444,11 +2502,10 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
/** Use adaptive send using net_bandwidth and stat.sendbytes
*
- * \param viams ???
* \todo Better description...
*
*/
-static void CL_ConnectToServer(boolean viams)
+static void CL_ConnectToServer(void)
{
INT32 pnumnodes, nodewaited = doomcom->numnodes, i;
tic_t oldtic;
@@ -2520,9 +2577,9 @@ static void CL_ConnectToServer(boolean viams)
{
// If the connection was aborted for some reason, leave
#ifndef NONET
- if (!CL_ServerConnectionTicker(viams, tmpsave, &oldtic, &asksent))
+ if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent))
#else
- if (!CL_ServerConnectionTicker(viams, (char*)NULL, &oldtic, (tic_t *)NULL))
+ if (!CL_ServerConnectionTicker((char*)NULL, &oldtic, (tic_t *)NULL))
#endif
return;
@@ -2648,6 +2705,7 @@ static void Command_ClearBans(void)
return;
I_ClearBans();
+ D_SaveBan();
reasontail = NULL;
while (reasonhead)
{
@@ -2702,9 +2760,6 @@ static void Command_ReloadBan(void) //recheck ban.txt
static void Command_connect(void)
{
- // Assume we connect directly.
- boolean viams = false;
-
if (COM_Argc() < 2 || *COM_Argv(1) == 0)
{
CONS_Printf(M_GetText(
@@ -2738,9 +2793,6 @@ static void Command_connect(void)
if (netgame && !stricmp(COM_Argv(1), "node"))
{
servernode = (SINT8)atoi(COM_Argv(2));
-
- // Use MS to traverse NAT firewalls.
- viams = true;
}
else if (netgame)
{
@@ -2749,7 +2801,6 @@ static void Command_connect(void)
}
else if (I_NetOpenSocket)
{
- MSCloseUDPSocket(); // Tidy up before wiping the slate.
I_NetOpenSocket();
netgame = true;
multiplayer = true;
@@ -2778,7 +2829,7 @@ static void Command_connect(void)
}
botingame = false;
botskin = 0;
- CL_ConnectToServer(viams);
+ CL_ConnectToServer();
}
#endif
@@ -3829,7 +3880,6 @@ boolean SV_SpawnServer(void)
SV_GenContext();
if (netgame && I_NetOpenSocket)
{
- MSCloseUDPSocket(); // Tidy up before wiping the slate.
I_NetOpenSocket();
if (ms_RoomId > 0)
RegisterServer();
@@ -3837,7 +3887,7 @@ boolean SV_SpawnServer(void)
// non dedicated server just connect to itself
if (!dedicated)
- CL_ConnectToServer(false);
+ CL_ConnectToServer();
else doomcom->numslots = 1;
}
@@ -5674,7 +5724,13 @@ FILESTAMP
if (nowtime > resptime)
{
resptime = nowtime;
+#ifdef HAVE_THREADS
+ I_lock_mutex(&m_menu_mutex);
+#endif
M_Ticker();
+#ifdef HAVE_THREADS
+ I_unlock_mutex(m_menu_mutex);
+#endif
CON_Ticker();
}
SV_FileSendTicker();
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index e9b180df..a872b02e 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -18,6 +18,7 @@
#include "d_netcmd.h"
#include "tables.h"
#include "d_player.h"
+#include "mserv.h"
/*
The 'packet version' is used to distinguish packet formats.
@@ -531,6 +532,7 @@ typedef enum
} kickreason_t;
extern boolean server;
+extern boolean serverrunning;
#define client (!server)
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH;
@@ -577,6 +579,7 @@ void CL_RemoveSplitscreenPlayer(UINT8 p);
void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_RemovePlayer(INT32 playernum, INT32 reason);
+void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
// Is there a game running
boolean Playing(void);
diff --git a/src/d_main.c b/src/d_main.c
index 15116b53..4c496c8a 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -50,6 +50,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#include "hu_stuff.h"
#include "i_sound.h"
#include "i_system.h"
+#include "i_threads.h"
#include "i_video.h"
#include "m_argv.h"
#include "m_menu.h"
@@ -143,6 +144,8 @@ boolean advancedemo;
INT32 debugload = 0;
#endif
+char savegamename[256];
+
#ifdef _arch_dreamcast
char srb2home[256] = "/cd";
char srb2path[256] = "/cd";
@@ -185,35 +188,6 @@ UINT8 shiftdown = 0; // 0x1 left, 0x2 right
UINT8 ctrldown = 0; // 0x1 left, 0x2 right
UINT8 altdown = 0; // 0x1 left, 0x2 right
boolean capslock = 0; // gee i wonder what this does.
-//
-// D_ModifierKeyResponder
-// Sets global shift/ctrl/alt variables, never actually eats events
-//
-static inline void D_ModifierKeyResponder(event_t *ev)
-{
- if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
- {
- case KEY_LSHIFT: shiftdown |= 0x1; return;
- case KEY_RSHIFT: shiftdown |= 0x2; return;
- case KEY_LCTRL: ctrldown |= 0x1; return;
- case KEY_RCTRL: ctrldown |= 0x2; return;
- case KEY_LALT: altdown |= 0x1; return;
- case KEY_RALT: altdown |= 0x2; return;
- case KEY_CAPSLOCK: capslock = !capslock; return;
-
- default: return;
- }
- else if (ev->type == ev_keyup) switch (ev->data1)
- {
- case KEY_LSHIFT: shiftdown &= ~0x1; return;
- case KEY_RSHIFT: shiftdown &= ~0x2; return;
- case KEY_LCTRL: ctrldown &= ~0x1; return;
- case KEY_RCTRL: ctrldown &= ~0x2; return;
- case KEY_LALT: altdown &= ~0x1; return;
- case KEY_RALT: altdown &= ~0x2; return;
- default: return;
- }
-}
//
// D_ProcessEvents
@@ -223,6 +197,8 @@ void D_ProcessEvents(void)
{
event_t *ev;
+ boolean eaten;
+
for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
{
ev = &events[eventtail];
@@ -244,7 +220,17 @@ void D_ProcessEvents(void)
}
// Menu input
- if (M_Responder(ev))
+#ifdef HAVE_THREADS
+ I_lock_mutex(&m_menu_mutex);
+#endif
+ {
+ eaten = M_Responder(ev);
+ }
+#ifdef HAVE_THREADS
+ I_unlock_mutex(m_menu_mutex);
+#endif
+
+ if (eaten)
continue; // menu ate the event
// Demo input:
@@ -253,7 +239,17 @@ void D_ProcessEvents(void)
continue; // demo ate the event
// console input
- if (CON_Responder(ev))
+#ifdef HAVE_THREADS
+ I_lock_mutex(&con_mutex);
+#endif
+ {
+ eaten = CON_Responder(ev);
+ }
+#ifdef HAVE_THREADS
+ I_unlock_mutex(con_mutex);
+#endif
+
+ if (eaten)
continue; // ate the event
G_Responder(ev);
@@ -280,7 +276,7 @@ static void D_Display(void)
{
if (nodrawers)
return; // for comparative timing/profiling
-
+
// check for change of screen size (video mode)
if (setmodeneeded && !wipe)
SCR_SetMode(); // change video mode
@@ -549,7 +545,13 @@ static void D_Display(void)
if (gamestate != GS_TIMEATTACK)
CON_Drawer();
+#ifdef HAVE_THREADS
+ I_lock_mutex(&m_menu_mutex);
+#endif
M_Drawer(); // menu is drawn even on top of everything
+#ifdef HAVE_THREADS
+ I_unlock_mutex(m_menu_mutex);
+#endif
// focus lost moved to M_Drawer
//
diff --git a/src/d_net.h b/src/d_net.h
index 30de2991..cc80fcaa 100644
--- a/src/d_net.h
+++ b/src/d_net.h
@@ -19,7 +19,9 @@
#define __D_NET__
// Max computers in a game
-#define MAXNETNODES 64
+// 127 is probably as high as this can go, because
+// SINT8 is used for nodes sometimes >:(
+#define MAXNETNODES 127
#define BROADCASTADDR MAXNETNODES
#define NETSPLITSCREEN // Kart's splitscreen netgame feature
diff --git a/src/d_netfil.c b/src/d_netfil.c
index fd28413b..621ce295 100644
--- a/src/d_netfil.c
+++ b/src/d_netfil.c
@@ -784,7 +784,7 @@ void SV_FileSendTicker(void)
if (ram)
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
- I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
+ I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile));
p->position = LONG(transfer[i].position);
// Put flag so receiver knows the total size
if (transfer[i].position + size == f->size)
@@ -863,7 +863,7 @@ void Got_Filetxpak(void)
// We can receive packet in the wrong order, anyway all os support gaped file
fseek(file->file, pos, SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
- I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
+ I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file));
file->currentsize += size;
// Finished?
@@ -1106,7 +1106,7 @@ void CURLPrepareFile(const char* url, int dfilenum)
// Only allow HTTP and HTTPS
curl_easy_setopt(http_handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
- curl_easy_setopt(http_handle, CURLOPT_USERAGENT, va("SRB2Kart/v%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION)); // Set user agent as some servers won't accept invalid user agents.
+ curl_easy_setopt(http_handle, CURLOPT_USERAGENT, va("SRB2Kart/v%d.%d", VERSION, SUBVERSION)); // Set user agent as some servers won't accept invalid user agents.
// Follow a redirect request, if sent by the server.
curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1L);
diff --git a/src/doomdef.h b/src/doomdef.h
index ed41e346..9ee55d94 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -155,8 +155,8 @@ extern char logfilename[1024];
#else
#define VERSION 1 // Game version
#define SUBVERSION 2 // more precise version number
-#define VERSIONSTRING "v1.2"
-#define VERSIONSTRINGW L"v1.2"
+#define VERSIONSTRING "v1.2 (HTTP MS)"
+#define VERSIONSTRINGW L"v1.2 (HTTP MS)"
// Hey! If you change this, add 1 to the MODVERSION below! Otherwise we can't force updates!
// And change CMakeLists.txt, for CMake users!
// AND appveyor.yml, for the build bots!
@@ -506,7 +506,7 @@ void CONS_Debug(INT32 debugflags, const char *fmt, ...) FUNCDEBUG;
// Things that used to be in dstrings.h
#define SAVEGAMENAME "srb2sav"
-char savegamename[256];
+extern char savegamename[256];
// m_misc.h
#ifdef GETTEXT
diff --git a/src/f_finale.c b/src/f_finale.c
index 909ca261..ade26bbe 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -24,6 +24,7 @@
#include "w_wad.h"
#include "z_zone.h"
#include "i_system.h"
+#include "i_threads.h"
#include "m_menu.h"
#include "dehacked.h"
#include "g_input.h"
@@ -317,7 +318,13 @@ void F_IntroDrawer(void)
{
I_OsPolling();
I_UpdateNoBlit();
+#ifdef HAVE_THREADS
+ I_lock_mutex(&m_menu_mutex);
+#endif
M_Drawer(); // menu is drawn even on top of wipes
+#ifdef HAVE_THREADS
+ I_unlock_mutex(m_menu_mutex);
+#endif
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
}
}
diff --git a/src/f_wipe.c b/src/f_wipe.c
index bb1397bc..8bcb1278 100644
--- a/src/f_wipe.c
+++ b/src/f_wipe.c
@@ -22,6 +22,7 @@
#include "z_zone.h"
#include "i_system.h"
+#include "i_threads.h"
#include "m_menu.h"
#include "console.h"
#include "d_main.h"
@@ -379,7 +380,15 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
I_UpdateNoBlit();
if (drawMenu)
+ {
+#ifdef HAVE_THREADS
+ I_lock_mutex(&m_menu_mutex);
+#endif
M_Drawer(); // menu is drawn even on top of wipes
+#ifdef HAVE_THREADS
+ I_unlock_mutex(m_menu_mutex);
+#endif
+ }
I_FinishUpdate(); // page flip or blit buffer
diff --git a/src/g_game.c b/src/g_game.c
index bf0557d0..dc5874b6 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -6368,7 +6368,9 @@ void G_BeginRecording(void)
demoflags |= DF_ENCORE;
#ifdef HAVE_BLUA
- demoflags |= DF_LUAVARS;
+ if (!modeattacking) // Ghosts don't read luavars, and you shouldn't ever need to save Lua in replays, you doof!
+ // SERIOUSLY THOUGH WHY WOULD YOU LOAD HOSTMOD AND RECORD A GHOST WITH IT !????
+ demoflags |= DF_LUAVARS;
#endif
// Setup header.
@@ -6474,8 +6476,9 @@ void G_BeginRecording(void)
WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing
#ifdef HAVE_BLUA
- // player lua vars, always saved even if empty
- LUA_ArchiveDemo();
+ // player lua vars, always saved even if empty... Unless it's record attack.
+ if (!modeattacking)
+ LUA_ArchiveDemo();
#endif
memset(&oldcmd,0,sizeof(oldcmd));
@@ -7543,6 +7546,7 @@ void G_DoPlayDemo(char *defdemoname)
if (!gL) // No Lua state! ...I guess we'll just start one...
LUA_ClearState();
+ // No modeattacking check, DF_LUAVARS won't be present here.
LUA_UnArchiveDemo();
}
#endif
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 1bad26ee..c7ff5a4a 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -407,7 +407,7 @@ void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t fixedhei
if (angle) // Only needs to be done if there's an altered angle
{
- angle = (InvAngle(angle)+ANGLE_180)>>ANGLETOFINESHIFT;
+ angle = InvAngle(angle)>>ANGLETOFINESHIFT;
// This needs to be done so that it scrolls in a different direction after rotation like software
/*tempxsow = FLOAT_TO_FIXED(scrollx);
@@ -439,7 +439,7 @@ void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t fixedhei
tempxsow = FLOAT_TO_FIXED(v3d->s);
tempytow = FLOAT_TO_FIXED(v3d->t);
v3d->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
- v3d->t = (FIXED_TO_FLOAT(-FixedMul(tempxsow, FINESINE(angle)) - FixedMul(tempytow, FINECOSINE(angle))));
+ v3d->t = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
}
//v3d->s = (float)(v3d->s - flatxref + scrollx);
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 5dc46099..eef723e5 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -143,7 +143,7 @@ static const GLfloat byte2float[256] = {
// -----------------+
#ifdef DEBUG_TO_FILE
-FILE *gllogstream;
+FILE *gllogstream = NULL;
#endif
FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
@@ -152,14 +152,14 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
char str[4096] = "";
va_list arglist;
- if (!gllogstream)
- gllogstream = fopen("ogllog.txt", "w");
+ if (gllogstream)
+ {
+ va_start(arglist, format);
+ vsnprintf(str, 4096, format, arglist);
+ va_end(arglist);
- va_start(arglist, format);
- vsnprintf(str, 4096, format, arglist);
- va_end(arglist);
-
- fwrite(str, strlen(str), 1, gllogstream);
+ fwrite(str, strlen(str), 1, gllogstream);
+ }
#else
(void)format;
#endif
@@ -823,7 +823,7 @@ EXPORT boolean HWRAPI(LoadShaders) (void)
#ifdef GL_SHADERS
GLuint gl_vertShader, gl_fragShader;
GLint i, result;
-
+
if (!pglUseProgram) return false;
gl_customvertexshaders[0] = NULL;
@@ -2002,11 +2002,11 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall
boolean stopFlag = false;
boolean changeState = false;
boolean changeShader = false;
- GLuint nextShader;
+ GLuint nextShader = 0U;
boolean changeTexture = false;
- GLuint nextTexture;
+ GLuint nextTexture = 0U;
boolean changePolyFlags = false;
- FBITFIELD nextPolyFlags;
+ FBITFIELD nextPolyFlags = 0U;
boolean changeSurfaceInfo = false;
FSurfaceInfo nextSurfaceInfo;
@@ -2307,7 +2307,7 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI
pglColor4ubv((GLubyte*)&pSurf->PolyColor.s);
}
-
+
// Tint color
tint.red = byte2float[pSurf->TintColor.s.red];
tint.green = byte2float[pSurf->TintColor.s.green];
diff --git a/src/http-mserv.c b/src/http-mserv.c
new file mode 100644
index 00000000..9d05b80e
--- /dev/null
+++ b/src/http-mserv.c
@@ -0,0 +1,675 @@
+// SONIC ROBO BLAST 2 KART
+//-----------------------------------------------------------------------------
+// Copyright (C) 2020 by James R.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+// \brief HTTP based master server
+
+/*
+Documentation available here.
+
+
+*/
+
+#include
+
+#include "doomdef.h"
+#include "d_clisrv.h"
+#include "command.h"
+#include "m_argv.h"
+#include "m_menu.h"
+#include "mserv.h"
+#include "i_tcp.h"/* for current_port */
+#include "i_threads.h"
+
+/* reasonable default I guess?? */
+#define DEFAULT_BUFFER_SIZE (4096)
+
+/* I just stop myself from making macros anymore. */
+#define Blame( ... ) \
+ CONS_Printf("\x85" __VA_ARGS__)
+
+static void MasterServer_Debug_OnChange (void);
+
+consvar_t cv_masterserver_timeout = {
+ "masterserver_timeout", "5", CV_SAVE, CV_Unsigned,
+ NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
+};
+
+consvar_t cv_masterserver_debug = {
+ "masterserver_debug", "Off", CV_SAVE|CV_CALL, CV_OnOff,
+ MasterServer_Debug_OnChange, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
+};
+
+consvar_t cv_masterserver_token = {
+ "masterserver_token", "", CV_SAVE, NULL,
+ NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
+};
+
+static int hms_started;
+
+static char *hms_api;
+#ifdef HAVE_THREADS
+static I_mutex hms_api_mutex;
+#endif
+
+static char *hms_server_token;
+
+struct HMS_buffer
+{
+ CURL *curl;
+ char *buffer;
+ int needle;
+ int end;
+};
+
+static void
+Contact_error (void)
+{
+ CONS_Alert(CONS_ERROR,
+ "There was a problem contacting the master server...\n"
+ );
+}
+
+static size_t
+HMS_on_read (char *s, size_t _1, size_t n, void *userdata)
+{
+ struct HMS_buffer *buffer;
+ size_t blocks;
+
+ (void)_1;
+
+ buffer = userdata;
+
+ if (n >= (size_t)( buffer->end - buffer->needle ))
+ {
+ /* resize to next multiple of buffer size */
+ blocks = ( n / DEFAULT_BUFFER_SIZE + 1 );
+ buffer->end += ( blocks * DEFAULT_BUFFER_SIZE );
+
+ buffer->buffer = realloc(buffer->buffer, buffer->end);
+ }
+
+ memcpy(&buffer->buffer[buffer->needle], s, n);
+ buffer->needle += n;
+
+ return n;
+}
+
+static struct HMS_buffer *
+HMS_connect (const char *format, ...)
+{
+ va_list ap;
+ CURL *curl;
+ char *url;
+ char *quack_token;
+ size_t seek;
+ size_t token_length;
+ struct HMS_buffer *buffer;
+
+ if (! hms_started)
+ {
+ if (curl_global_init(CURL_GLOBAL_ALL) != 0)
+ {
+ Contact_error();
+ Blame("From curl_global_init.\n");
+ return NULL;
+ }
+ else
+ {
+ atexit(curl_global_cleanup);
+ hms_started = 1;
+ }
+ }
+
+ curl = curl_easy_init();
+
+ if (! curl)
+ {
+ Contact_error();
+ Blame("From curl_easy_init.\n");
+ return NULL;
+ }
+
+ if (cv_masterserver_token.string[0])
+ {
+ quack_token = curl_easy_escape(curl, cv_masterserver_token.string, 0);
+ token_length = ( sizeof "?token="-1 )+ strlen(quack_token);
+ }
+ else
+ {
+ quack_token = NULL;
+ token_length = 0;
+ }
+
+#ifdef HAVE_THREADS
+ I_lock_mutex(&hms_api_mutex);
+#endif
+
+ seek = strlen(hms_api) + 1;/* + '/' */
+
+ va_start (ap, format);
+ url = malloc(seek + vsnprintf(0, 0, format, ap) + token_length + 1);
+ va_end (ap);
+
+ sprintf(url, "%s/", hms_api);
+
+#ifdef HAVE_THREADS
+ I_unlock_mutex(hms_api_mutex);
+#endif
+
+ va_start (ap, format);
+ seek += vsprintf(&url[seek], format, ap);
+ va_end (ap);
+
+ if (quack_token)
+ sprintf(&url[seek], "?token=%s", quack_token);
+
+ CONS_Printf("HMS: connecting '%s'...\n", url);
+
+ buffer = malloc(sizeof *buffer);
+ buffer->curl = curl;
+ buffer->end = DEFAULT_BUFFER_SIZE;
+ buffer->buffer = malloc(buffer->end);
+ buffer->needle = 0;
+
+ if (cv_masterserver_debug.value)
+ {
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+ curl_easy_setopt(curl, CURLOPT_STDERR, logstream);
+ }
+
+ if (M_CheckParm("-bindaddr") && M_IsNextParm())
+ {
+ curl_easy_setopt(curl, CURLOPT_INTERFACE, M_GetNextParm());
+ }
+
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
+
+ curl_free(quack_token);
+ free(url);
+
+ return buffer;
+}
+
+static int
+HMS_do (struct HMS_buffer *buffer)
+{
+ CURLcode cc;
+ long status;
+
+ char *p;
+
+ cc = curl_easy_perform(buffer->curl);
+
+ if (cc != CURLE_OK)
+ {
+ Contact_error();
+ Blame(
+ "From curl_easy_perform: %s\n",
+ curl_easy_strerror(cc)
+ );
+ return 0;
+ }
+
+ buffer->buffer[buffer->needle] = '\0';
+
+ curl_easy_getinfo(buffer->curl, CURLINFO_RESPONSE_CODE, &status);
+
+ if (status != 200)
+ {
+ p = strchr(buffer->buffer, '\n');
+
+ if (p)
+ *p = '\0';
+
+ Contact_error();
+ Blame(
+ "Master server error %ld: %s%s\n",
+ status,
+ buffer->buffer,
+ ( (p) ? "" : " (malformed)" )
+ );
+
+ return 0;
+ }
+ else
+ return 1;
+}
+
+static void
+HMS_end (struct HMS_buffer *buffer)
+{
+ curl_easy_cleanup(buffer->curl);
+ free(buffer->buffer);
+ free(buffer);
+}
+
+int
+HMS_fetch_rooms (int joining, int query_id)
+{
+ struct HMS_buffer *hms;
+ int ok;
+
+ int doing_shit;
+
+ char *id;
+ char *title;
+ char *room_motd;
+
+ int id_no;
+
+ char *p;
+ char *end;
+
+ int i;
+
+ (void)query_id;
+
+ hms = HMS_connect("rooms");
+
+ if (! hms)
+ return 0;
+
+ if (HMS_do(hms))
+ {
+ doing_shit = 1;
+
+ p = hms->buffer;
+
+ for (i = 0; i < NUM_LIST_ROOMS && ( end = strstr(p, "\n\n\n") );)
+ {
+ *end = '\0';
+
+ id = strtok(p, "\n");
+ title = strtok(0, "\n");
+ room_motd = strtok(0, "");
+
+ if (id && title && room_motd)
+ {
+ id_no = atoi(id);
+
+ /*
+ Don't show the 'All' room if hosting. And it's a hack like this
+ because I'm way too lazy to add another feature to the MS.
+ */
+ if (joining || id_no != 0)
+ {
+#ifdef HAVE_THREADS
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ if (query_id != ms_QueryId)
+ doing_shit = 0;
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+
+ if (! doing_shit)
+ break;
+#endif
+
+ room_list[i].header.buffer[0] = 1;
+
+ room_list[i].id = id_no;
+ strlcpy(room_list[i].name, title, sizeof room_list[i].name);
+ strlcpy(room_list[i].motd, room_motd, sizeof room_list[i].motd);
+
+ i++;
+ }
+
+ p = ( end + 3 );/* skip the three linefeeds */
+ }
+ else
+ break;
+ }
+
+ if (doing_shit)
+ room_list[i].header.buffer[0] = 0;
+
+ ok = 1;
+
+ if (doing_shit)
+ {
+#ifdef HAVE_THREADS
+ I_lock_mutex(&m_menu_mutex);
+#endif
+ {
+ for (i = 0; room_list[i].header.buffer[0]; i++)
+ {
+ if(*room_list[i].name != '\0')
+ {
+ MP_RoomMenu[i+1].text = room_list[i].name;
+ roomIds[i] = room_list[i].id;
+ MP_RoomMenu[i+1].status = IT_STRING|IT_CALL;
+ }
+ }
+ }
+#ifdef HAVE_THREADS
+ I_unlock_mutex(m_menu_mutex);
+#endif
+ }
+ }
+ else
+ ok = 0;
+
+ HMS_end(hms);
+
+ return ok;
+}
+
+int
+HMS_register (void)
+{
+ struct HMS_buffer *hms;
+ int ok;
+
+ char post[256];
+
+ char *title;
+
+ hms = HMS_connect("rooms/%d/register", ms_RoomId);
+
+ if (! hms)
+ return 0;
+
+ title = curl_easy_escape(hms->curl, cv_servername.string, 0);
+
+ snprintf(post, sizeof post,
+ "port=%d&"
+ "title=%s&"
+ "version=%d.%d",
+
+ current_port,
+
+ title,
+
+ VERSION,
+ SUBVERSION
+ );
+
+ curl_free(title);
+
+ curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post);
+
+ ok = HMS_do(hms);
+
+ if (ok)
+ {
+ hms_server_token = strdup(strtok(hms->buffer, "\n"));
+ }
+
+ HMS_end(hms);
+
+ return ok;
+}
+
+int
+HMS_unlist (void)
+{
+ struct HMS_buffer *hms;
+ int ok;
+
+ hms = HMS_connect("servers/%s/unlist", hms_server_token);
+
+ if (! hms)
+ return 0;
+
+ curl_easy_setopt(hms->curl, CURLOPT_CUSTOMREQUEST, "POST");
+
+ ok = HMS_do(hms);
+ HMS_end(hms);
+
+ free(hms_server_token);
+
+ return ok;
+}
+
+int
+HMS_update (void)
+{
+ struct HMS_buffer *hms;
+ int ok;
+
+ char post[256];
+
+ char *title;
+
+ hms = HMS_connect("servers/%s/update", hms_server_token);
+
+ if (! hms)
+ return 0;
+
+ title = curl_easy_escape(hms->curl, cv_servername.string, 0);
+
+ snprintf(post, sizeof post,
+ "title=%s",
+ title
+ );
+
+ curl_free(title);
+
+ curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post);
+
+ ok = HMS_do(hms);
+ HMS_end(hms);
+
+ return ok;
+}
+
+void
+HMS_list_servers (void)
+{
+ struct HMS_buffer *hms;
+
+ char *p;
+
+ hms = HMS_connect("servers");
+
+ if (! hms)
+ return;
+
+ if (HMS_do(hms))
+ {
+ p = &hms->buffer[strlen(hms->buffer)];
+ while (*--p == '\n')
+ ;
+
+ CONS_Printf("%s\n", hms->buffer);
+ }
+
+ HMS_end(hms);
+}
+
+msg_server_t *
+HMS_fetch_servers (msg_server_t *list, int room_number, int query_id)
+{
+ struct HMS_buffer *hms;
+
+ int doing_shit;
+
+ char local_version[9];
+
+ char *room;
+
+ char *address;
+ char *port;
+ char *title;
+ char *version;
+
+ char *end;
+ char *section_end;
+ char *p;
+
+ int i;
+
+ (void)query_id;
+
+ if (room_number > 0)
+ {
+ hms = HMS_connect("rooms/%d/servers", room_number);
+ }
+ else
+ hms = HMS_connect("servers");
+
+ if (! hms)
+ return NULL;
+
+ if (HMS_do(hms))
+ {
+ doing_shit = 1;
+
+ snprintf(local_version, sizeof local_version,
+ "%d.%d",
+ VERSION,
+ SUBVERSION
+ );
+
+ p = hms->buffer;
+ i = 0;
+
+ do
+ {
+ section_end = strstr(p, "\n\n");
+
+ room = strtok(p, "\n");
+
+ p = strtok(0, "");
+
+ if (! p)
+ break;
+
+ while (i < MAXSERVERLIST && ( end = strchr(p, '\n') ))
+ {
+ *end = '\0';
+
+ address = strtok(p, " ");
+ port = strtok(0, " ");
+ title = strtok(0, " ");
+ version = strtok(0, "");
+
+ if (address && port && title && version)
+ {
+#ifdef HAVE_THREADS
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ if (query_id != ms_QueryId)
+ doing_shit = 0;
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+
+ if (! doing_shit)
+ break;
+#endif
+
+ if (strcmp(version, local_version) == 0)
+ {
+ strlcpy(list[i].ip, address, sizeof list[i].ip);
+ strlcpy(list[i].port, port, sizeof list[i].port);
+ strlcpy(list[i].name, title, sizeof list[i].name);
+ strlcpy(list[i].version, version, sizeof list[i].version);
+
+ list[i].room = atoi(room);
+
+ list[i].header.buffer[0] = 1;
+
+ i++;
+ }
+
+ if (end == section_end)/* end of list for this room */
+ break;
+ else
+ p = ( end + 1 );/* skip server delimiter */
+ }
+ else
+ {
+ section_end = 0;/* malformed so quit the parsing */
+ break;
+ }
+ }
+
+ if (! doing_shit)
+ break;
+
+ p = ( section_end + 2 );
+ }
+ while (section_end) ;
+
+ if (doing_shit)
+ list[i].header.buffer[0] = 0;
+ }
+ else
+ list = NULL;
+
+ HMS_end(hms);
+
+ return list;
+}
+
+int
+HMS_compare_mod_version (char *buffer, size_t buffer_size)
+{
+ struct HMS_buffer *hms;
+ int ok;
+
+ char *version;
+ char *version_name;
+
+ hms = HMS_connect("versions/%d", MODID);
+
+ if (! hms)
+ return 0;
+
+ ok = 0;
+
+ if (HMS_do(hms))
+ {
+ version = strtok(hms->buffer, " ");
+ version_name = strtok(0, "\n");
+
+ if (version && version_name)
+ {
+ if (atoi(version) != MODVERSION)
+ {
+ strlcpy(buffer, version_name, buffer_size);
+ ok = 1;
+ }
+ else
+ ok = -1;
+ }
+ }
+
+ HMS_end(hms);
+
+ return ok;
+}
+
+void
+HMS_set_api (char *api)
+{
+#ifdef HAVE_THREADS
+ I_lock_mutex(&hms_api_mutex);
+#endif
+ {
+ free(hms_api);
+ hms_api = api;
+ }
+#ifdef HAVE_THREADS
+ I_unlock_mutex(hms_api_mutex);
+#endif
+}
+
+static void
+MasterServer_Debug_OnChange (void)
+{
+ /* TODO: change to 'latest-log.txt' for log files revision. */
+ if (cv_masterserver_debug.value)
+ CONS_Printf("Master server debug messages will appear in log.txt\n");
+}
diff --git a/src/i_threads.h b/src/i_threads.h
new file mode 100644
index 00000000..45a3dcc3
--- /dev/null
+++ b/src/i_threads.h
@@ -0,0 +1,39 @@
+// SONIC ROBO BLAST 2 KART
+//-----------------------------------------------------------------------------
+// Copyright (C) 2020 by James R.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file i_threads.h
+/// \brief Multithreading abstraction
+
+#ifdef HAVE_THREADS
+
+#ifndef I_THREADS_H
+#define I_THREADS_H
+
+typedef void (*I_thread_fn)(void *userdata);
+
+typedef void * I_mutex;
+typedef void * I_cond;
+
+void I_start_threads (void);
+void I_stop_threads (void);
+
+void I_spawn_thread (const char *name, I_thread_fn, void *userdata);
+
+/* check in your thread whether to return early */
+int I_thread_is_stopped (void);
+
+void I_lock_mutex (I_mutex *);
+void I_unlock_mutex (I_mutex);
+
+void I_hold_cond (I_cond *, I_mutex);
+
+void I_wake_one_cond (I_cond *);
+void I_wake_all_cond (I_cond *);
+
+#endif/*I_THREADS_H*/
+#endif/*HAVE_THREADS*/
diff --git a/src/k_kart.c b/src/k_kart.c
index cc5504bb..b4c2992e 100644
--- a/src/k_kart.c
+++ b/src/k_kart.c
@@ -898,6 +898,7 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp
newodds = 0;
else
POWERITEMODDS(newodds);
+ break;
case KITEM_HYUDORO:
if ((hyubgone > 0) || COOLDOWNONSTART)
newodds = 0;
@@ -1061,6 +1062,10 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
bestbumper = players[i].kartstuff[k_bumper];
}
+ // No forced SPB in 1v1s, it has to be randomly rolled
+ if (pingame <= 2)
+ dontforcespb = true;
+
// This makes the roulette produce the random noises.
if ((player->kartstuff[k_itemroulette] % 3) == 1 && P_IsDisplayPlayer(player) && !demo.freecam)
{
@@ -3312,7 +3317,8 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter)
if (!thismine || P_MobjWasRemoved(thismine))
return;
- if (thismine->type == MT_SSMINE_SHIELD) // Create a new mine
+ //This guarantees you hit a mine being dragged
+ if (thismine->type == MT_SSMINE_SHIELD) // Create a new mine, and clean up the old one
{
mine = P_SpawnMobj(thismine->x, thismine->y, thismine->z, MT_SSMINE);
P_SetTarget(&mine->target, thismine->target);
@@ -3320,7 +3326,19 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter)
mine->flags2 = thismine->flags2;
mine->floorz = thismine->floorz;
mine->ceilingz = thismine->ceilingz;
+
+ //Since we aren't using P_KillMobj, we need to clean up the hnext reference
+ {
+ P_SetTarget(&thismine->target->hnext, NULL); //target is the player who owns the mine
+ thismine->target->player->kartstuff[k_bananadrag] = 0;
+ thismine->target->player->kartstuff[k_itemheld] = 0;
+
+ if (--thismine->target->player->kartstuff[k_itemamount] <= 0)
+ thismine->target->player->kartstuff[k_itemtype] = KITEM_NONE;
+ }
+
P_RemoveMobj(thismine);
+
}
else
mine = thismine;
@@ -3870,6 +3888,62 @@ void K_DropItems(player_t *player)
K_StripItems(player);
}
+void K_DropRocketSneaker(player_t *player)
+{
+ mobj_t *shoe = player->mo;
+ fixed_t flingangle;
+ boolean leftshoe = true; //left shoe is first
+
+ if (!(player->mo && !P_MobjWasRemoved(player->mo) && player->mo->hnext && !P_MobjWasRemoved(player->mo->hnext)))
+ return;
+
+ while ((shoe = shoe->hnext) && !P_MobjWasRemoved(shoe))
+ {
+ if (shoe->type != MT_ROCKETSNEAKER)
+ return; //woah, not a rocketsneaker, bail! safeguard in case this gets used when you're holding non-rocketsneakers
+
+ shoe->flags2 &= ~MF2_DONTDRAW;
+ shoe->flags &= ~MF_NOGRAVITY;
+ shoe->angle += ANGLE_45;
+
+ if (shoe->eflags & MFE_VERTICALFLIP)
+ shoe->z -= shoe->height;
+ else
+ shoe->z += shoe->height;
+
+ //left shoe goes off tot eh left, right shoe off to the right
+ if (leftshoe)
+ flingangle = -(ANG60);
+ else
+ flingangle = ANG60;
+
+ S_StartSound(shoe, shoe->info->deathsound);
+ P_SetObjectMomZ(shoe, 8*FRACUNIT, false);
+ P_InstaThrust(shoe, R_PointToAngle2(shoe->target->x, shoe->target->y, shoe->x, shoe->y)+flingangle, 16*FRACUNIT);
+ shoe->momx += shoe->target->momx;
+ shoe->momy += shoe->target->momy;
+ shoe->momz += shoe->target->momz;
+ shoe->extravalue2 = 1;
+
+ leftshoe = false;
+ }
+ P_SetTarget(&player->mo->hnext, NULL);
+ player->kartstuff[k_rocketsneakertimer] = 0;
+}
+
+void K_DropKitchenSink(player_t *player)
+{
+ if (!(player->mo && !P_MobjWasRemoved(player->mo) && player->mo->hnext && !P_MobjWasRemoved(player->mo->hnext)))
+ return;
+
+ if (player->mo->hnext->type != MT_SINK_SHIELD)
+ return; //so we can just call this function regardless of what is being held
+
+ P_KillMobj(player->mo->hnext, NULL, NULL);
+
+ P_SetTarget(&player->mo->hnext, NULL);
+}
+
// When an item in the hnext chain dies.
void K_RepairOrbitChain(mobj_t *orbit)
{
@@ -4490,6 +4564,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
fast->momx = 3*player->mo->momx/4;
fast->momy = 3*player->mo->momy/4;
fast->momz = 3*player->mo->momz/4;
+ P_SetTarget(&fast->target, player->mo); // easier lua access
K_MatchGenericExtraFlags(fast, player->mo);
}
@@ -5195,12 +5270,12 @@ void K_KartUpdatePosition(player_t *player)
//
void K_StripItems(player_t *player)
{
+ K_DropRocketSneaker(player);
+ K_DropKitchenSink(player);
player->kartstuff[k_itemtype] = KITEM_NONE;
player->kartstuff[k_itemamount] = 0;
player->kartstuff[k_itemheld] = 0;
- player->kartstuff[k_rocketsneakertimer] = 0;
-
if (!player->kartstuff[k_itemroulette] || player->kartstuff[k_roulettetype] != 2)
{
player->kartstuff[k_itemroulette] = 0;
@@ -8634,7 +8709,7 @@ void K_drawKartFreePlay(UINT32 flashtime)
return;
V_DrawKartString((BASEVIDWIDTH - (LAPS_X+1)) - (12*9), // mirror the laps thingy
- LAPS_Y+3, V_SNAPTOBOTTOM|V_SNAPTORIGHT, "FREE PLAY");
+ LAPS_Y+3, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, "FREE PLAY");
}
static void K_drawDistributionDebugger(void)
diff --git a/src/k_kart.h b/src/k_kart.h
index 2ba5d1bd..79606540 100644
--- a/src/k_kart.h
+++ b/src/k_kart.h
@@ -11,7 +11,7 @@
#define KART_FULLTURN 800
-UINT8 colortranslations[MAXTRANSLATIONS][16];
+extern UINT8 colortranslations[MAXTRANSLATIONS][16];
extern const char *KartColor_Names[MAXSKINCOLORS];
extern const UINT8 KartColor_Opposite[MAXSKINCOLORS*2];
void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor);
@@ -55,6 +55,8 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue);
INT32 K_GetKartDriftSparkValue(player_t *player);
void K_KartUpdatePosition(player_t *player);
void K_DropItems(player_t *player);
+void K_DropRocketSneaker(player_t *player);
+void K_DropKitchenSink(player_t *player);
void K_StripItems(player_t *player);
void K_StripOther(player_t *player);
void K_MomentumToFacing(player_t *player);
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index d9766513..3aeeed73 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -17,6 +17,7 @@
#include "d_player.h"
#include "g_game.h"
#include "p_local.h"
+#include "d_clisrv.h"
#include "lua_script.h"
#include "lua_libs.h"
@@ -118,7 +119,7 @@ static int lib_iterateDisplayplayers(lua_State *L)
for (i++; i < MAXSPLITSCREENPLAYERS; i++)
{
- if (!playeringame[displayplayers[i]] || i > splitscreen)
+ if (i > splitscreen || !playeringame[displayplayers[i]])
return 0; // Stop! There are no more players for us to go through. There will never be a player gap in displayplayers.
if (!players[displayplayers[i]].mo)
@@ -139,6 +140,8 @@ static int lib_getDisplayplayers(lua_State *L)
lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0 || i >= MAXSPLITSCREENPLAYERS)
return luaL_error(L, "displayplayers[] index %d out of range (0 - %d)", i, MAXSPLITSCREENPLAYERS-1);
+ if (i > splitscreen)
+ return 0;
if (!playeringame[displayplayers[i]])
return 0;
if (!players[displayplayers[i]].mo)
@@ -385,6 +388,8 @@ static int player_get(lua_State *L)
else if (fastcmp(field,"fovadd"))
lua_pushfixed(L, plr->fovadd);
#endif
+ else if (fastcmp(field,"ping"))
+ lua_pushinteger(L, playerpingtable[( plr - players )]);
else {
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));
diff --git a/src/m_argv.c b/src/m_argv.c
index e8bfdd3d..e1046f8a 100644
--- a/src/m_argv.c
+++ b/src/m_argv.c
@@ -16,6 +16,7 @@
#include "doomdef.h"
#include "command.h"
#include "m_argv.h"
+#include "m_misc.h"
/** \brief number of arg
*/
@@ -166,7 +167,7 @@ void M_FindResponseFile(void)
if (!file)
I_Error("No more free memory for the response file");
if (fread(file, size, 1, handle) != 1)
- I_Error("Couldn't read response file because %s", strerror(ferror(handle)));
+ I_Error("Couldn't read response file because %s", M_FileError(handle));
fclose(handle);
// keep all the command line arguments following @responsefile
diff --git a/src/m_menu.c b/src/m_menu.c
index e08a53c5..850b8d74 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -32,6 +32,7 @@
#include "sounds.h"
#include "s_sound.h"
#include "i_system.h"
+#include "i_threads.h"
// Addfile
#include "filesrch.h"
@@ -118,6 +119,12 @@ typedef enum
NUM_QUITMESSAGES
} text_enum;
+#ifdef HAVE_THREADS
+I_mutex m_menu_mutex;
+#endif
+
+M_waiting_mode_t m_waiting_mode = M_NOT_WAITING;
+
const char *quitmsg[NUM_QUITMESSAGES];
// Stuff for customizing the player select screen Tails 09-22-2003
@@ -1039,7 +1046,7 @@ enum
FIRSTSERVERLINE
};
-static menuitem_t MP_RoomMenu[] =
+menuitem_t MP_RoomMenu[] =
{
{IT_STRING | IT_CALL, NULL, "", M_ChooseRoom, 9},
{IT_DISABLED, NULL, "", M_ChooseRoom, 18},
@@ -2896,7 +2903,6 @@ boolean M_Responder(event_t *ev)
//make sure the game doesn't still think we're in a netgame.
if (!Playing() && netgame && multiplayer)
{
- MSCloseUDPSocket(); // Clean up so we can re-open the connection later.
netgame = false;
multiplayer = false;
}
@@ -3304,6 +3310,30 @@ void M_SetupNextMenu(menu_t *menudef)
{
INT16 i;
+#ifdef HAVE_THREADS
+ if (currentMenu == &MP_RoomDef || currentMenu == &MP_ConnectDef)
+ {
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ ms_QueryId++;
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+ }
+
+ if (currentMenu == &MP_ConnectDef)
+ {
+ I_lock_mutex(&ms_ServerList_mutex);
+ {
+ if (ms_ServerList)
+ {
+ free(ms_ServerList);
+ ms_ServerList = NULL;
+ }
+ }
+ I_unlock_mutex(ms_ServerList_mutex);
+ }
+#endif/*HAVE_THREADS*/
+
if (currentMenu->quitroutine)
{
// If you're going from a menu to itself, why are you running the quitroutine? You're not quitting it! -SH
@@ -3361,6 +3391,19 @@ void M_Ticker(void)
if (--vidm_testingmode == 0)
setmodeneeded = vidm_previousmode + 1;
}
+
+#ifdef HAVE_THREADS
+ I_lock_mutex(&ms_ServerList_mutex);
+ {
+ if (ms_ServerList)
+ {
+ CL_QueryServerList(ms_ServerList);
+ free(ms_ServerList);
+ ms_ServerList = NULL;
+ }
+ }
+ I_unlock_mutex(ms_ServerList_mutex);
+#endif
}
//
@@ -4833,7 +4876,7 @@ static boolean M_AddonsRefresh(void)
else if (majormods && !prevmajormods)
{
S_StartSound(NULL, sfx_s221);
- message = va("%c%s\x80\nGameplay has now been modified.\nIf you wish to play Record Attack mode, restart the game to clear existing addons.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
+ message = va("%c%s\x80\nYou've loaded a gameplay-modifying addon.\n\nRecord Attack has been disabled, but you\ncan still play alone in local Multiplayer.\n\nIf you wish to play Record Attack mode, restart the game to disable loaded addons.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
prevmajormods = majormods;
}
@@ -8327,22 +8370,65 @@ static INT32 menuRoomIndex = 0;
static void M_DrawRoomMenu(void)
{
+ static int frame = -12;
+ int dot_frame;
+ char text[4];
+
const char *rmotd;
+ const char *waiting_message;
+
+ int dots;
+
+ if (m_waiting_mode)
+ {
+ dot_frame = frame / 4;
+ dots = dot_frame + 3;
+
+ strcpy(text, " ");
+
+ if (dots > 0)
+ {
+ if (dot_frame < 0)
+ dot_frame = 0;
+
+ strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame));
+ }
+
+ if (++frame == 12)
+ frame = -12;
+
+ currentMenu->menuitems[0].text = text;
+ }
// use generic drawer for cursor, items and title
M_DrawGenericMenu();
V_DrawString(currentMenu->x - 16, currentMenu->y, highlightflags, M_GetText("Select a room"));
- M_DrawTextBox(144, 24, 20, 20);
+ if (m_waiting_mode == M_NOT_WAITING)
+ {
+ M_DrawTextBox(144, 24, 20, 20);
- if (itemOn == 0)
- rmotd = M_GetText("Don't connect to the Master Server.");
- else
- rmotd = room_list[itemOn-1].motd;
+ if (itemOn == 0)
+ rmotd = M_GetText("Don't connect to the Master Server.");
+ else
+ rmotd = room_list[itemOn-1].motd;
- rmotd = V_WordWrap(0, 20*8, 0, rmotd);
- V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd);
+ rmotd = V_WordWrap(0, 20*8, 0, rmotd);
+ V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd);
+ }
+
+ if (m_waiting_mode)
+ {
+ // Display a little "please wait" message.
+ M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
+ if (m_waiting_mode == M_WAITING_VERSION)
+ waiting_message = "Checking for updates...";
+ else
+ waiting_message = "Fetching room info...";
+ V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, waiting_message);
+ V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
+ }
}
static void M_DrawConnectMenu(void)
@@ -8416,6 +8502,14 @@ static void M_DrawConnectMenu(void)
localservercount = serverlistcount;
M_DrawGenericMenu();
+
+ if (m_waiting_mode)
+ {
+ // 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.");
+ }
}
static boolean M_CancelConnect(void)
@@ -8497,10 +8591,10 @@ void M_SortServerList(void)
#ifndef NONET
#ifdef UPDATE_ALERT
-static boolean M_CheckMODVersion(void)
+static boolean M_CheckMODVersion(int id)
{
char updatestring[500];
- const char *updatecheck = GetMODVersion();
+ const char *updatecheck = GetMODVersion(id);
if(updatecheck)
{
sprintf(updatestring, UPDATE_ALERT_STRING, VERSIONSTRING, updatecheck);
@@ -8509,7 +8603,62 @@ static boolean M_CheckMODVersion(void)
} else
return true;
}
-#endif
+
+#ifdef HAVE_THREADS
+static void
+Check_new_version_thread (int *id)
+{
+ int hosting;
+ int okay;
+
+ okay = 0;
+
+ if (M_CheckMODVersion(*id))
+ {
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ okay = ( *id == ms_QueryId );
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+
+ if (okay)
+ {
+ I_lock_mutex(&m_menu_mutex);
+ {
+ m_waiting_mode = M_WAITING_ROOMS;
+ hosting = ( currentMenu->prevMenu == &MP_ServerDef );
+ }
+ I_unlock_mutex(m_menu_mutex);
+
+ GetRoomsList(hosting, *id);
+ }
+ }
+ else
+ {
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ okay = ( *id == ms_QueryId );
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+ }
+
+ if (okay)
+ {
+ I_lock_mutex(&m_menu_mutex);
+ {
+ if (m_waiting_mode)
+ {
+ m_waiting_mode = M_NOT_WAITING;
+ MP_RoomMenu[0].text = "";
+ }
+ }
+ I_unlock_mutex(m_menu_mutex);
+ }
+
+ free(id);
+}
+#endif/*HAVE_THREADS*/
+#endif/*UPDATE_ALERT*/
static void M_ConnectMenu(INT32 choice)
{
@@ -8538,18 +8687,21 @@ static void M_ConnectMenuModChecks(INT32 choice)
if (modifiedgame)
{
- M_StartMessage(M_GetText("Addons are currently loaded.\n\nYou will only be able to join a server if\nit has the same ones loaded in the same order, which may be unlikely.\n\nIf you wish to play on other servers,\nrestart the game to clear existing addons.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER);
+ M_StartMessage(M_GetText("You have addons loaded.\nYou won't be able to join netgames!\n\nTo play online, restart the game\nand don't load any addons.\nSRB2Kart will automatically add\neverything you need when you join.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER);
return;
}
M_ConnectMenu(-1);
}
-static UINT32 roomIds[NUM_LIST_ROOMS];
+UINT32 roomIds[NUM_LIST_ROOMS];
static void M_RoomMenu(INT32 choice)
{
INT32 i;
+#ifdef HAVE_THREADS
+ int *id;
+#endif
(void)choice;
@@ -8562,34 +8714,47 @@ static void M_RoomMenu(INT32 choice)
if (rendermode == render_soft)
I_FinishUpdate(); // page flip or blit buffer
- if (GetRoomsList(currentMenu == &MP_ServerDef) < 0)
- return;
-
-#ifdef UPDATE_ALERT
- if (!M_CheckMODVersion())
- return;
-#endif
-
for (i = 1; i < NUM_LIST_ROOMS+1; ++i)
MP_RoomMenu[i].status = IT_DISABLED;
memset(roomIds, 0, sizeof(roomIds));
- for (i = 0; room_list[i].header.buffer[0]; i++)
- {
- if(*room_list[i].name != '\0')
- {
- MP_RoomMenu[i+1].text = room_list[i].name;
- roomIds[i] = room_list[i].id;
- MP_RoomMenu[i+1].status = IT_STRING|IT_CALL;
- }
- }
-
MP_RoomDef.prevMenu = currentMenu;
M_SetupNextMenu(&MP_RoomDef);
+
+#ifdef UPDATE_ALERT
+#ifdef HAVE_THREADS
+ m_waiting_mode = M_WAITING_VERSION;
+ MP_RoomMenu[0].text = "";
+
+ id = malloc(sizeof *id);
+
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ *id = ms_QueryId;
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+
+ I_spawn_thread("check-new-version",
+ (I_thread_fn)Check_new_version_thread, id);
+#else/*HAVE_THREADS*/
+ if (M_CheckMODVersion(0))
+ {
+ GetRoomsList(currentMenu->prevMenu == &MP_ServerDef, 0);
+ }
+#endif/*HAVE_THREADS*/
+#endif/*UPDATE_ALERT*/
}
static void M_ChooseRoom(INT32 choice)
{
+#ifdef HAVE_THREADS
+ I_lock_mutex(&ms_QueryId_mutex);
+ {
+ ms_QueryId++;
+ }
+ I_unlock_mutex(ms_QueryId_mutex);
+#endif
+
if (choice == 0)
ms_RoomId = -1;
else
diff --git a/src/m_menu.h b/src/m_menu.h
index 86a84089..1ad20c77 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -17,6 +17,8 @@
#include "d_event.h"
#include "command.h"
+#include "i_threads.h"
+#include "mserv.h"
#include "r_things.h" // for SKINNAMESIZE
//
@@ -72,6 +74,18 @@ typedef enum
} menumessagetype_t;
void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype);
+typedef enum
+{
+ M_NOT_WAITING,
+
+ M_WAITING_VERSION,
+ M_WAITING_ROOMS,
+ M_WAITING_SERVERS,
+}
+M_waiting_mode_t;
+
+extern M_waiting_mode_t m_waiting_mode;
+
// Called by linux_x/i_video_xshm.c
void M_QuitResponse(INT32 ch);
@@ -161,6 +175,9 @@ typedef struct menuitem_s
extern menuitem_t PlayerMenu[MAXSKINS];
+extern menuitem_t MP_RoomMenu[];
+extern UINT32 roomIds[NUM_LIST_ROOMS];
+
typedef struct menu_s
{
const char *menutitlepic;
@@ -176,6 +193,10 @@ typedef struct menu_s
void M_SetupNextMenu(menu_t *menudef);
void M_ClearMenus(boolean callexitmenufunc);
+#ifdef HAVE_THREADS
+extern I_mutex m_menu_mutex;
+#endif
+
extern menu_t *currentMenu;
extern menu_t MainDef;
diff --git a/src/m_misc.c b/src/m_misc.c
index 87d648b2..0246a2cf 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -23,6 +23,8 @@
#include
#endif
+#include
+
// Extended map support.
#include
@@ -2363,3 +2365,13 @@ void M_SetupMemcpy(void)
M_Memcpy = cpu_cpy;
#endif
}
+
+/** Return the appropriate message for a file error or end of file.
+*/
+const char *M_FileError(FILE *fp)
+{
+ if (ferror(fp))
+ return strerror(errno);
+ else
+ return "end-of-file";
+}
diff --git a/src/m_misc.h b/src/m_misc.h
index 658028b4..1e7befb1 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -100,6 +100,8 @@ void strcatbf(char *s1, const char *s2, const char *s3);
void M_SetupMemcpy(void);
+const char *M_FileError(FILE *handle);
+
// counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);
diff --git a/src/mserv.c b/src/mserv.c
index 12469928..f3d414c9 100644
--- a/src/mserv.c
+++ b/src/mserv.c
@@ -2,242 +2,77 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2018 by Sonic Team Junior.
+// Copyright (C) 2020 by James R.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file mserv.c
-/// \brief Commands used for communicate with the master server
-
-#ifdef __GNUC__
-#include
-#include
-#include
-#endif
+/// \brief Commands used to communicate with the master server
#if !defined (UNDER_CE)
#include
#endif
-#if (defined (NOMD5) || defined (NOMSERV)) && !defined (NONET)
-#define NONET
-#endif
-
-#ifndef NONET
-
-#ifndef NO_IPV6
-#define HAVE_IPV6
-#endif
-
-#if (defined (_WIN32) || defined (_WIN32_WCE)) && !defined (_XBOX)
-#define RPC_NO_WINDOWS_H
-#ifdef HAVE_IPV6
-#include
-#else
-#include // socket(),...
-#endif //!HAVE_IPV6
-#else
-#ifdef __OS2__
-#include
-#endif // __OS2__
-
-#ifdef HAVE_LWIP
-#include
-#include
-#include
-#define ioctl lwip_ioctl
-#else
-#include
-#ifdef __APPLE_CC__
-#ifndef _BSD_SOCKLEN_T_
-#define _BSD_SOCKLEN_T_
-#endif
-#endif
-#include // socket(),...
-#include // sockaddr_in
-#ifdef _PS3
-#include
-#elif !defined(_arch_dreamcast)
-#include // getaddrinfo(),...
-#include
-#endif
-#endif
-
-#ifdef _arch_dreamcast
-#include "sdl12/SRB2DC/dchelp.h"
-#endif
-
-#include // timeval,... (TIMEOUT)
-#include
-#endif // _WIN32/_WIN32_WCE
-
-#ifdef __OS2__
-#include
-#endif // __OS2__
-#endif // !NONET
-
#include "doomstat.h"
#include "doomdef.h"
#include "command.h"
-#include "i_net.h"
-#include "console.h"
+#include "i_threads.h"
#include "mserv.h"
-#include "d_net.h"
-#include "i_tcp.h"
-#include "i_system.h"
-#include "byteptr.h"
#include "m_menu.h"
-#include "m_argv.h" // Alam is going to kill me <3
-#include "m_misc.h" // GetRevisionString()
+#include "z_zone.h"
-#ifdef _WIN32_WCE
-#include "sdl12/SRB2CE/cehelp.h"
-#endif
+static int MSId;
+static int MSRegisteredId = -1;
-#include "i_addrinfo.h"
+static boolean MSRegistered;
+static boolean MSInProgress;
+static boolean MSUpdateAgain;
-// ================================ DEFINITIONS ===============================
+static time_t MSLastPing;
-#define PACKET_SIZE 1024
+#ifdef HAVE_THREADS
+static I_mutex MSMutex;
+static I_cond MSCond;
+# define Lock_state() I_lock_mutex (&MSMutex)
+# define Unlock_state() I_unlock_mutex (MSMutex)
+#else/*HAVE_THREADS*/
+# define Lock_state()
+# define Unlock_state()
+#endif/*HAVE_THREADS*/
-#define MS_NO_ERROR 0
-#define MS_SOCKET_ERROR -201
-#define MS_CONNECT_ERROR -203
-#define MS_WRITE_ERROR -210
-#define MS_READ_ERROR -211
-#define MS_CLOSE_ERROR -212
-#define MS_GETHOSTBYNAME_ERROR -220
-#define MS_GETHOSTNAME_ERROR -221
-#define MS_TIMEOUT_ERROR -231
-
-// see master server code for the values
-#define ADD_SERVER_MSG 101
-#define REMOVE_SERVER_MSG 103
-#define ADD_SERVERv2_MSG 104
-#define GET_SERVER_MSG 200
-#define GET_SHORT_SERVER_MSG 205
-#define ASK_SERVER_MSG 206
-#define ANSWER_ASK_SERVER_MSG 207
-#define ASK_SERVER_MSG 206
-#define ANSWER_ASK_SERVER_MSG 207
-#define GET_MOTD_MSG 208
-#define SEND_MOTD_MSG 209
-#define GET_ROOMS_MSG 210
-#define SEND_ROOMS_MSG 211
-#define GET_ROOMS_HOST_MSG 212
-#define GET_VERSION_MSG 213
-#define SEND_VERSION_MSG 214
-#define GET_BANNED_MSG 215 // Someone's been baaaaaad!
-#define PING_SERVER_MSG 216
-
-#define HEADER_SIZE (sizeof (INT32)*4)
-
-#define HEADER_MSG_POS 0
-#define IP_MSG_POS 16
-#define PORT_MSG_POS 32
-#define HOSTNAME_MSG_POS 40
-
-
-#if defined(_MSC_VER)
-#pragma pack(1)
-#endif
-
-/** A message to be exchanged with the master server.
- */
-typedef struct
-{
- INT32 id; ///< Unused?
- INT32 type; ///< Type of message.
- INT32 room; ///< Because everyone needs a roomie.
- UINT32 length; ///< Length of the message.
- char buffer[PACKET_SIZE]; ///< Actual contents of the message.
-} ATTRPACK msg_t;
-
-#if defined(_MSC_VER)
-#pragma pack()
-#endif
-
-typedef struct Copy_CVarMS_t
-{
- char ip[64];
- char port[8];
- char name[64];
-} Copy_CVarMS_s;
-static Copy_CVarMS_s registered_server;
-static time_t MSLastPing;
-
-#if defined(_MSC_VER)
-#pragma pack(1)
-#endif
-typedef struct
-{
- char ip[16]; // Big enough to hold a full address.
- UINT16 port;
- UINT8 padding1[2];
- tic_t time;
-} ATTRPACK ms_holepunch_packet_t;
-#if defined(_MSC_VER)
-#pragma pack()
-#endif
-
-// win32 or djgpp
-#if defined (_WIN32) || defined (_WIN32_WCE) || defined (__DJGPP__)
-#define ioctl ioctlsocket
-#define close closesocket
-#ifdef WATTCP
-#define strerror strerror_s
-#endif
-#if defined (_WIN32) || defined (_WIN32_WCE)
-#undef errno
-#define errno h_errno // some very strange things happen when not using h_error
-#endif
-#ifndef AI_ADDRCONFIG
-#define AI_ADDRCONFIG 0x00000400
-#endif
-#endif
+static void Update_parameters (void);
#ifndef NONET
static void Command_Listserv_f(void);
#endif
static void MasterServer_OnChange(void);
-static void ServerName_OnChange(void);
-#define DEF_PORT "28900"
-consvar_t cv_masterserver = {"masterserver", "ms.srb2.org:"DEF_PORT, CV_SAVE, NULL, MasterServer_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_servername = {"servername", "SRB2Kart server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, ServerName_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
+ {2, "MIN"},
+ {60, "MAX"},
+ {0}
+};
+
+consvar_t cv_masterserver = {"masterserver", "https://mb.srb2.org/MS/0", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_servername = {"servername", "SRB2Kart server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
+
+consvar_t cv_masterserver_update_rate = {"masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
INT16 ms_RoomId = -1;
-static enum { MSCS_NONE, MSCS_WAITING, MSCS_REGISTERED, MSCS_FAILED } con_state = MSCS_NONE;
+#ifdef HAVE_THREADS
+int ms_QueryId;
+I_mutex ms_QueryId_mutex;
+
+msg_server_t *ms_ServerList;
+I_mutex ms_ServerList_mutex;
+#endif
-static INT32 msnode = -1;
UINT16 current_port = 0;
-#if (defined (_WIN32) || defined (_WIN32_WCE) || defined (_WIN32)) && !defined (NONET)
-typedef SOCKET SOCKET_TYPE;
-#define ERRSOCKET (SOCKET_ERROR)
-#else
-#if (defined (__unix__) && !defined (MSDOS)) || defined (__APPLE__) || defined (__HAIKU__) || defined (_PS3)
-typedef int SOCKET_TYPE;
-#else
-typedef unsigned long SOCKET_TYPE;
-#endif
-#define ERRSOCKET (-1)
-#endif
-
-#if (defined (WATTCP) && !defined (__libsocket_socklen_t)) || defined (_WIN32)
-typedef int socklen_t;
-#endif
-
-#ifndef NONET
-static SOCKET_TYPE socket_fd = ERRSOCKET; // WINSOCK socket
-static struct timeval select_timeout;
-static fd_set wset;
-static size_t recvfull(SOCKET_TYPE s, char *buf, size_t len, int flags);
-#endif
-
// Room list is an external variable now.
// Avoiding having to get info ten thousand times...
msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test
@@ -251,371 +86,96 @@ void AddMServCommands(void)
{
#ifndef NONET
CV_RegisterVar(&cv_masterserver);
+ CV_RegisterVar(&cv_masterserver_update_rate);
+ CV_RegisterVar(&cv_masterserver_timeout);
+ CV_RegisterVar(&cv_masterserver_debug);
+ CV_RegisterVar(&cv_masterserver_token);
CV_RegisterVar(&cv_servername);
COM_AddCommand("listserv", Command_Listserv_f);
#endif
}
-/** Closes the connection to the master server.
- *
- * \todo Fix for Windows?
- */
-static void CloseConnection(void)
+static void WarnGUI (void)
{
-#ifndef NONET
- if (socket_fd != (SOCKET_TYPE)ERRSOCKET)
- close(socket_fd);
- socket_fd = ERRSOCKET;
+#ifdef HAVE_THREADS
+ I_lock_mutex(&m_menu_mutex);
#endif
-}
-
-//
-// MS_Write():
-//
-static INT32 MS_Write(msg_t *msg)
-{
-#ifdef NONET
- (void)msg;
- return MS_WRITE_ERROR;
-#else
- size_t len;
-
- if (msg->length == 0)
- msg->length = (INT32)strlen(msg->buffer);
- len = msg->length + HEADER_SIZE;
-
- msg->type = htonl(msg->type);
- msg->length = htonl(msg->length);
- msg->room = htonl(msg->room);
-
- if ((size_t)send(socket_fd, (char *)msg, (int)len, 0) != len)
- return MS_WRITE_ERROR;
- return 0;
+ M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n\nCheck the console for details.\n"), NULL, MM_NOTHING);
+#ifdef HAVE_THREADS
+ I_unlock_mutex(m_menu_mutex);
#endif
}
-//
-// MS_Read():
-//
-static INT32 MS_Read(msg_t *msg)
-{
-#ifdef NONET
- (void)msg;
- return MS_READ_ERROR;
-#else
- if (recvfull(socket_fd, (char *)msg, HEADER_SIZE, 0) != HEADER_SIZE)
- return MS_READ_ERROR;
-
- msg->type = ntohl(msg->type);
- msg->length = ntohl(msg->length);
- msg->room = ntohl(msg->room);
-
- if (!msg->length) // fix a bug in Windows 2000
- return 0;
-
- if (recvfull(socket_fd, (char *)msg->buffer, msg->length, 0) != msg->length)
- return MS_READ_ERROR;
- return 0;
-#endif
-}
-
-#ifndef NONET
-/** Gets a list of game servers from the master server.
- */
-static INT32 GetServersList(void)
-{
- msg_t msg;
- INT32 count = 0;
-
- msg.type = GET_SERVER_MSG;
- msg.length = 0;
- msg.room = 0;
- if (MS_Write(&msg) < 0)
- return MS_WRITE_ERROR;
-
- while (MS_Read(&msg) >= 0)
- {
- if (!msg.length)
- {
- if (!count)
- CONS_Alert(CONS_NOTICE, M_GetText("No servers currently running.\n"));
- return MS_NO_ERROR;
- }
- count++;
- CONS_Printf("%s",msg.buffer);
- }
-
- return MS_READ_ERROR;
-}
-#endif
-
-//
-// MS_Connect()
-//
-static INT32 MS_Connect(const char *ip_addr, const char *str_port, INT32 async)
-{
-#ifdef NONET
- (void)ip_addr;
- (void)str_port;
- (void)async;
-#else
- struct my_addrinfo *ai, *runp, hints;
- int gaie;
-
- memset (&hints, 0x00, sizeof(hints));
-#ifdef AI_ADDRCONFIG
- hints.ai_flags = AI_ADDRCONFIG;
-#endif
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
-
- //I_InitTcpNetwork(); this is already done on startup in D_SRB2Main()
- if (!I_InitTcpDriver()) // this is done only if not already done
- return MS_SOCKET_ERROR;
-
- gaie = I_getaddrinfo(ip_addr, str_port, &hints, &ai);
- if (gaie != 0)
- return MS_GETHOSTBYNAME_ERROR;
- else
- runp = ai;
-
- while (runp != NULL)
- {
- socket_fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
- if (socket_fd != (SOCKET_TYPE)ERRSOCKET)
- {
- if (async) // do asynchronous connection
- {
-#ifdef FIONBIO
-#ifdef WATTCP
- char res = 1;
-#else
- unsigned long res = 1;
-#endif
-
- ioctl(socket_fd, FIONBIO, &res);
-#endif
-
- if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) == ERRSOCKET)
- {
-#ifdef _WIN32 // humm, on win32/win64 it doesn't work with EINPROGRESS (stupid windows)
- if (WSAGetLastError() != WSAEWOULDBLOCK)
-#else
- if (errno != EINPROGRESS)
-#endif
- {
- con_state = MSCS_FAILED;
- CloseConnection();
- I_freeaddrinfo(ai);
- return MS_CONNECT_ERROR;
- }
- }
- con_state = MSCS_WAITING;
- FD_ZERO(&wset);
- FD_SET(socket_fd, &wset);
- select_timeout.tv_sec = 0, select_timeout.tv_usec = 0;
- I_freeaddrinfo(ai);
- return 0;
- }
- else if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) != ERRSOCKET)
- {
- I_freeaddrinfo(ai);
- return 0;
- }
- }
- runp = runp->ai_next;
- }
- I_freeaddrinfo(ai);
-#endif
- return MS_CONNECT_ERROR;
-}
-
#define NUM_LIST_SERVER MAXSERVERLIST
-const msg_server_t *GetShortServersList(INT32 room)
+msg_server_t *GetShortServersList(INT32 room, int id)
{
- static msg_server_t server_list[NUM_LIST_SERVER+1]; // +1 for easy test
- msg_t msg;
- INT32 i;
+ msg_server_t *server_list;
- // we must be connected to the master server before writing to it
- if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
- {
- CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
- M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
- return NULL;
- }
+ // +1 for easy test
+ server_list = malloc(( NUM_LIST_SERVER + 1 ) * sizeof *server_list);
- msg.type = GET_SHORT_SERVER_MSG;
- msg.length = 0;
- msg.room = room;
- if (MS_Write(&msg) < 0)
- return NULL;
-
- for (i = 0; i < NUM_LIST_SERVER && MS_Read(&msg) >= 0; i++)
- {
- if (!msg.length)
- {
- server_list[i].header.buffer[0] = 0;
- CloseConnection();
- return server_list;
- }
- M_Memcpy(&server_list[i], msg.buffer, sizeof (msg_server_t));
- server_list[i].header.buffer[0] = 1;
- }
- CloseConnection();
- if (i == NUM_LIST_SERVER)
- {
- server_list[i].header.buffer[0] = 0;
+ if (HMS_fetch_servers(server_list, room, id))
return server_list;
- }
else
+ {
+ free(server_list);
+ WarnGUI();
return NULL;
+ }
}
-INT32 GetRoomsList(boolean hosting)
+INT32 GetRoomsList(boolean hosting, int id)
{
- static msg_ban_t banned_info[1];
- msg_t msg;
- INT32 i;
-
- // we must be connected to the master server before writing to it
- if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
- {
- CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
- M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
- return -1;
- }
-
- if (hosting)
- msg.type = GET_ROOMS_HOST_MSG;
- else
- msg.type = GET_ROOMS_MSG;
- msg.length = 0;
- msg.room = 0;
- if (MS_Write(&msg) < 0)
- {
- room_list[0].id = 1;
- strcpy(room_list[0].motd,"Master Server Offline.");
- strcpy(room_list[0].name,"Offline");
- return -1;
- }
-
- for (i = 0; i < NUM_LIST_ROOMS && MS_Read(&msg) >= 0; i++)
- {
- if(msg.type == GET_BANNED_MSG)
- {
- char banmsg[1000];
- M_Memcpy(&banned_info[0], msg.buffer, sizeof (msg_ban_t));
- if (hosting)
- sprintf(banmsg, M_GetText("You have been banned from\nhosting netgames.\n\nUnder the following IP Range:\n%s - %s\n\nFor the following reason:\n%s\n\nYour ban will expire on:\n%s"),banned_info[0].ipstart,banned_info[0].ipend,banned_info[0].reason,banned_info[0].endstamp);
- else
- sprintf(banmsg, M_GetText("You have been banned from\njoining netgames.\n\nUnder the following IP Range:\n%s - %s\n\nFor the following reason:\n%s\n\nYour ban will expire on:\n%s"),banned_info[0].ipstart,banned_info[0].ipend,banned_info[0].reason,banned_info[0].endstamp);
- M_StartMessage(banmsg, NULL, MM_NOTHING);
- ms_RoomId = -1;
- return -2;
- }
- if (!msg.length)
- {
- room_list[i].header.buffer[0] = 0;
- CloseConnection();
- return 1;
- }
- M_Memcpy(&room_list[i], msg.buffer, sizeof (msg_rooms_t));
- room_list[i].header.buffer[0] = 1;
- }
- CloseConnection();
- if (i == NUM_LIST_ROOMS)
- {
- room_list[i].header.buffer[0] = 0;
+ if (HMS_fetch_rooms( ! hosting, id))
return 1;
- }
else
{
- room_list[0].id = 1;
- strcpy(room_list[0].motd,M_GetText("Master Server Offline."));
- strcpy(room_list[0].name,M_GetText("Offline"));
+ WarnGUI();
return -1;
}
}
#ifdef UPDATE_ALERT
-const char *GetMODVersion(void)
+char *GetMODVersion(int id)
{
- static msg_t msg;
+ char *buffer;
+ int c;
- // we must be connected to the master server before writing to it
- if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
+ (void)id;
+
+ buffer = malloc(16);
+
+ c = HMS_compare_mod_version(buffer, 16);
+
+#ifdef HAVE_THREADS
+ I_lock_mutex(&ms_QueryId_mutex);
{
- CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
- M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
- return NULL;
+ if (id != ms_QueryId)
+ c = -1;
}
+ I_unlock_mutex(ms_QueryId_mutex);
+#endif
- msg.type = GET_VERSION_MSG;
- msg.length = sizeof MODVERSION;
- msg.room = MODID; // Might as well use it for something.
- sprintf(msg.buffer,"%d",MODVERSION);
- if (MS_Write(&msg) < 0)
- {
- CONS_Alert(CONS_ERROR, M_GetText("Could not send to the Master Server\n"));
- M_StartMessage(M_GetText("Could not send to the Master Server\n"), NULL, MM_NOTHING);
- CloseConnection();
- return NULL;
- }
-
- if (MS_Read(&msg) < 0)
- {
- CONS_Alert(CONS_ERROR, M_GetText("No reply from the Master Server\n"));
- M_StartMessage(M_GetText("No reply from the Master Server\n"), NULL, MM_NOTHING);
- CloseConnection();
- return NULL;
- }
-
- CloseConnection();
-
- if(strcmp(msg.buffer,"NULL") != 0)
- {
- return msg.buffer;
- }
+ if (c > 0)
+ return buffer;
else
+ {
+ free(buffer);
+
+ if (! c)
+ WarnGUI();
+
return NULL;
+ }
}
// Console only version of the above (used before game init)
void GetMODVersion_Console(void)
{
- static msg_t msg;
+ char buffer[16];
- // we must be connected to the master server before writing to it
- if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
- {
- CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
- return;
- }
-
- msg.type = GET_VERSION_MSG;
- msg.length = sizeof MODVERSION;
- msg.room = MODID; // Might as well use it for something.
- sprintf(msg.buffer,"%d",MODVERSION);
- if (MS_Write(&msg) < 0)
- {
- CONS_Alert(CONS_ERROR, M_GetText("Could not send to the Master Server\n"));
- CloseConnection();
- return;
- }
-
- if (MS_Read(&msg) < 0)
- {
- CONS_Alert(CONS_ERROR, M_GetText("No reply from the Master Server\n"));
- CloseConnection();
- return;
- }
-
- CloseConnection();
-
- if(strcmp(msg.buffer,"NULL") != 0)
- I_Error(UPDATE_ALERT_STRING_CONSOLE, VERSIONSTRING, msg.buffer);
+ if (HMS_compare_mod_version(buffer, sizeof buffer) > 0)
+ I_Error(UPDATE_ALERT_STRING_CONSOLE, VERSIONSTRING, buffer);
}
#endif
@@ -624,401 +184,347 @@ void GetMODVersion_Console(void)
*/
static void Command_Listserv_f(void)
{
- if (con_state == MSCS_WAITING)
- {
- CONS_Alert(CONS_NOTICE, M_GetText("Not yet connected to the Master Server.\n"));
- return;
- }
-
CONS_Printf(M_GetText("Retrieving server list...\n"));
- if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
{
- CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
- return;
+ HMS_list_servers();
}
-
- if (GetServersList())
- CONS_Alert(CONS_ERROR, M_GetText("Cannot get server list\n"));
-
- CloseConnection();
}
#endif
-FUNCMATH static const char *int2str(INT32 n)
+static void
+Finish_registration (void)
{
- INT32 i;
- static char res[16];
+ int registered;
- res[15] = '\0';
- res[14] = (char)((char)(n%10)+'0');
- for (i = 13; (n /= 10); i--)
- res[i] = (char)((char)(n%10)+'0');
+ CONS_Printf("Registering this server on the master server...\n");
- return &res[i+1];
-}
+ registered = HMS_register();
-#ifndef NONET
-static INT32 ConnectionFailed(void)
-{
- con_state = MSCS_FAILED;
- CONS_Alert(CONS_ERROR, M_GetText("Connection to Master Server failed\n"));
- CloseConnection();
- return MS_CONNECT_ERROR;
-}
-#endif
-
-/** Tries to register the local game server on the master server.
- */
-static INT32 AddToMasterServer(boolean firstadd)
-{
-#ifdef NONET
- (void)firstadd;
-#else
- static INT32 retry = 0;
- int i, res;
- socklen_t j;
- msg_t msg;
- msg_server_t *info = (msg_server_t *)msg.buffer;
- INT32 room = -1;
- fd_set tset;
- time_t timestamp = time(NULL);
- UINT32 signature, tmp;
- const char *insname;
-
- M_Memcpy(&tset, &wset, sizeof (tset));
- res = select(255, NULL, &tset, NULL, &select_timeout);
- if (res != ERRSOCKET && !res)
+ Lock_state();
{
- if (retry++ > 30) // an about 30 second timeout
+ MSRegistered = registered;
+ MSRegisteredId = MSId;
+
+ time(&MSLastPing);
+ }
+ Unlock_state();
+
+ if (registered)
+ CONS_Printf("Master server registration successful.\n");
+}
+
+static void
+Finish_update (void)
+{
+ int registered;
+ int done;
+
+ Lock_state();
+ {
+ registered = MSRegistered;
+ MSUpdateAgain = false;/* this will happen anyway */
+ }
+ Unlock_state();
+
+ if (registered)
+ {
+ if (HMS_update())
{
- retry = 0;
- CONS_Alert(CONS_ERROR, M_GetText("Master Server timed out\n"));
- MSLastPing = timestamp;
- return ConnectionFailed();
+ Lock_state();
+ {
+ time(&MSLastPing);
+ MSRegistered = true;
+ }
+ Unlock_state();
+
+ CONS_Printf("Updated master server listing.\n");
}
- return MS_CONNECT_ERROR;
+ else
+ Finish_registration();
}
- retry = 0;
- /*
- Somehow we can still select our old socket despite it being closed(?).
- Atleast, that's what I THINK is happening. Anyway, we have to check that we
- haven't open a socket, and actually open it!
- */
- /*if (res == ERRSOCKET)*//* wtf? no! */
- if (socket_fd == (SOCKET_TYPE)ERRSOCKET)
+ else
+ Finish_registration();
+
+ Lock_state();
{
- if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
+ done = ! MSUpdateAgain;
+
+ if (done)
+ MSInProgress = false;
+ }
+ Unlock_state();
+
+ if (! done)
+ Finish_update();
+}
+
+static void
+Finish_unlist (void)
+{
+ int registered;
+
+ Lock_state();
+ {
+ registered = MSRegistered;
+ }
+ Unlock_state();
+
+ if (registered)
+ {
+ CONS_Printf("Removing this server from the master server...\n");
+
+ if (HMS_unlist())
+ CONS_Printf("Server deregistration request successfully sent.\n");
+
+ Lock_state();
{
- CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error #%u: %s\n"), errno, strerror(errno));
- MSLastPing = timestamp;
- return ConnectionFailed();
+ MSRegistered = false;
}
- }
+ Unlock_state();
- // so, the socket is writable, but what does that mean, that the connection is
- // ok, or bad... let see that!
- j = (socklen_t)sizeof (i);
- getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, (char *)&i, &j);
- /*
- This is also wrong. If getsockopt fails, i doesn't have to be set. Plus, if
- it is set (which it appearantly is on linux), we check errno anyway. And in
- the case that i is returned as normal, we don't even report the correct
- value! So we accomplish NOTHING, except returning due to dumb luck.
- If you care, fix this--I don't. -James (R.)
- */
- if (i) // it was bad
- {
- CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error #%u: %s\n"), errno, strerror(errno));
- MSLastPing = timestamp;
- return ConnectionFailed();
- }
-
-#ifdef PARANOIA
- if (ms_RoomId <= 0)
- I_Error("Attmepted to host in room \"All\"!\n");
+#ifdef HAVE_THREADS
+ I_wake_all_cond(&MSCond);
#endif
- room = ms_RoomId;
-
- for(signature = 0, insname = cv_servername.string; *insname; signature += *insname++);
- tmp = (UINT32)(signature * (size_t)&MSLastPing);
- signature *= tmp;
- signature &= 0xAAAAAAAA;
- M_Memcpy(&info->header.signature, &signature, sizeof (UINT32));
-
- strcpy(info->ip, "");
- strcpy(info->port, int2str(current_port));
- strcpy(info->name, cv_servername.string);
- M_Memcpy(&info->room, & room, sizeof (INT32));
-#if VERSION > 0 || SUBVERSION > 0
- sprintf(info->version, "%d.%d", VERSION, SUBVERSION);
-#else // Trunk build, send revision info
- strcpy(info->version, GetRevisionString());
-#endif
- strcpy(registered_server.name, cv_servername.string);
-
- if(firstadd)
- msg.type = ADD_SERVER_MSG;
- else
- msg.type = PING_SERVER_MSG;
-
- msg.length = (UINT32)sizeof (msg_server_t);
- msg.room = 0;
- if (MS_Write(&msg) < 0)
- {
- MSLastPing = timestamp;
- return ConnectionFailed();
}
- if(con_state != MSCS_REGISTERED)
- CONS_Printf(M_GetText("Master Server update successful.\n"));
-
- MSLastPing = timestamp;
- con_state = MSCS_REGISTERED;
- CloseConnection();
-#endif
- return MS_NO_ERROR;
-}
-
-static INT32 RemoveFromMasterSever(void)
-{
- msg_t msg;
- msg_server_t *info = (msg_server_t *)msg.buffer;
-
- strcpy(info->header.buffer, "");
- strcpy(info->ip, "");
- strcpy(info->port, int2str(current_port));
- strcpy(info->name, registered_server.name);
- sprintf(info->version, "%d.%d", VERSION, SUBVERSION);
-
- msg.type = REMOVE_SERVER_MSG;
- msg.length = (UINT32)sizeof (msg_server_t);
- msg.room = 0;
- if (MS_Write(&msg) < 0)
- return MS_WRITE_ERROR;
-
- return MS_NO_ERROR;
-}
-
-const char *GetMasterServerPort(void)
-{
- const char *t = cv_masterserver.string;
-
- while ((*t != ':') && (*t != '\0'))
- t++;
-
- if (*t)
- return ++t;
- else
- return DEF_PORT;
-}
-
-/** Gets the IP address of the master server. Actually, it seems to just
- * return the hostname, instead; the lookup is done elsewhere.
- *
- * \return Hostname of the master server, without port number on the end.
- * \todo Rename function?
- */
-const char *GetMasterServerIP(void)
-{
- static char str_ip[64];
- char *t = str_ip;
-
- if (strstr(cv_masterserver.string, "srb2.ssntails.org:28910")
- || strstr(cv_masterserver.string, "srb2.servegame.org:28910")
- || strstr(cv_masterserver.string, "srb2.servegame.org:28900")
- )
+ Lock_state();
{
- // replace it with the current default one
- CV_Set(&cv_masterserver, cv_masterserver.defaultvalue);
+ if (MSId == MSRegisteredId)
+ MSId++;
}
-
- strcpy(t, cv_masterserver.string);
-
- while ((*t != ':') && (*t != '\0'))
- t++;
- *t = '\0';
-
- return str_ip;
+ Unlock_state();
}
-void MSOpenUDPSocket(void)
+#ifdef HAVE_THREADS
+static int *
+Server_id (void)
{
-#ifndef NONET
- if (I_NetMakeNodewPort)
+ int *id;
+ id = malloc(sizeof *id);
+ Lock_state();
{
- // If it's already open, there's nothing to do.
- if (msnode < 0)
- msnode = I_NetMakeNodewPort(GetMasterServerIP(), GetMasterServerPort());
+ *id = MSId;
}
- else
-#endif
- msnode = -1;
+ Unlock_state();
+ return id;
}
-void MSCloseUDPSocket(void)
+static int *
+New_server_id (void)
{
- if (msnode != INT16_MAX) I_NetFreeNodenum(msnode);
- msnode = -1;
+ int *id;
+ id = malloc(sizeof *id);
+ Lock_state();
+ {
+ *id = ++MSId;
+ I_wake_all_cond(&MSCond);
+ }
+ Unlock_state();
+ return id;
}
+static void
+Register_server_thread (int *id)
+{
+ int same;
+
+ Lock_state();
+ {
+ /* wait for previous unlist to finish */
+ while (*id == MSId && MSRegistered)
+ I_hold_cond(&MSCond, MSMutex);
+
+ same = ( *id == MSId );/* it could have been a while */
+ }
+ Unlock_state();
+
+ if (same)/* it could have been a while */
+ Finish_registration();
+
+ free(id);
+}
+
+static void
+Update_server_thread (int *id)
+{
+ int same;
+
+ Lock_state();
+ {
+ same = ( *id == MSRegisteredId );
+ }
+ Unlock_state();
+
+ if (same)
+ Finish_update();
+
+ free(id);
+}
+
+static void
+Unlist_server_thread (int *id)
+{
+ int same;
+
+ Lock_state();
+ {
+ same = ( *id == MSRegisteredId );
+ }
+ Unlock_state();
+
+ if (same)
+ Finish_unlist();
+
+ free(id);
+}
+
+static void
+Change_masterserver_thread (char *api)
+{
+ Lock_state();
+ {
+ while (MSRegistered)
+ I_hold_cond(&MSCond, MSMutex);
+ }
+ Unlock_state();
+
+ HMS_set_api(api);
+}
+#endif/*HAVE_THREADS*/
+
void RegisterServer(void)
{
- if (con_state == MSCS_REGISTERED || con_state == MSCS_WAITING)
- return;
-
- CONS_Printf(M_GetText("Registering this server on the Master Server...\n"));
-
- strcpy(registered_server.ip, GetMasterServerIP());
- strcpy(registered_server.port, GetMasterServerPort());
-
- if (MS_Connect(registered_server.ip, registered_server.port, 1))
- {
- CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
- return;
- }
- MSOpenUDPSocket();
-
- // keep the TCP connection open until AddToMasterServer() is completed;
+#ifdef HAVE_THREADS
+ I_spawn_thread(
+ "register-server",
+ (I_thread_fn)Register_server_thread,
+ New_server_id()
+ );
+#else
+ Finish_registration();
+#endif
}
-static inline void SendPingToMasterServer(void)
+static void UpdateServer(void)
{
-/* static tic_t next_time = 0;
- tic_t cur_time;
- char *inbuffer = (char*)netbuffer;
-
- cur_time = I_GetTime();
- if (!netgame)
- UnregisterServer();
- else if (cur_time > next_time) // ping every 2 second if possible
- {
- next_time = cur_time+2*TICRATE;
-
- if (con_state == MSCS_WAITING)
- AddToMasterServer();
-
- if (con_state != MSCS_REGISTERED)
- return;
-
- // cur_time is just a dummy data to send
- WRITEUINT32(inbuffer, cur_time);
- doomcom->datalength = sizeof (cur_time);
- doomcom->remotenode = (INT16)msnode;
- I_NetSend();
- }
-*/
-
-// Here, have a simpler MS Ping... - Cue
- if(time(NULL) > (MSLastPing+(60*2)) && con_state != MSCS_NONE)
- {
- //CONS_Debug(DBG_NETPLAY, "%ld (current time) is greater than %d (Last Ping Time)\n", time(NULL), MSLastPing);
- if(MSLastPing < 1)
- AddToMasterServer(true);
- else
- AddToMasterServer(false);
- }
-}
-
-void SendAskInfoViaMS(INT32 node, tic_t asktime)
-{
- const char *address;
- UINT16 port;
- char *inip;
- ms_holepunch_packet_t mshpp;
-
- MSOpenUDPSocket();
-
- // This must be called after calling MSOpenUDPSocket, due to the
- // static buffer.
- address = I_GetNodeAddress(node);
-
- // no address?
- if (!address)
- return;
-
- // Copy the IP address into the buffer.
- inip = mshpp.ip;
- while(*address && *address != ':') *inip++ = *address++;
- *inip = '\0';
-
- // Get the port.
- port = (UINT16)(*address++ ? atoi(address) : 0);
- mshpp.port = SHORT(port);
-
- // Set the time for ping calculation.
- mshpp.time = LONG(asktime);
-
- // Send to the MS.
- M_Memcpy(netbuffer, &mshpp, sizeof(mshpp));
- doomcom->datalength = sizeof(ms_holepunch_packet_t);
- doomcom->remotenode = (INT16)msnode;
- I_NetSend();
+#ifdef HAVE_THREADS
+ I_spawn_thread(
+ "update-server",
+ (I_thread_fn)Update_server_thread,
+ Server_id()
+ );
+#else
+ Finish_update();
+#endif
}
void UnregisterServer(void)
{
- if (con_state != MSCS_REGISTERED)
+#ifdef HAVE_THREADS
+ I_spawn_thread(
+ "unlist-server",
+ (I_thread_fn)Unlist_server_thread,
+ Server_id()
+ );
+#else
+ Finish_unlist();
+#endif
+}
+
+static boolean
+Online (void)
+{
+ return ( serverrunning && ms_RoomId > 0 );
+}
+
+static inline void SendPingToMasterServer(void)
+{
+ int ready;
+ time_t now;
+
+ if (Online())
{
- con_state = MSCS_NONE;
- CloseConnection();
- return;
+ time(&now);
+
+ Lock_state();
+ {
+ ready = (
+ MSRegisteredId == MSId &&
+ ! MSInProgress &&
+ now >= ( MSLastPing + 60 * cv_masterserver_update_rate.value )
+ );
+
+ if (ready)
+ MSInProgress = true;
+ }
+ Unlock_state();
+
+ if (ready)
+ UpdateServer();
}
+}
- con_state = MSCS_NONE;
+static void
+Update_parameters (void)
+{
+ int registered;
+ int delayed;
- CONS_Printf(M_GetText("Removing this server from the Master Server...\n"));
-
- if (MS_Connect(registered_server.ip, registered_server.port, 0))
+ if (Online())
{
- CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
- return;
+ Lock_state();
+ {
+ delayed = MSInProgress;
+
+ if (delayed)/* do another update after the current one */
+ MSUpdateAgain = true;
+ else
+ registered = MSRegistered;
+ }
+ Unlock_state();
+
+ if (! delayed && registered)
+ UpdateServer();
}
-
- if (RemoveFromMasterSever() < 0)
- CONS_Alert(CONS_ERROR, M_GetText("Cannot remove this server from the Master Server\n"));
-
- CloseConnection();
- MSCloseUDPSocket();
- MSLastPing = 0;
}
void MasterClient_Ticker(void)
{
- if (server && ms_RoomId > 0)
- SendPingToMasterServer();
+ SendPingToMasterServer();
}
-static void ServerName_OnChange(void)
+static void
+Set_api (const char *api)
{
- if (con_state == MSCS_REGISTERED)
- AddToMasterServer(false);
+#ifdef HAVE_THREADS
+ I_spawn_thread(
+ "change-masterserver",
+ (I_thread_fn)Change_masterserver_thread,
+ strdup(api)
+ );
+#else
+ HMS_set_api(strdup(api));
+#endif
}
static void MasterServer_OnChange(void)
{
UnregisterServer();
- RegisterServer();
-}
-#ifndef NONET
-// Like recv, but waits until we've got enough data to fill the buffer.
-static size_t recvfull(SOCKET_TYPE s, char *buf, size_t len, int flags)
-{
- /* Total received. */
- size_t totallen = 0;
-
- while(totallen < len)
- {
- ssize_t ret = (ssize_t)recv(s, buf + totallen, (int)(len - totallen), flags);
-
- /* Error. */
- if(ret == -1)
- return (size_t)-1;
-
- totallen += ret;
+ /*
+ TODO: remove this for v2, it's just a hack
+ for those coming in with an old config.
+ */
+ if (
+ ! cv_masterserver.changed &&
+ strcmp(cv_masterserver.string, "ms.srb2.org:28900") == 0
+ ){
+ CV_StealthSet(&cv_masterserver, cv_masterserver.defaultvalue);
}
- return totallen;
+ Set_api(cv_masterserver.string);
+
+ if (Online())
+ RegisterServer();
}
-#endif
diff --git a/src/mserv.h b/src/mserv.h
index 09cd4f08..9269c408 100644
--- a/src/mserv.h
+++ b/src/mserv.h
@@ -2,6 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2018 by Sonic Team Junior.
+// Copyright (C) 2020 by James R.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@@ -13,7 +14,7 @@
#ifndef _MSERV_H_
#define _MSERV_H_
-#define MASTERSERVERS21 // MasterServer v2.1
+#include "i_threads.h"
// lowered from 32 due to menu changes
#define NUM_LIST_ROOMS 16
@@ -64,33 +65,47 @@ typedef struct
// ================================ GLOBALS ===============================
extern consvar_t cv_masterserver, cv_servername;
+extern consvar_t cv_masterserver_update_rate;
+extern consvar_t cv_masterserver_timeout;
+extern consvar_t cv_masterserver_debug;
+extern consvar_t cv_masterserver_token;
// < 0 to not connect (usually -1) (offline mode)
// == 0 to show all rooms, not a valid hosting room
// anything else is whatever room the MS assigns to that number (online mode)
-INT16 ms_RoomId;
+extern INT16 ms_RoomId;
-const char *GetMasterServerPort(void);
-const char *GetMasterServerIP(void);
+#ifdef HAVE_THREADS
+extern int ms_QueryId;
+extern I_mutex ms_QueryId_mutex;
-void MSOpenUDPSocket(void);
-void MSCloseUDPSocket(void);
-
-void SendAskInfoViaMS(INT32 node, tic_t asktime);
+extern msg_server_t *ms_ServerList;
+extern I_mutex ms_ServerList_mutex;
+#endif
void RegisterServer(void);
void UnregisterServer(void);
void MasterClient_Ticker(void);
-const msg_server_t *GetShortServersList(INT32 room);
-INT32 GetRoomsList(boolean hosting);
+msg_server_t *GetShortServersList(INT32 room, int id);
+INT32 GetRoomsList(boolean hosting, int id);
#ifdef UPDATE_ALERT
-const char *GetMODVersion(void);
+char *GetMODVersion(int id);
void GetMODVersion_Console(void);
#endif
extern msg_rooms_t room_list[NUM_LIST_ROOMS+1];
void AddMServCommands(void);
+/* HTTP */
+void HMS_set_api (char *api);
+int HMS_fetch_rooms (int joining, int id);
+int HMS_register (void);
+int HMS_unlist (void);
+int HMS_update (void);
+void HMS_list_servers (void);
+msg_server_t * HMS_fetch_servers (msg_server_t *list, int room, int id);
+int HMS_compare_mod_version (char *buffer, size_t size_of_buffer);
+
#endif
diff --git a/src/p_enemy.c b/src/p_enemy.c
index a3bf5491..2693c8cc 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -8517,6 +8517,7 @@ void A_SPBChase(mobj_t *actor)
//fast->momz = (3*actor->momz)/4;
fast->color = SKINCOLOR_RED;
fast->colorized = true;
+ P_SetTarget(&fast->target, actor); // easier lua access
K_MatchGenericExtraFlags(fast, actor);
}
diff --git a/src/p_mobj.c b/src/p_mobj.c
index f7f2afe3..82a003a0 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -8312,18 +8312,7 @@ void P_MobjThinker(mobj_t *mobj)
if (!mobj->extravalue2)
{
- if (mobj->eflags & MFE_VERTICALFLIP)
- mobj->z -= mobj->height;
- else
- mobj->z += mobj->height;
-
- S_StartSound(mobj, mobj->info->deathsound);
- P_SetObjectMomZ(mobj, 8*FRACUNIT, false);
- P_InstaThrust(mobj, R_PointToAngle2(mobj->target->x, mobj->target->y, mobj->x, mobj->y)+ANGLE_90, 16*FRACUNIT);
- mobj->momx += mobj->target->momx;
- mobj->momy += mobj->target->momy;
- mobj->momz += mobj->target->momz;
- mobj->extravalue2 = 1;
+ K_DropRocketSneaker(mobj->target->player);
}
else if (P_IsObjectOnGround(mobj))
{
diff --git a/src/p_setup.c b/src/p_setup.c
index decdc529..85243d50 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1408,7 +1408,7 @@ static void P_LoadRawSideDefs2(void *data)
UINT16 i;
INT32 num;
size_t j;
- UINT32 cr, cg, cb;
+ RGBA_t color;
for (i = 0; i < numsides; i++)
{
@@ -1490,23 +1490,21 @@ static void P_LoadRawSideDefs2(void *data)
// encore mode colormaps!
// do it like software by aproximating a color to a palette index, and then convert it to its encore variant and then back to a color code.
// do this for both the start and fade colormaps.
-
- cr = (HEX2INT(col[1]) << 4) + (HEX2INT(col[2]) << 0);
- cg = (HEX2INT(col[3]) << 12) + (HEX2INT(col[4]) << 8);
- cb = (HEX2INT(col[5]) << 20) + (HEX2INT(col[6]) << 16);
+
+ color.s.red = (HEX2INT(col[1]) << 4) + HEX2INT(col[2]);
+ color.s.green = (HEX2INT(col[3]) << 4) + HEX2INT(col[4]);
+ color.s.blue = (HEX2INT(col[5]) << 4) + HEX2INT(col[6]);
#ifdef GLENCORE
if (encoremap)
{
- j = encoremap[NearestColor((UINT8)cr, (UINT8)cg, (UINT8)cb)];
+ j = encoremap[NearestColor(color.s.red, color.s.green, color.s.blue)];
//CONS_Printf("R_CreateColormap: encoremap[%d] = %d\n", j, encoremap[j]); -- moved encoremap upwards for optimisation
- cr = pLocalPalette[j].s.red;
- cg = pLocalPalette[j].s.green;
- cb = pLocalPalette[j].s.blue;
+ color = pLocalPalette[j]; // note: this sets alpha to 255, we will reset it below
}
#endif
-
- sec->extra_colormap->rgba = cr + cg + cb;
+ color.s.alpha = 0; // reset/init the alpha, so the addition below will work correctly
+ sec->extra_colormap->rgba = color.rgba;
// alpha
if (msd->toptexture[7])
@@ -1533,23 +1531,21 @@ static void P_LoadRawSideDefs2(void *data)
col = msd->bottomtexture;
// do the exact same thing as above here.
-
- cr = (HEX2INT(col[1]) << 4) + (HEX2INT(col[2]) << 0);
- cg = (HEX2INT(col[3]) << 12) + (HEX2INT(col[4]) << 8);
- cb = (HEX2INT(col[5]) << 20) + (HEX2INT(col[6]) << 16);
+
+ color.s.red = (HEX2INT(col[1]) << 4) + HEX2INT(col[2]);
+ color.s.green = (HEX2INT(col[3]) << 4) + HEX2INT(col[4]);
+ color.s.blue = (HEX2INT(col[5]) << 4) + HEX2INT(col[6]);
#ifdef GLENCORE
if (encoremap)
{
- j = encoremap[NearestColor((UINT8)cr, (UINT8)cg, (UINT8)cb)];
+ j = encoremap[NearestColor(color.s.red, color.s.green, color.s.blue)];
//CONS_Printf("R_CreateColormap: encoremap[%d] = %d\n", j, encoremap[j]); -- moved encoremap upwards for optimisation
- cr = pLocalPalette[j].s.red;
- cg = pLocalPalette[j].s.green;
- cb = pLocalPalette[j].s.blue;
+ color = pLocalPalette[j]; // note: this sets alpha to 255, we will reset it below
}
#endif
-
- sec->extra_colormap->fadergba = cr + cg + cb;
+ color.s.alpha = 0; // reset/init the alpha, so the addition below will work correctly
+ sec->extra_colormap->fadergba = color.rgba;
// alpha
if (msd->bottomtexture[7])
diff --git a/src/p_tick.c b/src/p_tick.c
index eaa8b462..4cc6c9ba 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -726,9 +726,9 @@ void P_Ticker(boolean run)
if (exitcountdown > 1)
exitcountdown--;
- if (indirectitemcooldown > 1)
+ if (indirectitemcooldown > 0)
indirectitemcooldown--;
- if (hyubgone > 1)
+ if (hyubgone > 0)
hyubgone--;
if (G_BattleGametype())
diff --git a/src/r_main.c b/src/r_main.c
index 2ec06497..6f2319b6 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1142,7 +1142,7 @@ void R_SetupFrame(player_t *player, boolean skybox)
aimingangle = player->aiming;
viewangle = viewmobj->angle;
- if (/*!demo.playback && */player->playerstate != PST_DEAD)
+ if (!demo.playback && player->playerstate != PST_DEAD)
{
if (player == &players[consoleplayer])
{
diff --git a/src/r_plane.c b/src/r_plane.c
index db5bfbda..659481ec 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -402,7 +402,7 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *check = freetail;
if (!check)
{
- check = calloc(2, sizeof (*check));
+ check = calloc(1, sizeof (*check));
if (check == NULL) I_Error("%s: Out of memory", "new_visplane"); // FIXME: ugly
}
else
diff --git a/src/s_sound.h b/src/s_sound.h
index 2a904faf..eeb1f0ab 100644
--- a/src/s_sound.h
+++ b/src/s_sound.h
@@ -236,7 +236,7 @@ void S_StopSoundByNum(sfxenum_t sfxnum);
#ifdef MUSICSLOT_COMPATIBILITY
// For compatibility with code/scripts relying on older versions
// This is a list of all the "special" slot names and their associated numbers
-const char *compat_special_music_slots[16];
+extern const char *compat_special_music_slots[16];
#endif
#endif
diff --git a/src/sdl/Makefile.cfg b/src/sdl/Makefile.cfg
index 58c4d086..b0c591ce 100644
--- a/src/sdl/Makefile.cfg
+++ b/src/sdl/Makefile.cfg
@@ -83,6 +83,11 @@ else
SDL_LDFLAGS+=-lSDL2_mixer
endif
+ifndef NOTHREADS
+ OPTS+=-DHAVE_THREADS
+ OBJS+=$(OBJDIR)/i_threads.o
+endif
+
ifdef SDL_TTF
OPTS+=-DHAVE_TTF
SDL_LDFLAGS+=-lSDL2_ttf -lfreetype -lz
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index 69b3465a..813e31a9 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -249,6 +249,7 @@
+
@@ -399,6 +400,7 @@
+
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 9e5b9837..f197a394 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -291,6 +291,9 @@
I_Interface
+
+ I_Interface
+
LUA
@@ -663,6 +666,9 @@
I_Interface
+
+ I_Interface
+
LUA
diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj
index b21eedb8..115e17a3 100644
--- a/src/sdl/Srb2SDL-vc9.vcproj
+++ b/src/sdl/Srb2SDL-vc9.vcproj
@@ -2782,6 +2782,50 @@
RelativePath="..\mserv.h"
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef void * (*Create_fn)(void);
+
+struct Link;
+struct Thread;
+
+typedef struct Link * Link;
+typedef struct Thread * Thread;
+
+struct Link
+{
+ void * data;
+ Link next;
+ Link prev;
+};
+
+struct Thread
+{
+ I_thread_fn entry;
+ void * userdata;
+
+ SDL_Thread * thread;
+};
+
+static Link i_thread_pool;
+static Link i_mutex_pool;
+static Link i_cond_pool;
+
+static I_mutex i_thread_pool_mutex;
+static I_mutex i_mutex_pool_mutex;
+static I_mutex i_cond_pool_mutex;
+
+static SDL_atomic_t i_threads_running = {1};
+
+static Link
+Insert_link (
+ Link * head,
+ Link link
+){
+ link->prev = NULL;
+ link->next = (*head);
+ if ((*head))
+ (*head)->prev = link;
+ (*head) = link;
+ return link;
+}
+
+static void
+Free_link (
+ Link * head,
+ Link link
+){
+ if (link->prev)
+ link->prev->next = link->next;
+ else
+ (*head) = link->next;
+
+ if (link->next)
+ link->next->prev = link->prev;
+
+ free(link->data);
+ free(link);
+}
+
+static Link
+New_link (void *data)
+{
+ Link link;
+
+ link = malloc(sizeof *link);
+
+ if (! link)
+ abort();
+
+ link->data = data;
+
+ return link;
+}
+
+static void *
+Identity (
+ Link * pool_anchor,
+ I_mutex pool_mutex,
+
+ void ** anchor,
+
+ Create_fn create_fn
+){
+ void * id;
+
+ id = SDL_AtomicGetPtr(anchor);
+
+ if (! id)
+ {
+ I_lock_mutex(&pool_mutex);
+ {
+ id = SDL_AtomicGetPtr(anchor);
+
+ if (! id)
+ {
+ id = (*create_fn)();
+
+ if (! id)
+ abort();
+
+ Insert_link(pool_anchor, New_link(id));
+
+ SDL_AtomicSetPtr(anchor, id);
+ }
+ }
+ I_unlock_mutex(pool_mutex);
+ }
+
+ return id;
+}
+
+static int
+Worker (
+ Link link
+){
+ Thread th;
+
+ th = link->data;
+
+ (*th->entry)(th->userdata);
+
+ if (SDL_AtomicGet(&i_threads_running))
+ {
+ I_lock_mutex(&i_thread_pool_mutex);
+ {
+ if (SDL_AtomicGet(&i_threads_running))
+ {
+ SDL_DetachThread(th->thread);
+ Free_link(&i_thread_pool, link);
+ }
+ }
+ I_unlock_mutex(i_thread_pool_mutex);
+ }
+
+ return 0;
+}
+
+void
+I_spawn_thread (
+ const char * name,
+ I_thread_fn entry,
+ void * userdata
+){
+ Link link;
+ Thread th;
+
+ th = malloc(sizeof *th);
+
+ if (! th)
+ abort();/* this is pretty GNU of me */
+
+ th->entry = entry;
+ th->userdata = userdata;
+
+ I_lock_mutex(&i_thread_pool_mutex);
+ {
+ link = Insert_link(&i_thread_pool, New_link(th));
+
+ if (SDL_AtomicGet(&i_threads_running))
+ {
+ th->thread = SDL_CreateThread(
+ (SDL_ThreadFunction)Worker,
+ name,
+ link
+ );
+
+ if (! th->thread)
+ abort();
+ }
+ }
+ I_unlock_mutex(i_thread_pool_mutex);
+}
+
+int
+I_thread_is_stopped (void)
+{
+ return ( ! SDL_AtomicGet(&i_threads_running) );
+}
+
+void
+I_start_threads (void)
+{
+ i_thread_pool_mutex = SDL_CreateMutex();
+ i_mutex_pool_mutex = SDL_CreateMutex();
+ i_cond_pool_mutex = SDL_CreateMutex();
+
+ if (!(
+ i_thread_pool_mutex &&
+ i_mutex_pool_mutex &&
+ i_cond_pool_mutex
+ )){
+ abort();
+ }
+}
+
+void
+I_stop_threads (void)
+{
+ Link link;
+ Link next;
+
+ Thread th;
+ SDL_mutex * mutex;
+ SDL_cond * cond;
+
+ if (i_threads_running.value)
+ {
+ /* rely on the good will of thread-san */
+ SDL_AtomicSet(&i_threads_running, 0);
+
+ I_lock_mutex(&i_thread_pool_mutex);
+ {
+ for (
+ link = i_thread_pool;
+ link;
+ link = next
+ ){
+ next = link->next;
+ th = link->data;
+
+ SDL_WaitThread(th->thread, NULL);
+
+ free(th);
+ free(link);
+ }
+ }
+ I_unlock_mutex(i_thread_pool_mutex);
+
+ for (
+ link = i_mutex_pool;
+ link;
+ link = next
+ ){
+ next = link->next;
+ mutex = link->data;
+
+ SDL_DestroyMutex(mutex);
+
+ free(link);
+ }
+
+ for (
+ link = i_cond_pool;
+ link;
+ link = next
+ ){
+ next = link->next;
+ cond = link->data;
+
+ SDL_DestroyCond(cond);
+
+ free(link);
+ }
+
+ SDL_DestroyMutex(i_thread_pool_mutex);
+ SDL_DestroyMutex(i_mutex_pool_mutex);
+ SDL_DestroyMutex(i_cond_pool_mutex);
+ }
+}
+
+void
+I_lock_mutex (
+ I_mutex * anchor
+){
+ SDL_mutex * mutex;
+
+ mutex = Identity(
+ &i_mutex_pool,
+ i_mutex_pool_mutex,
+ anchor,
+ (Create_fn)SDL_CreateMutex
+ );
+
+ if (SDL_LockMutex(mutex) == -1)
+ abort();
+}
+
+void
+I_unlock_mutex (
+ I_mutex id
+){
+ if (SDL_UnlockMutex(id) == -1)
+ abort();
+}
+
+void
+I_hold_cond (
+ I_cond * cond_anchor,
+ I_mutex mutex_id
+){
+ SDL_cond * cond;
+
+ cond = Identity(
+ &i_cond_pool,
+ i_cond_pool_mutex,
+ cond_anchor,
+ (Create_fn)SDL_CreateCond
+ );
+
+ if (SDL_CondWait(cond, mutex_id) == -1)
+ abort();
+}
+
+void
+I_wake_one_cond (
+ I_cond * anchor
+){
+ SDL_cond * cond;
+
+ cond = Identity(
+ &i_cond_pool,
+ i_cond_pool_mutex,
+ anchor,
+ (Create_fn)SDL_CreateCond
+ );
+
+ if (SDL_CondSignal(cond) == -1)
+ abort();
+}
+
+void
+I_wake_all_cond (
+ I_cond * anchor
+){
+ SDL_cond * cond;
+
+ cond = Identity(
+ &i_cond_pool,
+ i_cond_pool_mutex,
+ anchor,
+ (Create_fn)SDL_CreateCond
+ );
+
+ if (SDL_CondBroadcast(cond) == -1)
+ abort();
+}
diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c
index b006047f..eb8e12cb 100644
--- a/src/sdl/ogl_sdl.c
+++ b/src/sdl/ogl_sdl.c
@@ -33,6 +33,7 @@
#endif
#include "../doomdef.h"
+#include "../d_main.h"
#ifdef HWRENDER
#include "../hardware/r_opengl/r_opengl.h"
@@ -154,11 +155,26 @@ boolean OglSdlSurface(INT32 w, INT32 h)
{
INT32 cbpp = cv_scr_depth.value < 16 ? 16 : cv_scr_depth.value;
static boolean first_init = false;
+ const char *gllogdir = NULL;
oglflags = 0;
if (!first_init)
{
+ if (!gllogstream)
+ {
+ gllogdir = D_Home();
+
+#ifdef DEBUG_TO_FILE
+#ifdef DEFAULTDIR
+ if (gllogdir)
+ gllogstream = fopen(va("%s/"DEFAULTDIR"/ogllog.txt",gllogdir), "wt");
+ else
+#endif
+ gllogstream = fopen("./ogllog.txt", "wt");
+#endif
+ }
+
gl_version = pglGetString(GL_VERSION);
gl_renderer = pglGetString(GL_RENDERER);
gl_extensions = pglGetString(GL_EXTENSIONS);
diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c
index d9967ae0..4bb1b567 100644
--- a/src/sdl/sdl_sound.c
+++ b/src/sdl/sdl_sound.c
@@ -1173,7 +1173,10 @@ void I_StartupSound(void)
const char *sdrv_name = NULL;
#endif
#ifndef HAVE_MIXER
- midi_disabled = digital_disabled = true;
+#ifndef NO_MIDI
+ midi_disabled =
+#endif
+ digital_disabled = true;
#endif
memset(channels, 0, sizeof (channels)); //Alam: Clean it
diff --git a/src/sdl12/sdl_sound.c b/src/sdl12/sdl_sound.c
index ed1afd8e..1a7525fe 100644
--- a/src/sdl12/sdl_sound.c
+++ b/src/sdl12/sdl_sound.c
@@ -1435,7 +1435,7 @@ static boolean LoadSong(void *data, size_t lumplength, size_t selectpos)
if (fwrite(data, lumplength, 1, midfile) == 0)
{
- CONS_Printf(M_GetText("Couldn't write music into file %s because %s\n"), tempname, strerror(ferror(midfile)));
+ CONS_Printf(M_GetText("Couldn't write music into file %s because %s\n"), tempname, M_FileError(midfile));
Z_Free(data);
fclose(midfile);
return false;
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 008a1461..9a9af635 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1797,10 +1797,12 @@ static void ST_doItemFinderIconsAndSound(void) // SRB2kart - unused.
//
static void ST_overlayDrawer(void)
{
- /* SRB2kart doesn't need this stuff
//hu_showscores = auto hide score/time/rings when tab rankings are shown
if (!(hu_showscores && (netgame || multiplayer)))
{
+ K_drawKartHUD();
+
+ /* SRB2kart doesn't need this stuff
if (maptol & TOL_NIGHTS)
ST_drawNiGHTSHUD();
else
@@ -1824,8 +1826,8 @@ static void ST_overlayDrawer(void)
)
ST_drawLives();
}
- }
*/
+ }
// GAME OVER pic
/*if (G_GametypeUsesLives() && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer)))
@@ -1845,8 +1847,6 @@ static void ST_overlayDrawer(void)
// Countdown timer for Race Mode
// ...moved to k_kart.c so we can take advantage of the LAPS_Y value
- K_drawKartHUD();
-
/* SRB2kart doesn't need this stuff, I think
// If you are in overtime, put a big honkin' flashin' message on the screen.
if (G_BattleGametype() && cv_overtime.value
diff --git a/src/w_wad.c b/src/w_wad.c
index 841d8fd3..7fd7ac12 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -366,7 +366,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
// read the header
if (fread(&header, 1, sizeof header, handle) < sizeof header)
{
- CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), strerror(ferror(handle)));
+ CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), M_FileError(handle));
return NULL;
}
@@ -389,7 +389,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
if (fseek(handle, header.infotableofs, SEEK_SET) == -1
|| fread(fileinfo, 1, i, handle) < i)
{
- CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), strerror(ferror(handle)));
+ CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), M_FileError(handle));
free(fileinfov);
return NULL;
}
@@ -410,7 +410,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
handle) < sizeof realsize)
{
I_Error("corrupt compressed file: %s; maybe %s", /// \todo Avoid the bailout?
- filename, strerror(ferror(handle)));
+ filename, M_FileError(handle));
}
realsize = LONG(realsize);
if (realsize != 0)
@@ -548,7 +548,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
fseek(handle, -4, SEEK_CUR);
if (fread(&zend, 1, sizeof zend, handle) < sizeof zend)
{
- CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", strerror(ferror(handle)));
+ CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", M_FileError(handle));
return NULL;
}
numlumps = zend.entries;
@@ -565,7 +565,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
if (fread(zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t))
{
- CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", strerror(ferror(handle)));
+ CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle));
Z_Free(lumpinfo);
free(zentry);
return NULL;
@@ -585,7 +585,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
fullname = malloc(zentry->namelen + 1);
if (fgets(fullname, zentry->namelen + 1, handle) != fullname)
{
- CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", strerror(ferror(handle)));
+ CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle));
Z_Free(lumpinfo);
free(zentry);
free(fullname);
@@ -1319,8 +1319,8 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
{
size = 0;
zerr(zErr);
- (void)inflateEnd(&strm);
}
+ (void)inflateEnd(&strm);
}
else
{