Merge remote-tracking branch 'public/next' into discord-rpc-support

This commit is contained in:
Sally Coolatta 2020-08-22 07:28:21 -04:00
commit 5de27be169
18 changed files with 1089 additions and 241 deletions

View file

@ -100,7 +100,6 @@ set(SRB2_CORE_HEADERS
m_swap.h
md5.h
mserv.h
http-mserv.h
p5prof.h
s_sound.h
screen.h
@ -281,6 +280,7 @@ if(${SRB2_CONFIG_HAVE_BLUA})
blua/lfunc.c
blua/lgc.c
blua/linit.c
blua/liolib.c
blua/llex.c
blua/lmem.c
blua/lobject.c

View file

@ -18,6 +18,7 @@ OBJS:=$(OBJS) \
$(OBJDIR)/ldo.o \
$(OBJDIR)/lfunc.o \
$(OBJDIR)/linit.o \
$(OBJDIR)/liolib.o \
$(OBJDIR)/llex.o \
$(OBJDIR)/lmem.o \
$(OBJDIR)/lobject.o \

View file

@ -17,6 +17,7 @@
static const luaL_Reg lualibs[] = {
{"", luaopen_base},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_STRLIBNAME, luaopen_string},
{NULL, NULL}
};

589
src/blua/liolib.c Normal file
View file

