mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2025-01-13 05:11:01 +00:00
Merge branch 'next' into spectator-little-things
This commit is contained in:
commit
163b215b0a
38 changed files with 872 additions and 273 deletions
39
libs/drmingw/include/exchndl.h
Normal file
39
libs/drmingw/include/exchndl.h
Normal file
|
@ -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 <windows.h>
|
||||
|
||||
|
||||
// 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);
|
BIN
libs/drmingw/lib/win32/libexchndl.a
Normal file
BIN
libs/drmingw/lib/win32/libexchndl.a
Normal file
Binary file not shown.
BIN
libs/drmingw/lib/win32/libmgwhelp.a
Normal file
BIN
libs/drmingw/lib/win32/libmgwhelp.a
Normal file
Binary file not shown.
|
@ -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})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <URL> [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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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;
|
||||
|
|
138
src/discord.c
138
src/discord.c
|
@ -12,9 +12,7 @@
|
|||
|
||||
#ifdef HAVE_DISCORDRPC
|
||||
|
||||
#ifdef HAVE_CURL
|
||||
#include <curl/curl.h>
|
||||
#endif // HAVE_CURL
|
||||
#include <time.h>
|
||||
|
||||
#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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
117
src/k_kart.c
117
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<<FRACBITS)
|
||||
if (dist > fardist)
|
||||
{
|
||||
// ENEMY OUT OF RANGE !
|
||||
continue;
|
||||
else if (dist < 160<<FRACBITS) // engine sounds' approx. range
|
||||
}
|
||||
else if (dist < closedist)
|
||||
{
|
||||
// engine sounds' approx. range
|
||||
thisvol = 255;
|
||||
}
|
||||
else
|
||||
thisvol = (15 * (((160<<FRACBITS) - dist)>>FRACBITS)) / (((1536<<FRACBITS)-(160<<FRACBITS))>>(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, volumedampen)>>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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 <block> 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"))
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
17
src/m_swap.h
17
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
24
src/p_tick.c
24
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--;
|
||||
}
|
||||
}
|
||||
|
|
23
src/p_user.c
23
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
|
||||
{
|
||||
|
|
24
src/r_main.c
24
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
|
||||
|
|
|
@ -46,7 +46,10 @@
|
|||
//#define SHITPLANESPARENCY
|
||||
|
||||
//SoM: 3/23/2000: Use Boom visplane hashing.
|
||||
#define MAXVISPLANES 512
|
||||
#define VISPLANEHASHBITS 9
|
||||
#define VISPLANEHASHMASK ((1<<VISPLANEHASHBITS)-1)
|
||||
// the last visplane list is outside of the hash table and is used for fof planes
|
||||
#define MAXVISPLANES ((1<<VISPLANEHASHBITS)+1)
|
||||
|
||||
static visplane_t *visplanes[MAXVISPLANES];
|
||||
static visplane_t *freetail;
|
||||
|
@ -61,7 +64,7 @@ INT32 numffloors;
|
|||
|
||||
//SoM: 3/23/2000: Boom visplane hashing routine.
|
||||
#define visplane_hash(picnum,lightlevel,height) \
|
||||
((unsigned)((picnum)*3+(lightlevel)+(height)*7) & (MAXVISPLANES-1))
|
||||
((unsigned)((picnum)*3+(lightlevel)+(height)*7) & VISPLANEHASHMASK)
|
||||
|
||||
//SoM: 3/23/2000: Use boom opening limit removal
|
||||
size_t maxopenings;
|
||||
|
@ -466,29 +469,31 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
|||
lightlevel = 0;
|
||||
}
|
||||
|
||||
// New visplane algorithm uses hash table
|
||||
hash = visplane_hash(picnum, lightlevel, height);
|
||||
|
||||
for (check = visplanes[hash]; check; check = check->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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
236
src/stun.c
Normal file
236
src/stun.c
Normal file
|
@ -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 <sys/random.h>
|
||||
#elif defined (_WIN32)
|
||||
#define _CRT_RAND_S
|
||||
#elif defined (__APPLE__)
|
||||
#include <CommonCrypto/CommonRandom.h>
|
||||
#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;
|
||||
}
|
20
src/stun.h
Normal file
20
src/stun.h
Normal file
|
@ -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*/
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue