From 9ac3fd202f35f217d5844f4626c97a5808afb1b3 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 16 Oct 2018 00:00:53 +0200 Subject: [PATCH 01/33] Add a Snake minigame to the downloading screen --- src/d_clisrv.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3603bb20d..893bf47d6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1152,6 +1152,191 @@ static void CV_LoadPlayerNames(UINT8 **p) } #ifdef CLIENT_LOADINGSCREEN +#define SNAKE_SPEED 4 +#define SNAKE_NUM_BLOCKS_X 24 +#define SNAKE_NUM_BLOCKS_Y 14 +#define SNAKE_BLOCK_SIZE 8 +#define SNAKE_MAP_WIDTH (SNAKE_NUM_BLOCKS_X * SNAKE_BLOCK_SIZE) +#define SNAKE_MAP_HEIGHT (SNAKE_NUM_BLOCKS_Y * SNAKE_BLOCK_SIZE) +#define SNAKE_BORDER_SIZE 8 +#define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) +#define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) +#define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 64) +#define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) + +typedef struct snake_s +{ + tic_t time; + tic_t nextupdate; + boolean gameover; + + UINT8 snakedir; + UINT8 snakeprevdir; + + UINT16 snakelength; + UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakey[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakecolor[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + + UINT8 applex; + UINT8 appley; + UINT8 applecolor; +} snake_t; + +static snake_t *snake = NULL; + +static void CL_InitialiseSnake() +{ + if (!snake) + snake = malloc(sizeof(snake_t)); + + snake->time = 0; + snake->nextupdate = SNAKE_SPEED; + snake->gameover = false; + + snake->snakedir = 0; + snake->snakeprevdir = snake->snakedir; + + snake->snakelength = 1; + snake->snakex[0] = rand() % SNAKE_NUM_BLOCKS_X; + snake->snakey[0] = rand() % SNAKE_NUM_BLOCKS_Y; + snake->snakecolor[0] = rand() % 256; + + snake->applex = rand() % SNAKE_NUM_BLOCKS_X; + snake->appley = rand() % SNAKE_NUM_BLOCKS_Y; + snake->applecolor = rand() % 256; +} + +static void CL_HandleSnake(INT32 key) +{ + UINT8 x, y; + UINT16 i; + + snake->time++; + + // Update direction + switch (key) + { + case KEY_LEFTARROW: + if (snake->snakeprevdir != 2) + snake->snakedir = 1; + break; + case KEY_RIGHTARROW: + if (snake->snakeprevdir != 1) + snake->snakedir = 2; + break; + case KEY_UPARROW: + if (snake->snakeprevdir != 4) + snake->snakedir = 3; + break; + case KEY_DOWNARROW: + if (snake->snakeprevdir != 3) + snake->snakedir = 4; + break; + } + + snake->nextupdate--; + if (snake->nextupdate) + return; + snake->nextupdate = SNAKE_SPEED; + + snake->snakeprevdir = snake->snakedir; + + if (snake->gameover) + return; + + // Find new position + x = snake->snakex[0]; + y = snake->snakey[0]; + switch (snake->snakedir) + { + case 1: + x = x > 0 ? x - 1 : SNAKE_NUM_BLOCKS_X - 1; + break; + case 2: + x = x < SNAKE_NUM_BLOCKS_X - 1 ? x + 1 : 0; + break; + case 3: + y = y > 0 ? y - 1 : SNAKE_NUM_BLOCKS_Y - 1; + break; + case 4: + y = y < SNAKE_NUM_BLOCKS_Y - 1 ? y + 1 : 0; + break; + } + + // Check collision with snake + for (i = 1; i < snake->snakelength - 1; i++) + if (x == snake->snakex[i] && y == snake->snakey[i]) + { + snake->gameover = true; + S_StartSound(NULL, sfx_lose); + return; + } + + // Check collision with apple + if (x == snake->applex && y == snake->appley) + { + snake->snakelength++; + snake->snakex[snake->snakelength - 1] = snake->snakex[snake->snakelength - 2]; + snake->snakey[snake->snakelength - 1] = snake->snakey[snake->snakelength - 2]; + snake->snakecolor[snake->snakelength - 1] = snake->applecolor; + + snake->applex = rand() % SNAKE_NUM_BLOCKS_X; + snake->appley = rand() % SNAKE_NUM_BLOCKS_Y; + snake->applecolor = rand() % 256; + + S_StartSound(NULL, sfx_s3k6b); + } + + // Move + for (i = snake->snakelength - 1; i > 0; i--) + { + snake->snakex[i] = snake->snakex[i - 1]; + snake->snakey[i] = snake->snakey[i - 1]; + } + snake->snakex[0] = x; + snake->snakey[0] = y; +} + +static void CL_DrawSnake(void) +{ + UINT16 i; + + // Background + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_MAP_WIDTH, SNAKE_MAP_HEIGHT, 239); + + // Borders + V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Top + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_TOP_Y, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Right + V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Bottom + V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Left + + // Apple + V_DrawFill( + SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->applex * SNAKE_BLOCK_SIZE, + SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE, + SNAKE_BLOCK_SIZE, + SNAKE_BLOCK_SIZE, + snake->applecolor + ); + + // Snake + if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over + for (i = 0; i < snake->snakelength; i++) + { + V_DrawFill( + SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE, + SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE, + SNAKE_BLOCK_SIZE, + SNAKE_BLOCK_SIZE, + snake->snakecolor[i] + ); + } + + // Length + V_DrawString(SNAKE_RIGHT_X + 4, SNAKE_TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); +} + // // CL_DrawConnectionStatus // @@ -1215,6 +1400,8 @@ static inline void CL_DrawConnectionStatus(void) fileneeded_t *file = &fileneeded[lastfilenum]; char *filename = file->filename; + CL_DrawSnake(); + Net_GetNetStat(); dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); if (dldlength > 256) @@ -1975,7 +2162,10 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) } // no problem if can't send packet, we will retry later if (CL_SendRequestFile()) + { cl_mode = CL_DOWNLOADFILES; + CL_InitialiseSnake(); + } } } else @@ -2039,6 +2229,12 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic if (waitmore) break; // exit the case + if (snake) + { + free(snake); + snake = NULL; + } + cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now /* FALLTHRU */ @@ -2093,11 +2289,20 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic { CONS_Printf(M_GetText("Network game synchronization aborted.\n")); // M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); + + if (snake) + { + free(snake); + snake = NULL; + } + D_QuitNetGame(); CL_Reset(); D_StartTitle(); return false; } + else if (cl_mode == CL_DOWNLOADFILES && snake) + CL_HandleSnake(key); // why are these here? this is for servers, we're a client //if (key == 's' && server) From d235d401bc01eb59fa05013006d3f96c2cb05b59 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 1 Jan 2020 00:18:17 +0100 Subject: [PATCH 02/33] Improve controls handling in connection screen minigame --- src/d_clisrv.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 893bf47d6..d3fdd1ff9 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1215,24 +1215,25 @@ static void CL_HandleSnake(INT32 key) snake->time++; // Update direction - switch (key) + if (gamekeydown[KEY_LEFTARROW]) { - case KEY_LEFTARROW: - if (snake->snakeprevdir != 2) - snake->snakedir = 1; - break; - case KEY_RIGHTARROW: - if (snake->snakeprevdir != 1) - snake->snakedir = 2; - break; - case KEY_UPARROW: - if (snake->snakeprevdir != 4) - snake->snakedir = 3; - break; - case KEY_DOWNARROW: - if (snake->snakeprevdir != 3) - snake->snakedir = 4; - break; + if (snake->snakeprevdir != 2) + snake->snakedir = 1; + } + else if (gamekeydown[KEY_RIGHTARROW]) + { + if (snake->snakeprevdir != 1) + snake->snakedir = 2; + } + else if (gamekeydown[KEY_UPARROW]) + { + if (snake->snakeprevdir != 4) + snake->snakedir = 3; + } + else if (gamekeydown[KEY_DOWNARROW]) + { + if (snake->snakeprevdir != 3) + snake->snakedir = 4; } snake->nextupdate--; @@ -2281,11 +2282,11 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic // Call it only once by tic if (*oldtic != I_GetTime()) { - INT32 key; - I_OsPolling(); - key = I_GetKey(); - if (key == KEY_ESCAPE || key == KEY_JOY1+1) + for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) + G_MapEventsToControls(&events[eventtail]); + + if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1]) { CONS_Printf(M_GetText("Network game synchronization aborted.\n")); // M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); @@ -2299,6 +2300,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic D_QuitNetGame(); CL_Reset(); D_StartTitle(); + memset(gamekeydown, 0, NUMKEYS); return false; } else if (cl_mode == CL_DOWNLOADFILES && snake) From 10fbaaf781ab783a9bfe4bb598e5b1e8576a0f27 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Fri, 24 Apr 2020 22:19:05 +0200 Subject: [PATCH 03/33] Fix compiler warnings --- src/d_clisrv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d3fdd1ff9..a74a85cb3 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1185,7 +1185,7 @@ typedef struct snake_s static snake_t *snake = NULL; -static void CL_InitialiseSnake() +static void CL_InitialiseSnake(void) { if (!snake) snake = malloc(sizeof(snake_t)); @@ -1207,7 +1207,7 @@ static void CL_InitialiseSnake() snake->applecolor = rand() % 256; } -static void CL_HandleSnake(INT32 key) +static void CL_HandleSnake(void) { UINT8 x, y; UINT16 i; @@ -2304,7 +2304,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic return false; } else if (cl_mode == CL_DOWNLOADFILES && snake) - CL_HandleSnake(key); + CL_HandleSnake(); // why are these here? this is for servers, we're a client //if (key == 's' && server) From 7c9ce1faee11707397aff8d517aac617349d578a Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sun, 26 Apr 2020 21:17:15 +0200 Subject: [PATCH 04/33] Prevent edge warping in Snake minigame --- src/d_clisrv.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a74a85cb3..dfe8e0cf6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1252,18 +1252,32 @@ static void CL_HandleSnake(void) switch (snake->snakedir) { case 1: - x = x > 0 ? x - 1 : SNAKE_NUM_BLOCKS_X - 1; + if (x > 0) + x--; + else + snake->gameover = true; break; case 2: - x = x < SNAKE_NUM_BLOCKS_X - 1 ? x + 1 : 0; + if (x < SNAKE_NUM_BLOCKS_X - 1) + x++; + else + snake->gameover = true; break; case 3: - y = y > 0 ? y - 1 : SNAKE_NUM_BLOCKS_Y - 1; + if (y > 0) + y--; + else + snake->gameover = true; break; case 4: - y = y < SNAKE_NUM_BLOCKS_Y - 1 ? y + 1 : 0; + if (y < SNAKE_NUM_BLOCKS_Y - 1) + y++; + else + snake->gameover = true; break; } + if (snake->gameover) + return; // Check collision with snake for (i = 1; i < snake->snakelength - 1; i++) From 380e246be349704c3bbcf0ebac43d2a00da8dd63 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sun, 26 Apr 2020 21:57:17 +0200 Subject: [PATCH 05/33] Lower the download progress bar --- src/d_clisrv.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index dfe8e0cf6..2f5027fd5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1161,7 +1161,7 @@ static void CV_LoadPlayerNames(UINT8 **p) #define SNAKE_BORDER_SIZE 8 #define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) #define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) -#define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 64) +#define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) #define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) typedef struct snake_s @@ -1366,8 +1366,8 @@ static inline void CL_DrawConnectionStatus(void) V_DrawFadeScreen(0xFF00, 16); // force default // 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"); + 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) { @@ -1377,7 +1377,7 @@ static inline void CL_DrawConnectionStatus(void) const char *cltext; for (i = 0; i < 16; ++i) - V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-24, 16, 8, palstart + ((animtime - i) & 15)); + V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); switch (cl_mode) { @@ -1387,9 +1387,9 @@ static inline void CL_DrawConnectionStatus(void) { cltext = M_GetText("Downloading game state..."); Net_GetNetStat(); - V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, va(" %4uK",fileneeded[lastfilenum].currentsize>>10)); - V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, + V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, va("%3.1fK/s ", ((double)getbps)/1024)); } else @@ -1404,7 +1404,7 @@ static inline void CL_DrawConnectionStatus(void) cltext = M_GetText("Connecting to server..."); break; } - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, cltext); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, cltext); } else { @@ -1421,8 +1421,8 @@ static inline void CL_DrawConnectionStatus(void) dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); if (dldlength > 256) dldlength = 256; - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111); - V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 96); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, dldlength, 8, 96); memset(tempname, 0, sizeof(tempname)); // offset filename to just the name only part @@ -1440,15 +1440,15 @@ 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-16-24, 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-16, 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-16, V_20TRANS|V_MONOSPACE, va("%3.1fK/s ", ((double)getbps)/1024)); } else - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, M_GetText("Waiting to download files...")); } } From 58c0383e883f67e785af424c38dcf427ef086fb1 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 27 Apr 2020 13:01:14 +0200 Subject: [PATCH 06/33] Use sprites for snake and apple --- src/d_clisrv.c | 163 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 53 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 2f5027fd5..d9e76e69f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1153,12 +1153,12 @@ static void CV_LoadPlayerNames(UINT8 **p) #ifdef CLIENT_LOADINGSCREEN #define SNAKE_SPEED 4 -#define SNAKE_NUM_BLOCKS_X 24 -#define SNAKE_NUM_BLOCKS_Y 14 -#define SNAKE_BLOCK_SIZE 8 +#define SNAKE_NUM_BLOCKS_X 20 +#define SNAKE_NUM_BLOCKS_Y 10 +#define SNAKE_BLOCK_SIZE 12 #define SNAKE_MAP_WIDTH (SNAKE_NUM_BLOCKS_X * SNAKE_BLOCK_SIZE) #define SNAKE_MAP_HEIGHT (SNAKE_NUM_BLOCKS_Y * SNAKE_BLOCK_SIZE) -#define SNAKE_BORDER_SIZE 8 +#define SNAKE_BORDER_SIZE 12 #define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) #define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) #define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) @@ -1170,17 +1170,13 @@ typedef struct snake_s tic_t nextupdate; boolean gameover; - UINT8 snakedir; - UINT8 snakeprevdir; - UINT16 snakelength; UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; UINT8 snakey[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; - UINT8 snakecolor[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; + UINT8 snakedir[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; UINT8 applex; UINT8 appley; - UINT8 applecolor; } snake_t; static snake_t *snake = NULL; @@ -1194,46 +1190,49 @@ static void CL_InitialiseSnake(void) snake->nextupdate = SNAKE_SPEED; snake->gameover = false; - snake->snakedir = 0; - snake->snakeprevdir = snake->snakedir; - snake->snakelength = 1; - snake->snakex[0] = rand() % SNAKE_NUM_BLOCKS_X; - snake->snakey[0] = rand() % SNAKE_NUM_BLOCKS_Y; - snake->snakecolor[0] = rand() % 256; + snake->snakex[0] = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->snakey[0] = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + snake->snakedir[0] = 0; + snake->snakedir[1] = 0; - snake->applex = rand() % SNAKE_NUM_BLOCKS_X; - snake->appley = rand() % SNAKE_NUM_BLOCKS_Y; - snake->applecolor = rand() % 256; + snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); } static void CL_HandleSnake(void) { UINT8 x, y; + UINT8 oldx, oldy; UINT16 i; snake->time++; + x = snake->snakex[0]; + y = snake->snakey[0]; + oldx = snake->snakex[1]; + oldy = snake->snakey[1]; + // Update direction if (gamekeydown[KEY_LEFTARROW]) { - if (snake->snakeprevdir != 2) - snake->snakedir = 1; + if (snake->snakelength < 2 || x <= oldx) + snake->snakedir[0] = 1; } else if (gamekeydown[KEY_RIGHTARROW]) { - if (snake->snakeprevdir != 1) - snake->snakedir = 2; + if (snake->snakelength < 2 || x >= oldx) + snake->snakedir[0] = 2; } else if (gamekeydown[KEY_UPARROW]) { - if (snake->snakeprevdir != 4) - snake->snakedir = 3; + if (snake->snakelength < 2 || y <= oldy) + snake->snakedir[0] = 3; } else if (gamekeydown[KEY_DOWNARROW]) { - if (snake->snakeprevdir != 3) - snake->snakedir = 4; + if (snake->snakelength < 2 || y >= oldy) + snake->snakedir[0] = 4; } snake->nextupdate--; @@ -1241,15 +1240,11 @@ static void CL_HandleSnake(void) return; snake->nextupdate = SNAKE_SPEED; - snake->snakeprevdir = snake->snakedir; - if (snake->gameover) return; // Find new position - x = snake->snakex[0]; - y = snake->snakey[0]; - switch (snake->snakedir) + switch (snake->snakedir[0]) { case 1: if (x > 0) @@ -1294,28 +1289,53 @@ static void CL_HandleSnake(void) snake->snakelength++; snake->snakex[snake->snakelength - 1] = snake->snakex[snake->snakelength - 2]; snake->snakey[snake->snakelength - 1] = snake->snakey[snake->snakelength - 2]; - snake->snakecolor[snake->snakelength - 1] = snake->applecolor; + snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2]; - snake->applex = rand() % SNAKE_NUM_BLOCKS_X; - snake->appley = rand() % SNAKE_NUM_BLOCKS_Y; - snake->applecolor = rand() % 256; + snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); + snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); S_StartSound(NULL, sfx_s3k6b); } - // Move - for (i = snake->snakelength - 1; i > 0; i--) + if (snake->snakelength > 1) { - snake->snakex[i] = snake->snakex[i - 1]; - snake->snakey[i] = snake->snakey[i - 1]; + UINT8 dir = snake->snakedir[0]; + + // Move + for (i = snake->snakelength - 1; i > 0; i--) + { + snake->snakex[i] = snake->snakex[i - 1]; + snake->snakey[i] = snake->snakey[i - 1]; + snake->snakedir[i] = snake->snakedir[i - 1]; + } + + // Handle corners + if (x < oldx && dir == 3) + dir = 5; + else if (x > oldx && dir == 3) + dir = 6; + else if (x < oldx && dir == 4) + dir = 7; + else if (x > oldx && dir == 4) + dir = 8; + else if (y < oldy && dir == 1) + dir = 9; + else if (y < oldy && dir == 2) + dir = 10; + else if (y > oldy && dir == 1) + dir = 11; + else if (y > oldy && dir == 2) + dir = 12; + snake->snakedir[1] = dir; } + snake->snakex[0] = x; snake->snakey[0] = y; } static void CL_DrawSnake(void) { - UINT16 i; + INT16 i; // Background V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_MAP_WIDTH, SNAKE_MAP_HEIGHT, 239); @@ -1327,26 +1347,63 @@ static void CL_DrawSnake(void) V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE, SNAKE_BORDER_SIZE + SNAKE_MAP_HEIGHT, 242); // Left // Apple - V_DrawFill( - SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->applex * SNAKE_BLOCK_SIZE, - SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE, - SNAKE_BLOCK_SIZE, - SNAKE_BLOCK_SIZE, - snake->applecolor + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->applex * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + FRACUNIT / 4, + 0, + W_CachePatchName("DL_APPLE", PU_HUDGFX), + NULL ); // Snake if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over - for (i = 0; i < snake->snakelength; i++) + { + for (i = snake->snakelength - 1; i >= 0; i--) { - V_DrawFill( - SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE, - SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE, - SNAKE_BLOCK_SIZE, - SNAKE_BLOCK_SIZE, - snake->snakecolor[i] + const char *patchname; + UINT8 dir = snake->snakedir[i]; + + if (i == 0) // Head + { + switch (dir) + { + case 1: patchname = "DL_SNAKEHEAD_L"; break; + case 2: patchname = "DL_SNAKEHEAD_R"; break; + case 3: patchname = "DL_SNAKEHEAD_T"; break; + default: patchname = "DL_SNAKEHEAD_B"; + } + } + else // Body + { + switch (dir) + { + case 1: patchname = "DL_SNAKEBODY_L"; break; + case 2: patchname = "DL_SNAKEBODY_R"; break; + case 3: patchname = "DL_SNAKEBODY_T"; break; + case 4: patchname = "DL_SNAKEBODY_B"; break; + case 5: patchname = "DL_SNAKEBODY_LT"; break; + case 6: patchname = "DL_SNAKEBODY_RT"; break; + case 7: patchname = "DL_SNAKEBODY_LB"; break; + case 8: patchname = "DL_SNAKEBODY_RB"; break; + case 9: patchname = "DL_SNAKEBODY_TL"; break; + case 10: patchname = "DL_SNAKEBODY_TR"; break; + case 11: patchname = "DL_SNAKEBODY_BL"; break; + case 12: patchname = "DL_SNAKEBODY_BR"; break; + default: patchname = "DL_SNAKEBODY_B"; + } + } + + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchName(patchname, PU_HUDGFX), + NULL ); } + } // Length V_DrawString(SNAKE_RIGHT_X + 4, SNAKE_TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); From c7cd53d5b2cedfea0e70d5937e839285b4e644fb Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 27 Apr 2020 14:22:45 +0200 Subject: [PATCH 07/33] Call rand() a few times after calling srand() --- src/d_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/d_main.c b/src/d_main.c index 00aeb541d..d3539ed97 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1182,6 +1182,9 @@ void D_SRB2Main(void) // rand() needs seeded regardless of password srand((unsigned int)time(NULL)); + rand(); + rand(); + rand(); if (M_CheckParm("-password") && M_IsNextParm()) D_SetPassword(M_GetNextParm()); From 647d74bad5fbbf40b1baf6c51dfd982f73da5016 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 27 Apr 2020 15:31:38 +0200 Subject: [PATCH 08/33] Add a background to Snake minigame --- src/d_clisrv.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d9e76e69f..af60889b2 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1164,11 +1164,25 @@ static void CV_LoadPlayerNames(UINT8 **p) #define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) #define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) +static const char *snake_backgrounds[] = { + "RVPUMICF", + "FRSTRCKF", + "TAR", + "MMFLRB4", + "RVDARKF1", + "RVZWALF1", + "RVZWALF4", + "RVZWALF5", + "RVZGRS02", + "RVZGRS04", +}; + typedef struct snake_s { tic_t time; tic_t nextupdate; boolean gameover; + UINT8 background; UINT16 snakelength; UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; @@ -1189,6 +1203,7 @@ static void CL_InitialiseSnake(void) snake->time = 0; snake->nextupdate = SNAKE_SPEED; snake->gameover = false; + snake->background = M_RandomKey(sizeof(snake_backgrounds) / sizeof(*snake_backgrounds)); snake->snakelength = 1; snake->snakex[0] = M_RandomKey(SNAKE_NUM_BLOCKS_X); @@ -1338,7 +1353,13 @@ static void CL_DrawSnake(void) INT16 i; // Background - V_DrawFill(SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, SNAKE_MAP_WIDTH, SNAKE_MAP_HEIGHT, 239); + V_DrawFlatFill( + SNAKE_LEFT_X + SNAKE_BORDER_SIZE, + SNAKE_TOP_Y + SNAKE_BORDER_SIZE, + SNAKE_MAP_WIDTH, + SNAKE_MAP_HEIGHT, + W_GetNumForName(snake_backgrounds[snake->background]) + ); // Borders V_DrawFill(SNAKE_LEFT_X, SNAKE_TOP_Y, SNAKE_BORDER_SIZE + SNAKE_MAP_WIDTH, SNAKE_BORDER_SIZE, 242); // Top @@ -2386,9 +2407,12 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic #ifdef CLIENT_LOADINGSCREEN if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) { - F_MenuPresTicker(true); // title sky - F_TitleScreenTicker(true); - F_TitleScreenDrawer(); + if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_DOWNLOADSAVEGAME) + { + F_MenuPresTicker(true); // title sky + F_TitleScreenTicker(true); + F_TitleScreenDrawer(); + } CL_DrawConnectionStatus(); I_UpdateNoVsync(); // page flip or blit buffer if (moviemode) From a3dcc100c0761dcff4cac4e58993b678e038af01 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 27 Apr 2020 22:06:32 +0200 Subject: [PATCH 09/33] Add pause and retry to Snake minigame --- src/d_clisrv.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index af60889b2..95fe919b2 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1179,6 +1179,8 @@ static const char *snake_backgrounds[] = { typedef struct snake_s { + boolean paused; + boolean pausepressed; tic_t time; tic_t nextupdate; boolean gameover; @@ -1200,6 +1202,8 @@ static void CL_InitialiseSnake(void) if (!snake) snake = malloc(sizeof(snake_t)); + snake->paused = false; + snake->pausepressed = false; snake->time = 0; snake->nextupdate = SNAKE_SPEED; snake->gameover = false; @@ -1221,6 +1225,26 @@ static void CL_HandleSnake(void) UINT8 oldx, oldy; UINT16 i; + // Handle retry + if (snake->gameover && (PLAYER1INPUTDOWN(gc_jump) || gamekeydown[KEY_ENTER])) + { + CL_InitialiseSnake(); + snake->pausepressed = true; // Avoid accidental pause on respawn + } + + // Handle pause + if (PLAYER1INPUTDOWN(gc_pause) || gamekeydown[KEY_ENTER]) + { + if (!snake->pausepressed) + snake->paused = !snake->paused; + snake->pausepressed = true; + } + else + snake->pausepressed = false; + + if (snake->paused) + return; + snake->time++; x = snake->snakex[0]; From dfdace22bbf02eb20eab43bd29f4d81212864230 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 27 Apr 2020 23:10:13 +0200 Subject: [PATCH 10/33] Add bonuses and maluses to Snake minigame --- src/d_clisrv.c | 226 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 206 insertions(+), 20 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 95fe919b2..a79d398fa 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1164,6 +1164,29 @@ static void CV_LoadPlayerNames(UINT8 **p) #define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) #define SNAKE_TOP_Y (SNAKE_BOTTOM_Y - SNAKE_MAP_HEIGHT - SNAKE_BORDER_SIZE * 2 + 1) +enum snake_bonustype_s { + SNAKE_BONUS_NONE = 0, + SNAKE_BONUS_SLOW, + SNAKE_BONUS_FAST, + SNAKE_BONUS_GHOST, + SNAKE_BONUS_NUKE, + SNAKE_BONUS_SCISSORS, + SNAKE_BONUS_REVERSE, + SNAKE_BONUS_EGGMAN, + SNAKE_NUM_BONUSES, +}; + +static const char *snake_bonuspatches[] = { + NULL, + "DL_SLOW", + "TVSSC0", + "TVIVC0", + "TVARC0", + "DL_SCISSORS", + "TVRCC0", + "TVEGC0", +}; + static const char *snake_backgrounds[] = { "RVPUMICF", "FRSTRCKF", @@ -1187,12 +1210,18 @@ typedef struct snake_s UINT8 background; UINT16 snakelength; + enum snake_bonustype_s snakebonus; + tic_t snakebonustime; UINT8 snakex[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; UINT8 snakey[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; UINT8 snakedir[SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y]; UINT8 applex; UINT8 appley; + + enum snake_bonustype_s bonustype; + UINT8 bonusx; + UINT8 bonusy; } snake_t; static snake_t *snake = NULL; @@ -1210,6 +1239,7 @@ static void CL_InitialiseSnake(void) snake->background = M_RandomKey(sizeof(snake_backgrounds) / sizeof(*snake_backgrounds)); snake->snakelength = 1; + snake->snakebonus = SNAKE_BONUS_NONE; snake->snakex[0] = M_RandomKey(SNAKE_NUM_BLOCKS_X); snake->snakey[0] = M_RandomKey(SNAKE_NUM_BLOCKS_Y); snake->snakedir[0] = 0; @@ -1217,6 +1247,33 @@ static void CL_InitialiseSnake(void) snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + + snake->bonustype = SNAKE_BONUS_NONE; +} + +static UINT8 Snake_GetOppositeDir(UINT8 dir) +{ + if (dir == 1 || dir == 3) + return dir + 1; + else if (dir == 2 || dir == 4) + return dir - 1; + else + return 12 + 5 - dir; +} + +static void Snake_FindFreeSlot(UINT8 *x, UINT8 *y) +{ + UINT16 i; + + do + { + *x = M_RandomKey(SNAKE_NUM_BLOCKS_X); + *y = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + + for (i = 0; i < snake->snakelength; i++) + if (*x == snake->snakex[i] && *y == snake->snakey[i]) + break; + } while (i < snake->snakelength); } static void CL_HandleSnake(void) @@ -1274,10 +1331,22 @@ static void CL_HandleSnake(void) snake->snakedir[0] = 4; } + if (snake->snakebonustime) + { + snake->snakebonustime--; + if (!snake->snakebonustime) + snake->snakebonus = SNAKE_BONUS_NONE; + } + snake->nextupdate--; if (snake->nextupdate) return; - snake->nextupdate = SNAKE_SPEED; + if (snake->snakebonus == SNAKE_BONUS_SLOW) + snake->nextupdate = SNAKE_SPEED * 2; + else if (snake->snakebonus == SNAKE_BONUS_FAST) + snake->nextupdate = SNAKE_SPEED * 2 / 3; + else + snake->nextupdate = SNAKE_SPEED; if (snake->gameover) return; @@ -1310,36 +1379,64 @@ static void CL_HandleSnake(void) snake->gameover = true; break; } - if (snake->gameover) - return; // Check collision with snake - for (i = 1; i < snake->snakelength - 1; i++) - if (x == snake->snakex[i] && y == snake->snakey[i]) - { - snake->gameover = true; - S_StartSound(NULL, sfx_lose); - return; - } + if (snake->snakebonus != SNAKE_BONUS_GHOST) + for (i = 1; i < snake->snakelength - 1; i++) + if (x == snake->snakex[i] && y == snake->snakey[i]) + { + if (snake->snakebonus == SNAKE_BONUS_SCISSORS) + { + snake->snakebonus = SNAKE_BONUS_NONE; + snake->snakelength = i; + S_StartSound(NULL, sfx_adderr); + } + else + snake->gameover = true; + } + + if (snake->gameover) + { + S_StartSound(NULL, sfx_lose); + return; + } // Check collision with apple if (x == snake->applex && y == snake->appley) { - snake->snakelength++; - snake->snakex[snake->snakelength - 1] = snake->snakex[snake->snakelength - 2]; - snake->snakey[snake->snakelength - 1] = snake->snakey[snake->snakelength - 2]; - snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2]; + if (snake->snakelength + 1 < SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y) + { + snake->snakelength++; + snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2]; + snake->snakey [snake->snakelength - 1] = snake->snakey [snake->snakelength - 2]; + snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2]; + } - snake->applex = M_RandomKey(SNAKE_NUM_BLOCKS_X); - snake->appley = M_RandomKey(SNAKE_NUM_BLOCKS_Y); + // Spawn new apple + Snake_FindFreeSlot(&snake->applex, &snake->appley); + + // Spawn new bonus + if (!(snake->snakelength % 5)) + { + do + { + snake->bonustype = M_RandomKey(SNAKE_NUM_BONUSES - 1) + 1; + } while (snake->snakelength > SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y * 3 / 4 + && (snake->bonustype == SNAKE_BONUS_EGGMAN || snake->bonustype == SNAKE_BONUS_FAST || snake->bonustype == SNAKE_BONUS_REVERSE)); + + Snake_FindFreeSlot(&snake->bonusx, &snake->bonusy); + } S_StartSound(NULL, sfx_s3k6b); } - if (snake->snakelength > 1) + if (snake->snakelength > 1 && snake->snakedir[0]) { UINT8 dir = snake->snakedir[0]; + oldx = snake->snakex[1]; + oldy = snake->snakey[1]; + // Move for (i = snake->snakelength - 1; i > 0; i--) { @@ -1370,6 +1467,71 @@ static void CL_HandleSnake(void) snake->snakex[0] = x; snake->snakey[0] = y; + + // Check collision with bonus + if (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy) + { + S_StartSound(NULL, sfx_ncchip); + + switch (snake->bonustype) + { + case SNAKE_BONUS_SLOW: + snake->snakebonus = SNAKE_BONUS_SLOW; + snake->snakebonustime = 20 * TICRATE; + break; + case SNAKE_BONUS_FAST: + snake->snakebonus = SNAKE_BONUS_FAST; + snake->snakebonustime = 20 * TICRATE; + break; + case SNAKE_BONUS_GHOST: + snake->snakebonus = SNAKE_BONUS_GHOST; + snake->snakebonustime = 10 * TICRATE; + break; + case SNAKE_BONUS_NUKE: + for (i = 0; i < snake->snakelength; i++) + { + snake->snakex [i] = snake->snakex [0]; + snake->snakey [i] = snake->snakey [0]; + snake->snakedir[i] = snake->snakedir[0]; + } + + S_StartSound(NULL, sfx_bkpoof); + break; + case SNAKE_BONUS_SCISSORS: + snake->snakebonus = SNAKE_BONUS_SCISSORS; + snake->snakebonustime = 60 * TICRATE; + break; + case SNAKE_BONUS_REVERSE: + for (i = 0; i < (snake->snakelength + 1) / 2; i++) + { + UINT16 i2 = snake->snakelength - 1 - i; + UINT8 tmpx = snake->snakex [i]; + UINT8 tmpy = snake->snakey [i]; + UINT8 tmpdir = snake->snakedir[i]; + + // Swap first segment with last segment + snake->snakex [i] = snake->snakex [i2]; + snake->snakey [i] = snake->snakey [i2]; + snake->snakedir[i] = Snake_GetOppositeDir(snake->snakedir[i2]); + snake->snakex [i2] = tmpx; + snake->snakey [i2] = tmpy; + snake->snakedir[i2] = Snake_GetOppositeDir(tmpdir); + } + + snake->snakedir[0] = 0; + + S_StartSound(NULL, sfx_gravch); + break; + default: + if (snake->snakebonus != SNAKE_BONUS_GHOST) + { + snake->gameover = true; + S_StartSound(NULL, sfx_lose); + } + } + + snake->bonustype = SNAKE_BONUS_NONE; + } } static void CL_DrawSnake(void) @@ -1401,6 +1563,17 @@ static void CL_DrawSnake(void) NULL ); + // Bonus + if (snake->bonustype != SNAKE_BONUS_NONE) + V_DrawFixedPatch( + (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->bonusx * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 ) * FRACUNIT, + (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->bonusy * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 + 4) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchName(snake_bonuspatches[snake->bonustype], PU_HUDGFX), + NULL + ); + // Snake if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over { @@ -1416,7 +1589,8 @@ static void CL_DrawSnake(void) case 1: patchname = "DL_SNAKEHEAD_L"; break; case 2: patchname = "DL_SNAKEHEAD_R"; break; case 3: patchname = "DL_SNAKEHEAD_T"; break; - default: patchname = "DL_SNAKEHEAD_B"; + case 4: patchname = "DL_SNAKEHEAD_B"; break; + default: patchname = "DL_SNAKEHEAD_M"; } } else // Body @@ -1442,8 +1616,8 @@ static void CL_DrawSnake(void) V_DrawFixedPatch( (SNAKE_LEFT_X + SNAKE_BORDER_SIZE + snake->snakex[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, - FRACUNIT / 2, - 0, + i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2, + snake->snakebonus == SNAKE_BONUS_GHOST ? V_TRANSLUCENT : 0, W_CachePatchName(patchname, PU_HUDGFX), NULL ); @@ -1452,6 +1626,18 @@ static void CL_DrawSnake(void) // Length V_DrawString(SNAKE_RIGHT_X + 4, SNAKE_TOP_Y, V_MONOSPACE, va("%u", snake->snakelength)); + + // Bonus + if (snake->snakebonus != SNAKE_BONUS_NONE + && (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2)) + V_DrawFixedPatch( + (SNAKE_RIGHT_X + 10) * FRACUNIT, + (SNAKE_TOP_Y + 24) * FRACUNIT, + FRACUNIT / 2, + 0, + W_CachePatchName(snake_bonuspatches[snake->snakebonus], PU_HUDGFX), + NULL + ); } // From 231a835bf66bc2988ad64662e228d76a4ceec5ce Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 27 Apr 2020 23:15:18 +0200 Subject: [PATCH 11/33] Minor adjustements in Snake minigame --- src/d_clisrv.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a79d398fa..9c138a468 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1152,13 +1152,16 @@ static void CV_LoadPlayerNames(UINT8 **p) } #ifdef CLIENT_LOADINGSCREEN -#define SNAKE_SPEED 4 +#define SNAKE_SPEED 5 + #define SNAKE_NUM_BLOCKS_X 20 #define SNAKE_NUM_BLOCKS_Y 10 #define SNAKE_BLOCK_SIZE 12 +#define SNAKE_BORDER_SIZE 12 + #define SNAKE_MAP_WIDTH (SNAKE_NUM_BLOCKS_X * SNAKE_BLOCK_SIZE) #define SNAKE_MAP_HEIGHT (SNAKE_NUM_BLOCKS_Y * SNAKE_BLOCK_SIZE) -#define SNAKE_BORDER_SIZE 12 + #define SNAKE_LEFT_X ((BASEVIDWIDTH - SNAKE_MAP_WIDTH) / 2 - SNAKE_BORDER_SIZE) #define SNAKE_RIGHT_X (SNAKE_LEFT_X + SNAKE_MAP_WIDTH + SNAKE_BORDER_SIZE * 2 - 1) #define SNAKE_BOTTOM_Y (BASEVIDHEIGHT - 48) @@ -1226,7 +1229,7 @@ typedef struct snake_s static snake_t *snake = NULL; -static void CL_InitialiseSnake(void) +static void Snake_Initialise(void) { if (!snake) snake = malloc(sizeof(snake_t)); @@ -1276,7 +1279,7 @@ static void Snake_FindFreeSlot(UINT8 *x, UINT8 *y) } while (i < snake->snakelength); } -static void CL_HandleSnake(void) +static void Snake_Handle(void) { UINT8 x, y; UINT8 oldx, oldy; @@ -1285,7 +1288,7 @@ static void CL_HandleSnake(void) // Handle retry if (snake->gameover && (PLAYER1INPUTDOWN(gc_jump) || gamekeydown[KEY_ENTER])) { - CL_InitialiseSnake(); + Snake_Initialise(); snake->pausepressed = true; // Avoid accidental pause on respawn } @@ -1534,7 +1537,7 @@ static void CL_HandleSnake(void) } } -static void CL_DrawSnake(void) +static void Snake_Draw(void) { INT16 i; @@ -1703,7 +1706,7 @@ static inline void CL_DrawConnectionStatus(void) fileneeded_t *file = &fileneeded[lastfilenum]; char *filename = file->filename; - CL_DrawSnake(); + Snake_Draw(); Net_GetNetStat(); dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); @@ -2467,7 +2470,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) if (CL_SendRequestFile()) { cl_mode = CL_DOWNLOADFILES; - CL_InitialiseSnake(); + Snake_Initialise(); } } } @@ -2606,7 +2609,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic return false; } else if (cl_mode == CL_DOWNLOADFILES && snake) - CL_HandleSnake(); + Snake_Handle(); // why are these here? this is for servers, we're a client //if (key == 's' && server) From 752b48de3a92273742c07e7669626b65fd551780 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 28 Apr 2020 00:37:58 +0200 Subject: [PATCH 12/33] Update sound and closed captions in connection screen --- src/d_clisrv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 9c138a468..dc4631d86 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2630,6 +2630,8 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic I_UpdateNoVsync(); // page flip or blit buffer if (moviemode) M_SaveFrame(); + S_UpdateSounds(); + S_UpdateClosedCaptions(); } #else CON_Drawer(); From dc55ab9ae212aaea6e3eea87c9fa5edd4f9f594b Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sun, 10 May 2020 11:02:45 +0200 Subject: [PATCH 13/33] Use W_CachePatchLongName in Snake minigame --- src/d_clisrv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 63bb653fb..1857df04f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1566,7 +1566,7 @@ static void Snake_Draw(void) (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->appley * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, FRACUNIT / 4, 0, - W_CachePatchName("DL_APPLE", PU_HUDGFX), + W_CachePatchLongName("DL_APPLE", PU_HUDGFX), NULL ); @@ -1577,7 +1577,7 @@ static void Snake_Draw(void) (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->bonusy * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2 + 4) * FRACUNIT, FRACUNIT / 2, 0, - W_CachePatchName(snake_bonuspatches[snake->bonustype], PU_HUDGFX), + W_CachePatchLongName(snake_bonuspatches[snake->bonustype], PU_HUDGFX), NULL ); @@ -1625,7 +1625,7 @@ static void Snake_Draw(void) (SNAKE_TOP_Y + SNAKE_BORDER_SIZE + snake->snakey[i] * SNAKE_BLOCK_SIZE + SNAKE_BLOCK_SIZE / 2) * FRACUNIT, i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2, snake->snakebonus == SNAKE_BONUS_GHOST ? V_TRANSLUCENT : 0, - W_CachePatchName(patchname, PU_HUDGFX), + W_CachePatchLongName(patchname, PU_HUDGFX), NULL ); } @@ -1642,7 +1642,7 @@ static void Snake_Draw(void) (SNAKE_TOP_Y + 24) * FRACUNIT, FRACUNIT / 2, 0, - W_CachePatchName(snake_bonuspatches[snake->snakebonus], PU_HUDGFX), + W_CachePatchLongName(snake_bonuspatches[snake->snakebonus], PU_HUDGFX), NULL ); } From 061fd4761a0c752c56163ee039c31c646b811c7a Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 12 May 2020 19:06:40 +0200 Subject: [PATCH 14/33] Rename some file transfer functions --- src/d_clisrv.c | 16 ++++++++-------- src/d_netfil.c | 49 +++++++++++++++++++++++++------------------------ src/d_netfil.h | 14 +++++++------- src/i_tcp.c | 2 +- 4 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 43321d92d..a0a554609 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1598,7 +1598,7 @@ static void SV_SendSaveGame(INT32 node) WRITEUINT32(savebuffer, 0); } - SV_SendRam(node, buffertosend, length, SF_RAM, 0); + AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); save_p = NULL; // Remember when we started sending the savegame so we can handle timeouts @@ -1978,7 +1978,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) return false; } // no problem if can't send packet, we will retry later - if (CL_SendRequestFile()) + if (CL_SendFileRequest()) cl_mode = CL_DOWNLOADFILES; } } @@ -2106,7 +2106,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic // why are these here? this is for servers, we're a client //if (key == 's' && server) // doomcom->numnodes = (INT16)pnumnodes; - //SV_FileSendTicker(); + //FileSendTicker(); *oldtic = I_GetTime(); #ifdef CLIENT_LOADINGSCREEN @@ -3911,13 +3911,13 @@ static void HandlePacketFromAwayNode(SINT8 node) break; } SERVERONLY - Got_Filetxpak(); + PT_FileFragment(); break; case PT_REQUESTFILE: if (server) { - if (!cv_downloading.value || !Got_RequestFilePak(node)) + if (!cv_downloading.value || !PT_RequestFile(node)) Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway } else @@ -4216,7 +4216,7 @@ static void HandlePacketFromPlayer(SINT8 node) { char *name = va("%s" PATHSEP "%s", luafiledir, luafiletransfers->filename); boolean textmode = !strchr(luafiletransfers->mode, 'b'); - SV_SendLuaFile(node, name, textmode); + AddLuaFileToSendQueue(node, name, textmode); } break; case PT_HASLUAFILE: @@ -4348,7 +4348,7 @@ static void HandlePacketFromPlayer(SINT8 node) break; } if (client) - Got_Filetxpak(); + PT_FileFragment(); break; case PT_SENDINGLUAFILE: if (client) @@ -5073,7 +5073,7 @@ void NetUpdate(void) CON_Ticker(); } - SV_FileSendTicker(); + FileSendTicker(); } /** Returns the number of players playing. diff --git a/src/d_netfil.c b/src/d_netfil.c index 6d3ac7f9d..ec0a9b66c 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -56,7 +56,7 @@ #include // Prototypes -static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid); +static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid); // Sender structure typedef struct filetx_s @@ -253,7 +253,7 @@ boolean CL_CheckDownloadable(void) * \note Sends a PT_REQUESTFILE packet * */ -boolean CL_SendRequestFile(void) +boolean CL_SendFileRequest(void) { char *p; INT32 i; @@ -298,7 +298,7 @@ boolean CL_SendRequestFile(void) // get request filepak and put it on the send queue // returns false if a requested file was not found or cannot be sent -boolean Got_RequestFilePak(INT32 node) +boolean PT_RequestFile(INT32 node) { char wad[MAX_WADPATH+1]; UINT8 *p = netbuffer->u.textcmd; @@ -309,7 +309,7 @@ boolean Got_RequestFilePak(INT32 node) if (id == 0xFF) break; READSTRINGN(p, wad, MAX_WADPATH); - if (!SV_SendFile(node, wad, id)) + if (!AddFileToSendQueue(node, wad, id)) { SV_AbortSendFiles(node); return false; // don't read the rest of the files @@ -621,11 +621,11 @@ static INT32 filestosend = 0; * \param node The node to send the file to * \param filename The file to send * \param fileid ??? - * \sa SV_SendRam - * \sa SV_SendLuaFile + * \sa AddRamToSendQueue + * \sa AddLuaFileToSendQueue * */ -static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid) +static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid) { filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t *p; // The new file request @@ -643,7 +643,7 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid) // Allocate a file request and append it to the file list p = *q = (filetx_t *)malloc(sizeof (filetx_t)); if (!p) - I_Error("SV_SendFile: No more memory\n"); + I_Error("AddFileToSendQueue: No more memory\n"); // Initialise with zeros memset(p, 0, sizeof (filetx_t)); @@ -651,7 +651,7 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid) // Allocate the file name p->id.filename = (char *)malloc(MAX_WADPATH); if (!p->id.filename) - I_Error("SV_SendFile: No more memory\n"); + I_Error("AddFileToSendQueue: No more memory\n"); // Set the file name and get rid of the path strlcpy(p->id.filename, filename, MAX_WADPATH); @@ -712,11 +712,11 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid) * \param size The size of the block in bytes * \param freemethod How to free the block after it has been sent * \param fileid ??? - * \sa SV_SendFile - * \sa SV_SendLuaFile + * \sa AddFileToSendQueue + * \sa AddLuaFileToSendQueue * */ -void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid) +void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid) { filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t *p; // The new file request @@ -729,7 +729,7 @@ void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UI // Allocate a file request and append it to the file list p = *q = (filetx_t *)malloc(sizeof (filetx_t)); if (!p) - I_Error("SV_SendRam: No more memory\n"); + I_Error("AddRamToSendQueue: No more memory\n"); // Initialise with zeros memset(p, 0, sizeof (filetx_t)); @@ -749,11 +749,11 @@ void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UI * * \param node The node to send the file to * \param filename The file to send - * \sa SV_SendFile - * \sa SV_SendRam + * \sa AddFileToSendQueue + * \sa AddRamToSendQueue * */ -boolean SV_SendLuaFile(INT32 node, const char *filename, boolean textmode) +boolean AddLuaFileToSendQueue(INT32 node, const char *filename, boolean textmode) { filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t *p; // The new file request @@ -770,7 +770,7 @@ boolean SV_SendLuaFile(INT32 node, const char *filename, boolean textmode) // Allocate a file request and append it to the file list p = *q = (filetx_t *)malloc(sizeof (filetx_t)); if (!p) - I_Error("SV_SendLuaFile: No more memory\n"); + I_Error("AddLuaFileToSendQueue: No more memory\n"); // Initialise with zeros memset(p, 0, sizeof (filetx_t)); @@ -778,7 +778,7 @@ boolean SV_SendLuaFile(INT32 node, const char *filename, boolean textmode) // Allocate the file name p->id.filename = (char *)malloc(MAX_WADPATH); // !!! if (!p->id.filename) - I_Error("SV_SendLuaFile: No more memory\n"); + I_Error("AddLuaFileToSendQueue: No more memory\n"); // Set the file name and get rid of the path strlcpy(p->id.filename, filename, MAX_WADPATH); // !!! @@ -804,7 +804,8 @@ static void SV_EndFileSend(INT32 node) { filetx_t *p = transfer[node].txlist; - // Free the file request according to the freemethod parameter used with SV_SendFile/Ram + // Free the file request according to the freemethod + // parameter used with AddFileToSendQueue/AddRamToSendQueue switch (p->ram) { case SF_FILE: // It's a file, close it and free its filename @@ -842,7 +843,7 @@ static void SV_EndFileSend(INT32 node) * especially when the one downloading has high latency * */ -void SV_FileSendTicker(void) +void FileSendTicker(void) { static INT32 currentnode = 0; filetx_pak *p; @@ -938,7 +939,7 @@ void SV_FileSendTicker(void) if (f->textmode && feof(transfer[i].currentfile)) size = n; else if (fread(p->data, 1, size, transfer[i].currentfile) != size) - I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); + I_Error("FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); } } p->position = LONG(transfer[i].position); @@ -965,7 +966,7 @@ void SV_FileSendTicker(void) } } -void Got_Filetxpak(void) +void PT_FileFragment(void) { INT32 filenum = netbuffer->u.filetxpak.fileid; fileneeded_t *file = &fileneeded[filenum]; @@ -995,7 +996,7 @@ void Got_Filetxpak(void) if (file->status == FS_REQUESTED) { if (file->file) - I_Error("Got_Filetxpak: already open file\n"); + I_Error("PT_FileFragment: already open file\n"); file->file = fopen(filename, file->textmode ? "w" : "wb"); if (!file->file) I_Error("Can't create file %s: %s", filename, strerror(errno)); @@ -1078,7 +1079,7 @@ void Got_Filetxpak(void) * \return True if the node is downloading a file * */ -boolean SV_SendingFile(INT32 node) +boolean SendingFile(INT32 node) { return transfer[node].txlist != NULL; } diff --git a/src/d_netfil.h b/src/d_netfil.h index 7d6efada0..f212e16f8 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -61,16 +61,16 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave); INT32 CL_CheckFiles(void); void CL_LoadServerFiles(void); -void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, +void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid); -void SV_FileSendTicker(void); -void Got_Filetxpak(void); -boolean SV_SendingFile(INT32 node); +void FileSendTicker(void); +void PT_FileFragment(void); +boolean SendingFile(INT32 node); boolean CL_CheckDownloadable(void); -boolean CL_SendRequestFile(void); -boolean Got_RequestFilePak(INT32 node); +boolean CL_SendFileRequest(void); +boolean PT_RequestFile(INT32 node); typedef enum { @@ -96,7 +96,7 @@ extern char luafiledir[256 + 16]; void AddLuaFileTransfer(const char *filename, const char *mode); void SV_PrepareSendLuaFileToNextNode(void); -boolean SV_SendLuaFile(INT32 node, const char *filename, boolean textmode); +boolean AddLuaFileToSendQueue(INT32 node, const char *filename, boolean textmode); void SV_PrepareSendLuaFile(const char *filename); void SV_HandleLuaFileSent(UINT8 node); void RemoveLuaFileTransfer(void); diff --git a/src/i_tcp.c b/src/i_tcp.c index 373ea1bd0..5180869a5 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -487,7 +487,7 @@ static void cleanupnodes(void) // Why can't I start at zero? for (j = 1; j < MAXNETNODES; j++) - if (!(nodeingame[j] || SV_SendingFile(j))) + if (!(nodeingame[j] || SendingFile(j))) nodeconnected[j] = false; } From bf660dd35af7fe9e17e2641d3b82be9722d869c5 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 12 May 2020 19:58:16 +0200 Subject: [PATCH 15/33] Rename local variables --- src/d_netfil.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/d_netfil.c b/src/d_netfil.c index ec0a9b66c..f9d049be5 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -847,7 +847,7 @@ void FileSendTicker(void) { static INT32 currentnode = 0; filetx_pak *p; - size_t size; + size_t fragmentsize; filetx_t *f; INT32 packetsent, ram, i, j; INT32 maxpacketsent; @@ -926,33 +926,33 @@ void FileSendTicker(void) // Build a packet containing a file fragment p = &netbuffer->u.filetxpak; - size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE); - if (f->size-transfer[i].position < size) - size = f->size-transfer[i].position; + fragmentsize = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE); + if (f->size-transfer[i].position < fragmentsize) + fragmentsize = f->size-transfer[i].position; if (ram) - M_Memcpy(p->data, &f->id.ram[transfer[i].position], size); + M_Memcpy(p->data, &f->id.ram[transfer[i].position], fragmentsize); else { - size_t n = fread(p->data, 1, size, transfer[i].currentfile); - if (n != size) // Either an error or Windows turning CR-LF into LF + size_t n = fread(p->data, 1, fragmentsize, transfer[i].currentfile); + if (n != fragmentsize) // Either an error or Windows turning CR-LF into LF { if (f->textmode && feof(transfer[i].currentfile)) - size = n; - else if (fread(p->data, 1, size, transfer[i].currentfile) != size) - I_Error("FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); + fragmentsize = n; + else if (fread(p->data, 1, fragmentsize, transfer[i].currentfile) != fragmentsize) + I_Error("FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(fragmentsize), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); } } p->position = LONG(transfer[i].position); // Put flag so receiver knows the total size - if (transfer[i].position + size == f->size || (f->textmode && feof(transfer[i].currentfile))) + if (transfer[i].position + fragmentsize == f->size || (f->textmode && feof(transfer[i].currentfile))) p->position |= LONG(0x80000000); p->fileid = f->fileid; - p->size = SHORT((UINT16)size); + p->size = SHORT((UINT16)fragmentsize); // Send the packet - if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND + if (HSendPacket(i, true, 0, FILETXHEADER + fragmentsize)) // Reliable SEND { // Success - transfer[i].position = (UINT32)(transfer[i].position + size); + transfer[i].position = (UINT32)(transfer[i].position + fragmentsize); if (transfer[i].position == f->size || (f->textmode && feof(transfer[i].currentfile))) // Finish? SV_EndFileSend(i); } @@ -1007,20 +1007,20 @@ void PT_FileFragment(void) if (file->status == FS_DOWNLOADING) { - UINT32 pos = LONG(netbuffer->u.filetxpak.position); - UINT16 size = SHORT(netbuffer->u.filetxpak.size); + UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position); + UINT16 fragmentsize = SHORT(netbuffer->u.filetxpak.size); // Use a special trick to know when the file is complete (not always used) // WARNING: file fragments can arrive out of order so don't stop yet! - if (pos & 0x80000000) + if (fragmentpos & 0x80000000) { - pos &= ~0x80000000; - file->totalsize = pos + size; + fragmentpos &= ~0x80000000; + file->totalsize = fragmentpos + fragmentsize; } // We can receive packet in the wrong order, anyway all os support gaped file - fseek(file->file, pos, SEEK_SET); - if (size && fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1) + fseek(file->file, fragmentpos, SEEK_SET); + if (fragmentsize && fwrite(netbuffer->u.filetxpak.data,fragmentsize,1,file->file) != 1) I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file)); - file->currentsize += size; + file->currentsize += fragmentsize; // Finished? if (file->currentsize == file->totalsize) From 3c7c758d176f6f3fb1f92da6e15799f839825080 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sat, 16 May 2020 22:09:00 +0200 Subject: [PATCH 16/33] Rewrite file transfer code This code uses a custom packet acknowledgement system, which is more suited for file transfer and does not suffer from the small sender window used by the default acknowledgement system --- src/d_clisrv.c | 21 ++++ src/d_clisrv.h | 21 +++- src/d_net.c | 3 + src/d_netfil.c | 270 +++++++++++++++++++++++++++++++++++++------------ src/d_netfil.h | 11 +- 5 files changed, 262 insertions(+), 64 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a0a554609..a83d3033e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2103,6 +2103,9 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic return false; } + if (client && (cl_mode == CL_DOWNLOADFILES || cl_mode == CL_DOWNLOADSAVEGAME)) + FileReceiveTicker(); + // why are these here? this is for servers, we're a client //if (key == 's' && server) // doomcom->numnodes = (INT16)pnumnodes; @@ -3914,6 +3917,16 @@ static void HandlePacketFromAwayNode(SINT8 node) PT_FileFragment(); break; + case PT_FILEACK: + if (server) + PT_FileAck(); + break; + + case PT_FILERECEIVED: + if (server) + PT_FileReceived(); + break; + case PT_REQUESTFILE: if (server) { @@ -4350,6 +4363,14 @@ static void HandlePacketFromPlayer(SINT8 node) if (client) PT_FileFragment(); break; + case PT_FILEACK: + if (server) + PT_FileAck(); + break; + case PT_FILERECEIVED: + if (server) + PT_FileReceived(); + break; case PT_SENDINGLUAFILE: if (client) CL_PrepareDownloadLuaFile(); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 463240a2a..cbae55017 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -75,6 +75,8 @@ typedef enum // In addition, this packet can't occupy all the available slots. PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file. + PT_FILEACK, + PT_FILERECEIVED, PT_TEXTCMD, // Extra text commands from the client. PT_TEXTCMD2, // Splitscreen text commands. @@ -320,13 +322,28 @@ typedef struct UINT8 varlengthinputs[0]; // Playernames and netvars } ATTRPACK serverconfig_pak; -typedef struct { +typedef struct +{ UINT8 fileid; + UINT32 filesize; UINT32 position; UINT16 size; UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH } ATTRPACK filetx_pak; +typedef struct +{ + UINT32 start; + UINT32 acks; +} ATTRPACK fileacksegment_t; + +typedef struct +{ + UINT8 fileid; + UINT8 numsegments; + fileacksegment_t segments[0]; +} ATTRPACK fileack_pak; + #ifdef _MSC_VER #pragma warning(default : 4200) #endif @@ -442,6 +459,8 @@ typedef struct UINT8 resynchgot; // UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) filetx_pak filetxpak; // 139 bytes + fileack_pak fileack; + UINT8 filereceived; clientconfig_pak clientcfg; // 136 bytes UINT8 md5sum[16]; serverinfo_pak serverinfo; // 1024 bytes diff --git a/src/d_net.c b/src/d_net.c index 1db75f3da..c0f97ca87 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -806,6 +806,9 @@ static const char *packettypename[NUMPACKETTYPE] = "HASLUAFILE", "FILEFRAGMENT", + "FILEACK", + "FILERECEIVED", + "TEXTCMD", "TEXTCMD2", "CLIENTJOIN", diff --git a/src/d_netfil.c b/src/d_netfil.c index f9d049be5..9dc09a15f 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -78,6 +78,8 @@ typedef struct filetran_s { filetx_t *txlist; // Linked list of all files for the node UINT32 position; // The current position in the file + boolean *ackedfragments; + UINT32 ackedsize; FILE *currentfile; // The file currently being sent/received } filetran_t; static filetran_t transfer[MAXNETNODES]; @@ -88,6 +90,7 @@ static filetran_t transfer[MAXNETNODES]; // Receiver structure INT32 fileneedednum; // Number of files needed to join the server fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files +static tic_t lasttimeackpacketsent = 0; char downloaddir[512] = "DOWNLOAD"; #ifdef CLIENT_LOADINGSCREEN @@ -159,6 +162,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) for (i = 0; i < fileneedednum; i++) { fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet + fileneeded[i].justdownloaded = false; 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 @@ -173,6 +177,7 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave) { fileneedednum = 1; fileneeded[0].status = FS_REQUESTED; + fileneeded[0].justdownloaded = false; fileneeded[0].totalsize = UINT32_MAX; fileneeded[0].file = NULL; memset(fileneeded[0].md5sum, 0, 16); @@ -602,6 +607,7 @@ void CL_PrepareDownloadLuaFile(void) fileneedednum = 1; fileneeded[0].status = FS_REQUESTED; + fileneeded[0].justdownloaded = false; fileneeded[0].totalsize = UINT32_MAX; fileneeded[0].file = NULL; memset(fileneeded[0].md5sum, 0, 16); @@ -830,17 +836,17 @@ static void SV_EndFileSend(INT32 node) // Indicate that the transmission is over transfer[node].currentfile = NULL; + if (transfer[node].ackedfragments) + free(transfer[node].ackedfragments); + transfer[node].ackedfragments = NULL; filestosend--; } #define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH) +#define FILEFRAGMENTSIZE (software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE)) /** Handles file transmission - * - * \todo Use an acknowledging method more adapted to file transmission - * The current download speed suffers from lack of ack packets, - * especially when the one downloading has high latency * */ void FileSendTicker(void) @@ -850,23 +856,12 @@ void FileSendTicker(void) size_t fragmentsize; filetx_t *f; INT32 packetsent, ram, i, j; - INT32 maxpacketsent; if (!filestosend) // No file to send return; - if (cv_downloadspeed.value) // New (and experimental) behavior - { + if (cv_downloadspeed.value) // New behavior packetsent = cv_downloadspeed.value; - // Don't send more packets than we have free acks -#ifndef NONET - maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case -#else - maxpacketsent = 1; -#endif - if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet - packetsent = maxpacketsent; - } else // Old behavior { packetsent = PACKETPERTIC; @@ -883,11 +878,12 @@ void FileSendTicker(void) i = (i+1) % MAXNETNODES, j++) { if (transfer[i].txlist) - goto found; + break; } // no transfer to do - I_Error("filestosend=%d but no file to send found\n", filestosend); - found: + if (j >= MAXNETNODES) + I_Error("filestosend=%d but no file to send found\n", filestosend); + currentnode = (i+1) % MAXNETNODES; f = transfer[i].txlist; ram = f->ram; @@ -921,19 +917,37 @@ void FileSendTicker(void) } else // Sending RAM transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open + transfer[i].position = 0; + transfer[i].ackedsize = 0; + + transfer[i].ackedfragments = calloc(f->size / FILEFRAGMENTSIZE + 1, sizeof(*transfer[i].ackedfragments)); + if (!transfer[i].ackedfragments) + I_Error("FileSendTicker: No more memory\n"); + } + + // Find the first non-acknowledged fragment + while (transfer[i].ackedfragments[transfer[i].position / FILEFRAGMENTSIZE]) + { + transfer[i].position += FILEFRAGMENTSIZE; + if (transfer[i].position >= f->size) + transfer[i].position = 0; } // Build a packet containing a file fragment p = &netbuffer->u.filetxpak; - fragmentsize = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE); + fragmentsize = FILEFRAGMENTSIZE; if (f->size-transfer[i].position < fragmentsize) fragmentsize = f->size-transfer[i].position; if (ram) M_Memcpy(p->data, &f->id.ram[transfer[i].position], fragmentsize); else { - size_t n = fread(p->data, 1, fragmentsize, transfer[i].currentfile); + size_t n; + + fseek(transfer[i].currentfile, transfer[i].position, SEEK_SET); + + n = fread(p->data, 1, fragmentsize, transfer[i].currentfile); if (n != fragmentsize) // Either an error or Windows turning CR-LF into LF { if (f->textmode && feof(transfer[i].currentfile)) @@ -943,35 +957,145 @@ void FileSendTicker(void) } } p->position = LONG(transfer[i].position); - // Put flag so receiver knows the total size - if (transfer[i].position + fragmentsize == f->size || (f->textmode && feof(transfer[i].currentfile))) - p->position |= LONG(0x80000000); p->fileid = f->fileid; - p->size = SHORT((UINT16)fragmentsize); + p->filesize = LONG(f->size); + p->size = SHORT((UINT16)FILEFRAGMENTSIZE); // Send the packet - if (HSendPacket(i, true, 0, FILETXHEADER + fragmentsize)) // Reliable SEND + if (HSendPacket(i, false, 0, FILETXHEADER + fragmentsize)) // Don't use the default acknowledgement system { // Success transfer[i].position = (UINT32)(transfer[i].position + fragmentsize); - if (transfer[i].position == f->size || (f->textmode && feof(transfer[i].currentfile))) // Finish? - SV_EndFileSend(i); + if (transfer[i].position >= f->size) + transfer[i].position = 0; } else { // Not sent for some odd reason, retry at next call - if (!ram) - fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET); // Exit the while (can't send this one so why should i send the next?) break; } } } +void PT_FileAck(void) +{ + fileack_pak *packet = &netbuffer->u.fileack; + INT32 node = doomcom->remotenode; + filetran_t *trans = &transfer[node]; + INT32 i, j; + + // Wrong file id? Ignore it, it's probably a late packet + if (!(trans->txlist && packet->fileid == trans->txlist->fileid)) + return; + + if (packet->numsegments * sizeof(*packet->segments) != doomcom->datalength - BASEPACKETSIZE - sizeof(*packet)) + { + Net_CloseConnection(node); + return; + } + + for (i = 0; i < packet->numsegments; i++) + { + fileacksegment_t *segment = &packet->segments[i]; + + for (j = 0; j < 32; j++) + if (LONG(segment->acks) & (1 << j)) + { + if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size) + { + Net_CloseConnection(node); + return; + } + + if (!trans->ackedfragments[LONG(segment->start) + j]) + { + trans->ackedfragments[LONG(segment->start) + j] = true; + trans->ackedsize += FILEFRAGMENTSIZE; + + // If the last missing fragment was acked, finish! + if (trans->ackedsize == trans->txlist->size) + { + SV_EndFileSend(node); + return; + } + } + } + } +} + +void PT_FileReceived(void) +{ + filetx_t *trans = transfer[doomcom->remotenode].txlist; + + if (trans && netbuffer->u.filereceived == trans->fileid) + SV_EndFileSend(doomcom->remotenode); +} + +static void SendAckPacket(fileack_pak *packet, UINT8 fileid) +{ + size_t packetsize; + INT32 i; + + packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments); + + // Finalise the packet + packet->fileid = fileid; + for (i = 0; i < packet->numsegments; i++) + { + packet->segments[i].start = LONG(packet->segments[i].start); + packet->segments[i].acks = LONG(packet->segments[i].acks); + } + + // Send the packet + netbuffer->packettype = PT_FILEACK; + M_Memcpy(&netbuffer->u.fileack, packet, packetsize); + HSendPacket(servernode, false, 0, packetsize); + + // Clear the packet + memset(packet, 0, sizeof(*packet) + 512); +} + +static void AddFragmentToAckPacket(fileack_pak *packet, UINT32 fragmentpos, UINT8 fileid) +{ + fileacksegment_t *segment = &packet->segments[packet->numsegments - 1]; + + if (packet->numsegments == 0 + || fragmentpos < segment->start + || fragmentpos - segment->start >= 32) + { + // If the packet becomes too big, send it + if ((packet->numsegments + 1) * sizeof(*segment) > 512) + SendAckPacket(packet, fileid); + + packet->numsegments++; + segment = &packet->segments[packet->numsegments - 1]; + segment->start = fragmentpos; + } + + // Set the bit that represents the fragment + segment->acks |= 1 << (fragmentpos - segment->start); +} + +void FileReceiveTicker(void) +{ + INT32 i; + + if (lasttimeackpacketsent - I_GetTime() > TICRATE / 2) + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_DOWNLOADING) + { + SendAckPacket(fileneeded[i].ackpacket, i); + break; + } +} + void PT_FileFragment(void) { INT32 filenum = netbuffer->u.filetxpak.fileid; fileneeded_t *file = &fileneeded[filenum]; + UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position); + UINT16 fragmentsize = SHORT(netbuffer->u.filetxpak.size); + UINT16 boundedfragmentsize = doomcom->datalength - BASEPACKETSIZE - sizeof(netbuffer->u.filetxpak); char *filename; - static INT32 filetime = 0; filename = va("%s", file->filename); nameonly(filename); @@ -997,48 +1121,74 @@ void PT_FileFragment(void) { if (file->file) I_Error("PT_FileFragment: already open file\n"); + file->file = fopen(filename, file->textmode ? "w" : "wb"); if (!file->file) I_Error("Can't create file %s: %s", filename, strerror(errno)); + CONS_Printf("\r%s...\n",filename); file->currentsize = 0; file->status = FS_DOWNLOADING; + + file->totalsize = LONG(netbuffer->u.filetxpak.filesize); + + file->receivedfragments = calloc(file->totalsize / fragmentsize + 1, sizeof(*file->receivedfragments)); + file->ackpacket = calloc(1, sizeof(*file->ackpacket) + 512); + if (!(file->receivedfragments && file->ackpacket)) + I_Error("FileSendTicker: No more memory\n"); + lasttimeackpacketsent = I_GetTime(); } if (file->status == FS_DOWNLOADING) { - UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position); - UINT16 fragmentsize = SHORT(netbuffer->u.filetxpak.size); - // Use a special trick to know when the file is complete (not always used) - // WARNING: file fragments can arrive out of order so don't stop yet! - if (fragmentpos & 0x80000000) - { - fragmentpos &= ~0x80000000; - file->totalsize = fragmentpos + fragmentsize; - } - // We can receive packet in the wrong order, anyway all os support gaped file - fseek(file->file, fragmentpos, SEEK_SET); - if (fragmentsize && fwrite(netbuffer->u.filetxpak.data,fragmentsize,1,file->file) != 1) - I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file)); - file->currentsize += fragmentsize; + if (fragmentpos >= file->totalsize) + I_Error("Invalid file fragment\n"); - // Finished? - if (file->currentsize == file->totalsize) + if (!file->receivedfragments[fragmentpos / fragmentsize]) // Not received yet { - fclose(file->file); - file->file = NULL; - file->status = FS_FOUND; - CONS_Printf(M_GetText("Downloading %s...(done)\n"), - filename); - if (luafiletransfers) + file->receivedfragments[fragmentpos / fragmentsize] = true; + + // We can receive packets in the wrong order, anyway all OSes support gaped files + fseek(file->file, fragmentpos, SEEK_SET); + if (fragmentsize && fwrite(netbuffer->u.filetxpak.data, boundedfragmentsize, 1, file->file) != 1) + I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file)); + file->currentsize += boundedfragmentsize; + + AddFragmentToAckPacket(file->ackpacket, fragmentpos / fragmentsize, filenum); + + // Finished? + if (file->currentsize == file->totalsize) { + fclose(file->file); + file->file = NULL; + free(file->receivedfragments); + free(file->ackpacket); + file->status = FS_FOUND; + file->justdownloaded = true; + CONS_Printf(M_GetText("Downloading %s...(done)\n"), + filename); + // Tell the server we have received the file - netbuffer->packettype = PT_HASLUAFILE; - HSendPacket(servernode, true, 0, 0); + netbuffer->packettype = PT_FILERECEIVED; + netbuffer->u.filereceived = filenum; + HSendPacket(servernode, true, 0, 1); + + if (luafiletransfers) + { + // Tell the server we have received the file + netbuffer->packettype = PT_HASLUAFILE; + HSendPacket(servernode, true, 0, 0); + } } } + else // Already received + { + // If they are sending us the fragment again, it's probably because + // they missed our previous ack, so we must re-acknowledge it + AddFragmentToAckPacket(file->ackpacket, fragmentpos / fragmentsize, filenum); + } } - else + else if (!file->justdownloaded) { const char *s; switch(file->status) @@ -1061,12 +1211,6 @@ void PT_FileFragment(void) } I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s); } - // Send ack back quickly - if (++filetime == 3) - { - Net_SendAcks(servernode); - filetime = 0; - } #ifdef CLIENT_LOADINGSCREEN lastfilenum = filenum; @@ -1108,6 +1252,8 @@ void CloseNetFile(void) if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) { fclose(fileneeded[i].file); + free(fileneeded[i].receivedfragments); + free(fileneeded[i].ackpacket); // File is not complete delete it remove(fileneeded[i].filename); } diff --git a/src/d_netfil.h b/src/d_netfil.h index f212e16f8..c87ff6f8c 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -14,6 +14,7 @@ #define __D_NETFIL__ #include "d_net.h" +#include "d_clisrv.h" #include "w_wad.h" typedef enum @@ -41,9 +42,13 @@ typedef struct UINT8 md5sum[16]; // Used only for download FILE *file; + boolean *receivedfragments; + fileack_pak *ackpacket; + tic_t lasttimeackpacketsent; UINT32 currentsize; UINT32 totalsize; filestatus_t status; // The value returned by recsearch + boolean justdownloaded; // To prevent late fragments from causing an I_Error boolean textmode; // For files requested by Lua without the "b" option } fileneeded_t; @@ -65,9 +70,13 @@ void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemet UINT8 fileid); void FileSendTicker(void); -void PT_FileFragment(void); +void PT_FileAck(void); +void PT_FileReceived(void); boolean SendingFile(INT32 node); +void FileReceiveTicker(void); +void PT_FileFragment(void); + boolean CL_CheckDownloadable(void); boolean CL_SendFileRequest(void); boolean PT_RequestFile(INT32 node); From 66ecfb741a34179662b5a536baf75f91b91331d1 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sat, 16 May 2020 22:49:20 +0200 Subject: [PATCH 17/33] Show total size when downloading gamestate --- src/d_clisrv.c | 19 ++++++++++++++++--- src/d_netfil.c | 4 ++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a83d3033e..089d967af 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1180,8 +1180,9 @@ static inline void CL_DrawConnectionStatus(void) // 15 pal entries total. const char *cltext; - for (i = 0; i < 16; ++i) - V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-24, 16, 8, palstart + ((animtime - i) & 15)); + if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) + for (i = 0; i < 16; ++i) + V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-24, 16, 8, palstart + ((animtime - i) & 15)); switch (cl_mode) { @@ -1189,10 +1190,22 @@ static inline void CL_DrawConnectionStatus(void) case CL_DOWNLOADSAVEGAME: if (lastfilenum != -1) { + UINT32 currentsize = fileneeded[lastfilenum].currentsize; + UINT32 totalsize = fileneeded[lastfilenum].totalsize; + INT32 dldlength; + cltext = M_GetText("Downloading game state..."); Net_GetNetStat(); + + dldlength = (INT32)((currentsize/(double)totalsize) * 256); + if (dldlength > 256) + dldlength = 256; + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 96); + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, - va(" %4uK",fileneeded[lastfilenum].currentsize>>10)); + va(" %4uK/%4uK",currentsize>>10,totalsize>>10)); + V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, va("%3.1fK/s ", ((double)getbps)/1024)); } diff --git a/src/d_netfil.c b/src/d_netfil.c index 9dc09a15f..690a5e162 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -175,6 +175,10 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) void CL_PrepareDownloadSaveGame(const char *tmpsave) { +#ifdef CLIENT_LOADINGSCREEN + lastfilenum = -1; +#endif + fileneedednum = 1; fileneeded[0].status = FS_REQUESTED; fileneeded[0].justdownloaded = false; From db85c62c6fb2a5066a3ce37a6f99a4df93518520 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 19 May 2020 11:28:24 +0200 Subject: [PATCH 18/33] Allow resuming the most recent file transfer --- src/d_netfil.c | 146 +++++++++++++++++++++++++++++++++++++------- src/d_netfil.h | 4 +- src/sdl/i_system.c | 3 + src/win32/win_sys.c | 3 + 4 files changed, 132 insertions(+), 24 deletions(-) diff --git a/src/d_netfil.c b/src/d_netfil.c index 690a5e162..b5647ebe2 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -93,6 +93,17 @@ fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files static tic_t lasttimeackpacketsent = 0; char downloaddir[512] = "DOWNLOAD"; +// For resuming failed downloads +typedef struct +{ + char filename[MAX_WADPATH]; + UINT8 md5sum[16]; + boolean *receivedfragments; + UINT32 fragmentsize; + UINT32 currentsize; +} pauseddownload_t; +static pauseddownload_t *pauseddownload = NULL; + #ifdef CLIENT_LOADINGSCREEN // for cl loading screen INT32 lastfilenum = -1; @@ -255,6 +266,31 @@ boolean CL_CheckDownloadable(void) return false; } +/** Returns true if a needed file transfer can be resumed + * + * \param file The needed file to resume the transfer for + * \return True if the transfer can be resumed + * + */ +static boolean CL_CanResumeDownload(fileneeded_t *file) +{ + return pauseddownload + && !strcmp(pauseddownload->filename, file->filename) // Same name + && !memcmp(pauseddownload->md5sum, file->md5sum, 16) // Same checksum + && pauseddownload->fragmentsize == file->fragmentsize; // Same fragment size +} + +void CL_AbortDownloadResume(void) +{ + if (!pauseddownload) + return; + + free(pauseddownload->receivedfragments); + remove(pauseddownload->filename); + free(pauseddownload); + pauseddownload = NULL; +} + /** Sends requests for files in the ::fileneeded table with a status of * ::FS_NOTFOUND. * @@ -630,7 +666,7 @@ static INT32 filestosend = 0; * * \param node The node to send the file to * \param filename The file to send - * \param fileid ??? + * \param fileid The index of the file in the list of added files * \sa AddRamToSendQueue * \sa AddLuaFileToSendQueue * @@ -721,7 +757,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid * \param data The memory block to send * \param size The size of the block in bytes * \param freemethod How to free the block after it has been sent - * \param fileid ??? + * \param fileid The index of the file in the list of added files * \sa AddFileToSendQueue * \sa AddLuaFileToSendQueue * @@ -1083,13 +1119,36 @@ void FileReceiveTicker(void) { INT32 i; - if (lasttimeackpacketsent - I_GetTime() > TICRATE / 2) - for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status == FS_DOWNLOADING) + for (i = 0; i < fileneedednum; i++) + { + fileneeded_t *file = &fileneeded[i]; + + if (file->status == FS_DOWNLOADING) + { + if (lasttimeackpacketsent - I_GetTime() > TICRATE / 2) + SendAckPacket(file->ackpacket, i); + + // When resuming a tranfer, start with telling + // the server what parts we already received + if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING) { - SendAckPacket(fileneeded[i].ackpacket, i); - break; + // Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s + INT32 j; + for (j = 0; j < 2048; j++) + { + if (file->receivedfragments[file->ackresendposition]) + AddFragmentToAckPacket(file->ackpacket, file->ackresendposition, i); + + file->ackresendposition++; + if (file->ackresendposition * file->fragmentsize >= file->totalsize) + { + file->ackresendposition = UINT32_MAX; + break; + } + } } + } + } } void PT_FileFragment(void) @@ -1126,20 +1185,47 @@ void PT_FileFragment(void) if (file->file) I_Error("PT_FileFragment: already open file\n"); - file->file = fopen(filename, file->textmode ? "w" : "wb"); - if (!file->file) - I_Error("Can't create file %s: %s", filename, strerror(errno)); - - CONS_Printf("\r%s...\n",filename); - file->currentsize = 0; file->status = FS_DOWNLOADING; + file->fragmentsize = fragmentsize; - file->totalsize = LONG(netbuffer->u.filetxpak.filesize); - - file->receivedfragments = calloc(file->totalsize / fragmentsize + 1, sizeof(*file->receivedfragments)); file->ackpacket = calloc(1, sizeof(*file->ackpacket) + 512); - if (!(file->receivedfragments && file->ackpacket)) + if (!file->ackpacket) I_Error("FileSendTicker: No more memory\n"); + + if (CL_CanResumeDownload(file)) + { + file->file = fopen(filename, file->textmode ? "r+" : "r+b"); + if (!file->file) + I_Error("Can't reopen file %s: %s", filename, strerror(errno)); + CONS_Printf("\r%s...\n", filename); + + CONS_Printf("Resuming download...\n"); + file->currentsize = pauseddownload->currentsize; + file->receivedfragments = pauseddownload->receivedfragments; + file->ackresendposition = 0; + + free(pauseddownload); + pauseddownload = NULL; + } + else + { + CL_AbortDownloadResume(); + + file->file = fopen(filename, file->textmode ? "w" : "wb"); + if (!file->file) + I_Error("Can't create file %s: %s", filename, strerror(errno)); + + CONS_Printf("\r%s...\n",filename); + + file->currentsize = 0; + file->totalsize = LONG(netbuffer->u.filetxpak.filesize); + file->ackresendposition = UINT32_MAX; // Only used for resumed downloads + + file->receivedfragments = calloc(file->totalsize / fragmentsize + 1, sizeof(*file->receivedfragments)); + if (!file->receivedfragments) + I_Error("FileSendTicker: No more memory\n"); + } + lasttimeackpacketsent = I_GetTime(); } @@ -1256,14 +1342,28 @@ void CloseNetFile(void) if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) { fclose(fileneeded[i].file); - free(fileneeded[i].receivedfragments); free(fileneeded[i].ackpacket); - // File is not complete delete it - remove(fileneeded[i].filename); - } - // Remove PT_FILEFRAGMENT from acknowledge list - Net_AbortPacketType(PT_FILEFRAGMENT); + 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); + // File is not complete delete it + remove(fileneeded[i].filename); + } + } } // Functions cut and pasted from Doomatic :) diff --git a/src/d_netfil.h b/src/d_netfil.h index c87ff6f8c..171b3920f 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -43,10 +43,11 @@ typedef struct // Used only for download FILE *file; boolean *receivedfragments; + UINT32 fragmentsize; fileack_pak *ackpacket; - tic_t lasttimeackpacketsent; UINT32 currentsize; UINT32 totalsize; + UINT32 ackresendposition; // Used when resuming downloads filestatus_t status; // The value returned by recsearch boolean justdownloaded; // To prevent late fragments from causing an I_Error boolean textmode; // For files requested by Lua without the "b" option @@ -119,6 +120,7 @@ void MakePathDirs(char *path); void SV_AbortSendFiles(INT32 node); void CloseNetFile(void); +void CL_AbortDownloadResume(void); boolean fileexist(char *filename, time_t ptime); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index d2ed62516..e5cdb3206 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -293,6 +293,7 @@ static void I_ReportSignal(int num, int coredumped) FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) { D_QuitNetGame(); // Fix server freezes + CL_AbortDownloadResume(); I_ReportSignal(num, 0); I_ShutdownSystem(); signal(num, SIG_DFL); //default signal action @@ -2293,6 +2294,7 @@ void I_Quit(void) G_StopMetalRecording(false); D_QuitNetGame(); + CL_AbortDownloadResume(); I_ShutdownMusic(); I_ShutdownSound(); I_ShutdownCD(); @@ -2409,6 +2411,7 @@ void I_Error(const char *error, ...) G_StopMetalRecording(false); D_QuitNetGame(); + CL_AbortDownloadResume(); I_ShutdownMusic(); I_ShutdownSound(); I_ShutdownCD(); diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index f9d66be7f..fb0742c5a 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -465,6 +465,7 @@ static void signal_handler(int num) char sigdef[64]; D_QuitNetGame(); // Fix server freezes + CL_AbortDownloadResume(); I_ShutdownSystem(); switch (num) @@ -650,6 +651,7 @@ void I_Error(const char *error, ...) G_StopMetalRecording(false); D_QuitNetGame(); + CL_AbortDownloadResume(); // shutdown everything that was started I_ShutdownSystem(); @@ -745,6 +747,7 @@ void I_Quit(void) // or something else that will be finished by I_ShutdownSystem(), // so do it before. D_QuitNetGame(); + CL_AbortDownloadResume(); // shutdown everything that was started I_ShutdownSystem(); From 06d3af671634779a640c15a3fe9f9c953635aaa6 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 19 May 2020 15:16:51 +0200 Subject: [PATCH 19/33] Refactor Lua file transfer code --- src/blua/liolib.c | 11 +---------- src/d_netfil.c | 43 ++++++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/blua/liolib.c b/src/blua/liolib.c index b43052194..ce630a20b 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -314,16 +314,7 @@ void Got_LuaFile(UINT8 **cp, INT32 playernum) RemoveLuaFileTransfer(); if (server && luafiletransfers) - { - if (FIL_FileOK(luafiletransfers->realfilename)) - SV_PrepareSendLuaFileToNextNode(); - else - { - // Send a net command with 0 as its first byte to indicate the file couldn't be opened - success = 0; - SendNetXCmd(XD_LUAFILE, &success, 1); - } - } + SV_PrepareSendLuaFile(); } diff --git a/src/d_netfil.c b/src/d_netfil.c index b5647ebe2..2262a1f93 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -538,26 +538,9 @@ void AddLuaFileTransfer(const char *filename, const char *mode) strlcpy(filetransfer->mode, mode, sizeof(filetransfer->mode)); - if (server) - { - INT32 i; - - // Set status to "waiting" for everyone - for (i = 0; i < MAXNETNODES; i++) - filetransfer->nodestatus[i] = LFTNS_WAITING; - - if (!luafiletransfers->next) // Only if there is no transfer already going on - { - if (FIL_ReadFileOK(filetransfer->realfilename)) - SV_PrepareSendLuaFileToNextNode(); - else - { - // Send a net command with 0 as its first byte to indicate the file couldn't be opened - UINT8 success = 0; - SendNetXCmd(XD_LUAFILE, &success, 1); - } - } - } + // Only if there is no transfer already going on + if (server && filetransfer == luafiletransfers) + SV_PrepareSendLuaFile(); // Store the callback so it can be called once everyone has the file filetransfer->id = id; @@ -571,7 +554,7 @@ void AddLuaFileTransfer(const char *filename, const char *mode) } } -void SV_PrepareSendLuaFileToNextNode(void) +static void SV_PrepareSendLuaFileToNextNode(void) { INT32 i; UINT8 success = 1; @@ -595,6 +578,24 @@ void SV_PrepareSendLuaFileToNextNode(void) SendNetXCmd(XD_LUAFILE, &success, 1); } +void SV_PrepareSendLuaFile(void) +{ + INT32 i; + + // Set status to "waiting" for everyone + for (i = 0; i < MAXNETNODES; i++) + luafiletransfers->nodestatus[i] = LFTNS_WAITING; + + if (FIL_ReadFileOK(luafiletransfers->realfilename)) + SV_PrepareSendLuaFileToNextNode(); + else + { + // Send a net command with 0 as its first byte to indicate the file couldn't be opened + UINT8 success = 0; + SendNetXCmd(XD_LUAFILE, &success, 1); + } +} + void SV_HandleLuaFileSent(UINT8 node) { luafiletransfers->nodestatus[node] = LFTNS_SENT; From 34c5da39e25a4ecffea860d08086861c31b93d8b Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 19 May 2020 20:00:58 +0200 Subject: [PATCH 20/33] Create FIL_ConvertTextFileToBinary --- src/m_misc.c | 38 ++++++++++++++++++++++++++++++++++++++ src/m_misc.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/src/m_misc.c b/src/m_misc.c index 920a13198..c527d2296 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -297,6 +297,44 @@ size_t FIL_ReadFileTag(char const *name, UINT8 **buffer, INT32 tag) return length; } +/** Makes a copy of a text file with all newlines converted into LF newlines. + * + * \param textfilename The name of the source file + * \param binfilename The name of the destination file + */ +boolean FIL_ConvertTextFileToBinary(const char *textfilename, const char *binfilename) +{ + FILE *textfile; + FILE *binfile; + UINT8 buffer[1024]; + size_t count; + boolean success; + + textfile = fopen(textfilename, "r"); + if (!textfile) + return false; + + binfile = fopen(binfilename, "wb"); + if (!binfile) + { + fclose(textfile); + return false; + } + + do + { + count = fread(buffer, 1, sizeof(buffer), textfile); + fwrite(buffer, 1, count, binfile); + } while (count); + + success = !(ferror(textfile) || ferror(binfile)); + + fclose(textfile); + fclose(binfile); + + return success; +} + /** Check if the filename exists * * \param name Filename to check. diff --git a/src/m_misc.h b/src/m_misc.h index d64faea59..dbded37d0 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -48,6 +48,8 @@ boolean FIL_WriteFile(char const *name, const void *source, size_t length); size_t FIL_ReadFileTag(char const *name, UINT8 **buffer, INT32 tag); #define FIL_ReadFile(n, b) FIL_ReadFileTag(n, b, PU_STATIC) +boolean FIL_ConvertTextFileToBinary(const char *textfilename, const char *binfilename); + boolean FIL_FileExists(const char *name); boolean FIL_WriteFileOK(char const *name); boolean FIL_ReadFileOK(char const *name); From f620b52672870e82684e0d87ba0c73e1889315c5 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 19 May 2020 21:36:21 +0200 Subject: [PATCH 21/33] Fix sending Lua files in text mode --- src/blua/liolib.c | 10 ++++++++- src/d_clisrv.c | 6 +----- src/d_netfil.c | 52 ++++++++++++++++++++++++++--------------------- src/d_netfil.h | 6 ++---- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/blua/liolib.c b/src/blua/liolib.c index ce630a20b..2ccfa70e8 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -284,8 +284,16 @@ void Got_LuaFile(UINT8 **cp, INT32 playernum) // Push the first argument (file handle or nil) on the stack if (success) { + char mode[4]; + + // Ensure we are opening in binary mode + // (if it's a text file, newlines have been converted already) + strcpy(mode, luafiletransfers->mode); + if (!strchr(mode, 'b')) + strcat(mode, "b"); + pf = newfile(gL); // Create and push the file handle - *pf = fopen(luafiletransfers->realfilename, luafiletransfers->mode); // Open the file + *pf = fopen(luafiletransfers->realfilename, mode); // Open the file if (!*pf) I_Error("Can't open file \"%s\"\n", luafiletransfers->realfilename); // The file SHOULD exist } diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 089d967af..275eb790e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4239,11 +4239,7 @@ static void HandlePacketFromPlayer(SINT8 node) break; case PT_ASKLUAFILE: if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) - { - char *name = va("%s" PATHSEP "%s", luafiledir, luafiletransfers->filename); - boolean textmode = !strchr(luafiletransfers->mode, 'b'); - AddLuaFileToSendQueue(node, name, textmode); - } + AddLuaFileToSendQueue(node, luafiletransfers->realfilename); break; case PT_HASLUAFILE: if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_SENDING) diff --git a/src/d_netfil.c b/src/d_netfil.c index 2262a1f93..da190bc5c 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -69,7 +69,6 @@ typedef struct filetx_s UINT32 size; // Size of the file UINT8 fileid; INT32 node; // Destination - boolean textmode; // For files requested by Lua without the "b" option struct filetx_s *next; // Next file in the list } filetx_t; @@ -180,7 +179,6 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) fileneeded[i].file = NULL; // The file isn't open yet READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum - fileneeded[i].textmode = false; } } @@ -197,7 +195,6 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave) fileneeded[0].file = NULL; memset(fileneeded[0].md5sum, 0, 16); strcpy(fileneeded[0].filename, tmpsave); - fileneeded[0].textmode = false; } /** Checks the server to see if we CAN download all the files, @@ -507,8 +504,6 @@ void AddLuaFileTransfer(const char *filename, const char *mode) luafiletransfer_t *filetransfer; static INT32 id; - //CONS_Printf("AddLuaFileTransfer \"%s\"\n", filename); - // Find the last transfer in the list and set a pointer to its "next" field prevnext = &luafiletransfers; while (*prevnext) @@ -580,6 +575,7 @@ static void SV_PrepareSendLuaFileToNextNode(void) void SV_PrepareSendLuaFile(void) { + char *binfilename; INT32 i; // Set status to "waiting" for everyone @@ -587,7 +583,25 @@ void SV_PrepareSendLuaFile(void) luafiletransfers->nodestatus[i] = LFTNS_WAITING; if (FIL_ReadFileOK(luafiletransfers->realfilename)) + { + // If opening in text mode, convert all newlines to LF + if (!strchr(luafiletransfers->mode, 'b')) + { + binfilename = strdup(va("%s" PATHSEP "$$$%d%d.tmp", + luafiledir, rand(), rand())); + if (!binfilename) + I_Error("SV_PrepareSendLuaFile: Out of memory\n"); + + if (!FIL_ConvertTextFileToBinary(luafiletransfers->realfilename, binfilename)) + I_Error("SV_PrepareSendLuaFile: Failed to convert file newlines\n"); + + // Use the temporary file instead + free(luafiletransfers->realfilename); + luafiletransfers->realfilename = binfilename; + } + SV_PrepareSendLuaFileToNextNode(); + } else { // Send a net command with 0 as its first byte to indicate the file couldn't be opened @@ -606,6 +620,10 @@ void RemoveLuaFileTransfer(void) { luafiletransfer_t *filetransfer = luafiletransfers; + // If it was a temporary file, delete it + if (server && !strchr(filetransfer->mode, 'b')) + remove(filetransfer->realfilename); + RemoveLuaFileCallback(filetransfer->id); luafiletransfers = filetransfer->next; @@ -653,7 +671,6 @@ void CL_PrepareDownloadLuaFile(void) fileneeded[0].file = NULL; memset(fileneeded[0].md5sum, 0, 16); strcpy(fileneeded[0].filename, luafiletransfers->realfilename); - fileneeded[0].textmode = !strchr(luafiletransfers->mode, 'b'); // Make sure all directories in the file path exist MakePathDirs(fileneeded[0].filename); @@ -800,7 +817,7 @@ void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemet * \sa AddRamToSendQueue * */ -boolean AddLuaFileToSendQueue(INT32 node, const char *filename, boolean textmode) +boolean AddLuaFileToSendQueue(INT32 node, const char *filename) { filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t *p; // The new file request @@ -831,9 +848,6 @@ boolean AddLuaFileToSendQueue(INT32 node, const char *filename, boolean textmode strlcpy(p->id.filename, filename, MAX_WADPATH); // !!! //nameonly(p->id.filename); - // Open in text mode if required by the Lua script - p->textmode = textmode; - DEBFILE(va("Sending Lua file %s to %d\n", filename, node)); p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it p->next = NULL; // End of list @@ -937,7 +951,7 @@ void FileSendTicker(void) long filesize; transfer[i].currentfile = - fopen(f->id.filename, f->textmode ? "r" : "rb"); + fopen(f->id.filename, "rb"); if (!transfer[i].currentfile) I_Error("File %s does not exist", @@ -984,18 +998,10 @@ void FileSendTicker(void) M_Memcpy(p->data, &f->id.ram[transfer[i].position], fragmentsize); else { - size_t n; - fseek(transfer[i].currentfile, transfer[i].position, SEEK_SET); - n = fread(p->data, 1, fragmentsize, transfer[i].currentfile); - if (n != fragmentsize) // Either an error or Windows turning CR-LF into LF - { - if (f->textmode && feof(transfer[i].currentfile)) - fragmentsize = n; - else if (fread(p->data, 1, fragmentsize, transfer[i].currentfile) != fragmentsize) - I_Error("FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(fragmentsize), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); - } + if (fread(p->data, 1, fragmentsize, transfer[i].currentfile) != fragmentsize) + I_Error("FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(fragmentsize), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); } p->position = LONG(transfer[i].position); p->fileid = f->fileid; @@ -1195,7 +1201,7 @@ void PT_FileFragment(void) if (CL_CanResumeDownload(file)) { - file->file = fopen(filename, file->textmode ? "r+" : "r+b"); + file->file = fopen(filename, "r+b"); if (!file->file) I_Error("Can't reopen file %s: %s", filename, strerror(errno)); CONS_Printf("\r%s...\n", filename); @@ -1212,7 +1218,7 @@ void PT_FileFragment(void) { CL_AbortDownloadResume(); - file->file = fopen(filename, file->textmode ? "w" : "wb"); + file->file = fopen(filename, "wb"); if (!file->file) I_Error("Can't create file %s: %s", filename, strerror(errno)); diff --git a/src/d_netfil.h b/src/d_netfil.h index 171b3920f..dce2c929f 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -50,7 +50,6 @@ typedef struct UINT32 ackresendposition; // Used when resuming downloads filestatus_t status; // The value returned by recsearch boolean justdownloaded; // To prevent late fragments from causing an I_Error - boolean textmode; // For files requested by Lua without the "b" option } fileneeded_t; extern INT32 fileneedednum; @@ -105,9 +104,8 @@ extern boolean waitingforluafiletransfer; extern char luafiledir[256 + 16]; void AddLuaFileTransfer(const char *filename, const char *mode); -void SV_PrepareSendLuaFileToNextNode(void); -boolean AddLuaFileToSendQueue(INT32 node, const char *filename, boolean textmode); -void SV_PrepareSendLuaFile(const char *filename); +void SV_PrepareSendLuaFile(void); +boolean AddLuaFileToSendQueue(INT32 node, const char *filename); void SV_HandleLuaFileSent(UINT8 node); void RemoveLuaFileTransfer(void); void RemoveAllLuaFileTransfers(void); From c8948909d37e1421d4faf7959ab9be29ec4277a4 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 19 May 2020 23:50:37 +0200 Subject: [PATCH 22/33] Fix I_Error when queuing multiple Lua files --- src/blua/liolib.c | 6 ++++++ src/d_clisrv.c | 1 + src/d_netfil.c | 13 +++++++++++++ src/d_netfil.h | 2 ++ 4 files changed, 22 insertions(+) diff --git a/src/blua/liolib.c b/src/blua/liolib.c index 2ccfa70e8..a055aad3f 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -321,6 +321,12 @@ void Got_LuaFile(UINT8 **cp, INT32 playernum) RemoveLuaFileTransfer(); + if (waitingforluafilecommand) + { + waitingforluafilecommand = false; + CL_PrepareDownloadLuaFile(); + } + if (server && luafiletransfers) SV_PrepareSendLuaFile(); } diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 275eb790e..dbf10d58e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3256,6 +3256,7 @@ void D_QuitNetGame(void) CloseNetFile(); RemoveAllLuaFileTransfers(); waitingforluafiletransfer = false; + waitingforluafilecommand = false; if (server) { diff --git a/src/d_netfil.c b/src/d_netfil.c index da190bc5c..c5f3d8658 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -110,6 +110,7 @@ INT32 lastfilenum = -1; luafiletransfer_t *luafiletransfers = NULL; boolean waitingforluafiletransfer = false; +boolean waitingforluafilecommand = false; char luafiledir[256 + 16] = "luafiles"; @@ -536,6 +537,8 @@ void AddLuaFileTransfer(const char *filename, const char *mode) // Only if there is no transfer already going on if (server && filetransfer == luafiletransfers) SV_PrepareSendLuaFile(); + else + filetransfer->ongoing = false; // Store the callback so it can be called once everyone has the file filetransfer->id = id; @@ -578,6 +581,8 @@ void SV_PrepareSendLuaFile(void) char *binfilename; INT32 i; + luafiletransfers->ongoing = true; + // Set status to "waiting" for everyone for (i = 0; i < MAXNETNODES; i++) luafiletransfers->nodestatus[i] = LFTNS_WAITING; @@ -660,6 +665,12 @@ void CL_PrepareDownloadLuaFile(void) return; } + if (luafiletransfers->ongoing) + { + waitingforluafilecommand = true; + return; + } + // Tell the server we are ready to receive the file netbuffer->packettype = PT_ASKLUAFILE; HSendPacket(servernode, true, 0, 0); @@ -674,6 +685,8 @@ void CL_PrepareDownloadLuaFile(void) // Make sure all directories in the file path exist MakePathDirs(fileneeded[0].filename); + + luafiletransfers->ongoing = true; } // Number of files to send diff --git a/src/d_netfil.h b/src/d_netfil.h index dce2c929f..be58f807f 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -95,12 +95,14 @@ typedef struct luafiletransfer_s char *realfilename; char mode[4]; // rb+/wb+/ab+ + null character INT32 id; // Callback ID + boolean ongoing; luafiletransfernodestatus_t nodestatus[MAXNETNODES]; struct luafiletransfer_s *next; } luafiletransfer_t; extern luafiletransfer_t *luafiletransfers; extern boolean waitingforluafiletransfer; +extern boolean waitingforluafilecommand; extern char luafiledir[256 + 16]; void AddLuaFileTransfer(const char *filename, const char *mode); From 06060c02d38d174031e2d0fc1488f44920323611 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 20 May 2020 00:24:53 +0200 Subject: [PATCH 23/33] Add a command to list current file transfers --- src/d_netcmd.c | 2 ++ src/d_netfil.c | 34 ++++++++++++++++++++++++++++++++++ src/d_netfil.h | 2 ++ 3 files changed, 38 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index dfc7351f5..042b99cc7 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -501,6 +501,8 @@ void D_RegisterServerCommands(void) COM_AddCommand("archivetest", Command_Archivetest_f); #endif + COM_AddCommand("downloads", Command_Downloads_f); + // for master server connection AddMServCommands(); diff --git a/src/d_netfil.c b/src/d_netfil.c index c5f3d8658..9e43da791 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1386,6 +1386,40 @@ void CloseNetFile(void) } } +void Command_Downloads_f(void) +{ + INT32 node; + + for (node = 0; node < MAXNETNODES; node++) + if (transfer[node].txlist + && transfer[node].txlist->ram == SF_FILE) // Node is downloading a file? + { + const char *name = transfer[node].txlist->id.filename; + UINT32 position = transfer[node].position; + UINT32 size = transfer[node].txlist->size; + char ratecolor; + + // Avoid division by zero errors + if (!size) + size = 1; + + name = &name[strlen(name) - nameonlylength(name)]; + switch (4 * (position - 1) / size) + { + case 0: ratecolor = '\x85'; break; + case 1: ratecolor = '\x87'; break; + case 2: ratecolor = '\x82'; break; + case 3: ratecolor = '\x83'; break; + default: ratecolor = '\x80'; + } + + CONS_Printf("%2d %c%s ", node, ratecolor, name); // Node and file name + CONS_Printf("\x80%uK\x84/\x80%uK ", position / 1024, size / 1024); // Progress in kB + CONS_Printf("\x80(%c%u%%\x80) ", ratecolor, (UINT32)(100.0 * position / size)); // Progress in % + CONS_Printf("%s\n", I_GetNodeAddress(node)); // Address and newline + } +} + // Functions cut and pasted from Doomatic :) void nameonly(char *s) diff --git a/src/d_netfil.h b/src/d_netfil.h index be58f807f..a653d5a4b 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -122,6 +122,8 @@ void SV_AbortSendFiles(INT32 node); void CloseNetFile(void); void CL_AbortDownloadResume(void); +void Command_Downloads_f(void); + boolean fileexist(char *filename, time_t ptime); // Search a file in the wadpath, return FS_FOUND when found From bf00955786cf0628afb2639915ba1a1c8bf69eba Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 20 May 2020 16:21:18 +0200 Subject: [PATCH 24/33] Wait for acks before resending file fragments --- src/d_clisrv.h | 2 ++ src/d_netfil.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- src/d_netfil.h | 6 ++++-- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index cbae55017..c8241fede 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -326,6 +326,7 @@ typedef struct { UINT8 fileid; UINT32 filesize; + UINT8 iteration; UINT32 position; UINT16 size; UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH @@ -340,6 +341,7 @@ typedef struct typedef struct { UINT8 fileid; + UINT8 iteration; UINT8 numsegments; fileacksegment_t segments[0]; } ATTRPACK fileack_pak; diff --git a/src/d_netfil.c b/src/d_netfil.c index 9e43da791..560e4d334 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -76,10 +76,13 @@ typedef struct filetx_s typedef struct filetran_s { filetx_t *txlist; // Linked list of all files for the node + UINT8 iteration; + UINT8 ackediteration; UINT32 position; // The current position in the file boolean *ackedfragments; UINT32 ackedsize; FILE *currentfile; // The file currently being sent/received + tic_t dontsenduntil; } filetran_t; static filetran_t transfer[MAXNETNODES]; @@ -986,20 +989,36 @@ void FileSendTicker(void) else // Sending RAM transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open + transfer[i].iteration = 1; + transfer[i].ackediteration = 0; transfer[i].position = 0; transfer[i].ackedsize = 0; transfer[i].ackedfragments = calloc(f->size / FILEFRAGMENTSIZE + 1, sizeof(*transfer[i].ackedfragments)); if (!transfer[i].ackedfragments) I_Error("FileSendTicker: No more memory\n"); + + transfer[i].dontsenduntil = 0; } + // If the client hasn't acknowledged any fragment from the previous iteration, + // it is most likely because their acks haven't had enough time to reach the server + // yet, due to latency. In that case, we wait a little to avoid useless resend. + if (I_GetTime() < transfer[i].dontsenduntil) + continue; + // Find the first non-acknowledged fragment while (transfer[i].ackedfragments[transfer[i].position / FILEFRAGMENTSIZE]) { transfer[i].position += FILEFRAGMENTSIZE; if (transfer[i].position >= f->size) + { + if (transfer[i].ackediteration < transfer[i].iteration) + transfer[i].dontsenduntil = I_GetTime() + TICRATE / 2; + transfer[i].position = 0; + transfer[i].iteration++; + } } // Build a packet containing a file fragment @@ -1016,6 +1035,7 @@ void FileSendTicker(void) if (fread(p->data, 1, fragmentsize, transfer[i].currentfile) != fragmentsize) I_Error("FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(fragmentsize), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); } + p->iteration = transfer[i].iteration; p->position = LONG(transfer[i].position); p->fileid = f->fileid; p->filesize = LONG(f->size); @@ -1026,7 +1046,13 @@ void FileSendTicker(void) { // Success transfer[i].position = (UINT32)(transfer[i].position + fragmentsize); if (transfer[i].position >= f->size) + { + if (transfer[i].ackediteration < transfer[i].iteration) + transfer[i].dontsenduntil = I_GetTime() + TICRATE / 2; + transfer[i].position = 0; + transfer[i].iteration++; + } } else { // Not sent for some odd reason, retry at next call @@ -1053,6 +1079,13 @@ void PT_FileAck(void) return; } + if (packet->iteration > trans->ackediteration) + { + trans->ackediteration = packet->iteration; + if (trans->ackediteration >= trans->iteration - 1) + trans->dontsenduntil = 0; + } + for (i = 0; i < packet->numsegments; i++) { fileacksegment_t *segment = &packet->segments[i]; @@ -1114,10 +1147,12 @@ static void SendAckPacket(fileack_pak *packet, UINT8 fileid) memset(packet, 0, sizeof(*packet) + 512); } -static void AddFragmentToAckPacket(fileack_pak *packet, UINT32 fragmentpos, UINT8 fileid) +static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32 fragmentpos, UINT8 fileid) { fileacksegment_t *segment = &packet->segments[packet->numsegments - 1]; + packet->iteration = max(packet->iteration, iteration); + if (packet->numsegments == 0 || fragmentpos < segment->start || fragmentpos - segment->start >= 32) @@ -1157,7 +1192,7 @@ void FileReceiveTicker(void) for (j = 0; j < 2048; j++) { if (file->receivedfragments[file->ackresendposition]) - AddFragmentToAckPacket(file->ackpacket, file->ackresendposition, i); + AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i); file->ackresendposition++; if (file->ackresendposition * file->fragmentsize >= file->totalsize) @@ -1207,6 +1242,7 @@ void PT_FileFragment(void) file->status = FS_DOWNLOADING; file->fragmentsize = fragmentsize; + file->iteration = 0; file->ackpacket = calloc(1, sizeof(*file->ackpacket) + 512); if (!file->ackpacket) @@ -1254,6 +1290,8 @@ void PT_FileFragment(void) if (fragmentpos >= file->totalsize) I_Error("Invalid file fragment\n"); + file->iteration = max(file->iteration, netbuffer->u.filetxpak.iteration); + if (!file->receivedfragments[fragmentpos / fragmentsize]) // Not received yet { file->receivedfragments[fragmentpos / fragmentsize] = true; @@ -1264,7 +1302,7 @@ void PT_FileFragment(void) I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file)); file->currentsize += boundedfragmentsize; - AddFragmentToAckPacket(file->ackpacket, fragmentpos / fragmentsize, filenum); + AddFragmentToAckPacket(file->ackpacket, file->iteration, fragmentpos / fragmentsize, filenum); // Finished? if (file->currentsize == file->totalsize) @@ -1295,7 +1333,7 @@ void PT_FileFragment(void) { // If they are sending us the fragment again, it's probably because // they missed our previous ack, so we must re-acknowledge it - AddFragmentToAckPacket(file->ackpacket, fragmentpos / fragmentsize, filenum); + AddFragmentToAckPacket(file->ackpacket, file->iteration, fragmentpos / fragmentsize, filenum); } } else if (!file->justdownloaded) diff --git a/src/d_netfil.h b/src/d_netfil.h index a653d5a4b..2225157cb 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -40,16 +40,18 @@ typedef struct UINT8 willsend; // Is the server willing to send it? char filename[MAX_WADPATH]; UINT8 md5sum[16]; + filestatus_t status; // The value returned by recsearch + boolean justdownloaded; // To prevent late fragments from causing an I_Error + // Used only for download FILE *file; boolean *receivedfragments; UINT32 fragmentsize; + UINT8 iteration; fileack_pak *ackpacket; UINT32 currentsize; UINT32 totalsize; UINT32 ackresendposition; // Used when resuming downloads - filestatus_t status; // The value returned by recsearch - boolean justdownloaded; // To prevent late fragments from causing an I_Error } fileneeded_t; extern INT32 fileneedednum; From 1dbb75574323086cf7859584c9c4073361cf39a6 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Fri, 29 May 2020 17:35:07 +0200 Subject: [PATCH 25/33] Add dofile() to Lua --- src/blua/lbaselib.c | 26 ++++++++++++++++++++++++++ src/lua_script.c | 14 +++++++------- src/lua_script.h | 4 ++-- src/w_wad.c | 20 ++++++++++++++------ 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/blua/lbaselib.c b/src/blua/lbaselib.c index 3c919cb64..644565c28 100644 --- a/src/blua/lbaselib.c +++ b/src/blua/lbaselib.c @@ -11,6 +11,10 @@ #include #include +#include "../doomdef.h" +#include "../lua_script.h" +#include "../w_wad.h" + #define lbaselib_c #define LUA_LIB @@ -263,6 +267,27 @@ static int luaB_ipairs (lua_State *L) { } +// Edited to load PK3 entries instead +static int luaB_dofile (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + char fullfilename[256]; + UINT16 lumpnum; + int n = lua_gettop(L); + + if (wadfiles[numwadfiles - 1]->type != RET_PK3) + luaL_error(L, "dofile() only works with PK3 files"); + + snprintf(fullfilename, sizeof(fullfilename), "Lua/%s", filename); + lumpnum = W_CheckNumForFullNamePK3(fullfilename, numwadfiles - 1, 0); + if (lumpnum == INT16_MAX) + luaL_error(L, "can't find script " LUA_QS, fullfilename); + + LUA_LoadLump(numwadfiles - 1, lumpnum, false); + + return lua_gettop(L) - n; +} + + static int luaB_assert (lua_State *L) { luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) @@ -380,6 +405,7 @@ static const luaL_Reg base_funcs[] = { {"assert", luaB_assert}, {"collectgarbage", luaB_collectgarbage}, {"error", luaB_error}, + {"dofile", luaB_dofile}, {"gcinfo", luaB_gcinfo}, {"getfenv", luaB_getfenv}, {"getmetatable", luaB_getmetatable}, diff --git a/src/lua_script.c b/src/lua_script.c index 4f94b007e..0e0361535 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -395,10 +395,10 @@ void LUA_ClearExtVars(void) // Use this variable to prevent certain functions from running // if they were not called on lump load // (i.e. they were called in hooks or coroutines etc) -boolean lua_lumploading = false; +INT32 lua_lumploading = 0; // Load a script from a MYFILE -static inline void LUA_LoadFile(MYFILE *f, char *name) +static inline void LUA_LoadFile(MYFILE *f, char *name, boolean noresults) { if (!name) name = wadfiles[f->wad]->filename; @@ -408,19 +408,19 @@ static inline void LUA_LoadFile(MYFILE *f, char *name) lua_pushinteger(gL, f->wad); lua_setfield(gL, LUA_REGISTRYINDEX, "WAD"); - lua_lumploading = true; // turn on loading flag + lua_lumploading++; // turn on loading flag - if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, 0, 0)) { + if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, noresults ? 0 : LUA_MULTRET, 0)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); lua_pop(gL,1); } lua_gc(gL, LUA_GCCOLLECT, 0); - lua_lumploading = false; // turn off again + lua_lumploading--; // turn off again } // Load a script from a lump -void LUA_LoadLump(UINT16 wad, UINT16 lump) +void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults) { MYFILE f; char *name; @@ -447,7 +447,7 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump) name[len] = '\0'; } - LUA_LoadFile(&f, name); // actually load file! + LUA_LoadFile(&f, name, noresults); // actually load file! free(name); Z_Free(f.data); diff --git a/src/lua_script.h b/src/lua_script.h index 8d5bed7c7..6815434c5 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -37,9 +37,9 @@ void LUA_ClearExtVars(void); #endif -extern boolean lua_lumploading; // is LUA_LoadLump being called? +extern INT32 lua_lumploading; // is LUA_LoadLump being called? -void LUA_LoadLump(UINT16 wad, UINT16 lump); +void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults); #ifdef LUA_ALLOW_BYTECODE void LUA_DumpFile(const char *filename); #endif diff --git a/src/w_wad.c b/src/w_wad.c index 041222479..af9f9a7c0 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -199,12 +199,20 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile) { UINT16 posStart, posEnd; - posStart = W_CheckNumForFolderStartPK3("Lua/", wadnum, 0); + posStart = W_CheckNumForFullNamePK3("Init.lua", wadnum, 0); if (posStart != INT16_MAX) { - posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart); - for (; posStart < posEnd; posStart++) - LUA_LoadLump(wadnum, posStart); + LUA_LoadLump(wadnum, posStart, true); + } + else + { + posStart = W_CheckNumForFolderStartPK3("Lua/", wadnum, 0); + if (posStart != INT16_MAX) + { + posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart); + for (; posStart < posEnd; posStart++) + LUA_LoadLump(wadnum, posStart, true); + } } posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0); @@ -236,7 +244,7 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo; for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++) if (memcmp(lump_p->name,"LUA_",4)==0) - LUA_LoadLump(wadnum, lump); + LUA_LoadLump(wadnum, lump, true); } { @@ -854,7 +862,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) DEH_LoadDehackedLumpPwad(numwadfiles - 1, 0, mainfile); break; case RET_LUA: - LUA_LoadLump(numwadfiles - 1, 0); + LUA_LoadLump(numwadfiles - 1, 0, true); break; default: break; From d589e6bc959ff072531fbe61c8956b24563f665b Mon Sep 17 00:00:00 2001 From: SwitchKaze Date: Fri, 29 May 2020 21:41:20 -0500 Subject: [PATCH 26/33] Fix signpost shade. --- src/p_enemy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 18de57b54..68b246cdc 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5213,7 +5213,7 @@ void A_SignPlayer(mobj_t *actor) actor->tracer->color = signcolor; if (signcolor && signcolor < numskincolors) - signframe += (15 - skincolors[signcolor].invshade); + signframe += (15 - skincolors[facecolor].invshade); actor->tracer->frame = signframe; } From 5a18bdf20b3e062b3d7d8b1935bb93385fb37801 Mon Sep 17 00:00:00 2001 From: SwitchKaze Date: Sat, 30 May 2020 16:52:44 -0500 Subject: [PATCH 27/33] Fix SOC color name reading --- src/dehacked.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 627a3a119..b5ba248ce 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -769,7 +769,8 @@ static void readthing(MYFILE *f, INT32 num) static void readskincolor(MYFILE *f, INT32 num) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word, *word2, *word3; + char *word = s; + char *word2; char *tmp; Color_cons_t[num].value = num; @@ -781,32 +782,31 @@ static void readskincolor(MYFILE *f, INT32 num) if (s[0] == '\n') break; + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + tmp = strchr(s, '#'); if (tmp) *tmp = '\0'; if (s == tmp) continue; // Skip comment lines, but don't break. - word = strtok(s, " "); - if (word) - strupr(word); + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; else break; + strupr(word); - word2 = strtok(NULL, " = "); - if (word2) { - word3 = Z_StrDup(word2); - strupr(word2); - } else - break; - if (word2[strlen(word2)-1] == '\n') - word2[strlen(word2)-1] = '\0'; - if (word3[strlen(word3)-1] == '\n') - word3[strlen(word3)-1] = '\0'; + // Now get the part after + word2 = tmp += 2; if (fastcmp(word, "NAME")) { - deh_strlcpy(skincolors[num].name, word3, + deh_strlcpy(skincolors[num].name, word2, sizeof (skincolors[num].name), va("Skincolor %d: name", num)); } else if (fastcmp(word, "RAMP")) From 3c3a60d189981920f9b0837a4db24a3488ac9f53 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 1 Jun 2020 10:37:05 +0200 Subject: [PATCH 28/33] Fix "downloads" command reporting incorrect progress --- src/d_netfil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_netfil.c b/src/d_netfil.c index 560e4d334..7b99fddfb 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1433,7 +1433,7 @@ void Command_Downloads_f(void) && transfer[node].txlist->ram == SF_FILE) // Node is downloading a file? { const char *name = transfer[node].txlist->id.filename; - UINT32 position = transfer[node].position; + UINT32 position = transfer[node].ackedsize; UINT32 size = transfer[node].txlist->size; char ratecolor; From e6ffedbce8a3620fa9aada0b892b01379ac6c440 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 1 Jun 2020 15:21:16 +0200 Subject: [PATCH 29/33] Fix food occasionally spawning inside the snake --- src/d_clisrv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1857df04f..646f77baa 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1268,7 +1268,7 @@ static UINT8 Snake_GetOppositeDir(UINT8 dir) return 12 + 5 - dir; } -static void Snake_FindFreeSlot(UINT8 *x, UINT8 *y) +static void Snake_FindFreeSlot(UINT8 *x, UINT8 *y, UINT8 headx, UINT8 heady) { UINT16 i; @@ -1280,7 +1280,7 @@ static void Snake_FindFreeSlot(UINT8 *x, UINT8 *y) for (i = 0; i < snake->snakelength; i++) if (*x == snake->snakex[i] && *y == snake->snakey[i]) break; - } while (i < snake->snakelength); + } while (i < snake->snakelength || (*x == headx && *y == heady)); } static void Snake_Handle(void) @@ -1420,7 +1420,7 @@ static void Snake_Handle(void) } // Spawn new apple - Snake_FindFreeSlot(&snake->applex, &snake->appley); + Snake_FindFreeSlot(&snake->applex, &snake->appley, x, y); // Spawn new bonus if (!(snake->snakelength % 5)) @@ -1431,7 +1431,7 @@ static void Snake_Handle(void) } while (snake->snakelength > SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y * 3 / 4 && (snake->bonustype == SNAKE_BONUS_EGGMAN || snake->bonustype == SNAKE_BONUS_FAST || snake->bonustype == SNAKE_BONUS_REVERSE)); - Snake_FindFreeSlot(&snake->bonusx, &snake->bonusy); + Snake_FindFreeSlot(&snake->bonusx, &snake->bonusy, x, y); } S_StartSound(NULL, sfx_s3k6b); From 286b316cf98722a6c80130fd1714370762aa2663 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 1 Jun 2020 15:43:14 +0200 Subject: [PATCH 30/33] Fix dofile() return incorrect values --- src/lua_script.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lua_script.c b/src/lua_script.c index a0e4588a4..374294d6e 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -452,6 +452,8 @@ INT32 lua_lumploading = 0; // Load a script from a MYFILE static inline void LUA_LoadFile(MYFILE *f, char *name, boolean noresults) { + int errorhandlerindex; + if (!name) name = wadfiles[f->wad]->filename; CONS_Printf("Loading Lua script from %s\n", name); @@ -463,12 +465,13 @@ static inline void LUA_LoadFile(MYFILE *f, char *name, boolean noresults) lua_lumploading++; // turn on loading flag lua_pushcfunction(gL, LUA_GetErrorMessage); + errorhandlerindex = lua_gettop(gL); if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, noresults ? 0 : LUA_MULTRET, lua_gettop(gL) - 1)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); lua_pop(gL,1); } lua_gc(gL, LUA_GCCOLLECT, 0); - lua_pop(gL, 1); // Pop error handler + lua_remove(gL, errorhandlerindex); lua_lumploading--; // turn off again } From 2cefe8295094653eb54c1bb82e76315cdee7cd40 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Mon, 8 Jun 2020 00:08:07 -0400 Subject: [PATCH 31/33] Fix OSX null-pointer-arithmetic error --- src/hardware/r_opengl/r_opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index ed60f2175..73f6a4044 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1924,7 +1924,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model) } } -#define BUFFER_OFFSET(i) ((char*)NULL + (i)) +#define BUFFER_OFFSET(i) ((void*)(i)) static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 *color) { From a5f7f9a5342fb632a7887a7dc5995fc5f669ab51 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 6 Jun 2020 17:34:07 -0400 Subject: [PATCH 32/33] Fix OPENMPT deprecation error, openmpt_module_ctl_set --- src/sdl/mixer_sound.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 9a713608c..5a086880a 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -880,13 +880,18 @@ boolean I_SetSongSpeed(float speed) #ifdef HAVE_OPENMPT if (openmpt_mhandle) { - char modspd[13]; - if (speed > 4.0f) speed = 4.0f; // Limit this to 4x to prevent crashing, stupid fix but... ~SteelT 27/9/19 - - sprintf(modspd, "%g", speed); - openmpt_module_ctl_set(openmpt_mhandle, "play.tempo_factor", modspd); +#if OPENMPT_API_VERSION_MAJOR < 1 && OPENMPT_API_VERSION_MINOR < 5 + { + // deprecated in 0.5.0 + char modspd[13]; + sprintf(modspd, "%g", speed); + openmpt_module_ctl_set(openmpt_mhandle, "play.tempo_factor", modspd); + } +#else + openmpt_module_ctl_set_floatingpoint(openmpt_mhandle, "play.tempo_factor", (double)speed); +#endif return true; } #else From d3d5496a7834da0864897c9d005b2a372017b2fa Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Wed, 17 Jun 2020 14:09:49 -0400 Subject: [PATCH 33/33] Fix facecolor may be used uninitialized. --- src/p_enemy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 146c8f1aa..578874574 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5106,9 +5106,11 @@ void A_SignPlayer(mobj_t *actor) INT32 locvar2 = var2; skin_t *skin = NULL; mobj_t *ov; - UINT16 facecolor, signcolor = (UINT16)locvar2; + UINT16 facecolor, signcolor = 0; UINT32 signframe = states[actor->info->raisestate].frame; + facecolor = signcolor = (UINT16)locvar2; + if (LUA_CallAction("A_SignPlayer", actor)) return;