@ -0,0 +1,589 @@
/*
** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define liolib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "../i_system.h"
#include "../doomdef.h"
#include "../m_misc.h"
#define IO_INPUT 1
#define IO_OUTPUT 2
#define FILELIMIT 1024*1024 // Size limit for reading/writing files
static const char *const fnames[] = {"input", "output"};
static const char *whitelist[] = { // Allow scripters to write files of these types to SRB2's folder
".txt",
".sav2",
".cfg",
".png",
".bmp"
};
static int pushresult (lua_State *L, int i, const char *filename) {
int en = errno; /* calls to Lua API may change this value */
if (i) {
lua_pushboolean(L, 1);
return 1;
}
else {
lua_pushnil(L);
if (filename)
lua_pushfstring(L, "%s: %s", filename, strerror(en));
else
lua_pushfstring(L, "%s", strerror(en));
lua_pushinteger(L, en);
return 3;
}
}
static void fileerror (lua_State *L, int arg, const char *filename) {
lua_pushfstring(L, "%s: %s", filename, strerror(errno));
luaL_argerror(L, arg, lua_tostring(L, -1));
}
#define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE))
static int io_type (lua_State *L) {
void *ud;
luaL_checkany(L, 1);
ud = lua_touserdata(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1))
lua_pushnil(L); /* not a file */
else if (*((FILE **)ud) == NULL)
lua_pushliteral(L, "closed file");
else
lua_pushliteral(L, "file");
return 1;
}
static FILE *tofile (lua_State *L) {
FILE **f = tofilep(L);
if (*f == NULL)
luaL_error(L, "attempt to use a closed file");
return *f;
}
/*
** When creating file handles, always creates a `closed' file handle
** before opening the actual file; so, if there is a memory error, the
** file is not left opened.
*/
static FILE **newfile (lua_State *L) {
FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
*pf = NULL; /* file handle is currently `closed' */
luaL_getmetatable(L, LUA_FILEHANDLE);
lua_setmetatable(L, -2);
return pf;
}
/*
** function to (not) close the standard files stdin, stdout, and stderr
*/
static int io_noclose (lua_State *L) {
lua_pushnil(L);
lua_pushliteral(L, "cannot close standard file");
return 2;
}
/*
** function to close regular files
*/
static int io_fclose (lua_State *L) {
FILE **p = tofilep(L);
int ok = (fclose(*p) == 0);
*p = NULL;
return pushresult(L, ok, NULL);
}
static int aux_close (lua_State *L) {
lua_getfenv(L, 1);
lua_getfield(L, -1, "__close");
return (lua_tocfunction(L, -1))(L);
}
static int io_close (lua_State *L) {
if (lua_isnone(L, 1))
lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
tofile(L); /* make sure argument is a file */
return aux_close(L);
}
static int io_gc (lua_State *L) {
FILE *f = *tofilep(L);
/* ignore closed files */
if (f != NULL)
aux_close(L);
return 0;
}
static int io_tostring (lua_State *L) {
FILE *f = *tofilep(L);
if (f == NULL)
lua_pushliteral(L, "file (closed)");
else
lua_pushfstring(L, "file (%p)", f);
return 1;
}
static int StartsWith(const char *a, const char *b) // this is wolfs being lazy yet again
{
if(strncmp(a, b, strlen(b)) == 0) return 1;
return 0;
}
static int io_open (lua_State *L) {
FILE **pf;
const char *filename = luaL_checkstring(L, 1);
int pass = 0;
size_t i;
int length = strlen(filename);
char *splitter, *forward, *backward;
char *destFilename;
const char *mode = luaL_optstring(L, 2, "r");
for (i = 0; i < (sizeof (whitelist) / sizeof(const char *)); i++)
{
if (!stricmp(&filename[length - strlen(whitelist[i])], whitelist[i]))
{
pass = 1;
break;
}
}
if (strstr(filename, "..") || strchr(filename, ':') || StartsWith(filename, "\\")
|| StartsWith(filename, "/") || !pass)
{
luaL_error(L,"access denied to %s", filename);
return pushresult(L,0,filename);
}
destFilename = va("luafiles"PATHSEP"%s", filename);
// Make directories as needed
splitter = destFilename;
forward = strchr(splitter, '/');
backward = strchr(splitter, '\\');
while ((splitter = (forward && backward) ? min(forward, backward) : (forward ?: backward)))
{
*splitter = 0;
I_mkdir(destFilename, 0755);
*splitter = '/';
splitter++;
forward = strchr(splitter, '/');
backward = strchr(splitter, '\\');
}
pf = newfile(L);
*pf = fopen(destFilename, mode);
return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
}
static int io_tmpfile (lua_State *L) {
FILE **pf = newfile(L);
*pf = tmpfile();
return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
}
static FILE *getiofile (lua_State *L, int findex) {
FILE *f;
lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
f = *(FILE **)lua_touserdata(L, -1);
if (f == NULL)
luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
return f;
}
static int g_iofile (lua_State *L, int f, const char *mode) {
if (!lua_isnoneornil(L, 1)) {
const char *filename = lua_tostring(L, 1);
if (filename) {
FILE **pf = newfile(L);
*pf = fopen(filename, mode);
if (*pf == NULL)
fileerror(L, 1, filename);
}
else {
tofile(L); /* check that it's a valid file handle */
lua_pushvalue(L, 1);
}
lua_rawseti(L, LUA_ENVIRONINDEX, f);
}
/* return current value */
lua_rawgeti(L, LUA_ENVIRONINDEX, f);
return 1;
}
static int io_input (lua_State *L) {
return g_iofile(L, IO_INPUT, "r");
}
static int io_output (lua_State *L) {
return g_iofile(L, IO_OUTPUT, "w");
}
static int io_readline (lua_State *L);
static void aux_lines (lua_State *L, int idx, int toclose) {
lua_pushvalue(L, idx);
lua_pushboolean(L, toclose); /* close/not close file when finished */
lua_pushcclosure(L, io_readline, 2);
}
static int f_lines (lua_State *L) {
tofile(L); /* check that it's a valid file handle */
aux_lines(L, 1, 0);
return 1;
}
static int io_lines (lua_State *L) {
if (lua_isnoneornil(L, 1)) { /* no arguments? */
/* will iterate over default input */
lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
return f_lines(L);
}
else {
const char *filename = luaL_checkstring(L, 1);
FILE **pf = newfile(L);
*pf = fopen(filename, "r");
if (*pf == NULL)
fileerror(L, 1, filename);
aux_lines(L, lua_gettop(L), 1);
return 1;
}
}
/*
** {======================================================
** READ
** =======================================================
*/
static int read_number (lua_State *L, FILE *f) {
lua_Number d;
if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
lua_pushnumber(L, d);
return 1;
}
else return 0; /* read fails */
}
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
ungetc(c, f);
lua_pushlstring(L, NULL, 0);
return (c != EOF);
}
static int read_line (lua_State *L, FILE *f) {
luaL_Buffer b;
luaL_buffinit(L, &b);
for (;;) {
size_t l;
char *p = luaL_prepbuffer(&b);
if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
luaL_pushresult(&b); /* close buffer */
return (lua_objlen(L, -1) > 0); /* check whether read something */
}
l = strlen(p);
if (l == 0 || p[l-1] != '\n')
luaL_addsize(&b, l);
else {
luaL_addsize(&b, l - 1); /* do not include `eol' */
luaL_pushresult(&b); /* close buffer */
return 1; /* read at least an `eol' */
}
}
}
static int read_chars (lua_State *L, FILE *f, size_t n) {
size_t rlen; /* how much to read */
size_t nr; /* number of chars actually read */
luaL_Buffer b;
luaL_buffinit(L, &b);
rlen = LUAL_BUFFERSIZE; /* try to read that much each time */
do {
char *p = luaL_prepbuffer(&b);
if (rlen > n) rlen = n; /* cannot read more than asked */
nr = fread(p, sizeof(char), rlen, f);
luaL_addsize(&b, nr);
n -= nr; /* still have to read `n' chars */
} while (n > 0 && nr == rlen); /* until end of count or eof */
luaL_pushresult(&b); /* close buffer */
return (n == 0 || lua_objlen(L, -1) > 0);
}
static int g_read (lua_State *L, FILE *f, int first) {
int nargs = lua_gettop(L) - 1;
int success;
int n;
clearerr(f);
if (nargs == 0) { /* no arguments? */
success = read_line(L, f);
n = first+1; /* to return 1 result */
}
else { /* ensure stack space for all results and for auxlib's buffer */
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
success = 1;
for (n = first; nargs-- && success; n++) {
if (lua_type(L, n) == LUA_TNUMBER) {
size_t l = (size_t)lua_tointeger(L, n);
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
}
else {
const char *p = lua_tostring(L, n);
luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
switch (p[1]) {
case 'n': /* number */
success = read_number(L, f);
break;
case 'l': /* line */
success = read_line(L, f);
break;
case 'a': /* file */
read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
success = 1; /* always success */
break;
default:
return luaL_argerror(L, n, "invalid format");
}
}
}
}
if (ferror(f))
return pushresult(L, 0, NULL);
if (!success) {
lua_pop(L, 1); /* remove last result */
lua_pushnil(L); /* push nil instead */
}
return n - first;
}
static int io_read (lua_State *L) {
return g_read(L, getiofile(L, IO_INPUT), 1);
}
static int f_read (lua_State *L) {
return g_read(L, tofile(L), 2);
}
static int io_readline (lua_State *L) {
FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
int sucess;
if (f == NULL) /* file is already closed? */
luaL_error(L, "file is already closed");
sucess = read_line(L, f);
if (ferror(f))
return luaL_error(L, "%s", strerror(errno));
if (sucess) return 1;
else { /* EOF */
if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */
lua_settop(L, 0);
lua_pushvalue(L, lua_upvalueindex(1));
aux_close(L); /* close it */
}
return 0;
}
}
/* }====================================================== */
static int g_write (lua_State *L, FILE *f, int arg) {
int nargs = lua_gettop(L) - 1;
int status = 1;
size_t count;
for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
status = status &&
fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
}
else {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
count += l;
if (ftell(f) + l > FILELIMIT)
{
luaL_error(L,"write limit bypassed in file. Changes have been discarded.");
break;
}
status = status && (fwrite(s, sizeof(char), l, f) == l);
}
}
return pushresult(L, status, NULL);
}
static int io_write (lua_State *L) {
return g_write(L, getiofile(L, IO_OUTPUT), 1);
}
static int f_write (lua_State *L) {
return g_write(L, tofile(L), 2);
}
static int f_seek (lua_State *L) {
static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, "cur", modenames);
long offset = luaL_optlong(L, 3, 0);
op = fseek(f, offset, mode[op]);
if (op)
return pushresult(L, 0, NULL); /* error */
else {
lua_pushinteger(L, ftell(f));
return 1;
}
}
static int f_setvbuf (lua_State *L) {
static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
static const char *const modenames[] = {"no", "full", "line", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], sz);
return pushresult(L, res == 0, NULL);
}
static int io_flush (lua_State *L) {
return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
}
static int f_flush (lua_State *L) {
return pushresult(L, fflush(tofile(L)) == 0, NULL);
}
static const luaL_Reg iolib[] = {
{"close", io_close},
{"flush", io_flush},
{"input", io_input},
{"lines", io_lines},
{"open", io_open},
{"output", io_output},
{"read", io_read},
{"tmpfile", io_tmpfile},
{"type", io_type},
{"write", io_write},
{NULL, NULL}
};
static const luaL_Reg flib[] = {
{"close", io_close},
{"flush", f_flush},
{"lines", f_lines},
{"read", f_read},
{"seek", f_seek},
{"setvbuf", f_setvbuf},
{"write", f_write},
{"__gc", io_gc},
{"__tostring", io_tostring},
{NULL, NULL}
};
static void createmeta (lua_State *L) {
luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
lua_pushvalue(L, -1); /* push metatable */
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
luaL_register(L, NULL, flib); /* file methods */
}
static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
*newfile(L) = f;
if (k > 0) {
lua_pushvalue(L, -1);
lua_rawseti(L, LUA_ENVIRONINDEX, k);
}
lua_pushvalue(L, -2); /* copy environment */
lua_setfenv(L, -2); /* set it */
lua_setfield(L, -3, fname);
}
static void newfenv (lua_State *L, lua_CFunction cls) {
lua_createtable(L, 0, 1);
lua_pushcfunction(L, cls);
lua_setfield(L, -2, "__close");
}
LUALIB_API int luaopen_io (lua_State *L) {
createmeta(L);
/* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
newfenv(L, io_fclose);
lua_replace(L, LUA_ENVIRONINDEX);
/* open library */
luaL_register(L, LUA_IOLIBNAME, iolib);
/* create (and set) default files */
newfenv(L, io_noclose); /* close function for default files */
createstdfile(L, stdin, IO_INPUT, "stdin");
createstdfile(L, stdout, IO_OUTPUT, "stdout");
createstdfile(L, stderr, 0, "stderr");
lua_pop(L, 1); /* pop environment for default files */
return 1;
}

View file

@ -21,6 +21,9 @@ LUALIB_API int (luaopen_base) (lua_State *L);
#define LUA_TABLIBNAME "table"
LUALIB_API int (luaopen_table) (lua_State *L);
#define LUA_IOLIBNAME "io"
LUALIB_API int (luaopen_io) (lua_State *L);
#define LUA_STRLIBNAME "string"
LUALIB_API int (luaopen_string) (lua_State *L);

