Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2210-release
  • 304-the-amount-of-mashing-to-kill-a-pterabyte-should-be-reduced
  • 555-2-2-9-rotated-patches-are-cropped-have-incorrect-dimensions
  • 610-p_setupstateanimation-array-bounds-warnings-on-gcc-11
  • 622-teamlives-hud
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • S_SKIN-missing-flag
  • accel-momentum
  • addfolder_nocache
  • alien-breed-3d
  • appveyor
  • better-download
  • better-refusal
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • catchup-timeout
  • cleanup-opengl
  • cons-escape
  • continue_tweaks
  • crawlacommander-sprites
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delete-connection-screen-and-midgame-joins
  • delete-lua
  • delete-slopes
  • deprecate-lua-dedicated-server
  • dofile
  • dpl-2
  • dropshadows-spawning
  • emblem-drawing
  • exchndl-xp-fix
  • facing-forwards
  • few-kart-lua-changes
  • ffloorclip
  • final-hours
  • final-tweaks
  • fix-allowjoin
  • fix-archiving-error-msg
  • fix-autoexec-netvars
  • fix-cvar-conflicts
  • fix-ded-servers
  • fix-fire-shield
  • fix-input-buffer
  • fix-intermission-mouse
  • fix-joiner-consoleplayer
  • fix-keepbody-ping
  • fix-opengl-shear-roll
  • fix-packet-name
  • fix-playercmd
  • fix-polyobject-rotation-crash
  • fix-rollout-rock-crash
  • fix-spawn-desynch
  • fix-splitscreen
  • fix-stacktrace
  • fix-ticcmd-received
  • fix-timeout
  • fixargstr
  • fixmul
  • flipfuncpointers
  • flipfuncpointers-master
  • floorsprite-and-shadow-fake-planes-fix
  • fof-lightlist-fixes
  • folder
  • font-FUCK
  • font_drawer
  • frictionrefactor
  • fuck-macros-1
  • fullscreen-toggle
  • gamepad_experiments
  • ghost-networking
  • gif-splitting
  • grr-lj
  • high-resolution-timer-2
  • hitboxviewer
  • hwr-texture-cache-refactor
  • improve-439
  • increase-input-buffer
  • increase-input-buffer-more
  • increase-packet-tics
  • increase-unlockables
  • input-display
  • input-display-translucency
  • io
  • ipv6
  • join-delay
  • joystick-juggling-maz
  • keep-body
  • keycodes-only
  • ksf-wadfiles
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
138 results

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
117 results
Select Git revision
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2214-pre4
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • acs
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • clipmidtex
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • extra-textures
  • few-kart-lua-changes
  • ffloorclip
  • fix-167
  • fix-cvar-conflicts
  • fix-opengl-parameter-crash
  • fix-opengl-shear-roll
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • frictionrefactor
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-maxconditionsets
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • just-in-case
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • map-components-signedness-fixes
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.15
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
142 results
Show changes
Commits on Source (4)
...@@ -127,10 +127,14 @@ static UINT8 localtextcmd[MAXTEXTCMD]; ...@@ -127,10 +127,14 @@ static UINT8 localtextcmd[MAXTEXTCMD];
static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen
static tic_t neededtic; static tic_t neededtic;
SINT8 servernode = 0; // the number of the server node SINT8 servernode = 0; // the number of the server node
/// \brief do we accept new players? /// \brief do we accept new players?
/// \todo WORK! /// \todo WORK!
boolean acceptnewnode = true; boolean acceptnewnode = true;
static 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
static tic_t firstconnectattempttime = 0;
// engine // engine
// Must be a power of two // Must be a power of two
...@@ -510,18 +514,24 @@ static INT16 Consistancy(void); ...@@ -510,18 +514,24 @@ static INT16 Consistancy(void);
typedef enum typedef enum
{ {
CL_SEARCHING, CL_SEARCHING,
CL_CHECKFILES,
CL_DOWNLOADFILES, CL_DOWNLOADFILES,
CL_ASKJOIN, CL_ASKJOIN,
CL_LOADFILES,
CL_WAITJOINRESPONSE, CL_WAITJOINRESPONSE,
CL_DOWNLOADSAVEGAME, CL_DOWNLOADSAVEGAME,
CL_CONNECTED, CL_CONNECTED,
CL_ABORTED CL_ABORTED,
CL_ASKFULLFILELIST,
CL_CONFIRMCONNECT
} cl_mode_t; } cl_mode_t;
static void GetPackets(void); static void GetPackets(void);
static cl_mode_t cl_mode = CL_SEARCHING; static cl_mode_t cl_mode = CL_SEARCHING;
static UINT16 cl_lastcheckedfilecount = 0; // used for full file list
#ifndef NONET #ifndef NONET
#define SNAKE_SPEED 5 #define SNAKE_SPEED 5
...@@ -919,6 +929,8 @@ static void Snake_Draw(void) ...@@ -919,6 +929,8 @@ static void Snake_Draw(void)
INT16 i; INT16 i;
// Background // Background
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
V_DrawFlatFill( V_DrawFlatFill(
SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_LEFT_X + SNAKE_BORDER_SIZE,
SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE,
...@@ -1020,6 +1032,13 @@ static void Snake_Draw(void) ...@@ -1020,6 +1032,13 @@ static void Snake_Draw(void)
); );
} }
static void CL_DrawConnectionStatusBox(void)
{
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1);
if (cl_mode != CL_CONFIRMCONNECT)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort");
}
// //
// CL_DrawConnectionStatus // CL_DrawConnectionStatus
// //
...@@ -1030,28 +1049,32 @@ static inline void CL_DrawConnectionStatus(void) ...@@ -1030,28 +1049,32 @@ static inline void CL_DrawConnectionStatus(void)
INT32 ccstime = I_GetTime(); INT32 ccstime = I_GetTime();
// Draw background fade // Draw background fade
if (!menuactive) // menu already draws its own fade V_DrawFadeScreen(0xFF00, 16); // force default
V_DrawFadeScreen(0xFF00, 16); // force default
// Draw the bottom box. if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES)
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort");
if (cl_mode != CL_DOWNLOADFILES)
{ {
INT32 i, animtime = ((ccstime / 4) & 15) + 16; INT32 i, animtime = ((ccstime / 4) & 15) + 16;
UINT8 palstart = (cl_mode == CL_SEARCHING) ? 32 : 96; UINT8 palstart;
// 15 pal entries total.
const char *cltext; const char *cltext;
// Draw the bottom box.
CL_DrawConnectionStatusBox();
if (cl_mode == CL_SEARCHING)
palstart = 32; // Red
else if (cl_mode == CL_CONFIRMCONNECT)
palstart = 48; // Orange
else
palstart = 96; // Green
if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1))
for (i = 0; i < 16; ++i) for (i = 0; i < 16; ++i) // 15 pal entries total.
V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15));
switch (cl_mode) switch (cl_mode)
{ {
case CL_DOWNLOADSAVEGAME: case CL_DOWNLOADSAVEGAME:
if (lastfilenum != -1) if (fileneeded && lastfilenum != -1)
{ {
UINT32 currentsize = fileneeded[lastfilenum].currentsize; UINT32 currentsize = fileneeded[lastfilenum].currentsize;
UINT32 totalsize = fileneeded[lastfilenum].totalsize; UINT32 totalsize = fileneeded[lastfilenum].totalsize;
...@@ -1075,9 +1098,22 @@ static inline void CL_DrawConnectionStatus(void) ...@@ -1075,9 +1098,22 @@ static inline void CL_DrawConnectionStatus(void)
else else
cltext = M_GetText("Waiting to download game state..."); cltext = M_GetText("Waiting to download game state...");
break; break;
case CL_ASKFULLFILELIST:
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_ASKJOIN:
case CL_WAITJOINRESPONSE: 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; break;
default: default:
cltext = M_GetText("Connecting to server..."); cltext = M_GetText("Connecting to server...");
...@@ -1087,14 +1123,51 @@ static inline void CL_DrawConnectionStatus(void) ...@@ -1087,14 +1123,51 @@ static inline void CL_DrawConnectionStatus(void)
} }
else else
{ {
if (lastfilenum != -1) if (cl_mode == CL_LOADFILES)
{
INT32 totalfileslength;
INT32 loadcompletednum = 0;
INT32 i;
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort");
//ima just count files here
if (fileneeded)
{
for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_OPEN)
loadcompletednum++;
}
// Loading progress
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, "Loading server addons...");
totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256);
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, totalfileslength, 8, 96);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE,
va(" %2u/%2u Files",loadcompletednum,fileneedednum));
}
else if (lastfilenum != -1)
{ {
INT32 dldlength; INT32 dldlength;
static char tempname[28]; static char tempname[28];
fileneeded_t *file = &fileneeded[lastfilenum]; fileneeded_t *file;
char *filename = file->filename; char *filename;
Snake_Draw(); if (snake)
Snake_Draw();
// Draw the bottom box.
CL_DrawConnectionStatusBox();
if (fileneeded)
{
file = &fileneeded[lastfilenum];
filename = file->filename;
}
else
return;
Net_GetNetStat(); Net_GetNetStat();
dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256);
...@@ -1127,20 +1200,32 @@ static inline void CL_DrawConnectionStatus(void) ...@@ -1127,20 +1200,32 @@ static inline void CL_DrawConnectionStatus(void)
va("%3.1fK/s ", ((double)getbps)/1024)); va("%3.1fK/s ", ((double)getbps)/1024));
} }
else else
{
if (snake)
Snake_Draw();
CL_DrawConnectionStatusBox();
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP,
M_GetText("Waiting to download files...")); M_GetText("Waiting to download files..."));
}
} }
} }
#endif #endif
static boolean CL_AskFileList(INT32 firstfile)
{
netbuffer->packettype = PT_TELLFILESNEEDED;
netbuffer->u.filesneedednum = firstfile;
return HSendPacket(servernode, false, 0, sizeof (INT32));
}
/** Sends a special packet to declare how many players in local /** Sends a special packet to declare how many players in local
* Used only in arbitratrenetstart() * Used only in arbitratrenetstart()
* Sends a PT_CLIENTJOIN packet to the server * Sends a PT_CLIENTJOIN packet to the server
* *
* \return True if the packet was successfully sent * \return True if the packet was successfully sent
* \todo Improve the description... * \todo Improve the description...
* Because to be honest, I have no idea what arbitratrenetstart is...
* Is it even used...?
* *
*/ */
static boolean CL_SendJoin(void) static boolean CL_SendJoin(void)
...@@ -1232,7 +1317,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) ...@@ -1232,7 +1317,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
sizeof netbuffer->u.serverinfo.gametypename); sizeof netbuffer->u.serverinfo.gametypename);
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
netbuffer->u.serverinfo.isdedicated = (UINT8)dedicated; netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0);
strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, strncpy(netbuffer->u.serverinfo.servername, cv_servername.string,
MAXSERVERNAME); MAXSERVERNAME);
strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7);
...@@ -1267,7 +1352,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) ...@@ -1267,7 +1352,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
if (mapheaderinfo[gamemap-1]) if (mapheaderinfo[gamemap-1])
netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum; netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum;
p = PutFileNeeded(); p = PutFileNeeded(0);
HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
} }
...@@ -1521,6 +1606,8 @@ static void CL_LoadReceivedSavegame(boolean reloading) ...@@ -1521,6 +1606,8 @@ static void CL_LoadReceivedSavegame(boolean reloading)
size_t length, decompressedlen; size_t length, decompressedlen;
char tmpsave[256]; char tmpsave[256];
FreeFileNeeded();
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
length = FIL_ReadFile(tmpsave, &savebuffer); length = FIL_ReadFile(tmpsave, &savebuffer);
...@@ -1829,6 +1916,162 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) ...@@ -1829,6 +1916,162 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
#endif // ifndef NONET #endif // ifndef NONET
static void M_ConfirmConnect(event_t *ev)
{
#ifndef NONET
if (ev->type == ev_keydown)
{
if (ev->data1 == ' ' || ev->data1 == 'y' || ev->data1 == KEY_ENTER)
{
if (totalfilesrequestednum > 0)
{
if (CL_SendFileRequest())
{
cl_mode = CL_DOWNLOADFILES;
Snake_Initialise();
}
}
else
cl_mode = CL_LOADFILES;
M_ClearMenus(true);
}
else if (ev->data1 == 'n' || ev->data1 == KEY_ESCAPE)
{
cl_mode = CL_ABORTED;
M_ClearMenus(true);
}
}
#else
(void)ev;
#endif
}
static boolean CL_FinishedFileList(void)
{
INT32 i;
char *downloadsize = NULL;
//CONS_Printf(M_GetText("Checking files...\n"));
i = CL_CheckFiles();
if (i == 4) // still checking ...
{
return true;
}
else if (i == 3) // too many files
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You have too many WAD files loaded\n"
"to add ones the server is using.\n"
"Please restart SRB2 before connecting.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
else if (i == 2) // cannot join for some reason
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You have the wrong addons loaded.\n\n"
"To play on this server, restart\n"
"the game and don't load any addons.\n"
"SRB2 will automatically add\n"
"everything you need when you join.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
else if (i == 1)
{
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 ENTER to continue\nor ESC to cancel.\n\n"
), M_ConfirmConnect, MM_EVENTHANDLER);
cl_mode = CL_CONFIRMCONNECT;
curfadevalue = 0;
}
else
cl_mode = CL_LOADFILES;
}
else
{
// must download something
// can we, though?
if (!CL_CheckDownloadable()) // nope!
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"An error occured when trying to\n"
"download missing addons.\n"
"(This is almost always a problem\n"
"with the server, not your game.)\n\n"
"See the console or log file\n"
"for additional details.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
#ifndef NONET
downloadcompletednum = 0;
downloadcompletedsize = 0;
totalfilesrequestednum = 0;
totalfilesrequestedsize = 0;
if (fileneeded == NULL)
I_Error("CL_FinishedFileList: fileneeded == NULL");
#endif
for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)
{
#ifndef NONET
totalfilesrequestednum++;
totalfilesrequestedsize += fileneeded[i].totalsize;
#endif
}
#ifndef NONET
if (totalfilesrequestedsize>>20 >= 100)
downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20));
else
downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10));
#endif
if (serverisfull)
M_StartMessage(va(M_GetText(
"This server is full!\n"
"Download of %s additional content\nis required to join.\n"
"\n"
"You may download, load server addons,\nand wait for a slot.\n"
"\n"
"Press ENTER to continue\nor ESC to cancel.\n"
), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER);
else
M_StartMessage(va(M_GetText(
"Download of %s additional content\nis required to join.\n"
"\n"
"Press ENTER to continue\nor ESC to cancel.\n"
), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER);
Z_Free(downloadsize);
cl_mode = CL_CONFIRMCONNECT;
curfadevalue = 0;
}
return true;
}
/** Called by CL_ServerConnectionTicker /** Called by CL_ServerConnectionTicker
* *
* \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit.
...@@ -1860,15 +2103,15 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) ...@@ -1860,15 +2103,15 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
} }
// Quit here rather than downloading files and being refused later. // Quit here rather than downloading files and being refused later.
if (serverlist[i].info.refusereason) if (serverlist[i].info.refusereason == 2)
serverisfull = true;
else if (serverlist[i].info.refusereason)
{ {
D_QuitNetGame(); D_QuitNetGame();
CL_Reset(); CL_Reset();
D_StartTitle(); D_StartTitle();
if (serverlist[i].info.refusereason == 1) if (serverlist[i].info.refusereason == 1)
M_StartMessage(M_GetText("The server is not accepting\njoins for the moment.\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("The server is not accepting\njoins for the moment.\n\nPress ESC\n"), NULL, MM_NOTHING);
else if (serverlist[i].info.refusereason == 2)
M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING);
else else
M_StartMessage(M_GetText("You can't join.\nI don't know why,\nbut you can't join.\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("You can't join.\nI don't know why,\nbut you can't join.\n\nPress ESC\n"), NULL, MM_NOTHING);
return false; return false;
...@@ -1876,71 +2119,22 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) ...@@ -1876,71 +2119,22 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
if (client) if (client)
{ {
D_ParseFileneeded(serverlist[i].info.fileneedednum, D_ParseFileneeded(serverlist[i].info.fileneedednum, serverlist[i].info.fileneeded, 0);
serverlist[i].info.fileneeded);
CONS_Printf(M_GetText("Checking files...\n")); if (serverlist[i].info.flags & SV_LOTSOFADDONS)
i = CL_CheckFiles();
if (i == 3) // too many files
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You have too many WAD files loaded\n"
"to add ones the server is using.\n"
"Please restart SRB2 before connecting.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
else if (i == 2) // cannot join for some reason
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You have the wrong addons loaded.\n\n"
"To play on this server, restart\n"
"the game and don't load any addons.\n"
"SRB2 will automatically add\n"
"everything you need when you join.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
else if (i == 1)
cl_mode = CL_ASKJOIN;
else
{ {
// must download something cl_mode = CL_ASKFULLFILELIST;
// can we, though? cl_lastcheckedfilecount = 0;
if (!CL_CheckDownloadable()) // nope! return true;
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You cannot connect to this server\n"
"because you cannot download the files\n"
"that you are missing from the server.\n\n"
"See the console or log file for\n"
"more details.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
// no problem if can't send packet, we will retry later
if (CL_SendFileRequest())
{
cl_mode = CL_DOWNLOADFILES;
#ifndef NONET
Snake_Initialise();
#endif
}
} }
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;
} }
...@@ -1986,6 +2180,22 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic ...@@ -1986,6 +2180,22 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
return false; return false;
break; break;
case CL_ASKFULLFILELIST:
if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved
cl_mode = CL_CHECKFILES;
else if (fileneedednum != cl_lastcheckedfilecount || I_GetTime() >= *asksent)
{
if (CL_AskFileList(fileneedednum))
{
cl_lastcheckedfilecount = fileneedednum;
*asksent = I_GetTime() + NEWTICRATE;
}
}
break;
case CL_CHECKFILES:
if (!CL_FinishedFileList())
return false;
break;
case CL_DOWNLOADFILES: case CL_DOWNLOADFILES:
waitmore = false; waitmore = false;
for (i = 0; i < fileneedednum; i++) for (i = 0; i < fileneedednum; i++)
...@@ -2006,21 +2216,50 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic ...@@ -2006,21 +2216,50 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
} }
#endif #endif
cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now cl_mode = CL_LOADFILES;
/* FALLTHRU */ break;
case CL_LOADFILES:
if (CL_LoadServerFiles())
{
*asksent = 0; //This ensure the first join ask is right away
firstconnectattempttime = I_GetTime();
cl_mode = CL_ASKJOIN;
}
break;
case CL_ASKJOIN: 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;
}
#ifndef NONET #ifndef NONET
// prepare structures to save the file // prepare structures to save the file
// WARNING: this can be useless in case of server not in GS_LEVEL // WARNING: this can be useless in case of server not in GS_LEVEL
// but since the network layer doesn't provide ordered packets... // but since the network layer doesn't provide ordered packets...
CL_PrepareDownloadSaveGame(tmpsave); CL_PrepareDownloadSaveGame(tmpsave);
#endif #endif
if (CL_SendJoin()) if (I_GetTime() >= *asksent && CL_SendJoin())
{
*asksent = I_GetTime() + NEWTICRATE*3;
cl_mode = CL_WAITJOINRESPONSE; cl_mode = CL_WAITJOINRESPONSE;
}
break;
case CL_WAITJOINRESPONSE:
if (I_GetTime() >= *asksent)
{
cl_mode = CL_ASKJOIN;
}
break; break;
#ifndef NONET #ifndef NONET
case CL_DOWNLOADSAVEGAME: case CL_DOWNLOADSAVEGAME:
// At this state, the first (and only) needed file is the gamestate // At this state, the first (and only) needed file is the gamestate
...@@ -2034,8 +2273,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic ...@@ -2034,8 +2273,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
break; break;
#endif #endif
case CL_WAITJOINRESPONSE:
case CL_CONNECTED: case CL_CONNECTED:
case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect
default: default:
break; break;
...@@ -2043,7 +2282,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic ...@@ -2043,7 +2282,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
case CL_ABORTED: case CL_ABORTED:
cl_mode = CL_SEARCHING; cl_mode = CL_SEARCHING;
return false; return false;
} }
GetPackets(); GetPackets();
...@@ -2053,13 +2291,19 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic ...@@ -2053,13 +2291,19 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
if (*oldtic != I_GetTime()) if (*oldtic != I_GetTime())
{ {
I_OsPolling(); I_OsPolling();
for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
G_MapEventsToControls(&events[eventtail]);
if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1]) if (cl_mode == CL_CONFIRMCONNECT)
D_ProcessEvents(); //needed for menu system to receive inputs
else
{
for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
G_MapEventsToControls(&events[eventtail]);
}
if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1] || cl_mode == CL_ABORTED)
{ {
CONS_Printf(M_GetText("Network game synchronization aborted.\n")); CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
#ifndef NONET #ifndef NONET
if (snake) if (snake)
...@@ -2092,13 +2336,20 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic ...@@ -2092,13 +2336,20 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
#ifndef NONET #ifndef NONET
if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
{ {
if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_DOWNLOADSAVEGAME) if (!snake)
{ {
F_MenuPresTicker(true); // title sky F_MenuPresTicker(true); // title sky
F_TitleScreenTicker(true); F_TitleScreenTicker(true);
F_TitleScreenDrawer(); F_TitleScreenDrawer();
} }
CL_DrawConnectionStatus(); 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 I_UpdateNoVsync(); // page flip or blit buffer
if (moviemode) if (moviemode)
M_SaveFrame(); M_SaveFrame();
...@@ -2160,8 +2411,10 @@ static void CL_ConnectToServer(void) ...@@ -2160,8 +2411,10 @@ static void CL_ConnectToServer(void)
ClearAdminPlayers(); ClearAdminPlayers();
pnumnodes = 1; pnumnodes = 1;
oldtic = I_GetTime() - 1; oldtic = I_GetTime() - 1;
#ifndef NONET #ifndef NONET
asksent = (tic_t) - TICRATE; asksent = (tic_t) - TICRATE;
firstconnectattempttime = I_GetTime();
i = SL_SearchServer(servernode); i = SL_SearchServer(servernode);
...@@ -2602,8 +2855,16 @@ void CL_Reset(void) ...@@ -2602,8 +2855,16 @@ void CL_Reset(void)
CV_RevertNetVars(); CV_RevertNetVars();
// make sure we don't leave any fileneeded gunk over from a failed join // make sure we don't leave any fileneeded gunk over from a failed join
FreeFileNeeded();
fileneedednum = 0; fileneedednum = 0;
memset(fileneeded, 0, sizeof(fileneeded));
#ifndef NONET
totalfilesrequestednum = 0;
totalfilesrequestedsize = 0;
#endif
firstconnectattempttime = 0;
serverisfull = false;
connectiontimeout = (tic_t)cv_nettimeout.value; //reset this temporary hack
// D_StartTitle should get done now, but the calling function will handle it // D_StartTitle should get done now, but the calling function will handle it
} }
...@@ -3830,31 +4091,40 @@ static void HandlePacketFromAwayNode(SINT8 node) ...@@ -3830,31 +4091,40 @@ static void HandlePacketFromAwayNode(SINT8 node)
switch (netbuffer->packettype) switch (netbuffer->packettype)
{ {
case PT_ASKINFOVIAMS: case PT_ASKINFOVIAMS:
#if 0 Net_CloseConnection(node);
break;
case PT_TELLFILESNEEDED:
if (server && serverrunning) if (server && serverrunning)
{ {
INT32 clientnode; UINT8 *p;
if (ms_RoomId < 0) // ignore if we're not actually on the MS right now INT32 firstfile = netbuffer->u.filesneedednum;
{
Net_CloseConnection(node); // and yes, close connection netbuffer->packettype = PT_MOREFILESNEEDED;
return; netbuffer->u.filesneededcfg.first = firstfile;
} netbuffer->u.filesneededcfg.more = 0;
clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
if (clientnode != -1) p = PutFileNeeded(firstfile);
{
SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time)); HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
SV_SendPlayerInfo(clientnode); // Send extra info }
Net_CloseConnection(clientnode); else // Shouldn't get this if you aren't the server...?
// Don't close connection to MS... Net_CloseConnection(node);
} break;
else
Net_CloseConnection(node); // ...unless the IP address is not valid case PT_MOREFILESNEEDED:
if (server && serverrunning)
{ // But wait I thought I'm the server?
Net_CloseConnection(node);
break;
}
SERVERONLY
if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum)
{
D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first);
if (!netbuffer->u.filesneededcfg.more)
cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list
} }
else
Net_CloseConnection(node); // you're not supposed to get it, so ignore it
#else
Net_CloseConnection(node);
#endif
break; break;
case PT_ASKINFO: case PT_ASKINFO:
...@@ -3880,13 +4150,24 @@ static void HandlePacketFromAwayNode(SINT8 node) ...@@ -3880,13 +4150,24 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (!reason) if (!reason)
I_Error("Out of memory!\n"); I_Error("Out of memory!\n");
D_QuitNetGame(); if (strstr(reason, "Maximum players reached"))
CL_Reset(); {
D_StartTitle(); 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"), M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
reason), NULL, MM_NOTHING); reason), NULL, MM_NOTHING);
D_QuitNetGame();
CL_Reset();
D_StartTitle();
free(reason); free(reason);
// Will be reset by caller. Signals refusal. // Will be reset by caller. Signals refusal.
......
...@@ -26,7 +26,7 @@ The 'packet version' is used to distinguish packet formats. ...@@ -26,7 +26,7 @@ The 'packet version' is used to distinguish packet formats.
This version is independent of VERSION and SUBVERSION. Different This version is independent of VERSION and SUBVERSION. Different
applications may follow different packet versions. applications may follow different packet versions.
*/ */
#define PACKETVERSION 3 #define PACKETVERSION 4
// Network play related stuff. // Network play related stuff.
// There is a data struct that stores network // There is a data struct that stores network
...@@ -90,6 +90,9 @@ typedef enum ...@@ -90,6 +90,9 @@ typedef enum
PT_LOGIN, // Login attempt from the client. PT_LOGIN, // Login attempt from the client.
PT_TELLFILESNEEDED, // Client, to server: "what other files do I need starting from this number?"
PT_MOREFILESNEEDED, // Server, to client: "you need these (+ more on top of those)"
PT_PING, // Packet sent to tell clients the other client's latency to server. PT_PING, // Packet sent to tell clients the other client's latency to server.
NUMPACKETTYPE NUMPACKETTYPE
} packettype_t; } packettype_t;
...@@ -200,6 +203,9 @@ typedef struct ...@@ -200,6 +203,9 @@ typedef struct
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME]; char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME];
} ATTRPACK clientconfig_pak; } ATTRPACK clientconfig_pak;
#define SV_DEDICATED 0x40 // server is dedicated
#define SV_LOTSOFADDONS 0x20 // flag used to ask for full file list in d_netfil
#define MAXSERVERNAME 32 #define MAXSERVERNAME 32
#define MAXFILENEEDED 915 #define MAXFILENEEDED 915
// This packet is too large // This packet is too large
...@@ -221,7 +227,7 @@ typedef struct ...@@ -221,7 +227,7 @@ typedef struct
char gametypename[24]; char gametypename[24];
UINT8 modifiedgame; UINT8 modifiedgame;
UINT8 cheatsenabled; UINT8 cheatsenabled;
UINT8 isdedicated; UINT8 flags;
UINT8 fileneedednum; UINT8 fileneedednum;
tic_t time; tic_t time;
tic_t leveltime; tic_t leveltime;
...@@ -275,6 +281,14 @@ typedef struct ...@@ -275,6 +281,14 @@ typedef struct
UINT8 ctfteam; UINT8 ctfteam;
} ATTRPACK plrconfig; } ATTRPACK plrconfig;
typedef struct
{
INT32 first;
UINT8 num;
UINT8 more;
UINT8 files[MAXFILENEEDED]; // is filled with writexxx (byteptr.h)
} ATTRPACK filesneededconfig_pak;
// //
// Network packet data // Network packet data
// //
...@@ -304,6 +318,8 @@ typedef struct ...@@ -304,6 +318,8 @@ typedef struct
msaskinfo_pak msaskinfo; // 22 bytes msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?)
INT32 filesneedednum; // 4 bytes
filesneededconfig_pak filesneededcfg; // ??? bytes
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
} u; // This is needed to pack diff packet types data together } u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t; } ATTRPACK doomdata_t;
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
#include "m_cond.h" // condition initialization #include "m_cond.h" // condition initialization
#include "fastcmp.h" #include "fastcmp.h"
#include "keys.h" #include "keys.h"
#include "filesrch.h" // refreshdirmenu, mainwadstally #include "filesrch.h" // refreshdirmenu
#include "g_input.h" // tutorial mode control scheming #include "g_input.h" // tutorial mode control scheming
#include "m_perfstats.h" #include "m_perfstats.h"
...@@ -96,11 +96,8 @@ int SUBVERSION; ...@@ -96,11 +96,8 @@ int SUBVERSION;
// platform independant focus loss // platform independant focus loss
UINT8 window_notinfocus = false; UINT8 window_notinfocus = false;
// static addfilelist_t startupwadfiles;
// DEMO LOOP static addfilelist_t startuppwads;
//
static char *startupwadfiles[MAX_WADFILES];
static char *startuppwads[MAX_WADFILES];
boolean devparm = false; // started game with -devparm boolean devparm = false; // started game with -devparm
...@@ -119,6 +116,9 @@ boolean midi_disabled = false; ...@@ -119,6 +116,9 @@ boolean midi_disabled = false;
boolean sound_disabled = false; boolean sound_disabled = false;
boolean digital_disabled = false; boolean digital_disabled = false;
//
// DEMO LOOP
//
boolean advancedemo; boolean advancedemo;
#ifdef DEBUGFILE #ifdef DEBUGFILE
INT32 debugload = 0; INT32 debugload = 0;
...@@ -860,35 +860,47 @@ void D_StartTitle(void) ...@@ -860,35 +860,47 @@ void D_StartTitle(void)
tutorialmode = false; tutorialmode = false;
} }
// static void D_AddFile(addfilelist_t *list, const char *file)
// D_AddFile
//
static void D_AddFile(char **list, const char *file)
{ {
size_t pnumwadfiles;
char *newfile; char *newfile;
size_t index = 0;
for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++) if (list->files == NULL)
; {
list->files = calloc(sizeof(list->files), 2);
list->numfiles = 1;
}
else
{
index = list->numfiles;
list->files = realloc(list->files, sizeof(list->files) * ((++list->numfiles) + 1));
if (list->files == NULL)
I_Error("D_AddFile: No more free memory to add file %s (list reallocation)", file);
}
newfile = malloc(strlen(file) + 1); newfile = malloc(strlen(file) + 1);
if (!newfile) if (!newfile)
{ I_Error("D_AddFile: No more free memory to add file %s (filename allocation)", file);
I_Error("No more free memory to AddFile %s",file);
}
strcpy(newfile, file); strcpy(newfile, file);
list[pnumwadfiles] = newfile; list->files[index] = newfile;
list->files[index + 1] = NULL;
} }
static inline void D_CleanFile(char **list) static inline void D_CleanFile(addfilelist_t *list)
{ {
size_t pnumwadfiles; if (list->files)
for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++)
{ {
free(list[pnumwadfiles]); size_t pnumwadfiles = 0;
list[pnumwadfiles] = NULL;
for (; pnumwadfiles < list->numfiles; pnumwadfiles++)
free(list->files[pnumwadfiles]);
free(list->files);
list->files = NULL;
} }
list->numfiles = 0;
} }
///\brief Checks if a netgame URL is being handled, and changes working directory to the EXE's if so. ///\brief Checks if a netgame URL is being handled, and changes working directory to the EXE's if so.
...@@ -972,7 +984,7 @@ static void IdentifyVersion(void) ...@@ -972,7 +984,7 @@ static void IdentifyVersion(void)
// Load the IWAD // Load the IWAD
if (srb2wad != NULL && FIL_ReadFileOK(srb2wad)) if (srb2wad != NULL && FIL_ReadFileOK(srb2wad))
D_AddFile(startupwadfiles, srb2wad); D_AddFile(&startupwadfiles, srb2wad);
else else
I_Error("srb2.pk3 not found! Expected in %s, ss file: %s\n", srb2waddir, srb2wad); I_Error("srb2.pk3 not found! Expected in %s, ss file: %s\n", srb2waddir, srb2wad);
...@@ -983,14 +995,14 @@ static void IdentifyVersion(void) ...@@ -983,14 +995,14 @@ static void IdentifyVersion(void)
// checking in D_SRB2Main // checking in D_SRB2Main
// Add the maps // Add the maps
D_AddFile(startupwadfiles, va(pandf,srb2waddir,"zones.pk3")); D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "zones.pk3"));
// Add the players // Add the players
D_AddFile(startupwadfiles, va(pandf,srb2waddir, "player.dta")); D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "player.dta"));
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
// Add our crappy patches to fix our bugs // Add our crappy patches to fix our bugs
D_AddFile(startupwadfiles, va(pandf,srb2waddir,"patch.pk3")); D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "patch.pk3"));
#endif #endif
#if !defined (HAVE_SDL) || defined (HAVE_MIXER) #if !defined (HAVE_SDL) || defined (HAVE_MIXER)
...@@ -1000,7 +1012,7 @@ static void IdentifyVersion(void) ...@@ -1000,7 +1012,7 @@ static void IdentifyVersion(void)
const char *musicpath = va(pandf,srb2waddir,str);\ const char *musicpath = va(pandf,srb2waddir,str);\
int ms = W_VerifyNMUSlumps(musicpath, false); \ int ms = W_VerifyNMUSlumps(musicpath, false); \
if (ms == 1) \ if (ms == 1) \
D_AddFile(startupwadfiles, musicpath); \ D_AddFile(&startupwadfiles, musicpath); \
else if (ms == 0) \ else if (ms == 0) \
I_Error("File "str" has been modified with non-music/sound lumps"); \ I_Error("File "str" has been modified with non-music/sound lumps"); \
} }
...@@ -1187,7 +1199,7 @@ void D_SRB2Main(void) ...@@ -1187,7 +1199,7 @@ void D_SRB2Main(void)
const char *s = M_GetNextParm(); const char *s = M_GetNextParm();
if (s) // Check for NULL? if (s) // Check for NULL?
D_AddFile(startuppwads, s); D_AddFile(&startuppwads, s);
} }
} }
} }
...@@ -1227,8 +1239,8 @@ void D_SRB2Main(void) ...@@ -1227,8 +1239,8 @@ void D_SRB2Main(void)
// load wad, including the main wad file // load wad, including the main wad file
CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n"); CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n");
W_InitMultipleFiles(startupwadfiles); W_InitMultipleFiles(&startupwadfiles);
D_CleanFile(startupwadfiles); D_CleanFile(&startupwadfiles);
#ifndef DEVELOP // md5s last updated 22/02/20 (ddmmyy) #ifndef DEVELOP // md5s last updated 22/02/20 (ddmmyy)
...@@ -1243,8 +1255,6 @@ void D_SRB2Main(void) ...@@ -1243,8 +1255,6 @@ void D_SRB2Main(void)
// ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for.
#endif //ifndef DEVELOP #endif //ifndef DEVELOP
mainwadstally = packetsizetally; // technically not accurate atm, remember to port the two-stage -file process from kart in 2.2.x
cht_Init(); cht_Init();
//---------------------------------------------------- READY SCREEN //---------------------------------------------------- READY SCREEN
...@@ -1275,9 +1285,12 @@ void D_SRB2Main(void) ...@@ -1275,9 +1285,12 @@ void D_SRB2Main(void)
I_RegisterSysCommands(); I_RegisterSysCommands();
CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n"); if (startuppwads.numfiles)
W_InitMultipleFiles(startuppwads); {
D_CleanFile(startuppwads); CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n");
W_InitMultipleFiles(&startuppwads);
D_CleanFile(&startuppwads);
}
CONS_Printf("HU_LoadGraphics()...\n"); CONS_Printf("HU_LoadGraphics()...\n");
HU_LoadGraphics(); HU_LoadGraphics();
......
...@@ -815,6 +815,8 @@ static const char *packettypename[NUMPACKETTYPE] = ...@@ -815,6 +815,8 @@ static const char *packettypename[NUMPACKETTYPE] =
"CLIENTJOIN", "CLIENTJOIN",
"NODETIMEOUT", "NODETIMEOUT",
"LOGIN", "LOGIN",
"TELLFILESNEEDED",
"MOREFILESNEEDED",
"PING" "PING"
}; };
......
...@@ -3322,10 +3322,9 @@ static void Command_Addfile(void) ...@@ -3322,10 +3322,9 @@ static void Command_Addfile(void)
break; break;
++p; ++p;
// check total packet size and no of files currently loaded // check no of files currently loaded
// See W_LoadWadFile in w_wad.c // See W_LoadWadFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES) if (numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8)))
{ {
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
return; return;
...@@ -3401,9 +3400,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) ...@@ -3401,9 +3400,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
return; return;
} }
// See W_LoadWadFile in w_wad.c if (numwadfiles >= MAX_WADFILES)
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8)))
toomany = true; toomany = true;
else else
ncs = findfile(filename,md5sum,true); ncs = findfile(filename,md5sum,true);
...@@ -3485,7 +3482,13 @@ static void Command_ListWADS_f(void) ...@@ -3485,7 +3482,13 @@ static void Command_ListWADS_f(void)
{ {
INT32 i = numwadfiles; INT32 i = numwadfiles;
char *tempname; char *tempname;
CONS_Printf(M_GetText("There are %d wads loaded:\n"),numwadfiles);
#ifdef ENFORCE_WAD_LIMIT
CONS_Printf(M_GetText("There are %d/%d files loaded:\n"),numwadfiles,MAX_WADFILES);
#else
CONS_Printf(M_GetText("There are %d files loaded:\n"),numwadfiles);
#endif
for (i--; i >= 0; i--) for (i--; i >= 0; i--)
{ {
nameonly(tempname = va("%s", wadfiles[i]->filename)); nameonly(tempname = va("%s", wadfiles[i]->filename));
......
...@@ -73,6 +73,7 @@ extern consvar_t cv_teamscramble; ...@@ -73,6 +73,7 @@ extern consvar_t cv_teamscramble;
extern consvar_t cv_scrambleonchange; extern consvar_t cv_scrambleonchange;
extern consvar_t cv_netstat; extern consvar_t cv_netstat;
extern consvar_t cv_nettimeout;
extern consvar_t cv_countdowntime; extern consvar_t cv_countdowntime;
extern consvar_t cv_runscripts; extern consvar_t cv_runscripts;
......
...@@ -87,7 +87,7 @@ static filetran_t transfer[MAXNETNODES]; ...@@ -87,7 +87,7 @@ static filetran_t transfer[MAXNETNODES];
// Receiver structure // Receiver structure
INT32 fileneedednum; // Number of files needed to join the server INT32 fileneedednum; // Number of files needed to join the server
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files fileneeded_t *fileneeded; // List of needed files
static tic_t lasttimeackpacketsent = 0; static tic_t lasttimeackpacketsent = 0;
char downloaddir[512] = "DOWNLOAD"; char downloaddir[512] = "DOWNLOAD";
...@@ -105,6 +105,10 @@ static pauseddownload_t *pauseddownload = NULL; ...@@ -105,6 +105,10 @@ static pauseddownload_t *pauseddownload = NULL;
#ifndef NONET #ifndef NONET
// for cl loading screen // for cl loading screen
INT32 lastfilenum = -1; INT32 lastfilenum = -1;
INT32 downloadcompletednum = 0;
UINT32 downloadcompletedsize = 0;
INT32 totalfilesrequestednum = 0;
UINT32 totalfilesrequestedsize = 0;
#endif #endif
luafiletransfer_t *luafiletransfers = NULL; luafiletransfer_t *luafiletransfers = NULL;
...@@ -119,19 +123,40 @@ char luafiledir[256 + 16] = "luafiles"; ...@@ -119,19 +123,40 @@ char luafiledir[256 + 16] = "luafiles";
* Used to have size limiting built in - now handled via W_LoadWadFile in w_wad.c * Used to have size limiting built in - now handled via W_LoadWadFile in w_wad.c
* *
*/ */
UINT8 *PutFileNeeded(void) UINT8 *PutFileNeeded(UINT16 firstfile)
{ {
size_t i, count = 0; size_t i;
UINT8 *p = netbuffer->u.serverinfo.fileneeded; UINT8 count = 0;
UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded;
UINT8 *p = p_start;
char wadfilename[MAX_WADPATH] = ""; char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus; UINT8 filestatus;
for (i = 0; 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 it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important) if (!wadfiles[i]->important)
continue; continue;
if (firstfile)
{ // Skip files until we reach the first file.
firstfile--;
continue;
}
nameonly(strcpy(wadfilename, wadfiles[i]->filename));
// Look below at the WRITE macros to understand what these numbers mean.
if (p + 1 + 4 + min(strlen(wadfilename) + 1, MAX_WADPATH) + 16 > p_start + MAXFILENEEDED)
{
// Too many files to send all at once
if (netbuffer->packettype == PT_MOREFILESNEEDED)
netbuffer->u.filesneededcfg.more = 1;
else
netbuffer->u.serverinfo.flags |= SV_LOTSOFADDONS;
break;
}
filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS
// Store in the upper four bits // Store in the upper four bits
...@@ -146,32 +171,52 @@ UINT8 *PutFileNeeded(void) ...@@ -146,32 +171,52 @@ UINT8 *PutFileNeeded(void)
count++; count++;
WRITEUINT32(p, wadfiles[i]->filesize); WRITEUINT32(p, wadfiles[i]->filesize);
nameonly(strcpy(wadfilename, wadfiles[i]->filename));
WRITESTRINGN(p, wadfilename, MAX_WADPATH); WRITESTRINGN(p, wadfilename, MAX_WADPATH);
WRITEMEM(p, wadfiles[i]->md5sum, 16); WRITEMEM(p, wadfiles[i]->md5sum, 16);
} }
netbuffer->u.serverinfo.fileneedednum = (UINT8)count;
if (netbuffer->packettype == PT_MOREFILESNEEDED)
netbuffer->u.filesneededcfg.num = count;
else
netbuffer->u.serverinfo.fileneedednum = count;
return p; return p;
} }
void AllocFileNeeded(INT32 size)
{
if (fileneeded == NULL)
fileneeded = Z_Calloc(sizeof(fileneeded_t) * size, PU_STATIC, NULL);
}
void FreeFileNeeded(void)
{
if (fileneeded == NULL)
Z_Free(fileneeded);
fileneeded = NULL;
}
/** Parses the serverinfo packet and fills the fileneeded table on client /** Parses the serverinfo packet and fills the fileneeded table on client
* *
* \param fileneedednum_parm The number of files needed to join the server * \param fileneedednum_parm The number of files needed to join the server
* \param fileneededstr The memory block containing the list of needed files * \param fileneededstr The memory block containing the list of needed files
* *
*/ */
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile)
{ {
INT32 i; INT32 i;
UINT8 *p; UINT8 *p;
UINT8 filestatus; UINT8 filestatus;
fileneedednum = fileneedednum_parm; fileneedednum = firstfile + fileneedednum_parm;
p = (UINT8 *)fileneededstr; p = (UINT8 *)fileneededstr;
for (i = 0; i < fileneedednum; i++)
AllocFileNeeded(fileneedednum);
for (i = firstfile; i < fileneedednum; i++)
{ {
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet fileneeded[i].type = FILENEEDED_WAD;
fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet
fileneeded[i].justdownloaded = false; fileneeded[i].justdownloaded = false;
filestatus = READUINT8(p); // The first byte is the file status filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].willsend = (UINT8)(filestatus >> 4); fileneeded[i].willsend = (UINT8)(filestatus >> 4);
...@@ -188,7 +233,10 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave) ...@@ -188,7 +233,10 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
lastfilenum = -1; lastfilenum = -1;
#endif #endif
AllocFileNeeded(1);
fileneedednum = 1; fileneedednum = 1;
fileneeded[0].type = FILENEEDED_SAVEGAME;
fileneeded[0].status = FS_REQUESTED; fileneeded[0].status = FS_REQUESTED;
fileneeded[0].justdownloaded = false; fileneeded[0].justdownloaded = false;
fileneeded[0].totalsize = UINT32_MAX; fileneeded[0].totalsize = UINT32_MAX;
...@@ -371,17 +419,8 @@ INT32 CL_CheckFiles(void) ...@@ -371,17 +419,8 @@ INT32 CL_CheckFiles(void)
{ {
INT32 i, j; INT32 i, j;
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
INT32 ret = 1; size_t filestoload = 0;
size_t packetsize = 0; boolean downloadrequired = false;
size_t filestoget = 0;
// if (M_CheckParm("-nofiles"))
// return 1;
// the first is the iwad (the main wad file)
// we don't care if it's called srb2.pk3 or not.
// Never download the IWAD, just assume it's there and identical
fileneeded[0].status = FS_OPEN;
// Modified game handling -- check for an identical file list // Modified game handling -- check for an identical file list
// must be identical in files loaded AND in order // must be identical in files loaded AND in order
...@@ -389,7 +428,7 @@ INT32 CL_CheckFiles(void) ...@@ -389,7 +428,7 @@ INT32 CL_CheckFiles(void)
if (modifiedgame) if (modifiedgame)
{ {
CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n"); CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n");
for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;) for (i = 0, j = mainwads+1; i < fileneedednum || j < numwadfiles;)
{ {
if (j < numwadfiles && !wadfiles[j]->important) if (j < numwadfiles && !wadfiles[j]->important)
{ {
...@@ -416,15 +455,21 @@ INT32 CL_CheckFiles(void) ...@@ -416,15 +455,21 @@ INT32 CL_CheckFiles(void)
return 1; return 1;
} }
// See W_LoadWadFile in w_wad.c for (i = 0; i < fileneedednum; i++)
packetsize = packetsizetally;
for (i = 1; i < fileneedednum; i++)
{ {
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)
downloadrequired = true;
if (fileneeded[i].status != FS_OPEN)
filestoload++;
if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics
continue;
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// Check in already loaded files // Check in already loaded files
for (j = 1; wadfiles[j]; j++) for (j = mainwads+1; wadfiles[j]; j++)
{ {
nameonly(strcpy(wadfilename, wadfiles[j]->filename)); nameonly(strcpy(wadfilename, wadfiles[j]->filename));
if (!stricmp(wadfilename, fileneeded[i].filename) && if (!stricmp(wadfilename, fileneeded[i].filename) &&
...@@ -432,37 +477,30 @@ INT32 CL_CheckFiles(void) ...@@ -432,37 +477,30 @@ INT32 CL_CheckFiles(void)
{ {
CONS_Debug(DBG_NETPLAY, "already loaded\n"); CONS_Debug(DBG_NETPLAY, "already loaded\n");
fileneeded[i].status = FS_OPEN; fileneeded[i].status = FS_OPEN;
break; return 4;
} }
} }
if (fileneeded[i].status != FS_NOTFOUND)
continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
if ((numwadfiles+filestoget >= MAX_WADFILES)
|| (packetsize > MAXFILENEEDED*sizeof(UINT8)))
return 3;
filestoget++; fileneeded[i].status = FS_NOTFOUND; //findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND) return 4;
ret = 0;
} }
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 // Load it now
void CL_LoadServerFiles(void) boolean CL_LoadServerFiles(void)
{ {
INT32 i; INT32 i;
// if (M_CheckParm("-nofiles")) for (i = 0; i < fileneedednum; i++)
// return;
for (i = 1; i < fileneedednum; i++)
{ {
if (fileneeded[i].status == FS_OPEN) if (fileneeded[i].status == FS_OPEN)
continue; // Already loaded continue; // Already loaded
...@@ -471,6 +509,7 @@ void CL_LoadServerFiles(void) ...@@ -471,6 +509,7 @@ void CL_LoadServerFiles(void)
P_AddWadFile(fileneeded[i].filename); P_AddWadFile(fileneeded[i].filename);
G_SetGameModified(true); G_SetGameModified(true);
fileneeded[i].status = FS_OPEN; fileneeded[i].status = FS_OPEN;
return false;
} }
else if (fileneeded[i].status == FS_MD5SUMBAD) else if (fileneeded[i].status == FS_MD5SUMBAD)
I_Error("Wrong version of file %s", fileneeded[i].filename); I_Error("Wrong version of file %s", fileneeded[i].filename);
...@@ -496,6 +535,7 @@ void CL_LoadServerFiles(void) ...@@ -496,6 +535,7 @@ void CL_LoadServerFiles(void)
fileneeded[i].status, s); fileneeded[i].status, s);
} }
} }
return true;
} }
void AddLuaFileTransfer(const char *filename, const char *mode) void AddLuaFileTransfer(const char *filename, const char *mode)
...@@ -677,7 +717,10 @@ void CL_PrepareDownloadLuaFile(void) ...@@ -677,7 +717,10 @@ void CL_PrepareDownloadLuaFile(void)
netbuffer->packettype = PT_ASKLUAFILE; netbuffer->packettype = PT_ASKLUAFILE;
HSendPacket(servernode, true, 0, 0); HSendPacket(servernode, true, 0, 0);
AllocFileNeeded(1);
fileneedednum = 1; fileneedednum = 1;
fileneeded[0].type = FILENEEDED_LUAFILE;
fileneeded[0].status = FS_REQUESTED; fileneeded[0].status = FS_REQUESTED;
fileneeded[0].justdownloaded = false; fileneeded[0].justdownloaded = false;
fileneeded[0].totalsize = UINT32_MAX; fileneeded[0].totalsize = UINT32_MAX;
...@@ -756,7 +799,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid ...@@ -756,7 +799,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid
// This formerly checked if (!findfile(p->id.filename, NULL, true)) // This formerly checked if (!findfile(p->id.filename, NULL, true))
// Not found // Not found
// Don't inform client (probably someone who thought they could leak 2.2 ACZ) // Don't inform client
DEBFILE(va("Client %d request %s: not found\n", node, filename)); DEBFILE(va("Client %d request %s: not found\n", node, filename));
free(p->id.filename); free(p->id.filename);
free(p); free(p);
...@@ -1341,6 +1384,7 @@ void PT_FileFragment(void) ...@@ -1341,6 +1384,7 @@ void PT_FileFragment(void)
// Tell the server we have received the file // Tell the server we have received the file
netbuffer->packettype = PT_HASLUAFILE; netbuffer->packettype = PT_HASLUAFILE;
HSendPacket(servernode, true, 0, 0); HSendPacket(servernode, true, 0, 0);
FreeFileNeeded();
} }
} }
} }
...@@ -1411,32 +1455,37 @@ void CloseNetFile(void) ...@@ -1411,32 +1455,37 @@ void CloseNetFile(void)
SV_AbortSendFiles(i); SV_AbortSendFiles(i);
// Receiving a file? // Receiving a file?
for (i = 0; i < MAX_WADFILES; i++) if (fileneeded)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) {
{ for (i = 0; i < fileneedednum; i++)
fclose(fileneeded[i].file); if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
free(fileneeded[i].ackpacket);
if (!pauseddownload && i != 0) // 0 is either srb2.srb or the gamestate...
{
// Don't remove the file, save it for later in case we resume the download
pauseddownload = malloc(sizeof(*pauseddownload));
if (!pauseddownload)
I_Error("CloseNetFile: No more memory\n");
strcpy(pauseddownload->filename, fileneeded[i].filename);
memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16);
pauseddownload->currentsize = fileneeded[i].currentsize;
pauseddownload->receivedfragments = fileneeded[i].receivedfragments;
pauseddownload->fragmentsize = fileneeded[i].fragmentsize;
}
else
{ {
free(fileneeded[i].receivedfragments); fclose(fileneeded[i].file);
// File is not complete delete it free(fileneeded[i].ackpacket);
remove(fileneeded[i].filename);
if (!pauseddownload && (fileneeded[i].type == FILENEEDED_WAD || i != 0)) // 0 is the gamestate...
{
// Don't remove the file, save it for later in case we resume the download
pauseddownload = malloc(sizeof(*pauseddownload));
if (!pauseddownload)
I_Error("CloseNetFile: No more memory\n");
strcpy(pauseddownload->filename, fileneeded[i].filename);
memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16);
pauseddownload->currentsize = fileneeded[i].currentsize;
pauseddownload->receivedfragments = fileneeded[i].receivedfragments;
pauseddownload->fragmentsize = fileneeded[i].fragmentsize;
}
else
{
// File is not complete, delete it.
free(fileneeded[i].receivedfragments);
remove(fileneeded[i].filename);
}
} }
} }
FreeFileNeeded();
} }
void Command_Downloads_f(void) void Command_Downloads_f(void)
......
...@@ -27,6 +27,7 @@ typedef enum ...@@ -27,6 +27,7 @@ typedef enum
typedef enum typedef enum
{ {
FS_NOTCHECKED,
FS_NOTFOUND, FS_NOTFOUND,
FS_FOUND, FS_FOUND,
FS_REQUESTED, FS_REQUESTED,
...@@ -35,12 +36,20 @@ typedef enum ...@@ -35,12 +36,20 @@ typedef enum
FS_MD5SUMBAD FS_MD5SUMBAD
} filestatus_t; } filestatus_t;
typedef enum
{
FILENEEDED_WAD,
FILENEEDED_SAVEGAME,
FILENEEDED_LUAFILE
} fileneededtype_t;
typedef struct typedef struct
{ {
UINT8 willsend; // Is the server willing to send it?
char filename[MAX_WADPATH]; char filename[MAX_WADPATH];
UINT8 md5sum[16]; UINT8 md5sum[16];
filestatus_t status; // The value returned by recsearch filestatus_t status; // The value returned by recsearch
UINT8 willsend; // Is the server willing to send it?
fileneededtype_t type;
boolean justdownloaded; // To prevent late fragments from causing an I_Error boolean justdownloaded; // To prevent late fragments from causing an I_Error
// Used only for download // Used only for download
...@@ -55,19 +64,25 @@ typedef struct ...@@ -55,19 +64,25 @@ typedef struct
} fileneeded_t; } fileneeded_t;
extern INT32 fileneedednum; extern INT32 fileneedednum;
extern fileneeded_t fileneeded[MAX_WADFILES]; extern fileneeded_t *fileneeded;
extern char downloaddir[512]; extern char downloaddir[512];
#ifndef NONET #ifndef NONET
extern INT32 lastfilenum; extern INT32 lastfilenum;
extern INT32 downloadcompletednum;
extern UINT32 downloadcompletedsize;
extern INT32 totalfilesrequestednum;
extern UINT32 totalfilesrequestedsize;
#endif #endif
UINT8 *PutFileNeeded(void); void AllocFileNeeded(INT32 size);
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr); void FreeFileNeeded(void);
UINT8 *PutFileNeeded(UINT16 firstfile);
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile);
void CL_PrepareDownloadSaveGame(const char *tmpsave); void CL_PrepareDownloadSaveGame(const char *tmpsave);
INT32 CL_CheckFiles(void); INT32 CL_CheckFiles(void);
void CL_LoadServerFiles(void); boolean CL_LoadServerFiles(void);
void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod, void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod,
UINT8 fileid); UINT8 fileid);
......
...@@ -151,6 +151,9 @@ extern char logfilename[1024]; ...@@ -151,6 +151,9 @@ extern char logfilename[1024];
// Comment or uncomment this as necessary. // Comment or uncomment this as necessary.
#define USE_PATCH_DTA #define USE_PATCH_DTA
// Enforce a limit of loaded WAD files.
//#define ENFORCE_WAD_LIMIT
// Use .kart extension addons // Use .kart extension addons
//#define USE_KART //#define USE_KART
......
...@@ -337,9 +337,6 @@ size_t dir_on[menudepth]; ...@@ -337,9 +337,6 @@ size_t dir_on[menudepth];
UINT8 refreshdirmenu = 0; UINT8 refreshdirmenu = 0;
char *refreshdirname = NULL; char *refreshdirname = NULL;
size_t packetsizetally = 0;
size_t mainwadstally = 0;
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth)
{ {
filestatus_t retval = FS_NOTFOUND; filestatus_t retval = FS_NOTFOUND;
...@@ -453,8 +450,7 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl ...@@ -453,8 +450,7 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl
#endif #endif
"\5.pk3", "\5.soc", "\5.lua"}; // addfile "\5.pk3", "\5.soc", "\5.lua"}; // addfile
char filenamebuf[MAX_WADFILES][MAX_WADPATH]; static char (*filenamebuf)[MAX_WADPATH];
static boolean filemenucmp(char *haystack, char *needle) static boolean filemenucmp(char *haystack, char *needle)
{ {
...@@ -732,6 +728,10 @@ boolean preparefilemenu(boolean samedepth) ...@@ -732,6 +728,10 @@ boolean preparefilemenu(boolean samedepth)
if (ext >= EXT_LOADSTART) if (ext >= EXT_LOADSTART)
{ {
size_t i; size_t i;
if (filenamebuf == NULL)
filenamebuf = calloc(sizeof(char) * MAX_WADPATH, numwadfiles);
for (i = 0; i < numwadfiles; i++) for (i = 0; i < numwadfiles; i++)
{ {
if (!filenamebuf[i][0]) if (!filenamebuf[i][0])
...@@ -781,6 +781,12 @@ boolean preparefilemenu(boolean samedepth) ...@@ -781,6 +781,12 @@ boolean preparefilemenu(boolean samedepth)
} }
} }
if (filenamebuf)
{
free(filenamebuf);
filenamebuf = NULL;
}
closedir(dirhandle); closedir(dirhandle);
if ((menudepthleft != menudepth-1) // now for UP... entry if ((menudepthleft != menudepth-1) // now for UP... entry
......
...@@ -42,9 +42,6 @@ extern size_t dir_on[menudepth]; ...@@ -42,9 +42,6 @@ extern size_t dir_on[menudepth];
extern UINT8 refreshdirmenu; extern UINT8 refreshdirmenu;
extern char *refreshdirname; extern char *refreshdirname;
extern size_t packetsizetally;
extern size_t mainwadstally;
typedef enum typedef enum
{ {
EXT_FOLDER = 0, EXT_FOLDER = 0,
......
...@@ -3213,7 +3213,7 @@ boolean M_Responder(event_t *ev) ...@@ -3213,7 +3213,7 @@ boolean M_Responder(event_t *ev)
if (gamestate == GS_TITLESCREEN && finalecount < TICRATE) if (gamestate == GS_TITLESCREEN && finalecount < TICRATE)
return false; return false;
if (CON_Ready()) if (CON_Ready() && gamestate != GS_WAITINGPLAYERS)
return false; return false;
if (noFurtherInput) if (noFurtherInput)
...@@ -6307,6 +6307,7 @@ static void M_Addons(INT32 choice) ...@@ -6307,6 +6307,7 @@ static void M_Addons(INT32 choice)
M_SetupNextMenu(&MISC_AddonsDef); M_SetupNextMenu(&MISC_AddonsDef);
} }
#ifdef ENFORCE_WAD_LIMIT
#define width 4 #define width 4
#define vpadding 27 #define vpadding 27
#define h (BASEVIDHEIGHT-(2*vpadding)) #define h (BASEVIDHEIGHT-(2*vpadding))
...@@ -6354,6 +6355,7 @@ static void M_DrawTemperature(INT32 x, fixed_t t) ...@@ -6354,6 +6355,7 @@ static void M_DrawTemperature(INT32 x, fixed_t t)
#undef vpadding #undef vpadding
#undef h #undef h
#undef NUMCOLOURS #undef NUMCOLOURS
#endif
static char *M_AddonsHeaderPath(void) static char *M_AddonsHeaderPath(void)
{ {
...@@ -6447,21 +6449,20 @@ static void M_DrawAddons(void) ...@@ -6447,21 +6449,20 @@ static void M_DrawAddons(void)
V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, LOCATIONSTRING1); V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, LOCATIONSTRING1);
// (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1) // (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)
#ifdef ENFORCE_WAD_LIMIT
if (numwadfiles <= mainwads+1) if (numwadfiles <= mainwads+1)
y = 0; y = 0;
else if (numwadfiles >= MAX_WADFILES) else if (numwadfiles >= MAX_WADFILES)
y = FRACUNIT; y = FRACUNIT;
else else
{ {
x = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))<<FRACBITS, ((ssize_t)MAX_WADFILES - (ssize_t)(mainwads+1))<<FRACBITS); y = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))<<FRACBITS, ((ssize_t)MAX_WADFILES - (ssize_t)(mainwads+1))<<FRACBITS);
y = FixedDiv((((ssize_t)packetsizetally-(ssize_t)mainwadstally)<<FRACBITS), ((((ssize_t)MAXFILENEEDED*sizeof(UINT8)-(ssize_t)mainwadstally)-(5+22))<<FRACBITS)); // 5+22 = (a.ext + checksum length) is minimum addition to packet size tally
if (x > y)
y = x;
if (y > FRACUNIT) // happens because of how we're shrinkin' it a little if (y > FRACUNIT) // happens because of how we're shrinkin' it a little
y = FRACUNIT; y = FRACUNIT;
} }
M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y); M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y);
#endif
// DRAW MENU // DRAW MENU
x = currentMenu->x; x = currentMenu->x;
......
...@@ -104,7 +104,7 @@ static UINT16 lumpnumcacheindex = 0; ...@@ -104,7 +104,7 @@ static UINT16 lumpnumcacheindex = 0;
// GLOBALS // GLOBALS
//=========================================================================== //===========================================================================
UINT16 numwadfiles; // number of active wadfiles UINT16 numwadfiles; // number of active wadfiles
wadfile_t *wadfiles[MAX_WADFILES]; // 0 to numwadfiles-1 are valid wadfile_t **wadfiles; // 0 to numwadfiles-1 are valid
// W_Shutdown // W_Shutdown
// Closes all of the WAD files before quitting // Closes all of the WAD files before quitting
...@@ -128,6 +128,8 @@ void W_Shutdown(void) ...@@ -128,6 +128,8 @@ void W_Shutdown(void)
Z_Free(wad->lumpinfo); Z_Free(wad->lumpinfo);
Z_Free(wad); Z_Free(wad);
} }
Z_Free(wadfiles);
} }
//=========================================================================== //===========================================================================
...@@ -715,7 +717,6 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) ...@@ -715,7 +717,6 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
#ifndef NOMD5 #ifndef NOMD5
size_t i; size_t i;
#endif #endif
size_t packetsize;
UINT8 md5sum[16]; UINT8 md5sum[16];
int important; int important;
...@@ -733,9 +734,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) ...@@ -733,9 +734,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
refreshdirname = NULL; refreshdirname = NULL;
//CONS_Debug(DBG_SETUP, "Loading %s\n", filename); //CONS_Debug(DBG_SETUP, "Loading %s\n", filename);
//
// check if limit of active wadfiles // Check if the game reached the limit of active wadfiles.
//
if (numwadfiles >= MAX_WADFILES) if (numwadfiles >= MAX_WADFILES)
{ {
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
...@@ -755,24 +755,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) ...@@ -755,24 +755,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
return INT16_MAX; return INT16_MAX;
} }
// Check if wad files will overflow fileneededbuffer. Only the filename part important = !important;
// is send in the packet; cf.
// see PutFileNeeded in d_netfil.c
if ((important = !important))
{
packetsize = packetsizetally + nameonlylength(filename) + 22;
if (packetsize > MAXFILENEEDED*sizeof(UINT8))
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
if (handle)
fclose(handle);
return W_InitFileError(filename, startup);
}
packetsizetally = packetsize;
}
#ifndef NOMD5 #ifndef NOMD5
// //
...@@ -782,16 +765,17 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) ...@@ -782,16 +765,17 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
// //
W_MakeFileMD5(filename, md5sum); W_MakeFileMD5(filename, md5sum);
for (i = 0; i < numwadfiles; i++) if (wadfiles)
{ {
if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) for (i = 0; i < numwadfiles; i++)
{ {
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); if (!memcmp(wadfiles[i]->md5sum, md5sum, 16))
if (important) {
packetsizetally -= nameonlylength(filename) + 22; CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename);
if (handle) if (handle)
fclose(handle); fclose(handle);
return W_InitFileError(filename, false); return W_InitFileError(filename, false);
}
} }
} }
#endif #endif
...@@ -853,6 +837,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) ...@@ -853,6 +837,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
// add the wadfile // add the wadfile
// //
CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps); CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps);
wadfiles = Z_Realloc(wadfiles, sizeof(wadfile_t) * (numwadfiles + 1), PU_STATIC, NULL);
wadfiles[numwadfiles] = wadfile; wadfiles[numwadfiles] = wadfile;
numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
...@@ -898,13 +883,14 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) ...@@ -898,13 +883,14 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
* *
* \param filenames A null-terminated list of files to use. * \param filenames A null-terminated list of files to use.
*/ */
void W_InitMultipleFiles(char **filenames) void W_InitMultipleFiles(addfilelist_t *list)
{ {
// will be realloced as lumps are added size_t i = 0;
for (; *filenames; filenames++)
for (; i < list->numfiles; i++)
{ {
//CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames); //CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames);
W_InitFile(*filenames, numwadfiles < mainwads, true); W_InitFile(list->files[i], numwadfiles < mainwads, true);
} }
} }
...@@ -913,7 +899,7 @@ void W_InitMultipleFiles(char **filenames) ...@@ -913,7 +899,7 @@ void W_InitMultipleFiles(char **filenames)
*/ */
static boolean TestValidLump(UINT16 wad, UINT16 lump) static boolean TestValidLump(UINT16 wad, UINT16 lump)
{ {
I_Assert(wad < MAX_WADFILES); I_Assert(wad < numwadfiles);
if (!wadfiles[wad]) // make sure the wad file exists if (!wadfiles[wad]) // make sure the wad file exists
return false; return false;
...@@ -1838,7 +1824,7 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5) ...@@ -1838,7 +1824,7 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5)
#else #else
I_Error I_Error
#endif #endif
(M_GetText("File is old, is corrupt or has been modified: %s (found md5: %s, wanted: %s)\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5); (M_GetText("File is old, is corrupt or has been modified:\n%s\nFound MD5: %s\nWanted MD5: %s\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5);
} }
#endif #endif
} }
......
...@@ -96,9 +96,15 @@ virtlump_t* vres_Find(const virtres_t*, const char*); ...@@ -96,9 +96,15 @@ virtlump_t* vres_Find(const virtres_t*, const char*);
// DYNAMIC WAD LOADING // DYNAMIC WAD LOADING
// ========================================================================= // =========================================================================
// Maximum of files that can be loaded
// (there is a max of simultaneous open files anyway)
#ifdef ENFORCE_WAD_LIMIT
#define MAX_WADFILES 2048 // This cannot be any higher than UINT16_MAX.
#else
#define MAX_WADFILES UINT16_MAX
#endif
#define MAX_WADPATH 512 #define MAX_WADPATH 512
#define MAX_WADFILES 48 // maximum of wad files used at the same time
// (there is a max of simultaneous open files anyway, and this should be plenty)
#define lumpcache_t void * #define lumpcache_t void *
...@@ -127,11 +133,17 @@ typedef struct wadfile_s ...@@ -127,11 +133,17 @@ typedef struct wadfile_s
boolean important; // also network - !W_VerifyNMUSlumps boolean important; // also network - !W_VerifyNMUSlumps
} wadfile_t; } wadfile_t;
#define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word #define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad file number in upper word
#define LUMPNUM(lumpnum) (UINT16)((lumpnum)&0xFFFF) // lump number for this pwad #define LUMPNUM(lumpnum) (UINT16)((lumpnum)&0xFFFF) // lump number for this pwad
extern UINT16 numwadfiles; extern UINT16 numwadfiles;
extern wadfile_t *wadfiles[MAX_WADFILES]; extern wadfile_t **wadfiles;
typedef struct
{
char **files;
size_t numfiles;
} addfilelist_t;
// ========================================================================= // =========================================================================
...@@ -143,7 +155,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors); ...@@ -143,7 +155,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors);
UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup); UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup);
// W_InitMultipleFiles exits if a file was not found, but not if all is okay. // W_InitMultipleFiles exits if a file was not found, but not if all is okay.
void W_InitMultipleFiles(char **filenames); void W_InitMultipleFiles(addfilelist_t *list);
const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump); const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
const char *W_CheckNameForNum(lumpnum_t lumpnum); const char *W_CheckNameForNum(lumpnum_t lumpnum);
......