...
 
Commits (64)
/*
* 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);
...@@ -364,8 +364,9 @@ if(${SRB2_CONFIG_HAVE_DISCORDRPC}) ...@@ -364,8 +364,9 @@ if(${SRB2_CONFIG_HAVE_DISCORDRPC})
if(${DISCORDRPC_FOUND}) if(${DISCORDRPC_FOUND})
set(SRB2_HAVE_DISCORDRPC ON) set(SRB2_HAVE_DISCORDRPC ON)
add_definitions(-DHAVE_DISCORDRPC) add_definitions(-DHAVE_DISCORDRPC)
set(SRB2_DISCORDRPC_SOURCES discord.c) add_definitions(-DUSE_STUN)
set(SRB2_DISCORDRPC_HEADERS discord.h) 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_SOURCES)
prepend_sources(SRB2_DISCORDRPC_HEADERS) prepend_sources(SRB2_DISCORDRPC_HEADERS)
source_group("Discord Rich Presence" FILES ${SRB2_DISCORDRPC_SOURCES} ${SRB2_DISCORDRPC_HEADERS}) source_group("Discord Rich Presence" FILES ${SRB2_DISCORDRPC_SOURCES} ${SRB2_DISCORDRPC_HEADERS})
......
...@@ -440,8 +440,8 @@ endif ...@@ -440,8 +440,8 @@ endif
ifdef HAVE_DISCORDRPC ifdef HAVE_DISCORDRPC
LIBS+=-ldiscord-rpc LIBS+=-ldiscord-rpc
CFLAGS+=-DHAVE_DISCORDRPC CFLAGS+=-DHAVE_DISCORDRPC -DUSE_STUN
OBJS+=$(OBJDIR)/discord.o OBJS+=$(OBJDIR)/discord.o $(OBJDIR)/stun.o
endif endif
ifndef NO_LUA ifndef NO_LUA
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "lualib.h" #include "lualib.h"
#include "../i_system.h" #include "../i_system.h"
#include "../doomdef.h" #include "../doomdef.h"
#include "../d_main.h"
#include "../m_misc.h" #include "../m_misc.h"
...@@ -190,7 +191,7 @@ static int io_open (lua_State *L) { ...@@ -190,7 +191,7 @@ static int io_open (lua_State *L) {
return pushresult(L,0,filename); return pushresult(L,0,filename);
} }
destFilename = va("luafiles"PATHSEP"%s", filename); destFilename = va("%s"PATHSEP"luafiles"PATHSEP"%s", srb2home, filename);
// Make directories as needed // Make directories as needed
splitter = destFilename; splitter = destFilename;
......
...@@ -20,6 +20,14 @@ ...@@ -20,6 +20,14 @@
// Command buffer & command execution // Command buffer & command execution
//=================================== //===================================
/* Lua command registration flags. */
enum
{
COM_ADMIN = 1,
COM_SPLITSCREEN = 2,
COM_LOCAL = 4,
};
typedef void (*com_func_t)(void); typedef void (*com_func_t)(void);
void COM_AddCommand(const char *name, com_func_t func); void COM_AddCommand(const char *name, com_func_t func);
......
...@@ -2263,7 +2263,10 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) ...@@ -2263,7 +2263,10 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
cl_mode = CL_CHECKFILES; cl_mode = CL_CHECKFILES;
} }
else else
{
cl_mode = CL_ASKJOIN; // files need not be checked for the server. cl_mode = CL_ASKJOIN; // files need not be checked for the server.
*asksent = 0;
}
return true; return true;
} }
...@@ -2465,7 +2468,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic ...@@ -2465,7 +2468,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
key = I_GetKey(); key = I_GetKey();
// Only ESC and non-keyboard keys abort connection // Only ESC and non-keyboard keys abort connection
if (key == KEY_ESCAPE || key >= KEY_MOUSE1 || cl_mode == CL_ABORTED) if (!modeattacking && (key == KEY_ESCAPE || key >= KEY_MOUSE1 || cl_mode == CL_ABORTED))
{ {
CONS_Printf(M_GetText("Network game synchronization aborted.\n")); CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
D_QuitNetGame(); D_QuitNetGame();
...@@ -3469,6 +3472,76 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) ...@@ -3469,6 +3472,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}}; 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}; consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
...@@ -3537,6 +3610,10 @@ void D_ClientServerInit(void) ...@@ -3537,6 +3610,10 @@ void D_ClientServerInit(void)
COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("reloadbans", Command_ReloadBan);
COM_AddCommand("connect", Command_connect); COM_AddCommand("connect", Command_connect);
COM_AddCommand("nodes", Command_Nodes); 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 #ifdef PACKETDROP
COM_AddCommand("drop", Command_Drop); COM_AddCommand("drop", Command_Drop);
COM_AddCommand("droprate", Command_Droprate); COM_AddCommand("droprate", Command_Droprate);
......
...@@ -35,13 +35,7 @@ applications may follow different packet versions. ...@@ -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... // 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 #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 #define VANILLA_GT_MATCH 3
#endif
// Networking and tick handling related. // Networking and tick handling related.
#define BACKUPTICS 32 #define BACKUPTICS 32
...@@ -508,6 +502,7 @@ extern INT32 mapchangepending; ...@@ -508,6 +502,7 @@ extern INT32 mapchangepending;
// Points inside doomcom // Points inside doomcom
extern doomdata_t *netbuffer; extern doomdata_t *netbuffer;
extern consvar_t cv_stunserver;
extern consvar_t cv_httpsource; extern consvar_t cv_httpsource;
extern consvar_t cv_showjoinaddress; extern consvar_t cv_showjoinaddress;
extern consvar_t cv_playbackspeed; extern consvar_t cv_playbackspeed;
......
...@@ -714,6 +714,10 @@ void D_RegisterServerCommands(void) ...@@ -714,6 +714,10 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_dummyconsvar); CV_RegisterVar(&cv_dummyconsvar);
#ifdef USE_STUN
CV_RegisterVar(&cv_stunserver);
#endif
CV_RegisterVar(&cv_discordinvites); CV_RegisterVar(&cv_discordinvites);
RegisterNetXCmd(XD_DISCORD, Got_DiscordInfo); RegisterNetXCmd(XD_DISCORD, Got_DiscordInfo);
} }
......
...@@ -128,6 +128,7 @@ static UINT32 curl_origfilesize; ...@@ -128,6 +128,7 @@ static UINT32 curl_origfilesize;
static UINT32 curl_origtotalfilesize; static UINT32 curl_origtotalfilesize;
static char *curl_realname = NULL; static char *curl_realname = NULL;
fileneeded_t *curl_curfile = NULL; fileneeded_t *curl_curfile = NULL;
HTTP_login *curl_logins;
#endif #endif
/** Fills a serverinfo packet with information about wad files loaded. /** Fills a serverinfo packet with information about wad files loaded.
...@@ -430,10 +431,10 @@ INT32 CL_CheckFiles(void) ...@@ -430,10 +431,10 @@ INT32 CL_CheckFiles(void)
for (i = 0; i < fileneedednum; i++) 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; downloadrequired = true;
if (fileneeded[i].status == FS_FOUND || fileneeded[i].status == FS_NOTFOUND) if (fileneeded[i].status != FS_OPEN)
filestoload++; 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 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 ...@@ -1082,6 +1083,8 @@ int curlprogress_callback(void *clientp, double dltotal, double dlnow, double ul
void CURLPrepareFile(const char* url, int dfilenum) void CURLPrepareFile(const char* url, int dfilenum)
{ {
HTTP_login *login;
#ifdef PARANOIA #ifdef PARANOIA
if (M_CheckParm("-nodownload")) if (M_CheckParm("-nodownload"))
I_Error("Attempted to download files in -nodownload mode"); I_Error("Attempted to download files in -nodownload mode");
...@@ -1110,6 +1113,14 @@ void CURLPrepareFile(const char* url, int dfilenum) ...@@ -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. 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. // Follow a redirect request, if sent by the server.
curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1L);
...@@ -1211,4 +1222,27 @@ void CURLGetFile(void) ...@@ -1211,4 +1222,27 @@ void CURLGetFile(void)
curl_global_cleanup(); 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 #endif
...@@ -63,6 +63,16 @@ extern UINT32 totalfilesrequestedsize; ...@@ -63,6 +63,16 @@ extern UINT32 totalfilesrequestedsize;
extern boolean curl_failedwebdownload; extern boolean curl_failedwebdownload;
extern boolean curl_running; extern boolean curl_running;
extern INT32 curl_transfers; extern INT32 curl_transfers;
typedef struct HTTP_login HTTP_login;
extern struct HTTP_login
{
char * url;
char * auth;
HTTP_login * next;
}
*curl_logins;
#endif #endif
UINT8 *PutFileNeeded(UINT16 firstfile); UINT8 *PutFileNeeded(UINT16 firstfile);
...@@ -98,6 +108,7 @@ size_t nameonlylength(const char *s); ...@@ -98,6 +108,7 @@ size_t nameonlylength(const char *s);
#ifdef HAVE_CURL #ifdef HAVE_CURL
void CURLPrepareFile(const char* url, int dfilenum); void CURLPrepareFile(const char* url, int dfilenum);
void CURLGetFile(void); void CURLGetFile(void);
HTTP_login * CURLGetLogin (const char *url, HTTP_login ***return_prev_next);
#endif #endif
#endif // __D_NETFIL__ #endif // __D_NETFIL__
...@@ -8685,6 +8685,11 @@ struct { ...@@ -8685,6 +8685,11 @@ struct {
{"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable {"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable
{"BT_CUSTOM3",BT_CUSTOM3}, // 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 // cvflags_t
{"CV_SAVE",CV_SAVE}, {"CV_SAVE",CV_SAVE},
{"CV_CALL",CV_CALL}, {"CV_CALL",CV_CALL},
...@@ -9682,6 +9687,9 @@ static inline int lib_getenum(lua_State *L) ...@@ -9682,6 +9687,9 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"leveltime")) { } else if (fastcmp(word,"leveltime")) {
lua_pushinteger(L, leveltime); lua_pushinteger(L, leveltime);
return 1; return 1;
} else if (fastcmp(word,"defrosting")) {
lua_pushinteger(L, hook_defrosting);
return 1;
} else if (fastcmp(word,"curWeather")) { } else if (fastcmp(word,"curWeather")) {
lua_pushinteger(L, curWeather); lua_pushinteger(L, curWeather);
return 1; return 1;
...@@ -9704,21 +9712,20 @@ static inline int lib_getenum(lua_State *L) ...@@ -9704,21 +9712,20 @@ static inline int lib_getenum(lua_State *L)
lua_pushinteger(L, mapmusposition); lua_pushinteger(L, mapmusposition);
return 1; return 1;
} else if (fastcmp(word,"server")) { } else if (fastcmp(word,"server")) {
if ((!multiplayer || !(netgame || demo.playback)) && !playeringame[serverplayer]) return LUA_PushServerPlayer(L);
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"consoleplayer")) { // Player controlling the console, basically our local player } 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]) if (consoleplayer < 0 || !playeringame[consoleplayer])
return 0; return 0;
LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER); LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER);
return 1; return 1;
/*} else if (fastcmp(word,"admin")) { } else if (fastcmp(word,"isserver")) {
LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)"); lua_pushboolean(L, server);
if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer)) return 1;
return 0; } else if (fastcmp(word, "isdedicatedserver")) {
LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER); lua_pushboolean(L, dedicated);
return 1;*/ return 1;
} else if (fastcmp(word,"gravity")) { } else if (fastcmp(word,"gravity")) {
lua_pushinteger(L, gravity); lua_pushinteger(L, gravity);
return 1; return 1;
......
...@@ -12,9 +12,7 @@ ...@@ -12,9 +12,7 @@
#ifdef HAVE_DISCORDRPC #ifdef HAVE_DISCORDRPC
#ifdef HAVE_CURL #include <time.h>
#include <curl/curl.h>
#endif // HAVE_CURL
#include "i_system.h" #include "i_system.h"
#include "d_clisrv.h" #include "d_clisrv.h"
...@@ -27,6 +25,8 @@ ...@@ -27,6 +25,8 @@
#include "mserv.h" // cv_advertise #include "mserv.h" // cv_advertise
#include "z_zone.h" #include "z_zone.h"
#include "byteptr.h" #include "byteptr.h"
#include "stun.h"
#include "i_tcp.h" // current_port
#include "discord.h" #include "discord.h"
#include "doomdef.h" #include "doomdef.h"
...@@ -45,16 +45,7 @@ struct discordInfo_s discordInfo; ...@@ -45,16 +45,7 @@ struct discordInfo_s discordInfo;
discordRequest_t *discordRequestList = NULL; discordRequest_t *discordRequestList = NULL;
#ifdef HAVE_CURL
struct SelfIPbuffer
{
CURL *curl;
char *pointer;
size_t length;
};
static char self_ip[IP_SIZE]; static char self_ip[IP_SIZE];
#endif // HAVE_CURL
/*-------------------------------------------------- /*--------------------------------------------------
static char *DRPC_XORIPString(const char *input) static char *DRPC_XORIPString(const char *input)
...@@ -335,39 +326,23 @@ void DRPC_Init(void) ...@@ -335,39 +326,23 @@ void DRPC_Init(void)
DRPC_UpdatePresence(); 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:- Input Arguments:-
s - Data to write address - IPv4 address of this machine, in network byte order.
size - Always 1.
n - Length of data
userdata - Passed in from CURLOPT_WRITEDATA, intended to be SelfIPbuffer
Return:- 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; const unsigned char * p = (const unsigned char *)&address;
size_t newlength; sprintf(self_ip, "%u.%u.%u.%u:%u", p[0], p[1], p[2], p[3], current_port);
DRPC_UpdatePresence();
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;
} }
#endif // HAVE_CURL
/*-------------------------------------------------- /*--------------------------------------------------
static const char *DRPC_GetServerIP(void) static const char *DRPC_GetServerIP(void)
...@@ -387,64 +362,21 @@ 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! // We're not the server, so we could successfully get the IP!
// No need to do anything else :) // 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]) if (self_ip[0])
{
return self_ip; return self_ip;
}
else 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) ...@@ -510,19 +442,6 @@ void DRPC_UpdatePresence(void)
// Server info // Server info
if (netgame) 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) if (DRPC_InvitesAreAllowed() == true)
{ {
const char *join; const char *join;
...@@ -536,7 +455,24 @@ void DRPC_UpdatePresence(void) ...@@ -536,7 +455,24 @@ void DRPC_UpdatePresence(void)
joinSecretSet = true; 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 else
{ {
......
...@@ -4714,6 +4714,9 @@ char *G_BuildMapTitle(INT32 mapnum) ...@@ -4714,6 +4714,9 @@ char *G_BuildMapTitle(INT32 mapnum)
if (mapnum == 0) if (mapnum == 0)
return Z_StrDup("Random"); return Z_StrDup("Random");
if (!mapheaderinfo[mapnum-1])
P_AllocMapHeader(mapnum-1);
if (strcmp(mapheaderinfo[mapnum-1]->lvlttl, "")) if (strcmp(mapheaderinfo[mapnum-1]->lvlttl, ""))
{ {
size_t len = 1; size_t len = 1;
......
...@@ -182,6 +182,7 @@ static UINT8 UPNP_support = TRUE; ...@@ -182,6 +182,7 @@ static UINT8 UPNP_support = TRUE;
#include "d_netfil.h" #include "d_netfil.h"
#include "i_tcp.h" #include "i_tcp.h"
#include "m_argv.h" #include "m_argv.h"
#include "stun.h"
#include "doomstat.h" #include "doomstat.h"
...@@ -612,6 +613,13 @@ static boolean SOCK_Get(void) ...@@ -612,6 +613,13 @@ static boolean SOCK_Get(void)
(void *)&fromaddress, &fromlen); (void *)&fromaddress, &fromlen);
if (c != ERRSOCKET) if (c != ERRSOCKET)
{ {
#ifdef USE_STUN
if (STUN_got_response(doomcom->data, c))
{
return false;
}
#endif
// find remote node number // find remote node number
for (j = 1; j <= MAXNETNODES; j++) //include LAN for (j = 1; j <= MAXNETNODES; j++) //include LAN
{ {
......
...@@ -4401,14 +4401,22 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source) ...@@ -4401,14 +4401,22 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source)
static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd)
{ {
const INT32 numsnds = 13; 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 INT32 class, s, w; // engine class number
UINT8 volume = 255; UINT8 volume = 255;
fixed_t volumedampen = 0; fixed_t volumedampen = FRACUNIT;
INT32 targetsnd = 0; INT32 targetsnd = 0;
INT32 i; INT32 i;
s = (player->kartspeed-1)/3; s = (player->kartspeed - 1) / 3;
w = (player->kartweight-1)/3; w = (player->kartweight - 1) / 3;
#define LOCKSTAT(stat) \ #define LOCKSTAT(stat) \
if (stat < 0) { stat = 0; } \ if (stat < 0) { stat = 0; } \
...@@ -4417,81 +4425,114 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) ...@@ -4417,81 +4425,114 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd)
LOCKSTAT(w); LOCKSTAT(w);
#undef LOCKSTAT #undef LOCKSTAT
class = s+(3*w); class = s + (3*w);
// Silence the engines
if (leveltime < 8 || player->spectator || player->exiting) 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; return;
} }
#if 0 #if 0
if ((leveltime % 8) != ((player-players) % 8)) // Per-player offset, to make engines sound distinct! if ((leveltime % 8) != ((player-players) % 8)) // Per-player offset, to make engines sound distinct!
#else #else
if (leveltime % 8) // .25 seconds of wait time between engine sounds if (leveltime % 8)
#endif #endif
{
// .25 seconds of wait time between each engine sound playback
return; 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); targetsnd = ((cmd->buttons & BT_ACCELERATE) ? 12 : 0);
}
else 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) if (targetsnd < 0) { targetsnd = 0; }
targetsnd = 0; if (targetsnd > 12) { targetsnd = 12; }
if (targetsnd > 12)
targetsnd = 12;
if (player->kartstuff[k_enginesnd] < targetsnd) if (player->kartstuff[k_enginesnd] < targetsnd) { player->kartstuff[k_enginesnd]++; }
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) if (player->kartstuff[k_enginesnd] < 0) { 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] > 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++) for (i = 0; i < MAXPLAYERS; i++)
{ {
UINT8 thisvol = 0; UINT8 thisvol = 0;
fixed_t dist; fixed_t dist;
if (!playeringame[i] || !players[i].mo || players[i].spectator || players[i].exiting) if (!playeringame[i] || !players[i].mo)
{
// This player doesn't exist.
continue; continue;
}
if (P_IsDisplayPlayer(&players[i])) if (players[i].spectator || players[i].exiting)
{ {
volumedampen += FRACUNIT; // We already know what this is gonna be, let's not waste our time. // This player isn't playing an engine sound.
continue; continue;
} }
dist = P_AproxDistance(P_AproxDistance(player->mo->x-players[i].mo->x, if (player == &players[i] || P_IsDisplayPlayer(&players[i]))
player->mo->y-players[i].mo->y), player->mo->z-players[i].mo->z) / 2; {
// 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); dist = FixedDiv(dist, mapobjectscale);
if (dist > 1536<<FRACBITS) if (dist > fardist)
{
// ENEMY OUT OF RANGE !
continue; continue;
else if (dist < 160<<FRACBITS) // engine sounds' approx. range }
else if (dist < closedist)
{
// engine sounds' approx. range
thisvol = 255; thisvol = 255;
}
else 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) 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; 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) static void K_UpdateInvincibilitySounds(player_t *player)
......
...@@ -238,7 +238,8 @@ static int lib_pAproxDistance(lua_State *L) ...@@ -238,7 +238,8 @@ static int lib_pAproxDistance(lua_State *L)
fixed_t dx = luaL_checkfixed(L, 1); fixed_t dx = luaL_checkfixed(L, 1);
fixed_t dy = luaL_checkfixed(L, 2); fixed_t dy = luaL_checkfixed(L, 2);
//HUDSAFE //HUDSAFE
lua_pushfixed(L, P_AproxDistance(dx, dy)); LUA_Deprecated(L, "P_AproxDistance", "FixedHypot");
lua_pushfixed(L, FixedHypot(dx, dy));
return 1; return 1;
} }
......
...@@ -113,12 +113,12 @@ void COM_Lua_f(void) ...@@ -113,12 +113,12 @@ void COM_Lua_f(void)
lua_rawgeti(gL, -1, 2); // push flags from command info table lua_rawgeti(gL, -1, 2); // push flags from command info table
if (lua_isboolean(gL, -1)) if (lua_isboolean(gL, -1))
flags = (lua_toboolean(gL, -1) ? 1 : 0); flags = (lua_toboolean(gL, -1) ? COM_ADMIN : 0);
else else
flags = (UINT8)lua_tointeger(gL, -1); flags = (UINT8)lua_tointeger(gL, -1);
lua_pop(gL, 1); // pop flags 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) if (!splitscreen)
{ {
...@@ -128,12 +128,12 @@ void COM_Lua_f(void) ...@@ -128,12 +128,12 @@ void COM_Lua_f(void)
playernum = displayplayers[1]; playernum = displayplayers[1];
} }
if (netgame) if (netgame && !( flags & COM_LOCAL ))/* don't send local commands */
{ // Send the command through the network { // Send the command through the network
UINT8 argc; UINT8 argc;
lua_pop(gL, 1); // pop command info table 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")); CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return; return;
...@@ -187,7 +187,15 @@ static int lib_comAddCommand(lua_State *L) ...@@ -187,7 +187,15 @@ static int lib_comAddCommand(lua_State *L)
if (lua_gettop(L) >= 3) if (lua_gettop(L) >= 3)
{ // For the third argument, only take a boolean or a number. { // For the third argument, only take a boolean or a number.
lua_settop(L, 3); 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); luaL_checktype(L, 3, LUA_TNUMBER);
} }
else else
...@@ -436,6 +444,45 @@ static int lib_cvFindVar(lua_State *L) ...@@ -436,6 +444,45 @@ static int lib_cvFindVar(lua_State *L)
return 0; 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 // CONS_Printf for a single player
// Use 'print' in baselib for a global message. // Use 'print' in baselib for a global message.
...@@ -475,8 +522,11 @@ static luaL_Reg lib[] = { ...@@ -475,8 +522,11 @@ static luaL_Reg lib[] = {
{"COM_BufAddText", lib_comBufAddText}, {"COM_BufAddText", lib_comBufAddText},
{"COM_BufInsertText", lib_comBufInsertText}, {"COM_BufInsertText", lib_comBufInsertText},
{"CV_RegisterVar", lib_cvRegisterVar}, {"CV_RegisterVar", lib_cvRegisterVar},
{"CONS_Printf", lib_consPrintf},
{"CV_FindVar", lib_cvFindVar}, {"CV_FindVar", lib_cvFindVar},
{"CV_Set", lib_cvSet},
{"CV_StealthSet", lib_cvStealthSet},
{"CV_AddValue", lib_cvAddValue},
{"CONS_Printf", lib_consPrintf},
{NULL, NULL} {NULL, NULL}
}; };
......
...@@ -20,7 +20,9 @@ enum hook { ...@@ -20,7 +20,9 @@ enum hook {
hook_MapChange, hook_MapChange,
hook_MapLoad, hook_MapLoad,
hook_PlayerJoin, hook_PlayerJoin,
hook_PreThinkFrame,
hook_ThinkFrame, hook_ThinkFrame,
hook_PostThinkFrame,
hook_MobjSpawn, hook_MobjSpawn,
hook_MobjCollide, hook_MobjCollide,
hook_MobjMoveCollide, hook_MobjMoveCollide,
...@@ -44,6 +46,7 @@ enum hook { ...@@ -44,6 +46,7 @@ enum hook {
hook_HurtMsg, hook_HurtMsg,
hook_PlayerSpawn, hook_PlayerSpawn,
hook_PlayerQuit, hook_PlayerQuit,
hook_PlayerThink,
hook_MusicChange, hook_MusicChange,
hook_ShouldSpin, //SRB2KART hook_ShouldSpin, //SRB2KART
hook_ShouldExplode, //SRB2KART hook_ShouldExplode, //SRB2KART
...@@ -60,11 +63,14 @@ enum hook { ...@@ -60,11 +63,14 @@ enum hook {
extern const char *const hookNames[]; 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 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_MapChange(INT16 mapnumber); // Hook for map change (before load)
void LUAh_MapLoad(void); // Hook for map load void LUAh_MapLoad(void); // Hook for map load
void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer 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_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_MobjHook(mobj_t *mo, enum hook which);
boolean LUAh_PlayerHook(player_t *plr, 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 #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 ...@@ -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_IntermissionThinker(void); // Hook for Y_Ticker
void LUAh_VoteThinker(void); // Hook for Y_VoteTicker void LUAh_VoteThinker(void); // Hook for Y_VoteTicker
#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink
#endif #endif
...@@ -31,7 +31,9 @@ const char *const hookNames[hook_MAX+1] = { ...@@ -31,7 +31,9 @@ const char *const hookNames[hook_MAX+1] = {
"MapChange", "MapChange",
"MapLoad", "MapLoad",
"PlayerJoin", "PlayerJoin",
"PreThinkFrame",
"ThinkFrame", "ThinkFrame",
"PostThinkFrame",
"MobjSpawn", "MobjSpawn",
"MobjCollide", "MobjCollide",
"MobjMoveCollide", "MobjMoveCollide",
...@@ -55,6 +57,7 @@ const char *const hookNames[hook_MAX+1] = { ...@@ -55,6 +57,7 @@ const char *const hookNames[hook_MAX+1] = {
"HurtMsg", "HurtMsg",
"PlayerSpawn", "PlayerSpawn",
"PlayerQuit", "PlayerQuit",
"PlayerThink",
"MusicChange", "MusicChange",
"ShouldSpin", "ShouldSpin",
"ShouldExplode", "ShouldExplode",
...@@ -206,6 +209,7 @@ static int lib_addHook(lua_State *L) ...@@ -206,6 +209,7 @@ static int lib_addHook(lua_State *L)
case hook_SpinSpecial: case hook_SpinSpecial:
case hook_JumpSpinSpecial: case hook_JumpSpinSpecial:
case hook_PlayerSpawn: case hook_PlayerSpawn:
case hook_PlayerThink:
lastp = &playerhooks; lastp = &playerhooks;
break; break;
case hook_LinedefExecute: case hook_LinedefExecute:
...@@ -402,6 +406,29 @@ void LUAh_PlayerJoin(int playernum) ...@@ -402,6 +406,29 @@ void LUAh_PlayerJoin(int playernum)
lua_settop(gL, 0); 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) // Hook for frame (after mobj and player thinkers)
void LUAh_ThinkFrame(void) void LUAh_ThinkFrame(void)
{ {
...@@ -423,6 +450,29 @@ 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 // Hook for Y_Ticker
void LUAh_IntermissionThinker(void) void LUAh_IntermissionThinker(void)
{ {
......
...@@ -27,25 +27,35 @@ ...@@ -27,25 +27,35 @@
static int lib_iteratePlayers(lua_State *L) static int lib_iteratePlayers(lua_State *L)
{ {
INT32 i = -1; INT32 i = -1;
if (lua_gettop(L) < 2) 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'."); //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); lua_pushcfunction(L, lib_iteratePlayers);
return 1; return 1;
} }
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // state is unused. lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1)) if (!lua_isnil(L, 1))
i = (INT32)(*((player_t **)luaL_checkudata(L, 1, META_PLAYER)) - players); 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]) if (!playeringame[i])
continue; continue;
if (!players[i].mo)
continue;
LUA_PushUserdata(L, &players[i], META_PLAYER); LUA_PushUserdata(L, &players[i], META_PLAYER);
return 1; return 1;
} }
return 0; return 0;
} }
...@@ -58,10 +68,10 @@ static int lib_getPlayer(lua_State *L) ...@@ -58,10 +68,10 @@ static int lib_getPlayer(lua_State *L)
lua_Integer i = luaL_checkinteger(L, 2); lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0 || i >= MAXPLAYERS) if (i < 0 || i >= MAXPLAYERS)
return luaL_error(L, "players[] index %d out of range (0 - %d)", i, MAXPLAYERS-1); 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]) if (!playeringame[i])
return 0; return 0;
if (!players[i].mo)
return 0;
LUA_PushUserdata(L, &players[i], META_PLAYER); LUA_PushUserdata(L, &players[i], META_PLAYER);
return 1; return 1;
} }
...@@ -122,8 +132,6 @@ static int lib_iterateDisplayplayers(lua_State *L) ...@@ -122,8 +132,6 @@ static int lib_iterateDisplayplayers(lua_State *L)
if (i > splitscreen || !playeringame[displayplayers[i]]) 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. 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_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'! 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; return 2;
...@@ -144,8 +152,6 @@ static int lib_getDisplayplayers(lua_State *L) ...@@ -144,8 +152,6 @@ static int lib_getDisplayplayers(lua_State *L)
return 0; return 0;
if (!playeringame[displayplayers[i]]) if (!playeringame[displayplayers[i]])
return 0; return 0;
if (!players[displayplayers[i]].mo)
return 0;
LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER); LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER);
return 1; return 1;
} }
...@@ -184,12 +190,7 @@ static int player_get(lua_State *L) ...@@ -184,12 +190,7 @@ static int player_get(lua_State *L)
else if (fastcmp(field,"name")) else if (fastcmp(field,"name"))
lua_pushstring(L, player_names[plr-players]); lua_pushstring(L, player_names[plr-players]);
else if (fastcmp(field,"mo")) else if (fastcmp(field,"mo"))
{ LUA_PushUserdata(L, plr->mo, META_MOBJ);
if (plr->spectator)
lua_pushnil(L);
else
LUA_PushUserdata(L, plr->mo, META_MOBJ);
}
else if (fastcmp(field,"cmd")) else if (fastcmp(field,"cmd"))
LUA_PushUserdata(L, &plr->cmd, META_TICCMD); LUA_PushUserdata(L, &plr->cmd, META_TICCMD);
else if (fastcmp(field,"playerstate")) else if (fastcmp(field,"playerstate"))
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
lua_State *gL = NULL; lua_State *gL = NULL;
int hook_defrosting;
// List of internal libraries to load from SRB2 // List of internal libraries to load from SRB2
static lua_CFunction liblist[] = { static lua_CFunction liblist[] = {
LUA_EnumLib, // global metatable for enums LUA_EnumLib, // global metatable for enums
...@@ -367,6 +369,14 @@ void LUA_PushUserdata(lua_State *L, void *data, const char *meta) ...@@ -367,6 +369,14 @@ void LUA_PushUserdata(lua_State *L, void *data, const char *meta)
lua_remove(L, -2); // remove LREG_VALID 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);
<