View file

@ -146,6 +146,9 @@ char connectedservername[MAXSERVERNAME];
/// \todo WORK!
boolean acceptnewnode = true;
boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not
tic_t firstconnectattempttime = 0;
// engine
// Must be a power of two
@ -1098,8 +1101,10 @@ static INT16 Consistancy(void);
typedef enum
{
CL_SEARCHING,
CL_CHECKFILES,
CL_DOWNLOADFILES,
CL_ASKJOIN,
CL_LOADFILES,
CL_WAITJOINRESPONSE,
#ifdef JOININGAME
CL_DOWNLOADSAVEGAME,
@ -1107,6 +1112,7 @@ typedef enum
CL_CONNECTED,
CL_ABORTED,
CL_ASKFULLFILELIST,
CL_CONFIRMCONNECT,
#ifdef HAVE_CURL
CL_PREPAREHTTPFILES,
CL_DOWNLOADHTTPFILES,
@ -1171,11 +1177,7 @@ static inline void CL_DrawConnectionStatus(void)
// Draw background fade
V_DrawFadeScreen(0xFF00, 16);
// Draw the bottom box.
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-24, V_YELLOWMAP, "Press ESC to abort");
if (cl_mode != CL_DOWNLOADFILES
if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES
#ifdef HAVE_CURL
&& cl_mode != CL_DOWNLOADHTTPFILES
#endif
@ -1186,6 +1188,10 @@ static inline void CL_DrawConnectionStatus(void)
// 15 pal entries total.
const char *cltext;
//Draw bottom box
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-24, V_YELLOWMAP, "Press ESC to abort");
for (i = 0; i < 16; ++i)
V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-24, 16, 8, palstart + ((animtime - i) & 15));
@ -1207,11 +1213,22 @@ static inline void CL_DrawConnectionStatus(void)
break;
#endif
case CL_ASKFULLFILELIST:
cltext = M_GetText("This server has a LOT of files!");
case CL_CHECKFILES:
cltext = M_GetText("Checking server addon list ...");
break;
case CL_CONFIRMCONNECT:
cltext = "";
break;
case CL_LOADFILES:
cltext = M_GetText("Loading server addons...");
break;
case CL_ASKJOIN:
case CL_WAITJOINRESPONSE:
cltext = M_GetText("Requesting to join...");
if (serverisfull)
cltext = M_GetText("Server full, waiting for a slot...");
else
cltext = M_GetText("Requesting to join...");
break;
#ifdef HAVE_CURL
case CL_PREPAREHTTPFILES:
@ -1226,19 +1243,47 @@ static inline void CL_DrawConnectionStatus(void)
}
else
{
if (lastfilenum != -1)
if (cl_mode == CL_LOADFILES)
{
INT32 totalfileslength;
INT32 loadcompletednum = 0;
INT32 i;
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-24, V_YELLOWMAP, "Press ESC to abort");
//ima just count files here
for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_OPEN)
loadcompletednum++;
// Loading progress
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, "Loading server addons...");
totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256);
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 160);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va(" %2u/%2u Files",loadcompletednum,fileneedednum));
}
else if (lastfilenum != -1)
{
INT32 dldlength;
INT32 totalfileslength;
UINT32 totaldldsize;
static char tempname[28];
fileneeded_t *file = &fileneeded[lastfilenum];
char *filename = file->filename;
// Draw the bottom box.
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-58-8, 32, 1);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-14, V_YELLOWMAP, "Press ESC to abort");
Net_GetNetStat();
dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256);
if (dldlength > 256)
dldlength = 256;
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-58, 256, 8, 175);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-58, dldlength, 8, 160);
memset(tempname, 0, sizeof(tempname));
// offset filename to just the name only part
@ -1256,16 +1301,52 @@ static inline void CL_DrawConnectionStatus(void)
strncpy(tempname, filename, sizeof(tempname)-1);
}
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-22, V_YELLOWMAP,
va(M_GetText("Downloading \"%s\""), tempname));
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE,
va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10));
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE,
va("%3.1fK/s ", ((double)getbps)/1024));
// Download progress
if (fileneeded[lastfilenum].currentsize != fileneeded[lastfilenum].totalsize)
totaldldsize = downloadcompletedsize+fileneeded[lastfilenum].currentsize; //Add in single file progress download if applicable
else
totaldldsize = downloadcompletedsize;
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-14, V_YELLOWMAP, "Overall Download Progress");
totalfileslength = (INT32)((totaldldsize/(double)totalfilesrequestedsize) * 256);
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 160);
if (totalfilesrequestedsize>>20 >= 100) //display in MB if over 100MB
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va(" %4uM/%4uM",totaldldsize>>20,totalfilesrequestedsize>>20));
else
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va(" %4uK/%4uK",totaldldsize>>10,totalfilesrequestedsize>>10));
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va("%2u/%2u Files ",downloadcompletednum,totalfilesrequestednum));
}
else
{
INT32 i, animtime = ((ccstime / 4) & 15) + 16;
UINT8 palstart = (cl_mode == CL_SEARCHING) ? 128 : 160;
// 15 pal entries total.
//Draw bottom box
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-24, V_YELLOWMAP, "Press ESC to abort");
for (i = 0; i < 16; ++i)
V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-24, 16, 8, palstart + ((animtime - i) & 15));
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
M_GetText("Waiting to download files..."));
}
}
}
#endif
@ -1314,10 +1395,8 @@ static boolean CL_SendJoin(void)
static void SV_SendServerInfo(INT32 node, tic_t servertime)
{
UINT8 *p;
#ifdef HAVE_CURL
size_t mirror_length;
const char *httpurl = cv_httpsource.string;
#endif
netbuffer->packettype = PT_SERVERINFO;
netbuffer->u.serverinfo._255 = 255;
@ -1406,7 +1485,6 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
netbuffer->u.serverinfo.actnum = 0; //mapheaderinfo[gamemap-1]->actnum
#ifdef HAVE_CURL
mirror_length = strlen(httpurl);
if (mirror_length > MAX_MIRROR_LENGTH)
mirror_length = MAX_MIRROR_LENGTH;
@ -1416,7 +1494,6 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
strncpy(netbuffer->u.serverinfo.httpsource, "", mirror_length);
netbuffer->u.serverinfo.httpsource[MAX_MIRROR_LENGTH-1] = '\0';
#endif
p = PutFileNeeded(0);
@ -1829,7 +1906,7 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
M_SortServerList();
}
#ifdef HAVE_THREADS
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
struct Fetch_servers_ctx
{
int room;
@ -1874,7 +1951,7 @@ Fetch_servers_thread (struct Fetch_servers_ctx *ctx)
free(ctx);
}
#endif/*HAVE_THREADS*/
#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/
void CL_QueryServerList (msg_server_t *server_list)
{
@ -1911,9 +1988,8 @@ void CL_QueryServerList (msg_server_t *server_list)
void CL_UpdateServerList(boolean internetsearch, INT32 room)
{
#ifdef HAVE_THREADS
struct Fetch_servers_ctx *ctx;
#endif
(void)internetsearch;
(void)room;
SL_ClearServerList(0);
@ -1930,9 +2006,12 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
if (netgame)
SendAskInfo(BROADCASTADDR);
#ifdef MASTERSERVER
if (internetsearch)
{
#ifdef HAVE_THREADS
struct Fetch_servers_ctx *ctx;
ctx = malloc(sizeof *ctx);
/* This called from M_Refresh so I don't use a mutex */
@ -1959,16 +2038,57 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
}
#endif
}
#endif/*MASTERSERVER*/
}
#endif // ifndef NONET
static void M_ConfirmConnect(event_t *ev)
{
if (ev->type == ev_keydown)
{
if (ev->data1 == ' ' || ev->data1 == 'y' || ev->data1 == KEY_ENTER || ev->data1 == gamecontrol[gc_accelerate][0] || ev->data1 == gamecontrol[gc_accelerate][1])
{
if (totalfilesrequestednum > 0)
{
#ifdef HAVE_CURL
if (http_source[0] == '\0' || curl_failedwebdownload)
#endif
{
if (CL_SendRequestFile())
{
cl_mode = CL_DOWNLOADFILES;
}
}
#ifdef HAVE_CURL
else
cl_mode = CL_PREPAREHTTPFILES;
#endif
}
else
cl_mode = CL_LOADFILES;
M_ClearMenus(true);
}
else if (ev->data1 == 'n' || ev->data1 == KEY_ESCAPE|| ev->data1 == gamecontrol[gc_brake][0] || ev->data1 == gamecontrol[gc_brake][1])
{
cl_mode = CL_ABORTED;
M_ClearMenus(true);
}
}
}
static boolean CL_FinishedFileList(void)
{
INT32 i;
CONS_Printf(M_GetText("Checking files...\n"));
char *downloadsize;
//CONS_Printf(M_GetText("Checking files...\n"));
i = CL_CheckFiles();
if (i == 3) // too many files
if (i == 4) // still checking ...
{
return true;
}
else if (i == 3) // too many files
{
D_QuitNetGame();
CL_Reset();
@ -1997,7 +2117,21 @@ static boolean CL_FinishedFileList(void)
return false;
}
else if (i == 1)
cl_mode = CL_ASKJOIN;
{
if (serverisfull)
{
M_StartMessage(M_GetText(
"This server is full!\n"
"\n"
"You may load server addons (if any), and wait for a slot.\n"
"\n"
"Press ACCEL to continue or BRAKE to cancel.\n\n"
), M_ConfirmConnect, MM_EVENTHANDLER);
cl_mode = CL_CONFIRMCONNECT;
}
else
cl_mode = CL_LOADFILES;
}
else
{
// must download something
@ -2022,14 +2156,55 @@ static boolean CL_FinishedFileList(void)
), NULL, MM_NOTHING);
return false;
}
}
if (CL_SendRequestFile())
cl_mode = CL_DOWNLOADFILES;
#ifdef HAVE_CURL
if (!curl_failedwebdownload)
#endif
{
downloadcompletednum = 0;
downloadcompletedsize = 0;
totalfilesrequestednum = 0;
totalfilesrequestedsize = 0;
for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)
{
totalfilesrequestednum++;
totalfilesrequestedsize += fileneeded[i].totalsize;
}
if (totalfilesrequestedsize>>20 >= 100)
downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20));
else
downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10));
if (serverisfull)
M_StartMessage(va(M_GetText(
"This server is full!\n"
"Download of %s additional content is required to join.\n"
"\n"
"You may download, load server addons, and wait for a slot.\n"
"\n"
"Press ACCEL to continue or BRAKE to cancel.\n\n"
), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER);
else
M_StartMessage(va(M_GetText(
"Download of %s additional content is required to join.\n"
"\n"
"Press ACCEL to continue or BRAKE to cancel.\n\n"
), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER);
Z_Free(downloadsize);
cl_mode = CL_CONFIRMCONNECT;
}
#ifdef HAVE_CURL
else
{
cl_mode = CL_PREPAREHTTPFILES;
if (CL_SendRequestFile())
{
cl_mode = CL_DOWNLOADFILES;
}
}
#endif
}
@ -2069,11 +2244,7 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
// Quit here rather than downloading files and being refused later.
if (serverlist[i].info.numberofplayer >= serverlist[i].info.maxplayer)
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING);
return false;
serverisfull = true;
}
if (client)
@ -2087,7 +2258,6 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
if (serverlist[i].info.httpsource[0])
CONS_Printf("We received a http url from the server, however it will not be used as this build lacks curl support (%s)\n", serverlist[i].info.httpsource);
#endif
D_ParseFileneeded(serverlist[i].info.fileneedednum, serverlist[i].info.fileneeded, 0);
if (serverlist[i].info.kartvars & SV_LOTSOFADDONS)
{
@ -2096,8 +2266,7 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
return true;
}
if (!CL_FinishedFileList())
return false;
cl_mode = CL_CHECKFILES;
}
else
cl_mode = CL_ASKJOIN; // files need not be checked for the server.
@ -2106,7 +2275,7 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
}
// Ask the info to the server (askinfo packet)
if (*asksent + NEWTICRATE < I_GetTime())
if ((I_GetTime() - NEWTICRATE) >= *asksent)
{
SendAskInfo(servernode);
*asksent = I_GetTime();
@ -2135,7 +2304,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{
boolean waitmore;
INT32 i;
#ifdef NONET
(void)tmpsave;
#endif
@ -2149,11 +2318,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
case CL_ASKFULLFILELIST:
if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved
{
if (!CL_FinishedFileList())
return false;
}
else if (fileneedednum != cl_lastcheckedfilecount || *asksent + NEWTICRATE < I_GetTime())
cl_mode = CL_CHECKFILES;
else if (fileneedednum != cl_lastcheckedfilecount || (I_GetTime() - NEWTICRATE) >= *asksent)
{
if (CL_AskFileList(fileneedednum))
{
@ -2162,15 +2328,20 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
}
}
break;
case CL_CHECKFILES:
if (!CL_FinishedFileList())
return false;
break;
#ifdef HAVE_CURL
case CL_PREPAREHTTPFILES:
if (http_source[0])
{
for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)
{
curl_transfers++;
}
cl_mode = CL_DOWNLOADHTTPFILES;
}
break;
@ -2194,19 +2365,13 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
if (curl_failedwebdownload && !curl_transfers)
{
if (!CL_FinishedFileList())
break;
CONS_Printf("One or more files failed to download, falling back to internal downloader\n");
if (CL_SendRequestFile())
{
cl_mode = CL_DOWNLOADFILES;
break;
}
cl_mode = CL_CHECKFILES;
break;
}
if (!curl_transfers)
cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now
cl_mode = CL_LOADFILES;
break;
#endif
@ -2222,21 +2387,50 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
if (waitmore)
break; // exit the case
cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now
/* FALLTHRU */
cl_mode = CL_LOADFILES;
break;
case CL_LOADFILES:
if (CL_LoadServerFiles())
{
*asksent = I_GetTime() - (NEWTICRATE*3); //This ensure the first join ask is right away
firstconnectattempttime = I_GetTime();
cl_mode = CL_ASKJOIN;
}
break;
case CL_ASKJOIN:
CL_LoadServerFiles();
if (firstconnectattempttime + NEWTICRATE*300 < I_GetTime() && !server)
{
CONS_Printf(M_GetText("5 minute wait time exceeded.\n"));
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"5 minute wait time exceeded.\n"
"You may retry connection.\n"
"\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
#ifdef JOININGAME
// prepare structures to save the file
// WARNING: this can be useless in case of server not in GS_LEVEL
// but since the network layer doesn't provide ordered packets...
CL_PrepareDownloadSaveGame(tmpsave);
#endif
if (CL_SendJoin())
if (( I_GetTime() - NEWTICRATE*3 ) >= *asksent && CL_SendJoin())
{
*asksent = I_GetTime();
cl_mode = CL_WAITJOINRESPONSE;
}
break;
case CL_WAITJOINRESPONSE:
if (( I_GetTime() - NEWTICRATE*3 ) >= *asksent)
{
cl_mode = CL_ASKJOIN;
}
break;
#ifdef JOININGAME
case CL_DOWNLOADSAVEGAME:
// At this state, the first (and only) needed file is the gamestate
@ -2245,13 +2439,13 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
// Gamestate is now handled within CL_LoadReceivedSavegame()
CL_LoadReceivedSavegame();
cl_mode = CL_CONNECTED;
break;
} // don't break case continue to CL_CONNECTED
else
break;
#endif
case CL_WAITJOINRESPONSE:
case CL_CONNECTED:
case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect
default:
break;
@ -2272,9 +2466,13 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
INT32 key;
I_OsPolling();
if (cl_mode == CL_CONFIRMCONNECT)
D_ProcessEvents(); //needed for menu system to receive inputs
key = I_GetKey();
// Only ESC and non-keyboard keys abort connection
if (key == KEY_ESCAPE || key >= KEY_MOUSE1)
if (key == KEY_ESCAPE || key >= KEY_MOUSE1 || cl_mode == CL_ABORTED)
{
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
D_QuitNetGame();
@ -2291,6 +2489,13 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
F_TitleScreenTicker(true);
F_TitleScreenDrawer();
CL_DrawConnectionStatus();
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
M_Drawer(); //Needed for drawing messageboxes on the connection screen
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
I_UpdateNoVsync(); // page flip or blit buffer
if (moviemode)
M_SaveFrame();
@ -2357,7 +2562,8 @@ static void CL_ConnectToServer(void)
pnumnodes = 1;
oldtic = I_GetTime() - 1;
#ifndef NONET
asksent = (tic_t) - TICRATE;
asksent = I_GetTime() - NEWTICRATE*3;
firstconnectattempttime = I_GetTime();
i = SL_SearchServer(servernode);
@ -2792,6 +2998,12 @@ void CL_Reset(void)
fileneedednum = 0;
memset(fileneeded, 0, sizeof(fileneeded));
totalfilesrequestednum = 0;
totalfilesrequestedsize = 0;
firstconnectattempttime = 0;
serverisfull = false;
connectiontimeout = (tic_t)cv_nettimeout.value; //reset this temporary hack
#ifdef HAVE_CURL
curl_failedwebdownload = false;
curl_transfers = 0;
@ -3449,8 +3661,10 @@ void D_QuitNetGame(void)
for (i = 0; i < MAXNETNODES; i++)
if (nodeingame[i])
HSendPacket(i, true, 0, 0);
#ifdef MASTERSERVER
if (serverrunning && ms_RoomId > 0)
UnregisterServer();
#endif
}
else if (servernode > 0 && servernode < MAXNETNODES && nodeingame[(UINT8)servernode])
{
@ -3710,8 +3924,10 @@ boolean SV_SpawnServer(void)
if (netgame && I_NetOpenSocket)
{
I_NetOpenSocket();
#ifdef MASTERSERVER
if (ms_RoomId > 0)
RegisterServer();
#endif
}
// non dedicated server just connect to itself
@ -3742,7 +3958,7 @@ void SV_StopServer(void)
D_Clearticcmd(i);
consoleplayer = 0;
cl_mode = CL_SEARCHING;
cl_mode = CL_ABORTED;
maketic = gametic+1;
neededtic = maketic;
serverrunning = false;
@ -3768,7 +3984,7 @@ static void SV_SendRefuse(INT32 node, const char *reason)
strcpy(netbuffer->u.serverrefuse.reason, reason);
netbuffer->packettype = PT_SERVERREFUSE;
HSendPacket(node, true, 0, strlen(netbuffer->u.serverrefuse.reason) + 1);
HSendPacket(node, false, 0, strlen(netbuffer->u.serverrefuse.reason) + 1);
Net_CloseConnection(node);
}
@ -4040,13 +4256,24 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (!reason)
I_Error("Out of memory!\n");
D_QuitNetGame();
CL_Reset();
D_StartTitle();
if (strstr(reason, "Maximum players reached"))
{
serverisfull = true;
//Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer
//We set it back to the value of cv_nettimeout.value in CL_Reset
connectiontimeout = NEWTICRATE*7;
cl_mode = CL_ASKJOIN;
free(reason);
break;
}
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
reason), NULL, MM_NOTHING);
D_QuitNetGame();
CL_Reset();
D_StartTitle();
free(reason);
// Will be reset by caller. Signals refusal.
@ -4066,7 +4293,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
}
SERVERONLY
/// \note how would this happen? and is it doing the right thing if it does?
if (cl_mode != CL_WAITJOINRESPONSE)
if (!(cl_mode == CL_WAITJOINRESPONSE || cl_mode == CL_ASKJOIN))
break;
if (client)
@ -5429,7 +5656,9 @@ FILESTAMP
GetPackets();
FILESTAMP
#ifdef MASTERSERVER
MasterClient_Ticker();
#endif
if (client)
{
@ -5486,7 +5715,9 @@ FILESTAMP
// client send the command after a receive of the server
// the server send before because in single player is beter
#ifdef MASTERSERVER
MasterClient_Ticker(); // Acking the Master Server
#endif
if (client)
{

View file

@ -43,6 +43,8 @@ extern SINT8 nodetoplayer4[MAXNETNODES]; // Say the numplayer for this node if a
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
extern boolean serverrunning;
INT32 Net_GetFreeAcks(boolean urgent);
void Net_AckTicker(void);

View file

@ -4111,7 +4111,7 @@ static void Command_RunSOC(void)
static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum)
{
char filename[256];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
@ -4283,7 +4283,7 @@ static void Command_Delfile(void)
static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
{
char filename[241];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
UINT8 md5sum[16];
boolean kick = false;
boolean toomany = false;
@ -4378,7 +4378,7 @@ static void Got_Delfilecmd(UINT8 **cp, INT32 playernum)
static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
{
char filename[241];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
UINT8 md5sum[16];
READSTRINGN(*cp, filename, 240);

View file

@ -108,6 +108,10 @@ char downloaddir[512] = "DOWNLOAD";
#ifdef CLIENT_LOADINGSCREEN
// for cl loading screen
INT32 lastfilenum = -1;
INT32 downloadcompletednum = 0;
UINT32 downloadcompletedsize = 0;
INT32 totalfilesrequestednum = 0;
UINT32 totalfilesrequestedsize = 0;
#endif
#ifdef HAVE_CURL
@ -141,7 +145,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus;
for (i = mainwads; i < numwadfiles; i++)
for (i = mainwads+1; i < numwadfiles; i++) //mainwads+1, otherwise we start on the first mainwad
{
// If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important)
@ -207,7 +211,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
p = (UINT8 *)fileneededstr;
for (i = firstfile; i < fileneedednum; i++)
{
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet
filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
@ -370,15 +374,17 @@ boolean Got_RequestFilePak(INT32 node)
* \return 0 if some files are missing
* 1 if all files exist
* 2 if some already loaded files are not requested or are in a different order
* 3 too many files, over WADLIMIT
* 4 still checking, continuing next tic
*
*/
INT32 CL_CheckFiles(void)
{
INT32 i, j;
char wadfilename[MAX_WADPATH];
INT32 ret = 1;
size_t packetsize = 0;
size_t filestoget = 0;
size_t filestoload = 0;
boolean downloadrequired = false;
// if (M_CheckParm("-nofiles"))
// return 1;
@ -395,7 +401,7 @@ INT32 CL_CheckFiles(void)
if (modifiedgame)
{
CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n");
for (i = 0, j = mainwads; i < fileneedednum || j < numwadfiles;)
for (i = 0, j = mainwads+1; i < fileneedednum || j < numwadfiles;)
{
if (j < numwadfiles && !wadfiles[j]->important)
{
@ -424,10 +430,19 @@ INT32 CL_CheckFiles(void)
for (i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_FALLBACK)
downloadrequired = true;
if (fileneeded[i].status == FS_FOUND || fileneeded[i].status == FS_NOTFOUND)
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
continue;
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// Check in already loaded files
for (j = mainwads; wadfiles[j]; j++)
for (j = mainwads+1; wadfiles[j]; j++)
{
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
if (!stricmp(wadfilename, fileneeded[i].filename) &&
@ -435,36 +450,35 @@ INT32 CL_CheckFiles(void)
{
CONS_Debug(DBG_NETPLAY, "already loaded\n");
fileneeded[i].status = FS_OPEN;
break;
return 4;
}
}
if (fileneeded[i].status != FS_NOTFOUND)
continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
if (mainwads+filestoget >= MAX_WADFILES)
return 3;
filestoget++;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND)
ret = 0;
return 4;
}
return ret;
//now making it here means we've checked the entire list and no FS_NOTCHECKED files remain
if (numwadfiles+filestoload > MAX_WADFILES)
return 3;
else if (downloadrequired)
return 0; //some stuff is FS_NOTFOUND, needs download
else
return 1; //everything is FS_OPEN or FS_FOUND, proceed to loading
}
// Load it now
void CL_LoadServerFiles(void)
boolean CL_LoadServerFiles(void)
{
INT32 i;
// if (M_CheckParm("-nofiles"))
// return;
for (i = 1; i < fileneedednum; i++)
for (i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_OPEN)
continue; // Already loaded
@ -473,6 +487,7 @@ void CL_LoadServerFiles(void)
P_AddWadFile(fileneeded[i].filename);
G_SetGameModified(true, false);
fileneeded[i].status = FS_OPEN;
return false;
}
else if (fileneeded[i].status == FS_MD5SUMBAD)
I_Error("Wrong version of file %s", fileneeded[i].filename);
@ -498,6 +513,7 @@ void CL_LoadServerFiles(void)
fileneeded[i].status, s);
}
}
return true;
}
// Number of files to send
@ -858,6 +874,8 @@ void Got_Filetxpak(void)
file->status = FS_FOUND;
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
filename);
downloadcompletednum++;
downloadcompletedsize += file->totalsize;
}
}
else
@ -1169,6 +1187,8 @@ void CURLGetFile(void)
{
nameonly(curl_realname);
CONS_Printf(M_GetText("Finished downloading %s\n"), curl_realname);
downloadcompletednum++;
downloadcompletedsize += curl_curfile->totalsize;
curl_curfile->status = FS_FOUND;
fclose(curl_curfile->file);
}

View file

@ -25,6 +25,7 @@ typedef enum
typedef enum
{
FS_NOTCHECKED,
FS_NOTFOUND,
FS_FOUND,
FS_REQUESTED,
@ -52,6 +53,10 @@ extern char downloaddir[512];
#ifdef CLIENT_LOADINGSCREEN
extern INT32 lastfilenum;
extern INT32 downloadcompletednum;
extern UINT32 downloadcompletedsize;
extern INT32 totalfilesrequestednum;
extern UINT32 totalfilesrequestedsize;
#endif
#ifdef HAVE_CURL
@ -65,7 +70,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
void CL_PrepareDownloadSaveGame(const char *tmpsave);
INT32 CL_CheckFiles(void);
void CL_LoadServerFiles(void);
boolean CL_LoadServerFiles(void);
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
UINT8 fileid);

View file

@ -681,4 +681,10 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Hardware renderer: OpenGL
#define GL_SHADERS
#ifdef HAVE_CURL
#define MASTERSERVER
#else
#undef UPDATE_ALERT
#endif
#endif // __DOOMDEF__

View file

@ -14,7 +14,9 @@ Documentation available here.
<http://mb.srb2.org/MS/tools/api/v1/>
*/
#ifdef HAVE_CURL
#include <curl/curl.h>
#endif
#include "doomdef.h"
#include "d_clisrv.h"
@ -49,6 +51,8 @@ consvar_t cv_masterserver_token = {
NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
};
#ifdef MASTERSERVER
static int hms_started;
static char *hms_api;
@ -666,10 +670,14 @@ HMS_set_api (char *api)
#endif
}
#endif/*MASTERSERVER*/
static void
MasterServer_Debug_OnChange (void)
{
#ifdef MASTERSERVER
/* TODO: change to 'latest-log.txt' for log files revision. */
if (cv_masterserver_debug.value)
CONS_Printf("Master server debug messages will appear in log.txt\n");
#endif
}

