diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db71b8c39..1d461a820 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -453,8 +453,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 b9a653eef..de857fd1d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -393,8 +393,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 include blua/Makefile.cfg diff --git a/src/command.h b/src/command.h index 851688b6c..44d5e50b3 100644 --- a/src/command.h +++ b/src/command.h @@ -35,7 +35,7 @@ enum /* Command buffer flags. */ enum { - COM_SAFE = 1, + COM_SAFE = 0x01, }; typedef void (*com_func_t)(void); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 062cfd535..12f52f95f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2346,7 +2346,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; } @@ -3575,6 +3578,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 = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); @@ -3650,6 +3723,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 2f1caa82e..c6d83fa1a 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -567,6 +567,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; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 6ff12ce3b..a87d04cb5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -749,6 +749,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 5ca99508a..3307d00e9 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -138,6 +138,7 @@ static UINT32 curl_origfilesize; static UINT32 curl_origtotalfilesize; static char *curl_realname = NULL; fileneeded_t *curl_curfile = NULL; +HTTP_login *curl_logins; #endif luafiletransfer_t *luafiletransfers = NULL; @@ -476,10 +477,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 @@ -1646,6 +1647,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"); @@ -1674,6 +1677,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); @@ -1775,4 +1786,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 31f9bc507..20a49f498 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -72,6 +72,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); @@ -151,6 +161,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/discord.c b/src/discord.c index 42b4d91e4..652303f65 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 5180869a5..a9ffe5f3b 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -152,6 +152,7 @@ static UINT8 UPNP_support = TRUE; #include "d_netfil.h" #include "i_tcp.h" #include "m_argv.h" +#include "stun.h" #include "doomstat.h" @@ -575,6 +576,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/lua_baselib.c b/src/lua_baselib.c index 0ee1a7a02..42e433254 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -387,7 +387,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 2ef17841f..6e3a3d331 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -536,7 +536,6 @@ static luaL_Reg lib[] = { {"CV_StealthSet", lib_cvStealthSet}, {"CV_AddValue", lib_cvAddValue}, {"CONS_Printf", lib_consPrintf}, - {"CV_FindVar", lib_cvFindVar}, {NULL, NULL} }; diff --git a/src/lua_hook.h b/src/lua_hook.h index d99d70327..915863626 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -109,10 +109,10 @@ void LUAh_PlayerQuit(player_t *plr, kickreason_t reason); // Hook for player qui boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping, UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms); // Hook for music changes -boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them. +boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them. void LUAh_IntermissionThinker(void); // Hook for Y_Ticker -void LUAh_VoteThinker(void); // Hook for Y_VoteTicker +void LUAh_VoteThinker(void); // Hook for Y_VoteTicker #define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb #define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities @@ -128,4 +128,3 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_ #define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing void LUAh_GameQuit(void); // Hook for game quitting -boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Hook for building player's ticcmd struct (Ported from SRB2Kart) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 4caf70ba9..8a0113f08 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -26,25 +26,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; } @@ -57,10 +67,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; } @@ -121,8 +131,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; @@ -143,8 +151,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; } @@ -182,17 +188,8 @@ static int player_get(lua_State *L) lua_pushboolean(L, true); else if (fastcmp(field,"name")) lua_pushstring(L, player_names[plr-players]); - else if (fastcmp(field,"realmo")) - LUA_PushUserdata(L, plr->mo, META_MOBJ); - // Kept for backward-compatibility - // Should be fixed to work like "realmo" later 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")) @@ -447,7 +444,7 @@ static int player_set(lua_State *L) if (hook_cmd_running) return luaL_error(L, "Do not alter player_t in BuildCMD code!"); - if (fastcmp(field,"mo") || fastcmp(field,"realmo")) { + if (fastcmp(field,"mo")) { mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); plr->mo->player = NULL; // remove player pointer from old mobj (newmo->player = plr)->mo = newmo; // set player pointer for new mobj, and set new mobj as the player's mobj diff --git a/src/lua_script.c b/src/lua_script.c index 0b964e5ea..291a1936c 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -731,6 +731,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 cf4efcccd..d90b5ef63 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -49,6 +49,7 @@ void LUA_DumpFile(const char *filename); fixed_t LUA_EvalMath(const char *word); void LUA_PushLightUserdata(lua_State *L, void *data, const char *meta); 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 eb10fd5f8..09d6936f2 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 b44d6de8c..c1e5e39b7 100644 --- a/src/m_swap.h +++ b/src/m_swap.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2018 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -14,39 +14,34 @@ #ifndef __M_SWAP__ #define __M_SWAP__ -// Endianess handling. -// WAD files are stored little endian. #include "endian.h" -// Little to big endian +#define SWAP_SHORT(x) ((INT16)(\ +(((UINT16)(x) & (UINT16)0x00ffU) << 8) \ +| \ +(((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ + +#define SWAP_LONG(x) ((INT32)(\ +(((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ +| \ +(((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ +| \ +(((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \ +| \ +(((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) + +// Endianess handling. +// WAD files are stored little endian. #ifdef SRB2_BIG_ENDIAN - - #define SHORT(x) ((INT16)(\ - (((UINT16)(x) & (UINT16)0x00ffU) << 8) \ - | \ - (((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ - - #define LONG(x) ((INT32)(\ - (((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ - | \ - (((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ - | \ - (((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \ - | \ - (((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) - +#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)) -#endif - -// Big to little endian -#ifdef SRB2_LITTLE_ENDIAN - #define BIGENDIAN_LONG(x) ((INT32)(((x)>>24)&0xff)|(((x)<<8)&0xff0000)|(((x)>>8)&0xff00)|(((x)<<24)&0xff000000)) - #define BIGENDIAN_SHORT(x) ((INT16)(((x)>>8)|((x)<<8))) -#else - #define BIGENDIAN_LONG(x) ((INT32)(x)) - #define BIGENDIAN_SHORT(x) ((INT16)(x)) +#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 10115e4a1..9131c24bb 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -24,19 +24,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 9349d0e53..ce4509ca9 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(const vector3_t *p, const vector3_t *line, vector3_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 6733fca79..7975a22f1 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -876,6 +876,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; @@ -1106,6 +1110,10 @@ static void Polyobj_rotateThings(polyobj_t *po, vector2_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_user.c b/src/p_user.c index cdaa24123..073cb8bbf 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4303,6 +4303,7 @@ void P_PlayerThink(player_t *player) if (player->playerstate == PST_DEAD) { + LUAh_PlayerThink(player); return; } } diff --git a/src/r_main.c b/src/r_main.c index 8e05b8d27..835ed26f7 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -368,29 +368,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/s_sound.c b/src/s_sound.c index a7d45e160..7c9abbf32 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2336,7 +2336,7 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) S_InitMusicVolume(); // switch between digi and sequence volume if (S_MusicNotInFocus()) - S_PauseAudio(); + I_SetMusicVolume(0); return true; } @@ -2780,9 +2780,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_video.c b/src/sdl/i_video.c index 5a9db4963..5e28e8643 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -651,7 +651,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) window_notinfocus = false; if (!paused) - S_ResumeAudio(); //resume it + S_InitMusicVolume(); if (cv_gamesounds.value) S_EnableSound(); @@ -670,7 +670,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 000000000..722d32906 --- /dev/null +++ b/src/stun.c @@ -0,0 +1,235 @@ +// 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 = CVAR_INIT ( + "stunserver", "stun.l.google.com:19302", CV_SAVE, NULL, NULL +); + +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 000000000..de23aeb42 --- /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*/