diff --git a/libs/drmingw/include/exchndl.h b/libs/drmingw/include/exchndl.h new file mode 100644 index 00000000..37dafb88 --- /dev/null +++ b/libs/drmingw/include/exchndl.h @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2015 Jose Fonseca + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#pragma once + + +#include + + +// Set the unhandled exception handler. +// Must be called when exchndll.dll is statically loaded (as opposed to loaded +// dynamically via LoadLibrary) +EXTERN_C VOID APIENTRY +ExcHndlInit(void); + + +// Override the report file name. +// +// Default is prog_name.RPT, in the same directory as the main executable. +// +// You can also pass "-" for stderr. +EXTERN_C BOOL APIENTRY +ExcHndlSetLogFileNameA(const char *szLogFileName); diff --git a/libs/drmingw/lib/win32/libexchndl.a b/libs/drmingw/lib/win32/libexchndl.a new file mode 100644 index 00000000..cd462a0d Binary files /dev/null and b/libs/drmingw/lib/win32/libexchndl.a differ diff --git a/libs/drmingw/lib/win32/libmgwhelp.a b/libs/drmingw/lib/win32/libmgwhelp.a new file mode 100644 index 00000000..330cb52f Binary files /dev/null and b/libs/drmingw/lib/win32/libmgwhelp.a differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c43464b7..9854567e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -364,8 +364,9 @@ if(${SRB2_CONFIG_HAVE_DISCORDRPC}) if(${DISCORDRPC_FOUND}) set(SRB2_HAVE_DISCORDRPC ON) add_definitions(-DHAVE_DISCORDRPC) - set(SRB2_DISCORDRPC_SOURCES discord.c) - set(SRB2_DISCORDRPC_HEADERS discord.h) + add_definitions(-DUSE_STUN) + set(SRB2_DISCORDRPC_SOURCES discord.c stun.c) + set(SRB2_DISCORDRPC_HEADERS discord.h stun.h) prepend_sources(SRB2_DISCORDRPC_SOURCES) prepend_sources(SRB2_DISCORDRPC_HEADERS) source_group("Discord Rich Presence" FILES ${SRB2_DISCORDRPC_SOURCES} ${SRB2_DISCORDRPC_HEADERS}) diff --git a/src/Makefile b/src/Makefile index fb859a33..da96f0cf 100644 --- a/src/Makefile +++ b/src/Makefile @@ -440,8 +440,8 @@ endif ifdef HAVE_DISCORDRPC LIBS+=-ldiscord-rpc -CFLAGS+=-DHAVE_DISCORDRPC -OBJS+=$(OBJDIR)/discord.o +CFLAGS+=-DHAVE_DISCORDRPC -DUSE_STUN +OBJS+=$(OBJDIR)/discord.o $(OBJDIR)/stun.o endif ifndef NO_LUA diff --git a/src/blua/liolib.c b/src/blua/liolib.c index a9e71f74..d1d6f469 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -19,6 +19,7 @@ #include "lualib.h" #include "../i_system.h" #include "../doomdef.h" +#include "../d_main.h" #include "../m_misc.h" @@ -190,7 +191,7 @@ static int io_open (lua_State *L) { return pushresult(L,0,filename); } - destFilename = va("luafiles"PATHSEP"%s", filename); + destFilename = va("%s"PATHSEP"luafiles"PATHSEP"%s", srb2home, filename); // Make directories as needed splitter = destFilename; diff --git a/src/command.h b/src/command.h index 0880065b..ae573a16 100644 --- a/src/command.h +++ b/src/command.h @@ -20,6 +20,14 @@ // Command buffer & command execution //=================================== +/* Lua command registration flags. */ +enum +{ + COM_ADMIN = 1, + COM_SPLITSCREEN = 2, + COM_LOCAL = 4, +}; + typedef void (*com_func_t)(void); void COM_AddCommand(const char *name, com_func_t func); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 008ad906..de43adfa 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2271,7 +2271,10 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) cl_mode = CL_CHECKFILES; } else + { cl_mode = CL_ASKJOIN; // files need not be checked for the server. + *asksent = 0; + } return true; } @@ -3477,6 +3480,76 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) } } +#ifdef HAVE_CURL +/** Add a login for HTTP downloads. If the + * user/password is missing, remove it. + * + * \sa Command_list_http_logins + */ +static void Command_set_http_login (void) +{ + HTTP_login *login; + HTTP_login **prev_next; + + if (COM_Argc() < 2) + { + CONS_Printf( + "set_http_login [user:password]: Set or remove a login to " + "authenticate HTTP downloads.\n" + ); + return; + } + + login = CURLGetLogin(COM_Argv(1), &prev_next); + + if (COM_Argc() == 2) + { + if (login) + { + (*prev_next) = login->next; + CONS_Printf("Login for '%s' removed.\n", login->url); + Z_Free(login); + } + } + else + { + if (login) + Z_Free(login->auth); + else + { + login = ZZ_Alloc(sizeof *login); + login->url = Z_StrDup(COM_Argv(1)); + } + + login->auth = Z_StrDup(COM_Argv(2)); + + login->next = curl_logins; + curl_logins = login; + } +} + +/** List logins for HTTP downloads. + * + * \sa Command_set_http_login + */ +static void Command_list_http_logins (void) +{ + HTTP_login *login; + + for ( + login = curl_logins; + login; + login = login->next + ){ + CONS_Printf( + "'%s' -> '%s'\n", + login->url, + login->auth + ); + } +} +#endif/*HAVE_CURL*/ + static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -3545,6 +3618,10 @@ void D_ClientServerInit(void) COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("connect", Command_connect); COM_AddCommand("nodes", Command_Nodes); +#ifdef HAVE_CURL + COM_AddCommand("set_http_login", Command_set_http_login); + COM_AddCommand("list_http_logins", Command_list_http_logins); +#endif #ifdef PACKETDROP COM_AddCommand("drop", Command_Drop); COM_AddCommand("droprate", Command_Droprate); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 98aec37e..7a8272b2 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -35,13 +35,7 @@ applications may follow different packet versions. // SOME numpty changed all the gametype constants and it fell out of sync with vanilla and now we have to pretend to be vanilla when talking to the master server... #define VANILLA_GT_RACE 2 -// Woah, what do these numbers mean? 200 refers to SRB2 2.0, 246 refers to -// SRB2Riders. Both use the old 2.0 gametype numbers. -#if VERSION == 200 || VERSION == 246 -#define VANILLA_GT_MATCH 1 -#else #define VANILLA_GT_MATCH 3 -#endif // Networking and tick handling related. #define BACKUPTICS 32 @@ -512,6 +506,7 @@ extern INT32 mapchangepending; // Points inside doomcom extern doomdata_t *netbuffer; +extern consvar_t cv_stunserver; extern consvar_t cv_httpsource; extern consvar_t cv_showjoinaddress; extern consvar_t cv_playbackspeed; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index cd8c2318..7fe1aa8d 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -722,6 +722,10 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_dummyconsvar); +#ifdef USE_STUN + CV_RegisterVar(&cv_stunserver); +#endif + CV_RegisterVar(&cv_discordinvites); RegisterNetXCmd(XD_DISCORD, Got_DiscordInfo); } diff --git a/src/d_netfil.c b/src/d_netfil.c index c9bfb4ea..d32d4d14 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -128,6 +128,7 @@ static UINT32 curl_origfilesize; static UINT32 curl_origtotalfilesize; static char *curl_realname = NULL; fileneeded_t *curl_curfile = NULL; +HTTP_login *curl_logins; #endif /** Fills a serverinfo packet with information about wad files loaded. @@ -430,10 +431,10 @@ INT32 CL_CheckFiles(void) for (i = 0; i < fileneedednum; i++) { - if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_FALLBACK) + if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK) downloadrequired = true; - if (fileneeded[i].status == FS_FOUND || fileneeded[i].status == FS_NOTFOUND) + if (fileneeded[i].status != FS_OPEN) filestoload++; if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics @@ -1082,6 +1083,8 @@ int curlprogress_callback(void *clientp, double dltotal, double dlnow, double ul void CURLPrepareFile(const char* url, int dfilenum) { + HTTP_login *login; + #ifdef PARANOIA if (M_CheckParm("-nodownload")) I_Error("Attempted to download files in -nodownload mode"); @@ -1110,6 +1113,14 @@ void CURLPrepareFile(const char* url, int dfilenum) 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. + // Authenticate if the user so wishes + login = CURLGetLogin(url, NULL); + + if (login) + { + curl_easy_setopt(http_handle, CURLOPT_USERPWD, login->auth); + } + // Follow a redirect request, if sent by the server. curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1L); @@ -1211,4 +1222,27 @@ void CURLGetFile(void) curl_global_cleanup(); } } + +HTTP_login * +CURLGetLogin (const char *url, HTTP_login ***return_prev_next) +{ + HTTP_login * login; + HTTP_login ** prev_next; + + for ( + prev_next = &curl_logins; + ( login = (*prev_next)); + prev_next = &login->next + ){ + if (strcmp(login->url, url) == 0) + { + if (return_prev_next) + (*return_prev_next) = prev_next; + + return login; + } + } + + return NULL; +} #endif diff --git a/src/d_netfil.h b/src/d_netfil.h index 905364e3..1ab50398 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -63,6 +63,16 @@ extern UINT32 totalfilesrequestedsize; extern boolean curl_failedwebdownload; extern boolean curl_running; extern INT32 curl_transfers; + +typedef struct HTTP_login HTTP_login; + +extern struct HTTP_login +{ + char * url; + char * auth; + HTTP_login * next; +} +*curl_logins; #endif UINT8 *PutFileNeeded(UINT16 firstfile); @@ -98,6 +108,7 @@ size_t nameonlylength(const char *s); #ifdef HAVE_CURL void CURLPrepareFile(const char* url, int dfilenum); void CURLGetFile(void); +HTTP_login * CURLGetLogin (const char *url, HTTP_login ***return_prev_next); #endif #endif // __D_NETFIL__ diff --git a/src/dehacked.c b/src/dehacked.c index 00f4fa96..d509cd49 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8685,6 +8685,11 @@ struct { {"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable {"BT_CUSTOM3",BT_CUSTOM3}, // Lua customizable + // Lua command registration flags + {"COM_ADMIN",COM_ADMIN}, + {"COM_SPLITSCREEN",COM_SPLITSCREEN}, + {"COM_LOCAL",COM_LOCAL}, + // cvflags_t {"CV_SAVE",CV_SAVE}, {"CV_CALL",CV_CALL}, @@ -9682,6 +9687,9 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"leveltime")) { lua_pushinteger(L, leveltime); return 1; + } else if (fastcmp(word,"defrosting")) { + lua_pushinteger(L, hook_defrosting); + return 1; } else if (fastcmp(word,"curWeather")) { lua_pushinteger(L, curWeather); return 1; @@ -9704,21 +9712,20 @@ static inline int lib_getenum(lua_State *L) lua_pushinteger(L, mapmusposition); return 1; } else if (fastcmp(word,"server")) { - if ((!multiplayer || !(netgame || demo.playback)) && !playeringame[serverplayer]) - return 0; - LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); - return 1; + return LUA_PushServerPlayer(L); } else if (fastcmp(word,"consoleplayer")) { // Player controlling the console, basically our local player + if (consoleplayer == serverplayer) + return LUA_PushServerPlayer(L); if (consoleplayer < 0 || !playeringame[consoleplayer]) return 0; LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER); return 1; - /*} else if (fastcmp(word,"admin")) { - LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)"); - if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer)) - return 0; - LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER); - return 1;*/ + } else if (fastcmp(word,"isserver")) { + lua_pushboolean(L, server); + return 1; + } else if (fastcmp(word, "isdedicatedserver")) { + lua_pushboolean(L, dedicated); + return 1; } else if (fastcmp(word,"gravity")) { lua_pushinteger(L, gravity); return 1; diff --git a/src/discord.c b/src/discord.c index b3798e29..4f72b714 100644 --- a/src/discord.c +++ b/src/discord.c @@ -12,9 +12,7 @@ #ifdef HAVE_DISCORDRPC -#ifdef HAVE_CURL -#include -#endif // HAVE_CURL +#include #include "i_system.h" #include "d_clisrv.h" @@ -27,6 +25,8 @@ #include "mserv.h" // cv_advertise #include "z_zone.h" #include "byteptr.h" +#include "stun.h" +#include "i_tcp.h" // current_port #include "discord.h" #include "doomdef.h" @@ -45,16 +45,7 @@ struct discordInfo_s discordInfo; discordRequest_t *discordRequestList = NULL; -#ifdef HAVE_CURL -struct SelfIPbuffer -{ - CURL *curl; - char *pointer; - size_t length; -}; - static char self_ip[IP_SIZE]; -#endif // HAVE_CURL /*-------------------------------------------------- static char *DRPC_XORIPString(const char *input) @@ -335,39 +326,23 @@ void DRPC_Init(void) DRPC_UpdatePresence(); } -#ifdef HAVE_CURL /*-------------------------------------------------- - static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata) + static void DRPC_GotServerIP(UINT32 address) - Writing function for use with curl. Only intended to be used with simple text. + Callback triggered by successful STUN response. Input Arguments:- - s - Data to write - size - Always 1. - n - Length of data - userdata - Passed in from CURLOPT_WRITEDATA, intended to be SelfIPbuffer + address - IPv4 address of this machine, in network byte order. Return:- - Number of bytes wrote in this pass. + None --------------------------------------------------*/ -static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata) +static void DRPC_GotServerIP(UINT32 address) { - struct SelfIPbuffer *buffer; - size_t newlength; - - buffer = userdata; - - newlength = buffer->length + size*n; - buffer->pointer = realloc(buffer->pointer, newlength+1); - - memcpy(buffer->pointer + buffer->length, s, size*n); - - buffer->pointer[newlength] = '\0'; - buffer->length = newlength; - - return size*n; + const unsigned char * p = (const unsigned char *)&address; + sprintf(self_ip, "%u.%u.%u.%u:%u", p[0], p[1], p[2], p[3], current_port); + DRPC_UpdatePresence(); } -#endif // HAVE_CURL /*-------------------------------------------------- static const char *DRPC_GetServerIP(void) @@ -387,64 +362,21 @@ static const char *DRPC_GetServerIP(void) { // We're not the server, so we could successfully get the IP! // No need to do anything else :) - return address; + sprintf(self_ip, "%s:%u", address, current_port); + return self_ip; } } -#ifdef HAVE_CURL - // This is a little bit goofy, but - // there's practically no good way to get your own public IP address, - // so we've gotta break out curl for this :V - if (!self_ip[0]) - { - CURL *curl; - - curl_global_init(CURL_GLOBAL_ALL); - curl = curl_easy_init(); - - if (curl) - { - // The API to get your public IP address from. - // Picked because it's stupid simple and it's been up for a long time. - const char *api = "http://ip4only.me/api/"; - - struct SelfIPbuffer buffer; - CURLcode success; - - buffer.length = 0; - buffer.pointer = malloc(buffer.length+1); - buffer.pointer[0] = '\0'; - - curl_easy_setopt(curl, CURLOPT_URL, api); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DRPC_WriteServerIP); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); - - success = curl_easy_perform(curl); - - if (success == CURLE_OK) - { - char *tmp; - tmp = strtok(buffer.pointer, ","); - - if (!strcmp(tmp, "IPv4")) // ensure correct type of IP - { - tmp = strtok(NULL, ","); - strncpy(self_ip, tmp, IP_SIZE); // Yay, we have the IP :) - } - } - - free(buffer.pointer); - curl_easy_cleanup(curl); - } - - curl_global_cleanup(); - } - if (self_ip[0]) + { return self_ip; + } else -#endif // HAVE_CURL - return NULL; // Could not get your IP for whatever reason, so we cannot do Discord invites + { + // There happens to be a good way to get it after all! :D + STUN_bind(DRPC_GotServerIP); + return NULL; + } } /*-------------------------------------------------- @@ -510,19 +442,6 @@ void DRPC_UpdatePresence(void) // Server info if (netgame) { - if (cv_advertise.value) - { - discordPresence.state = "Public"; - } - else - { - discordPresence.state = "Private"; - } - - discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field! - discordPresence.partySize = D_NumPlayers(); // Players in server - discordPresence.partyMax = discordInfo.maxPlayers; // Max players - if (DRPC_InvitesAreAllowed() == true) { const char *join; @@ -536,7 +455,24 @@ void DRPC_UpdatePresence(void) joinSecretSet = true; } + else + { + return; + } } + + if (cv_advertise.value) + { + discordPresence.state = "Public"; + } + else + { + discordPresence.state = "Private"; + } + + discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field! + discordPresence.partySize = D_NumPlayers(); // Players in server + discordPresence.partyMax = discordInfo.maxPlayers; // Max players } else { diff --git a/src/i_tcp.c b/src/i_tcp.c index 1f1cf4f2..ba973494 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -182,6 +182,7 @@ static UINT8 UPNP_support = TRUE; #include "d_netfil.h" #include "i_tcp.h" #include "m_argv.h" +#include "stun.h" #include "doomstat.h" @@ -612,6 +613,13 @@ static boolean SOCK_Get(void) (void *)&fromaddress, &fromlen); if (c != ERRSOCKET) { +#ifdef USE_STUN + if (STUN_got_response(doomcom->data, c)) + { + return false; + } +#endif + // find remote node number for (j = 1; j <= MAXNETNODES; j++) //include LAN { diff --git a/src/k_kart.c b/src/k_kart.c index 7fa062f4..389313b9 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4401,14 +4401,22 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source) static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) { const INT32 numsnds = 13; + + const fixed_t closedist = 160*FRACUNIT; + const fixed_t fardist = 1536*FRACUNIT; + + const UINT8 dampenval = 48; // 255 * 48 = close enough to FRACUNIT/6 + INT32 class, s, w; // engine class number + UINT8 volume = 255; - fixed_t volumedampen = 0; + fixed_t volumedampen = FRACUNIT; + INT32 targetsnd = 0; INT32 i; - s = (player->kartspeed-1)/3; - w = (player->kartweight-1)/3; + s = (player->kartspeed - 1) / 3; + w = (player->kartweight - 1) / 3; #define LOCKSTAT(stat) \ if (stat < 0) { stat = 0; } \ @@ -4417,81 +4425,114 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) LOCKSTAT(w); #undef LOCKSTAT - class = s+(3*w); + class = s + (3*w); - // Silence the engines if (leveltime < 8 || player->spectator || player->exiting) { - player->kartstuff[k_enginesnd] = 0; // Reset sound number + // Silence the engines, and reset sound number while we're at it. + player->kartstuff[k_enginesnd] = 0; return; } #if 0 if ((leveltime % 8) != ((player-players) % 8)) // Per-player offset, to make engines sound distinct! #else - if (leveltime % 8) // .25 seconds of wait time between engine sounds + if (leveltime % 8) #endif + { + // .25 seconds of wait time between each engine sound playback return; + } - if ((leveltime >= starttime-(2*TICRATE) && leveltime <= starttime) || (player->kartstuff[k_respawn] == 1)) // Startup boosts + if ((leveltime >= starttime-(2*TICRATE) && leveltime <= starttime) || (player->kartstuff[k_respawn] == 1)) + { + // Startup boosts only want to check for BT_ACCELERATE being pressed. targetsnd = ((cmd->buttons & BT_ACCELERATE) ? 12 : 0); + } else - targetsnd = (((6*cmd->forwardmove)/25) + ((player->speed / mapobjectscale)/5))/2; + { + // Average out the value of forwardmove and the speed that you're moving at. + targetsnd = (((6 * cmd->forwardmove) / 25) + ((player->speed / mapobjectscale) / 5)) / 2; + } - if (targetsnd < 0) - targetsnd = 0; - if (targetsnd > 12) - targetsnd = 12; + if (targetsnd < 0) { targetsnd = 0; } + if (targetsnd > 12) { targetsnd = 12; } - if (player->kartstuff[k_enginesnd] < targetsnd) - player->kartstuff[k_enginesnd]++; - if (player->kartstuff[k_enginesnd] > targetsnd) - player->kartstuff[k_enginesnd]--; + if (player->kartstuff[k_enginesnd] < targetsnd) { player->kartstuff[k_enginesnd]++; } + if (player->kartstuff[k_enginesnd] > targetsnd) { player->kartstuff[k_enginesnd]--; } - if (player->kartstuff[k_enginesnd] < 0) - player->kartstuff[k_enginesnd] = 0; - if (player->kartstuff[k_enginesnd] > 12) - player->kartstuff[k_enginesnd] = 12; + if (player->kartstuff[k_enginesnd] < 0) { player->kartstuff[k_enginesnd] = 0; } + if (player->kartstuff[k_enginesnd] > 12) { player->kartstuff[k_enginesnd] = 12; } + + // This code calculates how many players (and thus, how many engine sounds) are within ear shot, + // and rebalances the volume of your engine sound based on how far away they are. + + // This results in multiple things: + // - When on your own, you will hear your own engine sound extremely clearly. + // - When you were alone but someone is gaining on you, yours will go quiet, and you can hear theirs more clearly. + // - When around tons of people, engine sounds will try to rebalance to not be as obnoxious. for (i = 0; i < MAXPLAYERS; i++) { UINT8 thisvol = 0; fixed_t dist; - if (!playeringame[i] || !players[i].mo || players[i].spectator || players[i].exiting) - continue; - - if (P_IsDisplayPlayer(&players[i])) + if (!playeringame[i] || !players[i].mo) { - volumedampen += FRACUNIT; // We already know what this is gonna be, let's not waste our time. + // This player doesn't exist. continue; } - dist = P_AproxDistance(P_AproxDistance(player->mo->x-players[i].mo->x, - player->mo->y-players[i].mo->y), player->mo->z-players[i].mo->z) / 2; + if (players[i].spectator || players[i].exiting) + { + // This player isn't playing an engine sound. + continue; + } + + if (player == &players[i] || P_IsDisplayPlayer(&players[i])) + { + // Don't dampen yourself! + continue; + } + + dist = P_AproxDistance( + P_AproxDistance( + player->mo->x - players[i].mo->x, + player->mo->y - players[i].mo->y), + player->mo->z - players[i].mo->z) / 2; dist = FixedDiv(dist, mapobjectscale); - if (dist > 1536< fardist) + { + // ENEMY OUT OF RANGE ! continue; - else if (dist < 160<>FRACBITS)) / (((1536<>(FRACBITS+4)); + { + thisvol = (15 * ((closedist - dist) / FRACUNIT)) / ((fardist - closedist) >> (FRACBITS+4)); + } - if (thisvol == 0) - continue; - - volumedampen += (thisvol * 257); // 255 * 257 = FRACUNIT + volumedampen += (thisvol * dampenval); } if (volumedampen > FRACUNIT) - volume = FixedDiv(volume<>FRACBITS; + { + volume = FixedDiv(volume * FRACUNIT, volumedampen) / FRACUNIT; + } - if (volume <= 0) // Might as well + if (volume <= 0) + { + // Don't need to play the sound at all. return; + } - S_StartSoundAtVolume(player->mo, (sfx_krta00 + player->kartstuff[k_enginesnd]) + (class*numsnds), volume); + S_StartSoundAtVolume(player->mo, (sfx_krta00 + player->kartstuff[k_enginesnd]) + (class * numsnds), volume); } static void K_UpdateInvincibilitySounds(player_t *player) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 56b1a5a5..c50f53df 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -238,7 +238,8 @@ static int lib_pAproxDistance(lua_State *L) fixed_t dx = luaL_checkfixed(L, 1); fixed_t dy = luaL_checkfixed(L, 2); //HUDSAFE - lua_pushfixed(L, P_AproxDistance(dx, dy)); + LUA_Deprecated(L, "P_AproxDistance", "FixedHypot"); + lua_pushfixed(L, FixedHypot(dx, dy)); return 1; } diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 0c73459c..3869fdc7 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -113,12 +113,12 @@ void COM_Lua_f(void) lua_rawgeti(gL, -1, 2); // push flags from command info table if (lua_isboolean(gL, -1)) - flags = (lua_toboolean(gL, -1) ? 1 : 0); + flags = (lua_toboolean(gL, -1) ? COM_ADMIN : 0); else flags = (UINT8)lua_tointeger(gL, -1); lua_pop(gL, 1); // pop flags - if (flags & 2) // flag 2: splitscreen player command. TODO: support 4P + if (flags & COM_SPLITSCREEN) // flag 2: splitscreen player command. TODO: support 4P { if (!splitscreen) { @@ -128,12 +128,12 @@ void COM_Lua_f(void) playernum = displayplayers[1]; } - if (netgame) + if (netgame && !( flags & COM_LOCAL ))/* don't send local commands */ { // Send the command through the network UINT8 argc; lua_pop(gL, 1); // pop command info table - if (flags & 1 && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command. + if (flags & COM_ADMIN && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command. { CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); return; @@ -187,7 +187,15 @@ static int lib_comAddCommand(lua_State *L) if (lua_gettop(L) >= 3) { // For the third argument, only take a boolean or a number. lua_settop(L, 3); - if (lua_type(L, 3) != LUA_TBOOLEAN) + if (lua_type(L, 3) == LUA_TBOOLEAN) + { + CONS_Alert(CONS_WARNING, + "Using a boolean for admin commands is " + "deprecated and will be removed.\n" + "Use \"COM_ADMIN\" instead.\n" + ); + } + else luaL_checktype(L, 3, LUA_TNUMBER); } else @@ -436,6 +444,45 @@ static int lib_cvFindVar(lua_State *L) return 0; } +static int CVarSetFunction +( + lua_State *L, + void (*Set)(consvar_t *, const char *), + void (*SetValue)(consvar_t *, INT32) +){ + consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + + switch (lua_type(L, 2)) + { + case LUA_TSTRING: + (*Set)(cvar, lua_tostring(L, 2)); + break; + case LUA_TNUMBER: + (*SetValue)(cvar, (INT32)lua_tonumber(L, 2)); + break; + default: + return luaL_typerror(L, 1, "string or number"); + } + + return 0; +} + +static int lib_cvSet(lua_State *L) +{ + return CVarSetFunction(L, CV_Set, CV_SetValue); +} + +static int lib_cvStealthSet(lua_State *L) +{ + return CVarSetFunction(L, CV_StealthSet, CV_StealthSetValue); +} + +static int lib_cvAddValue(lua_State *L) +{ + consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + CV_AddValue(cvar, (INT32)luaL_checknumber(L, 2)); + return 0; +} // CONS_Printf for a single player // Use 'print' in baselib for a global message. @@ -475,8 +522,11 @@ static luaL_Reg lib[] = { {"COM_BufAddText", lib_comBufAddText}, {"COM_BufInsertText", lib_comBufInsertText}, {"CV_RegisterVar", lib_cvRegisterVar}, - {"CONS_Printf", lib_consPrintf}, {"CV_FindVar", lib_cvFindVar}, + {"CV_Set", lib_cvSet}, + {"CV_StealthSet", lib_cvStealthSet}, + {"CV_AddValue", lib_cvAddValue}, + {"CONS_Printf", lib_consPrintf}, {NULL, NULL} }; diff --git a/src/lua_hook.h b/src/lua_hook.h index 6af3941f..a17a7ac7 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -20,7 +20,9 @@ enum hook { hook_MapChange, hook_MapLoad, hook_PlayerJoin, + hook_PreThinkFrame, hook_ThinkFrame, + hook_PostThinkFrame, hook_MobjSpawn, hook_MobjCollide, hook_MobjMoveCollide, @@ -44,6 +46,7 @@ enum hook { hook_HurtMsg, hook_PlayerSpawn, hook_PlayerQuit, + hook_PlayerThink, hook_MusicChange, hook_ShouldSpin, //SRB2KART hook_ShouldExplode, //SRB2KART @@ -60,11 +63,14 @@ enum hook { extern const char *const hookNames[]; extern boolean hook_cmd_running; // This is used by PlayerCmd and lua_playerlib to prevent anything from being wirtten to player while we run PlayerCmd. +extern int hook_defrosting; void LUAh_MapChange(INT16 mapnumber); // Hook for map change (before load) void LUAh_MapLoad(void); // Hook for map load void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer +void LUAh_PreThinkFrame(void); // Hook for frame (before mobj and player thinkers) void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers) +void LUAh_PostThinkFrame(void); // Hook for frame (at end of tick, ie after overlays, precipitation, specials) boolean LUAh_MobjHook(mobj_t *mo, enum hook which); boolean LUAh_PlayerHook(player_t *plr, enum hook which); #define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type @@ -106,5 +112,6 @@ boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to p void LUAh_IntermissionThinker(void); // Hook for Y_Ticker void LUAh_VoteThinker(void); // Hook for Y_VoteTicker +#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 41a436e0..e9a4d0b4 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -31,7 +31,9 @@ const char *const hookNames[hook_MAX+1] = { "MapChange", "MapLoad", "PlayerJoin", + "PreThinkFrame", "ThinkFrame", + "PostThinkFrame", "MobjSpawn", "MobjCollide", "MobjMoveCollide", @@ -55,6 +57,7 @@ const char *const hookNames[hook_MAX+1] = { "HurtMsg", "PlayerSpawn", "PlayerQuit", + "PlayerThink", "MusicChange", "ShouldSpin", "ShouldExplode", @@ -206,6 +209,7 @@ static int lib_addHook(lua_State *L) case hook_SpinSpecial: case hook_JumpSpinSpecial: case hook_PlayerSpawn: + case hook_PlayerThink: lastp = &playerhooks; break; case hook_LinedefExecute: @@ -402,6 +406,29 @@ void LUAh_PlayerJoin(int playernum) lua_settop(gL, 0); } +// Hook for frame (before mobj and player thinkers) +void LUAh_PreThinkFrame(void) +{ + hook_p hookp; + if (!gL || !(hooksAvailable[hook_PreThinkFrame/8] & (1<<(hook_PreThinkFrame%8)))) + return; + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_PreThinkFrame) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + if (lua_pcall(gL, 0, 0, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } + } +} + // Hook for frame (after mobj and player thinkers) void LUAh_ThinkFrame(void) { @@ -423,6 +450,29 @@ void LUAh_ThinkFrame(void) } } +// Hook for frame (at end of tick, ie after overlays, precipitation, specials) +void LUAh_PostThinkFrame(void) +{ + hook_p hookp; + if (!gL || !(hooksAvailable[hook_PostThinkFrame/8] & (1<<(hook_PostThinkFrame%8)))) + return; + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_PostThinkFrame) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + if (lua_pcall(gL, 0, 0, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } + } +} + // Hook for Y_Ticker void LUAh_IntermissionThinker(void) { diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 26561a4d..e00af595 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -27,25 +27,35 @@ static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; + if (lua_gettop(L) < 2) { //return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do end'."); lua_pushcfunction(L, lib_iteratePlayers); return 1; } + lua_settop(L, 2); lua_remove(L, 1); // state is unused. + if (!lua_isnil(L, 1)) i = (INT32)(*((player_t **)luaL_checkudata(L, 1, META_PLAYER)) - players); - for (i++; i < MAXPLAYERS; i++) + + i++; + + if (i == serverplayer) + { + return LUA_PushServerPlayer(L); + } + + for (; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; - if (!players[i].mo) - continue; LUA_PushUserdata(L, &players[i], META_PLAYER); return 1; } + return 0; } @@ -58,10 +68,10 @@ static int lib_getPlayer(lua_State *L) lua_Integer i = luaL_checkinteger(L, 2); if (i < 0 || i >= MAXPLAYERS) return luaL_error(L, "players[] index %d out of range (0 - %d)", i, MAXPLAYERS-1); + if (i == serverplayer) + return LUA_PushServerPlayer(L); if (!playeringame[i]) return 0; - if (!players[i].mo) - return 0; LUA_PushUserdata(L, &players[i], META_PLAYER); return 1; } @@ -122,8 +132,6 @@ static int lib_iterateDisplayplayers(lua_State *L) 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) - continue; LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER); lua_pushinteger(L, i); // push this to recall what number we were on for the next function call. I suppose this also means you can retrieve the splitscreen player number with 'for p, n in displayplayers.iterate'! return 2; @@ -144,8 +152,6 @@ static int lib_getDisplayplayers(lua_State *L) return 0; if (!playeringame[displayplayers[i]]) return 0; - if (!players[displayplayers[i]].mo) - return 0; LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER); return 1; } @@ -184,12 +190,7 @@ static int player_get(lua_State *L) else if (fastcmp(field,"name")) lua_pushstring(L, player_names[plr-players]); else if (fastcmp(field,"mo")) - { - if (plr->spectator) - lua_pushnil(L); - else - LUA_PushUserdata(L, plr->mo, META_MOBJ); - } + LUA_PushUserdata(L, plr->mo, META_MOBJ); else if (fastcmp(field,"cmd")) LUA_PushUserdata(L, &plr->cmd, META_TICCMD); else if (fastcmp(field,"playerstate")) diff --git a/src/lua_script.c b/src/lua_script.c index 7c951efb..5aff5380 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -35,6 +35,8 @@ lua_State *gL = NULL; +int hook_defrosting; + // List of internal libraries to load from SRB2 static lua_CFunction liblist[] = { LUA_EnumLib, // global metatable for enums @@ -367,6 +369,14 @@ void LUA_PushUserdata(lua_State *L, void *data, const char *meta) lua_remove(L, -2); // remove LREG_VALID } +int LUA_PushServerPlayer(lua_State *L) +{ + if ((!multiplayer || !(netgame || demo.playback)) && !playeringame[serverplayer]) + return 0; + LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); + return 1; +} + // When userdata is freed, use this function to remove it from Lua. void LUA_InvalidateUserdata(void *data) { diff --git a/src/lua_script.h b/src/lua_script.h index b3ca16bc..5e2e171f 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -46,6 +46,7 @@ void LUA_DumpFile(const char *filename); #endif fixed_t LUA_EvalMath(const char *word); void LUA_PushUserdata(lua_State *L, void *data, const char *meta); +int LUA_PushServerPlayer(lua_State *L); void LUA_InvalidateUserdata(void *data); void LUA_InvalidateLevel(void); void LUA_InvalidateMapthings(void); diff --git a/src/m_fixed.c b/src/m_fixed.c index 7241be9c..3724144f 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -18,8 +18,10 @@ #define HAVE_SQRTF #endif #endif + #include "doomdef.h" #include "m_fixed.h" +#include "tables.h" // ANGLETOFINESHIFT #ifdef __USE_C_FIXEDMUL__ @@ -105,20 +107,34 @@ fixed_t FixedSqrt(fixed_t x) fixed_t FixedHypot(fixed_t x, fixed_t y) { - fixed_t ax, yx, yx2, yx1; - if (abs(y) > abs(x)) // |y|>|x| + // Moved the code from R_PointToDist2 to here, + // since R_PointToDist2 did the same thing, + // except less prone to overflowing. + + angle_t angle; + fixed_t dist; + + x = abs(x); + y = abs(y); + + if (y > x) { - ax = abs(y); // |y| => ax - yx = FixedDiv(x, y); // (x/y) + fixed_t temp; + + temp = x; + x = y; + y = temp; } - else // |x|>|y| - { - ax = abs(x); // |x| => ax - yx = FixedDiv(y, x); // (x/y) - } - yx2 = FixedMul(yx, yx); // (x/y)^2 - yx1 = FixedSqrt(1 * FRACUNIT + yx2); // (1 + (x/y)^2)^1/2 - return FixedMul(ax, yx1); // |x|*((1 + (x/y)^2)^1/2) + + if (!y) + return x; + + angle = (tantoangle[FixedDiv(y, x)>>DBITS] + ANGLE_90) >> ANGLETOFINESHIFT; + + // use as cosine + dist = FixedDiv(x, FINESINE(angle)); + + return dist; } vector2_t *FV2_Load(vector2_t *vec, fixed_t x, fixed_t y) diff --git a/src/m_swap.h b/src/m_swap.h index 2d42f613..c1e5e39b 100644 --- a/src/m_swap.h +++ b/src/m_swap.h @@ -16,16 +16,12 @@ #include "endian.h" -// Endianess handling. -// WAD files are stored little endian. -#ifdef SRB2_BIG_ENDIAN - -#define SHORT(x) ((INT16)(\ +#define SWAP_SHORT(x) ((INT16)(\ (((UINT16)(x) & (UINT16)0x00ffU) << 8) \ | \ (((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ -#define LONG(x) ((INT32)(\ +#define SWAP_LONG(x) ((INT32)(\ (((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ | \ (((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ @@ -34,9 +30,18 @@ | \ (((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) +// Endianess handling. +// WAD files are stored little endian. +#ifdef SRB2_BIG_ENDIAN +#define SHORT SWAP_SHORT +#define LONG SWAP_LONG +#define MSBF_SHORT(x) ((INT16)(x)) +#define MSBF_LONG(x) ((INT32)(x)) #else #define SHORT(x) ((INT16)(x)) #define LONG(x) ((INT32)(x)) +#define MSBF_SHORT SWAP_SHORT +#define MSBF_LONG SWAP_LONG #endif #endif diff --git a/src/p_maputl.c b/src/p_maputl.c index 260eb3ec..760e45c4 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -23,19 +23,6 @@ #include "p_slopes.h" #include "z_zone.h" -// -// P_AproxDistance -// Gives an estimation of distance (not exact) -// -fixed_t P_AproxDistance(fixed_t dx, fixed_t dy) -{ - dx = abs(dx); - dy = abs(dy); - if (dx < dy) - return dx + dy - (dx>>1); - return dx + dy - (dy>>1); -} - // // P_ClosestPointOnLine // Finds the closest point on a given line to the supplied point diff --git a/src/p_maputl.h b/src/p_maputl.h index be69e026..ec4a4aa3 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -41,7 +41,7 @@ typedef boolean (*traverser_t)(intercept_t *in); boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, INT32 pflags, traverser_t ptrav); -FUNCMATH fixed_t P_AproxDistance(fixed_t dx, fixed_t dy); +#define P_AproxDistance(dx, dy) FixedHypot(dx, dy) void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result); void P_ClosestPointOnLine3D(fixed_t x, fixed_t y, fixed_t z, line_t *line, vertex_t *result); INT32 P_PointOnLineSide(fixed_t x, fixed_t y, line_t *line); diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 60c653b1..cdcf37d9 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1042,6 +1042,10 @@ static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy) for (; mo; mo = mo->bnext) { + // lastlook is used by the SPB to determine targets, do not let it affect it + if (mo->type == MT_SPB) + continue; + if (mo->lastlook == pomovecount) continue; @@ -1286,6 +1290,10 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta, for (; mo; mo = mo->bnext) { + // lastlook is used by the SPB to determine targets, do not let it affect it + if (mo->type == MT_SPB) + continue; + if (mo->lastlook == pomovecount) continue; diff --git a/src/p_tick.c b/src/p_tick.c index 4cc6c9ba..6a85027f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -648,6 +648,10 @@ void P_Ticker(boolean run) #endif } +#ifdef HAVE_BLUA + LUAh_PreThinkFrame(); +#endif + for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerThink(&players[i]); @@ -779,6 +783,10 @@ void P_Ticker(boolean run) && --mapreset <= 1 && server) // Remember: server uses it for mapchange, but EVERYONE ticks down for the animation D_MapChange(gamemap, gametype, encoremode, true, 0, false, false); + +#ifdef HAVE_BLUA + LUAh_PostThinkFrame(); +#endif } // Always move the camera. @@ -799,16 +807,22 @@ void P_Ticker(boolean run) // Abbreviated ticker for pre-loading, calls thinkers and assorted things void P_PreTicker(INT32 frames) { - INT32 i,framecnt; + INT32 i; ticcmd_t temptic; for (i = 0; i <= splitscreen; i++) postimgtype[i] = postimg_none; - for (framecnt = 0; framecnt < frames; ++framecnt) + hook_defrosting = frames; + + while (hook_defrosting) { P_MapStart(); +#ifdef HAVE_BLUA + LUAh_PreThinkFrame(); +#endif + for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) { @@ -843,6 +857,12 @@ void P_PreTicker(INT32 frames) P_UpdateSpecials(); P_RespawnSpecials(); +#ifdef HAVE_BLUA + LUAh_PostThinkFrame(); +#endif + P_MapEnd(); + + hook_defrosting--; } } diff --git a/src/p_user.c b/src/p_user.c index 7f022df0..df5fb7be 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8247,7 +8247,12 @@ void P_PlayerThink(player_t *player) player->playerstate = PST_REBORN; } if (player->playerstate == PST_REBORN) + { +#ifdef HAVE_BLUA + LUAh_PlayerThink(player); +#endif return; + } } #ifdef SEENAMES @@ -8371,7 +8376,12 @@ void P_PlayerThink(player_t *player) P_DoTimeOver(player); if (player->playerstate == PST_DEAD) + { +#ifdef HAVE_BLUA + LUAh_PlayerThink(player); +#endif return; + } } } @@ -8435,7 +8445,9 @@ void P_PlayerThink(player_t *player) else player->mo->flags2 &= ~MF2_SHADOW; P_DeathThink(player); - +#ifdef HAVE_BLUA + LUAh_PlayerThink(player); +#endif return; } @@ -8620,7 +8632,12 @@ void P_PlayerThink(player_t *player) P_MovePlayer(player); if (!player->mo) + { +#ifdef HAVE_BLUA + LUAh_PlayerThink(player); +#endif return; // P_MovePlayer removed player->mo. + } // Unset statis flags after moving. // In other words, if you manually set stasis via code, @@ -8816,6 +8833,10 @@ void P_PlayerThink(player_t *player) K_KartPlayerThink(player, cmd); // SRB2kart +#ifdef HAVE_BLUA + LUAh_PlayerThink(player); +#endif + /* // Colormap verification { diff --git a/src/r_main.c b/src/r_main.c index 5f3639de..a78cd57e 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -393,29 +393,7 @@ angle_t R_PointToAngle2(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y) fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1) { - angle_t angle; - fixed_t dx, dy, dist; - - dx = abs(px1 - px2); - dy = abs(py1 - py2); - - if (dy > dx) - { - fixed_t temp; - - temp = dx; - dx = dy; - dy = temp; - } - if (!dy) - return dx; - - angle = (tantoangle[FixedDiv(dy, dx)>>DBITS] + ANGLE_90) >> ANGLETOFINESHIFT; - - // use as cosine - dist = FixedDiv(dx, FINESINE(angle)); - - return dist; + return FixedHypot(px1 - px2, py1 - py2); } // Little extra utility. Works in the same way as R_PointToAngle2 diff --git a/src/r_plane.c b/src/r_plane.c index d0027426..9b0691da 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -46,7 +46,10 @@ //#define SHITPLANESPARENCY //SoM: 3/23/2000: Use Boom visplane hashing. -#define MAXVISPLANES 512 +#define VISPLANEHASHBITS 9 +#define VISPLANEHASHMASK ((1<next) + if (!pfloor) { - if (check->polyobj && pfloor) - continue; - if (polyobj != check->polyobj) - continue; - if (height == check->height && picnum == check->picnum - && lightlevel == check->lightlevel - && xoff == check->xoffs && yoff == check->yoffs - && planecolormap == check->extra_colormap - && !pfloor && !check->ffloor - && check->viewx == viewx && check->viewy == viewy && check->viewz == viewz - && check->viewangle == viewangle - && check->plangle == plangle - && check->slope == slope - && check->noencore == noencore) + hash = visplane_hash(picnum, lightlevel, height); + for (check = visplanes[hash]; check; check = check->next) { - return check; + if (polyobj != check->polyobj) + continue; + if (height == check->height && picnum == check->picnum + && lightlevel == check->lightlevel + && xoff == check->xoffs && yoff == check->yoffs + && planecolormap == check->extra_colormap + && check->viewx == viewx && check->viewy == viewy && check->viewz == viewz + && check->viewangle == viewangle + && check->plangle == plangle + && check->slope == slope + && check->noencore == noencore) + { + return check; + } } } + else + { + hash = MAXVISPLANES - 1; + } check = new_visplane(hash); @@ -559,9 +564,17 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) } else /* Cannot use existing plane; create a new one */ { - unsigned hash = - visplane_hash(pl->picnum, pl->lightlevel, pl->height); - visplane_t *new_pl = new_visplane(hash); + visplane_t *new_pl; + if (pl->ffloor) + { + new_pl = new_visplane(MAXVISPLANES - 1); + } + else + { + unsigned hash = + visplane_hash(pl->picnum, pl->lightlevel, pl->height); + new_pl = new_visplane(hash); + } new_pl->height = pl->height; new_pl->picnum = pl->picnum; diff --git a/src/s_sound.c b/src/s_sound.c index 22586321..ea0a1bbe 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1952,7 +1952,7 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) S_InitMusicVolume(); // switch between digi and sequence volume if (window_notinfocus && !cv_playmusicifunfocused.value) - I_PauseSong(); + I_SetMusicVolume(0); return true; } @@ -2418,9 +2418,9 @@ static void PlayMusicIfUnfocused_OnChange(void) if (window_notinfocus) { if (cv_playmusicifunfocused.value) - I_PauseSong(); + I_SetMusicVolume(0); else - I_ResumeSong(); + S_InitMusicVolume(); } } diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index a2ce653e..e6644ec5 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -58,6 +58,10 @@ char logfilename[1024]; #endif #endif +#if defined (_WIN32) +#include "exchndl.h" +#endif + #if defined (_WIN32) #include "../win32/win_dbg.h" typedef BOOL (WINAPI *p_IsDebuggerPresent)(VOID); @@ -170,7 +174,7 @@ int main(int argc, char **argv) ) #endif { - LoadLibraryA("exchndl.dll"); + ExcHndlInit(); } } #ifndef __MINGW32__ diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 37eedf14..ba0f7f1d 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -624,8 +624,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) // Tell game we got focus back, resume music if necessary window_notinfocus = false; - if (!paused) - I_ResumeSong(); //resume it + S_InitMusicVolume(); if (cv_gamesounds.value) S_EnableSound(); @@ -641,7 +640,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) // Tell game we lost focus, pause music window_notinfocus = true; if (!cv_playmusicifunfocused.value) - I_PauseSong(); + I_SetMusicVolume(0); if (!cv_playsoundifunfocused.value) S_DisableSound(); diff --git a/src/stun.c b/src/stun.c new file mode 100644 index 00000000..dbcfe58e --- /dev/null +++ b/src/stun.c @@ -0,0 +1,236 @@ +// 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 stun.c +/// \brief RFC 5389 client implementation to fetch external IP address. + +/* https://tools.ietf.org/html/rfc5389 */ + +#if defined (__linux__) +#include +#elif defined (_WIN32) +#define _CRT_RAND_S +#elif defined (__APPLE__) +#include +#else +#error "Need CSPRNG." +#endif + +#include "doomdef.h" +#include "d_clisrv.h" +#include "command.h" +#include "i_net.h" +#include "stun.h" + +/* https://gist.github.com/zziuni/3741933 */ +/* I can only trust google to keep their shit up :y */ +consvar_t cv_stunserver = { + "stunserver", "stun.l.google.com:19302", CV_SAVE, NULL, + NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */ +}; + +static stun_callback_t stun_callback; + +/* 18.4 STUN UDP and TCP Port Numbers */ + +#define STUN_PORT "3478" + +/* 6. STUN Message Structure */ + +#define BIND_REQUEST 0x0001 +#define BIND_RESPONSE 0x0101 + +static const UINT32 MAGIC_COOKIE = MSBF_LONG (0x2112A442); + +static char transaction_id[12]; + +/* 18.2 STUN Attribute Registry */ + +#define XOR_MAPPED_ADDRESS 0x0020 + +/* 15.1 MAPPED-ADDRESS */ + +#define STUN_IPV4 0x01 + +static SINT8 +STUN_node (void) +{ + SINT8 node; + + char * const colon = strchr(cv_stunserver.zstring, ':'); + + const char * const host = cv_stunserver.zstring; + const char * const port = &colon[1]; + + I_Assert(I_NetMakeNodewPort != NULL); + + if (colon != NULL) + { + *colon = '\0'; + + node = I_NetMakeNodewPort(host, port); + + *colon = ':'; + } + else + { + node = I_NetMakeNodewPort(host, STUN_PORT); + } + + return node; +} + +static void +csprng +( + void * const buffer, + const size_t size +){ +#if defined (_WIN32) + size_t o; + + for (o = 0; o < size; o += sizeof (unsigned int)) + { + rand_s((unsigned int *)&((char *)buffer)[o]); + } +#elif defined (__linux__) + getrandom(buffer, size, 0U); +#elif defined (__APPLE__) + CCRandomGenerateBytes(buffer, size); +#elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) + arc4random_buf(buffer, size); +#endif +} + +void +STUN_bind (stun_callback_t callback) +{ + /* 6. STUN Message Structure */ + + const UINT16 type = MSBF_SHORT (BIND_REQUEST); + + const SINT8 node = STUN_node(); + + doomcom->remotenode = node; + doomcom->datalength = 20; + + csprng(transaction_id, 12U); + + memcpy(&doomcom->data[0], &type, 2U); + memset(&doomcom->data[2], 0, 2U); + memcpy(&doomcom->data[4], &MAGIC_COOKIE, 4U); + memcpy(&doomcom->data[8], transaction_id, 12U); + + stun_callback = callback; + + I_NetSend(); + Net_CloseConnection(node);/* will handle response at I_NetGet */ +} + +static size_t +STUN_xor_mapped_address (const char * const value) +{ + const UINT32 xaddr = *(const UINT32 *)&value[4]; + const UINT32 addr = xaddr ^ MAGIC_COOKIE; + + (*stun_callback)(addr); + + return 0U; +} + +static size_t +align4 (size_t n) +{ + return n + n % 4U; +} + +static size_t +STUN_parse_attribute (const char * const attribute) +{ + /* 15. STUN Attributes */ + const UINT16 type = MSBF_SHORT (*(const UINT16 *)&attribute[0]); + const UINT16 length = MSBF_SHORT (*(const UINT16 *)&attribute[2]); + + /* 15.2 XOR-MAPPED-ADDRESS */ + if ( + type == XOR_MAPPED_ADDRESS && + length == 8U && + (unsigned char)attribute[5] == STUN_IPV4 + ){ + return STUN_xor_mapped_address(&attribute[4]); + } + + return align4(4U + length); +} + +boolean +STUN_got_response +( + const char * const buffer, + const size_t size +){ + const char * const end = &buffer[size]; + + const char * p = &buffer[20]; + + UINT16 type; + UINT16 length; + + /* + Check for STUN response. + + Header is 20 bytes. + XOR-MAPPED-ADDRESS attribute is required. + Each attribute has a 2 byte header. + The XOR-MAPPED-ADDRESS attribute also has a 8 byte value. + This totals 10 bytes for the attribute. + */ + + if (size < 30U || stun_callback == NULL) + { + return false; + } + + /* 6. STUN Message Structure */ + + if ( + *(const UINT32 *)&buffer[4] == MAGIC_COOKIE && + memcmp(&buffer[8], transaction_id, 12U) == 0 + ){ + type = MSBF_SHORT (*(const UINT16 *)&buffer[0]); + length = MSBF_SHORT (*(const UINT16 *)&buffer[2]); + + if ( + (type >> 14) == 0U && + (length & 0x02) == 0U && + (20U + length) <= size + ){ + if (type == BIND_RESPONSE) + { + do + { + length = STUN_parse_attribute(p); + + if (length == 0U) + { + break; + } + + p += length; + } + while (p < end) ; + } + + stun_callback = NULL; + + return true; + } + } + + return false; +} diff --git a/src/stun.h b/src/stun.h new file mode 100644 index 00000000..de23aeb4 --- /dev/null +++ b/src/stun.h @@ -0,0 +1,20 @@ +// 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 stun.h +/// \brief RFC 5389 client implementation to fetch external IP address. + +#ifndef KART_STUN_H +#define KART_STUN_H + +typedef void (*stun_callback_t)(UINT32 address); + +void STUN_bind (stun_callback_t); +boolean STUN_got_response (const char * const buffer, const size_t size); + +#endif/*KART_STUN_H*/ diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg index 935b2722..6286a18b 100644 --- a/src/win32/Makefile.cfg +++ b/src/win32/Makefile.cfg @@ -60,6 +60,12 @@ else endif endif +ifndef MINGW64 + CPPFLAGS+=-I../libs/drmingw/include + LDFLAGS+=-L../libs/drmingw/lib/win32 + LIBS+=-lmgwhelp -lexchndl +endif + # name of the exefile ifdef SDL EXENAME?=srb2kart.exe @@ -158,3 +164,7 @@ else endif LIBS+=-ldiscord-rpc endif + +ifndef MINGW64 + LDFLAGS+=-Wl,--large-address-aware +endif