View file

@ -246,7 +246,8 @@ static size_t numbans = 0;
static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
static boolean init_tcp_driver = false;
static char port_name[8] = DEFAULTPORT;
static const char *serverport_name = DEFAULTPORT;
static const char *clientport_name;/* any port */
#ifndef NONET
@ -924,6 +925,7 @@ static boolean UDP_Socket(void)
#ifdef HAVE_IPV6
const INT32 b_ipv6 = M_CheckParm("-ipv6");
#endif
const char *serv;
for (s = 0; s < mysocketses; s++)
@ -939,11 +941,16 @@ static boolean UDP_Socket(void)
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
if (serverrunning)
serv = serverport_name;
else
serv = clientport_name;
if (M_CheckParm("-bindaddr"))
{
while (M_IsNextParm())
{
gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai);
gaie = I_getaddrinfo(M_GetNextParm(), serv, &hints, &ai);
if (gaie == 0)
{
runp = ai;
@ -964,7 +971,7 @@ static boolean UDP_Socket(void)
}
else
{
gaie = I_getaddrinfo("0.0.0.0", port_name, &hints, &ai);
gaie = I_getaddrinfo("0.0.0.0", serv, &hints, &ai);
if (gaie == 0)
{
runp = ai;
@ -979,8 +986,8 @@ static boolean UDP_Socket(void)
#ifdef HAVE_MINIUPNPC
if (UPNP_support)
{
I_UPnP_rem(port_name, "UDP");
I_UPnP_add(NULL, port_name, "UDP");
I_UPnP_rem(serverport_name, "UDP");
I_UPnP_add(NULL, serverport_name, "UDP");
}
#endif
}
@ -997,7 +1004,7 @@ static boolean UDP_Socket(void)
{
while (M_IsNextParm())
{
gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai);
gaie = I_getaddrinfo(M_GetNextParm(), serv, &hints, &ai);
if (gaie == 0)
{
runp = ai;
@ -1018,7 +1025,7 @@ static boolean UDP_Socket(void)
}
else
{
gaie = I_getaddrinfo("::", port_name, &hints, &ai);
gaie = I_getaddrinfo("::", serv, &hints, &ai);
if (gaie == 0)
{
runp = ai;
@ -1475,15 +1482,19 @@ boolean I_InitTcpNetwork(void)
if (!I_InitTcpDriver())
return false;
if (M_CheckParm("-port"))
if (M_CheckParm("-port") || M_CheckParm("-serverport"))
// Combined -udpport and -clientport into -port
// As it was really redundant having two seperate parms that does the same thing
/* Sorry Steel, I'm adding these back. But -udpport is a stupid name. */
{
if (M_IsNextParm())
strcpy(port_name, M_GetNextParm());
else
strcpy(port_name, "0");
/*
If it's NULL, that's okay! Because then
we'll get a random port from getaddrinfo.
*/
serverport_name = M_GetNextParm();
}
if (M_CheckParm("-clientport"))
clientport_name = M_GetNextParm();
// parse network game options,
if (M_CheckParm("-server") || dedicated)

View file

@ -3394,7 +3394,7 @@ void M_SetupNextMenu(menu_t *menudef)
{
INT16 i;
#ifdef HAVE_THREADS
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
if (currentMenu == &MP_RoomDef || currentMenu == &MP_ConnectDef)
{
I_lock_mutex(&ms_QueryId_mutex);
@ -3476,7 +3476,7 @@ void M_Ticker(void)
setmodeneeded = vidm_previousmode + 1;
}
#ifdef HAVE_THREADS
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
I_lock_mutex(&ms_ServerList_mutex);
{
if (ms_ServerList)
@ -8711,8 +8711,9 @@ static boolean M_CheckMODVersion(int id)
} else
return true;
}
#endif/*UPDATE_ALERT*/
#ifdef HAVE_THREADS
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
static void
Check_new_version_thread (int *id)
{
@ -8721,7 +8722,9 @@ Check_new_version_thread (int *id)
okay = 0;
#ifdef UPDATE_ALERT
if (M_CheckMODVersion(*id))
#endif
{
I_lock_mutex(&ms_QueryId_mutex);
{
@ -8765,8 +8768,7 @@ Check_new_version_thread (int *id)
free(id);
}
#endif/*HAVE_THREADS*/
#endif/*UPDATE_ALERT*/
#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/
static void M_ConnectMenu(INT32 choice)
{
@ -8807,7 +8809,7 @@ UINT32 roomIds[NUM_LIST_ROOMS];
static void M_RoomMenu(INT32 choice)
{
INT32 i;
#ifdef HAVE_THREADS
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
int *id;
#endif
@ -8829,9 +8831,14 @@ static void M_RoomMenu(INT32 choice)
MP_RoomDef.prevMenu = currentMenu;
M_SetupNextMenu(&MP_RoomDef);
#ifdef UPDATE_ALERT
#ifdef MASTERSERVER
#ifdef HAVE_THREADS
#ifdef UPDATE_ALERT
m_waiting_mode = M_WAITING_VERSION;
#else/*UPDATE_ALERT*/
m_waiting_mode = M_WAITING_ROOMS;
#endif/*UPDATE_ALERT*/
MP_RoomMenu[0].text = "";
id = malloc(sizeof *id);
@ -8845,17 +8852,19 @@ static void M_RoomMenu(INT32 choice)
I_spawn_thread("check-new-version",
(I_thread_fn)Check_new_version_thread, id);
#else/*HAVE_THREADS*/
#ifdef UPDATE_ALERT
if (M_CheckMODVersion(0))
#endif/*UPDATE_ALERT*/
{
GetRoomsList(currentMenu->prevMenu == &MP_ServerDef, 0);
}
#endif/*HAVE_THREADS*/
#endif/*UPDATE_ALERT*/
#endif/*MASTERSERVER*/
}
static void M_ChooseRoom(INT32 choice)
{
#ifdef HAVE_THREADS
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
I_lock_mutex(&ms_QueryId_mutex);
{
ms_QueryId++;

View file

@ -27,6 +27,8 @@
#include "discord.h"
#endif
#ifdef MASTERSERVER
static int MSId;
static int MSRegisteredId = -1;
@ -47,11 +49,14 @@ static I_cond MSCond;
# define Unlock_state()
#endif/*HAVE_THREADS*/
static void Update_parameters (void);
#ifndef NONET
static void Command_Listserv_f(void);
#endif
#endif/*MASTERSERVER*/
static void Update_parameters (void);
static void MasterServer_OnChange(void);
static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
@ -67,7 +72,7 @@ consvar_t cv_masterserver_update_rate = {"masterserver_update_rate", "15", CV_SA
INT16 ms_RoomId = -1;
#ifdef HAVE_THREADS
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
int ms_QueryId;
I_mutex ms_QueryId_mutex;
@ -95,10 +100,14 @@ void AddMServCommands(void)
CV_RegisterVar(&cv_masterserver_debug);
CV_RegisterVar(&cv_masterserver_token);
CV_RegisterVar(&cv_servername);
#ifdef MASTERSERVER
COM_AddCommand("listserv", Command_Listserv_f);
#endif
#endif
}
#ifdef MASTERSERVER
static void WarnGUI (void)
{
#ifdef HAVE_THREADS
@ -407,6 +416,7 @@ Change_masterserver_thread (char *api)
void RegisterServer(void)
{
#ifdef MASTERSERVER
#ifdef HAVE_THREADS
I_spawn_thread(
"register-server",
@ -416,6 +426,7 @@ void RegisterServer(void)
#else
Finish_registration();
#endif
#endif/*MASTERSERVER*/
}
static void UpdateServer(void)
@ -433,6 +444,7 @@ static void UpdateServer(void)
void UnregisterServer(void)
{
#ifdef MASTERSERVER
#ifdef HAVE_THREADS
I_spawn_thread(
"unlist-server",
@ -442,6 +454,7 @@ void UnregisterServer(void)
#else
Finish_unlist();
#endif
#endif/*MASTERSERVER*/
}
static boolean
@ -477,9 +490,33 @@ static inline void SendPingToMasterServer(void)
}
}
void MasterClient_Ticker(void)
{
#ifdef MASTERSERVER
SendPingToMasterServer();
#endif
}
static void
Set_api (const char *api)
{
#ifdef HAVE_THREADS
I_spawn_thread(
"change-masterserver",
(I_thread_fn)Change_masterserver_thread,
strdup(api)
);
#else
HMS_set_api(strdup(api));
#endif
}
#endif/*MASTERSERVER*/
static void
Update_parameters (void)
{
#ifdef MASTERSERVER
int registered;
int delayed;
@ -499,29 +536,12 @@ Update_parameters (void)
if (! delayed && registered)
UpdateServer();
}
}
void MasterClient_Ticker(void)
{
SendPingToMasterServer();
}
static void
Set_api (const char *api)
{
#ifdef HAVE_THREADS
I_spawn_thread(
"change-masterserver",
(I_thread_fn)Change_masterserver_thread,
strdup(api)
);
#else
HMS_set_api(strdup(api));
#endif
#endif/*MASTERSERVER*/
}
static void MasterServer_OnChange(void)
{
#ifdef MASTERSERVER
UnregisterServer();
/*
@ -539,4 +559,5 @@ static void MasterServer_OnChange(void)
if (Online())
RegisterServer();
#endif/*MASTERSERVER*/
}

View file

@ -7487,13 +7487,14 @@ void P_ResetCamera(player_t *player, camera_t *thiscam)
boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled)
{
static UINT8 lookbackdelay[4] = {0,0,0,0};
static boolean lookbackactive[MAXSPLITSCREENPLAYERS];
static UINT8 lookbackdelay[MAXSPLITSCREENPLAYERS];
UINT8 num;
angle_t angle = 0, focusangle = 0, focusaiming = 0;
fixed_t x, y, z, dist, height, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight;
fixed_t x, y, z, dist, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight;
fixed_t pan, xpan, ypan;
INT32 camrotate;
boolean camstill, lookback;
boolean camstill, lookback, lookbackdown;
UINT8 timeover;
mobj_t *mo;
fixed_t f1, f2;
@ -7684,15 +7685,19 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
camstill = true;
else if (lookback || lookbackdelay[num]) // SRB2kart - Camera flipper
{
#define MAXLOOKBACKDELAY 2
camspeed = FRACUNIT;
if (lookback)
{
camrotate += 180;
lookbackdelay[num] = 2;
lookbackdelay[num] = MAXLOOKBACKDELAY;
}
else
lookbackdelay[num]--;
}
lookbackdown = (lookbackdelay[num] == MAXLOOKBACKDELAY) != lookbackactive[num];
lookbackactive[num] = (lookbackdelay[num] == MAXLOOKBACKDELAY);
#undef MAXLOOKBACKDELAY
if (mo->eflags & MFE_VERTICALFLIP)
camheight += thiscam->height;
@ -7735,8 +7740,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
thiscam->angle = angle;
}
height = camheight;
// sets ideal cam pos
dist = camdist;
@ -7745,10 +7748,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
dist += abs(thiscam->momz)/4;
if (player->kartstuff[k_boostcam])
{
dist -= FixedMul(11*dist/16, player->kartstuff[k_boostcam]);
height -= FixedMul(height, player->kartstuff[k_boostcam]);
}
x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist);
y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist);
@ -8070,6 +8070,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
thiscam->aiming = ANGLE_22h;
}
if (lookbackdown)
P_MoveChaseCamera(player, thiscam, false);
return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming);
}

View file

@ -110,6 +110,27 @@ static void var_cleanup(void)
internal_volume = 100;
}
static const char* get_zlib_error(int zErr)
{
switch (zErr)
{
case Z_ERRNO:
return "Z_ERRNO";
case Z_STREAM_ERROR:
return "Z_STREAM_ERROR";
case Z_DATA_ERROR:
return "Z_DATA_ERROR";
case Z_MEM_ERROR:
return "Z_MEM_ERROR";
case Z_BUF_ERROR:
return "Z_BUF_ERROR";
case Z_VERSION_ERROR:
return "Z_VERSION_ERROR";
default:
return "unknown error";
}
}
/// ------------------------
/// Audio System
/// ------------------------
@ -371,51 +392,11 @@ void *I_GetSfx(sfxinfo_t *sfx)
}
}
else
{
const char *errorType;
switch (zErr)
{
case Z_ERRNO:
errorType = "Z_ERRNO"; break;
case Z_STREAM_ERROR:
errorType = "Z_STREAM_ERROR"; break;
case Z_DATA_ERROR:
errorType = "Z_DATA_ERROR"; break;
case Z_MEM_ERROR:
errorType = "Z_MEM_ERROR"; break;
case Z_BUF_ERROR:
errorType = "Z_BUF_ERROR"; break;
case Z_VERSION_ERROR:
errorType = "Z_VERSION_ERROR"; break;
default:
errorType = "unknown error";
}
CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", errorType, stream.msg);
}
CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", get_zlib_error(zErr), stream.msg);
(void)inflateEnd(&stream);
}
else // Hold up, zlib's got a problem
{
const char *errorType;
switch (zErr)
{
case Z_ERRNO:
errorType = "Z_ERRNO"; break;
case Z_STREAM_ERROR:
errorType = "Z_STREAM_ERROR"; break;
case Z_DATA_ERROR:
errorType = "Z_DATA_ERROR"; break;
case Z_MEM_ERROR:
errorType = "Z_MEM_ERROR"; break;
case Z_BUF_ERROR:
errorType = "Z_BUF_ERROR"; break;
case Z_VERSION_ERROR:
errorType = "Z_VERSION_ERROR"; break;
default:
errorType = "unknown error";
}
CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", errorType, stream.msg);
}
CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", get_zlib_error(zErr), stream.msg);
Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up
#else
return NULL; // No zlib support
@ -945,73 +926,25 @@ boolean I_LoadSong(char *data, size_t len)
// Run GME on new data
if (!gme_open_data(inflatedData, inflatedLen, &gme, 44100))
{
gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
gme_start_track(gme, 0);
current_track = 0;
gme_set_equalizer(gme, &eq);
Mix_HookMusic(mix_gme, gme);
Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around
return true;
}
}
else
{
const char *errorType;
switch (zErr)
{
case Z_ERRNO:
errorType = "Z_ERRNO"; break;
case Z_STREAM_ERROR:
errorType = "Z_STREAM_ERROR"; break;
case Z_DATA_ERROR:
errorType = "Z_DATA_ERROR"; break;
case Z_MEM_ERROR:
errorType = "Z_MEM_ERROR"; break;
case Z_BUF_ERROR:
errorType = "Z_BUF_ERROR"; break;
case Z_VERSION_ERROR:
errorType = "Z_VERSION_ERROR"; break;
default:
errorType = "unknown error";
}
CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", errorType, stream.msg);
}
CONS_Alert(CONS_ERROR, "Encountered %s when running inflate: %s\n", get_zlib_error(zErr), stream.msg);
(void)inflateEnd(&stream);
}
else // Hold up, zlib's got a problem
{
const char *errorType;
switch (zErr)
{
case Z_ERRNO:
errorType = "Z_ERRNO"; break;
case Z_STREAM_ERROR:
errorType = "Z_STREAM_ERROR"; break;
case Z_DATA_ERROR:
errorType = "Z_DATA_ERROR"; break;
case Z_MEM_ERROR:
errorType = "Z_MEM_ERROR"; break;
case Z_BUF_ERROR:
errorType = "Z_BUF_ERROR"; break;
case Z_VERSION_ERROR:
errorType = "Z_VERSION_ERROR"; break;
default:
errorType = "unknown error";
}
CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", errorType, stream.msg);
}
CONS_Alert(CONS_ERROR, "Encountered %s when running inflateInit: %s\n", get_zlib_error(zErr), stream.msg);
Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up
return false;
#else
CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n");
return true;
return false;
#endif
}
else if (!gme_open_data(data, len, &gme, 44100))
{
gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
gme_set_equalizer(gme, &eq);
return true;
}
#endif
rw = SDL_RWFromMem(data, len);
@ -1082,6 +1015,8 @@ boolean I_PlaySong(boolean looping)
#ifdef HAVE_LIBGME
if (gme)
{
gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
gme_set_equalizer(gme, &eq);
gme_start_track(gme, 0);
current_track = 0;
Mix_HookMusic(mix_gme, gme);

View file

@ -150,7 +150,10 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors)
{
FILE *handle;
strncpy(filenamebuf, *filename, MAX_WADPATH);
if (filenamebuf != *filename) {
// avoid overlap
strncpy(filenamebuf, *filename, MAX_WADPATH);
}
filenamebuf[MAX_WADPATH - 1] = '\0';
*filename = filenamebuf;