From c53762058b2d38fe68b1f538cb11c9b4081a97e2 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 31 Aug 2010 19:59:24 +0000 Subject: Don't double OPL sample values, as it causes horrible things to happen with the Heretic title screen music. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 1988 --- opl/opl_sdl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c index f6a3b229..5059fb5e 100644 --- a/opl/opl_sdl.c +++ b/opl/opl_sdl.c @@ -176,8 +176,8 @@ static void FillBuffer(int16_t *buffer, unsigned int nsamples) for (i=0; i" \ - % sys.argv[0] - print " -c : Provide documentation for the specified configuration file" - print " -m : Manpage output" - print " -w : Wikitext output" - print " -p : Plaintext output" - print " -V : Don't show Vanilla Doom options" + print("Usage: %s [-V] [-c filename ]( -m | -w | -p ) " \ + % sys.argv[0]) + print(" -c : Provide documentation for the specified configuration file") + print(" -m : Manpage output") + print(" -w : Wikitext output") + print(" -p : Plaintext output") + print(" -V : Don't show Vanilla Doom options") sys.exit(0) # Parse command line diff --git a/pkg/wince/wince-cabgen b/pkg/wince/wince-cabgen index 97cba132..76845cf9 100755 --- a/pkg/wince/wince-cabgen +++ b/pkg/wince/wince-cabgen @@ -3,10 +3,11 @@ import os import re import shutil +import struct import sys import tempfile -CAB_HEADER = "MSCE" +CAB_HEADER = "MSCE".encode("ascii") ARCHITECTURES = { "shx-sh3": 103, @@ -58,16 +59,10 @@ DIR_VARIABLES = { } def write_int16(f, value): - b1 = value & 0xff - b2 = (value >> 8) & 0xff - f.write("%c%c" % (b1, b2)) + f.write(struct.pack("> 8) & 0xff - b3 = (value >> 16) & 0xff - b4 = (value >> 24) & 0xff - f.write("%c%c%c%c" % (b1, b2, b3, b4)) + f.write(struct.pack(" " % sys.argv[0] + print("Usage: %s " % sys.argv[0]) sys.exit(0) if sys.argv[1] == "-d": -- cgit v1.2.3 From b03de59700f80c75308849ac5f89310d010af066 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 21 Nov 2010 15:44:43 +0000 Subject: Add -8in32 command line parameter to make the game run in 32-bit color mode, scaling up into an intermediate 8-bit buffer first. This should help with the palette problems experienced by Windows Vista/7 users. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2164 --- src/i_video.c | 98 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 31 deletions(-) diff --git a/src/i_video.c b/src/i_video.c index ee10a12e..1139157d 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -93,6 +93,12 @@ char *video_driver = ""; static SDL_Surface *screen; +// Intermediate 8-bit buffer that we draw to instead of 'screen'. +// This is used when we are rendering in 32-bit screen mode. +// When in a real 8-bit screen mode, screenbuffer == screen. + +static SDL_Surface *screenbuffer; + // palette static SDL_Color palette[256]; @@ -750,17 +756,18 @@ static boolean BlitArea(int x1, int y1, int x2, int y2) return true; } - x_offset = (screen->w - screen_mode->width) / 2; - y_offset = (screen->h - screen_mode->height) / 2; + x_offset = (screenbuffer->w - screen_mode->width) / 2; + y_offset = (screenbuffer->h - screen_mode->height) / 2; - if (SDL_LockSurface(screen) >= 0) + if (SDL_LockSurface(screenbuffer) >= 0) { - I_InitScale(screens[0], - (byte *) screen->pixels + (y_offset * screen->pitch) - + x_offset, - screen->pitch); + I_InitScale(screens[0], + (byte *) screenbuffer->pixels + + (y_offset * screenbuffer->pitch) + + x_offset, + screenbuffer->pitch); result = screen_mode->DrawScreen(x1, y1, x2, y2); - SDL_UnlockSurface(screen); + SDL_UnlockSurface(screenbuffer); } else { @@ -895,19 +902,30 @@ void I_FinishUpdate (void) // draw to screen BlitArea(0, 0, SCREENWIDTH, SCREENHEIGHT); - - // If we have a palette to set, the act of setting the palette - // updates the screen if (palette_to_set) { - SDL_SetColors(screen, palette, 0, 256); + SDL_SetColors(screenbuffer, palette, 0, 256); palette_to_set = false; + + // In native 8-bit mode, if we have a palette to set, the act + // of setting the palette updates the screen + + if (screenbuffer == screen) + { + return; + } } - else + + // In 8in32 mode, we must blit from the fake 8-bit screen buffer + // to the real screen before doing a screen flip. + + if (screenbuffer != screen) { - SDL_Flip(screen); + SDL_BlitSurface(screenbuffer, NULL, screen, NULL); } + + SDL_Flip(screen); } @@ -1540,6 +1558,7 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) { byte *doompal; int flags = 0; + int bpp = 8; doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); @@ -1552,7 +1571,16 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) // Set the video mode. - flags |= SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF; + flags |= SDL_SWSURFACE; + + if (M_CheckParm("-8in32")) + { + bpp = 32; + } + else + { + flags |= SDL_HWPALETTE | SDL_DOUBLEBUF; + } if (fullscreen) { @@ -1563,11 +1591,23 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) flags |= SDL_RESIZABLE; } - screen = SDL_SetVideoMode(w, h, 8, flags); + screen = SDL_SetVideoMode(w, h, bpp, flags); if (screen == NULL) { - I_Error("Error setting video mode: %s\n", SDL_GetError()); + I_Error("Error setting video mode %ix%ix%ibpp: %s\n", + w, h, bpp, SDL_GetError()); + } + + if (screen->format->BitsPerPixel == 8) + { + screenbuffer = screen; + } + else + { + screenbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, + screen->w, screen->h, 8, + 0, 0, 0, 0); } // If mode was not set, it must be set now that we know the @@ -1708,24 +1748,19 @@ void I_InitGraphics(void) // Start with a clear black screen // (screen will be flipped after we set the palette) - if (SDL_LockSurface(screen) >= 0) - { - byte *screenpixels; - int y; - - screenpixels = (byte *) screen->pixels; - - for (y=0; yh; ++y) - memset(screenpixels + screen->pitch * y, 0, screen->w); - - SDL_UnlockSurface(screen); - } + SDL_FillRect(screenbuffer, NULL, 0); // Set the palette doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); I_SetPalette(doompal); - SDL_SetColors(screen, palette, 0, 256); + SDL_SetColors(screenbuffer, palette, 0, 256); + + if (screen != screenbuffer) + { + SDL_BlitSurface(screenbuffer, NULL, screen, NULL); + SDL_Flip(screen); + } CreateCursors(); @@ -1747,7 +1782,8 @@ void I_InitGraphics(void) // Likewise if the screen pitch is not the same as the width // If we have to multiply, drawing is done to a separate 320x200 buf - native_surface = !SDL_MUSTLOCK(screen) + native_surface = screen == screenbuffer + && !SDL_MUSTLOCK(screen) && screen_mode == &mode_scale_1x && screen->pitch == SCREENWIDTH && aspect_ratio_correct; -- cgit v1.2.3 From cf82ce9d7bb8d71ae583753aab642c5ba4ee8d06 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Wed, 24 Nov 2010 08:09:48 +0000 Subject: Add workaround to stop freezeups with old versions of SDL_mixer. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2165 --- src/i_sdlsound.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/i_sdlsound.c b/src/i_sdlsound.c index a758289a..a26a81dd 100644 --- a/src/i_sdlsound.c +++ b/src/i_sdlsound.c @@ -53,6 +53,8 @@ #define MAX_SOUND_SLICE_TIME 70 /* ms */ #define NUM_CHANNELS 16 +static boolean setpanning_workaround = false; + static boolean sound_initialized = false; static Mix_Chunk sound_chunks[NUMSFX]; @@ -620,10 +622,19 @@ static void I_SDL_UpdateSoundParams(int handle, int vol, int sep) left = ((254 - sep) * vol) / 127; right = ((sep) * vol) / 127; + // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning + // function. A workaround is to call Mix_UnregisterAllEffects for + // the channel before calling it. This is undesirable as it may lead + // to the channel volumes resetting briefly. + + if (setpanning_workaround) + { + Mix_UnregisterAllEffects(handle); + } + Mix_SetPanning(handle, left, right); } - // // Starting a sound means adding it // to the current list of active sounds @@ -811,8 +822,34 @@ static boolean I_SDL_InitSound(void) } #endif + // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning + // function that can cause the game to lock up. If we're using an old + // version, we need to apply a workaround. But the workaround has its + // own drawbacks ... + + { + const SDL_version *mixer_version; + int v; + + mixer_version = Mix_Linked_Version(); + v = SDL_VERSIONNUM(mixer_version->major, + mixer_version->minor, + mixer_version->patch); + + if (v <= SDL_VERSIONNUM(1, 2, 8)) + { + setpanning_workaround = true; + fprintf(stderr, "\n" + "ATTENTION: You are using an old version of SDL_mixer!\n" + " This version has a bug that may cause " + "your sound to stutter.\n" + " Please upgrade to a newer version!\n" + "\n"); + } + } + Mix_AllocateChannels(NUM_CHANNELS); - + SDL_PauseAudio(0); sound_initialized = true; -- cgit v1.2.3 From 288d322c0b679675a80c0fc763b1063613c77ce5 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Wed, 24 Nov 2010 22:43:37 +0000 Subject: Add configuration file parameter and command line option to specify the screen pixel depth. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2166 --- setup/configfile.c | 1 + setup/display.c | 1 + setup/display.h | 1 + src/i_video.c | 42 ++++++++++++++++++++++++++++++++++-------- src/i_video.h | 1 + src/m_config.c | 6 ++++++ 6 files changed, 44 insertions(+), 8 deletions(-) diff --git a/setup/configfile.c b/setup/configfile.c index 2a3cb845..885bbd8f 100644 --- a/setup/configfile.c +++ b/setup/configfile.c @@ -265,6 +265,7 @@ static default_t extra_defaults_list[] = {"startup_delay", &startup_delay, DEFAULT_INT, 0, 0}, {"screen_width", &screen_width, DEFAULT_INT, 0, 0}, {"screen_height", &screen_height, DEFAULT_INT, 0, 0}, + {"screen_bpp", &screen_bpp, DEFAULT_INT, 0, 0}, {"grabmouse", &grabmouse, DEFAULT_INT, 0, 0}, {"novert", &novert, DEFAULT_INT, 0, 0}, {"mouse_acceleration", &mouse_acceleration, DEFAULT_FLOAT, 0, 0}, diff --git a/setup/display.c b/setup/display.c index 596b8a43..f9e2f712 100644 --- a/setup/display.c +++ b/setup/display.c @@ -75,6 +75,7 @@ int aspect_ratio_correct = 1; int fullscreen = 1; int screen_width = 320; int screen_height = 200; +int screen_bpp = 8; int startup_delay = 1000; int show_endoom = 1; diff --git a/setup/display.h b/setup/display.h index f0c76184..2419e807 100644 --- a/setup/display.h +++ b/setup/display.h @@ -26,6 +26,7 @@ extern int autoadjust_video_settings; extern int aspect_ratio_correct; extern int fullscreen; extern int screen_width, screen_height; +extern int screen_bpp; extern int startup_delay; extern int show_endoom; extern char *video_driver; diff --git a/src/i_video.c b/src/i_video.c index 1139157d..577b7415 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -126,6 +126,10 @@ static boolean native_surface; int screen_width = SCREENWIDTH; int screen_height = SCREENHEIGHT; +// Color depth. + +int screen_bpp = 8; + // Automatically adjust video settings if the selected mode is // not a valid video mode. @@ -1405,6 +1409,33 @@ static void CheckCommandLine(void) screen_height = atoi(myargv[i + 1]); } + //! + // @category video + // @arg + // + // Specify the color depth of the screen, in bits per pixel. + // + + i = M_CheckParm("-bpp"); + + if (i > 0) + { + screen_bpp = atoi(myargv[i + 1]); + } + + // Because we love Eternity: + + //! + // @category video + // + // Set the color depth of the screen to 32 bits per pixel. + // + + if (M_CheckParm("-8in32")) + { + screen_bpp = 32; + } + //! // @category video // @arg @@ -1558,7 +1589,6 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) { byte *doompal; int flags = 0; - int bpp = 8; doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); @@ -1573,11 +1603,7 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) flags |= SDL_SWSURFACE; - if (M_CheckParm("-8in32")) - { - bpp = 32; - } - else + if (screen_bpp == 8) { flags |= SDL_HWPALETTE | SDL_DOUBLEBUF; } @@ -1591,12 +1617,12 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) flags |= SDL_RESIZABLE; } - screen = SDL_SetVideoMode(w, h, bpp, flags); + screen = SDL_SetVideoMode(w, h, screen_bpp, flags); if (screen == NULL) { I_Error("Error setting video mode %ix%ix%ibpp: %s\n", - w, h, bpp, SDL_GetError()); + w, h, screen_bpp, SDL_GetError()); } if (screen->format->BitsPerPixel == 8) diff --git a/src/i_video.h b/src/i_video.h index 94ffcc29..44fe1cd2 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -89,6 +89,7 @@ extern char *video_driver; extern int autoadjust_video_settings; extern boolean screenvisible; extern int screen_width, screen_height; +extern int screen_bpp; extern int fullscreen; extern int aspect_ratio_correct; extern int grabmouse; diff --git a/src/m_config.c b/src/m_config.c index 2065700e..a4cacd95 100644 --- a/src/m_config.c +++ b/src/m_config.c @@ -615,6 +615,12 @@ static default_t extra_defaults_list[] = CONFIG_VARIABLE_INT(screen_height, screen_height), + //! + // Color depth of the screen, in bits. + // + + CONFIG_VARIABLE_INT(screen_bpp, screen_bpp), + //! // If this is non-zero, the mouse will be "grabbed" when running // in windowed mode so that it can be used as an input device. -- cgit v1.2.3 From 9de2b29cdc8e85c525589badc5af636005ca8e66 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Wed, 24 Nov 2010 23:34:18 +0000 Subject: Detect when running on Windows Vista or later, and switch to 32 bpp screen mode. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2167 --- setup/configfile.c | 21 +++++++++++++++++++++ src/m_config.c | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/setup/configfile.c b/setup/configfile.c index 885bbd8f..c4e8a408 100644 --- a/setup/configfile.c +++ b/setup/configfile.c @@ -768,5 +768,26 @@ void M_ApplyPlatformDefaults(void) } } #endif + + // Windows Vista or later? Set screen color depth to + // 32 bits per pixel, as 8-bit palettized screen modes + // don't work properly in recent versions. + +#if defined(_WIN32) && !defined(_WIN32_WCE) + { + OSVERSIONINFOEX version_info; + + ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); + version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + GetVersionEx((OSVERSIONINFO *) &version_info); + + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT + && version_info.dwMajorVersion >= 6) + { + screen_bpp = 32; + } + } +#endif } diff --git a/src/m_config.c b/src/m_config.c index a4cacd95..3abe7c63 100644 --- a/src/m_config.c +++ b/src/m_config.c @@ -1598,5 +1598,26 @@ void M_ApplyPlatformDefaults(void) } } #endif + + // Windows Vista or later? Set screen color depth to + // 32 bits per pixel, as 8-bit palettized screen modes + // don't work properly in recent versions. + +#if defined(_WIN32) && !defined(_WIN32_WCE) + { + OSVERSIONINFOEX version_info; + + ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); + version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + GetVersionEx((OSVERSIONINFO *) &version_info); + + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT + && version_info.dwMajorVersion >= 6) + { + screen_bpp = 32; + } + } +#endif } -- cgit v1.2.3 From ca81122db362eb01660598a4f3e980ed5274220d Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 26 Nov 2010 18:36:48 +0000 Subject: Turn double buffering on for non-palettized screen modes, as this may be the cause of screen tearing reports. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2169 --- src/i_video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i_video.c b/src/i_video.c index 577b7415..dab0e09d 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -1601,11 +1601,11 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) // Set the video mode. - flags |= SDL_SWSURFACE; + flags |= SDL_SWSURFACE | SDL_DOUBLEBUF; if (screen_bpp == 8) { - flags |= SDL_HWPALETTE | SDL_DOUBLEBUF; + flags |= SDL_HWPALETTE; } if (fullscreen) -- cgit v1.2.3 From 74c2dc333a383f27ebddf479e3b666a9068d6d36 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 26 Nov 2010 18:56:45 +0000 Subject: In non-palettized boxed screen modes, don't update the border areas of the screen. This is more CPU and memory efficient, and also fixes the "flashing border" bug when palette flashes occur. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2170 --- src/i_video.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/i_video.c b/src/i_video.c index dab0e09d..62c74b73 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -926,7 +926,14 @@ void I_FinishUpdate (void) if (screenbuffer != screen) { - SDL_BlitSurface(screenbuffer, NULL, screen, NULL); + SDL_Rect dst_rect; + + // Center the buffer within the full screen space. + + dst_rect.x = (screen->w - screenbuffer->w) / 2; + dst_rect.y = (screen->h - screenbuffer->h) / 2; + + SDL_BlitSurface(screenbuffer, NULL, screen, &dst_rect); } SDL_Flip(screen); @@ -1625,16 +1632,10 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) w, h, screen_bpp, SDL_GetError()); } - if (screen->format->BitsPerPixel == 8) - { - screenbuffer = screen; - } - else - { - screenbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, - screen->w, screen->h, 8, - 0, 0, 0, 0); - } + // Blank out the full screen area in case there is any junk in + // the borders that won't otherwise be overwritten. + + SDL_FillRect(screen, NULL, 0); // If mode was not set, it must be set now that we know the // screen size. @@ -1657,6 +1658,22 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) } } + // Create the screenbuffer surface; if we have a real 8-bit palettized + // screen, then we can use the screen as the screenbuffer. + + if (screen->format->BitsPerPixel == 8) + { + screenbuffer = screen; + } + else + { + screenbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, + mode->width, mode->height, 8, + 0, 0, 0, 0); + + SDL_FillRect(screenbuffer, NULL, 0); + } + // Save screen mode. screen_mode = mode; @@ -1782,12 +1799,6 @@ void I_InitGraphics(void) I_SetPalette(doompal); SDL_SetColors(screenbuffer, palette, 0, 256); - if (screen != screenbuffer) - { - SDL_BlitSurface(screenbuffer, NULL, screen, NULL); - SDL_Flip(screen); - } - CreateCursors(); UpdateFocus(); -- cgit v1.2.3 From 79446c49acfeb8b97fc535268cea4d9343cbaadf Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 27 Nov 2010 15:36:43 +0000 Subject: Fix -timer / -avg options to work like Vanilla when playing demos. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2171 --- src/d_main.c | 7 ++----- src/d_net.c | 20 +++++++++++++++----- src/p_spec.c | 5 ++--- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 671c4e9c..a5b38949 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1305,10 +1305,9 @@ void D_DoomMain (void) p = M_CheckParm ("-timer"); - if (p && p < myargc-1 && deathmatch) + if (p && p < myargc-1) { timelimit = atoi(myargv[p+1]); - printf("timer: %i\n", timelimit); } //! @@ -1320,10 +1319,8 @@ void D_DoomMain (void) p = M_CheckParm ("-avg"); - if (p && p < myargc-1 && deathmatch) + if (p && p < myargc-1) { - DEH_printf("Austin Virtual Gaming: Levels will end " - "after 20 minutes\n"); timelimit = 20; } diff --git a/src/d_net.c b/src/d_net.c index faf47821..b8e34dec 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -378,12 +378,22 @@ void D_CheckNetGame (void) // Show players here; the server might have specified a time limit - if (timelimit > 0) + if (timelimit > 0 && deathmatch) { - DEH_printf("Levels will end after %d minute", timelimit); - if (timelimit > 1) - printf("s"); - printf(".\n"); + // Gross hack to work like Vanilla: + + if (timelimit == 20 && M_CheckParm("-avg")) + { + DEH_printf("Austin Virtual Gaming: Levels will end " + "after 20 minutes\n"); + } + else + { + DEH_printf("Levels will end after %d minute", timelimit); + if (timelimit > 1) + printf("s"); + printf(".\n"); + } } } diff --git a/src/p_spec.c b/src/p_spec.c index 37beb850..fa3ec335 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1389,10 +1389,9 @@ void P_SpawnSpecials (void) if (W_CheckNumForName(DEH_String("texture2")) >= 0) episode = 2; - // See if -TIMER was specified. - if (timelimit > 0) + if (timelimit > 0 && deathmatch) { levelTimer = true; levelTimeCount = timelimit * 60 * TICRATE; @@ -1401,7 +1400,7 @@ void P_SpawnSpecials (void) { levelTimer = false; } - + // Init special SECTORs. sector = sectors; for (i=0 ; iindex = i; - // Hook into hash table + // Vanilla Doom does a linear search of the texures array + // and stops at the first entry it finds. If there are two + // entries with the same name, the first one in the array + // wins. The new entry must therefore be added at the end + // of the hash chain, so that earlier entries win. key = W_LumpNameHash(textures[i]->name) % numtextures; - textures[i]->next = textures_hashtable[key]; - textures_hashtable[key] = textures[i]; + rover = &textures_hashtable[key]; + + while (*rover != NULL) + { + rover = &(*rover)->next; + } + + // Hook into hash table + + textures[i]->next = NULL; + *rover = textures[i]; } } -- cgit v1.2.3 From d417ce23d62443acea51fd11d24e83dd83d46188 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 27 Nov 2010 23:23:12 +0000 Subject: Add dropdown list to setup tool to select screen BPP. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2173 --- setup/display.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 194 insertions(+), 3 deletions(-) diff --git a/setup/display.c b/setup/display.c index f9e2f712..b20b6667 100644 --- a/setup/display.c +++ b/setup/display.c @@ -29,6 +29,27 @@ #include "display.h" +typedef struct +{ + char *description; + int bpp; +} pixel_depth_t; + +// List of supported pixel depths. + +static pixel_depth_t pixel_depths[] = +{ + { "8-bit", 8 }, + { "16-bit", 16 }, + { "24-bit", 24 }, + { "32-bit", 32 }, +}; + +// List of strings containing supported pixel depths. + +static char **supported_bpps; +static int num_supported_bpps; + typedef struct { int w, h; @@ -86,6 +107,10 @@ int show_endoom = 1; static int selected_screen_width = 0, selected_screen_height; +// Index into the supported_bpps of the selected pixel depth. + +static int selected_bpp = 0; + static int system_video_env_set; // Set the SDL_VIDEODRIVER environment variable @@ -129,6 +154,128 @@ void SetDisplayDriver(void) } } +// Query SDL as to whether any fullscreen modes are available for the +// specified pixel depth. + +static int PixelDepthSupported(int bpp) +{ + SDL_PixelFormat format; + SDL_Rect **modes; + + format.BitsPerPixel = bpp; + format.BytesPerPixel = (bpp + 7) / 8; + + modes = SDL_ListModes(&format, SDL_FULLSCREEN); + + return modes != NULL; +} + +// Query SDL and populate the supported_bpps array. + +static void IdentifyPixelDepths(void) +{ + unsigned int i; + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + + if (supported_bpps != NULL) + { + free(supported_bpps); + } + + supported_bpps = malloc(sizeof(char *) * num_depths); + num_supported_bpps = 0; + + // Check each bit depth to determine if modes are available. + + for (i = 0; i < num_depths; ++i) + { + // If modes are available, add this bit depth to the list. + + if (PixelDepthSupported(pixel_depths[i].bpp)) + { + supported_bpps[num_supported_bpps] = pixel_depths[i].description; + ++num_supported_bpps; + } + } + + // No supported pixel depths? That's kind of a problem. Add 8bpp + // as a fallback. + + if (num_supported_bpps == 0) + { + supported_bpps[0] = pixel_depths[0].description; + ++num_supported_bpps; + } +} + +// Get the screen pixel depth corresponding to what selected_bpp is set to. + +static int GetSelectedBPP(void) +{ + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + unsigned int i; + + // Find which pixel depth is selected, and set screen_bpp. + + for (i = 0; i < num_depths; ++i) + { + if (pixel_depths[i].description == supported_bpps[selected_bpp]) + { + return pixel_depths[i].bpp; + } + } + + // Default fallback value. + + return 8; +} + +// Get the index into supported_bpps of the specified pixel depth string. + +static int GetSupportedBPPIndex(char *description) +{ + unsigned int i; + + for (i = 0; i < num_supported_bpps; ++i) + { + if (supported_bpps[i] == description) + { + return i; + } + } + + // Shouldn't happen; fall back to the first in the list. + + return 0; +} + +// Set selected_bpp to match screen_bpp. + +static void SetSelectedBPP(void) +{ + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + unsigned int i; + + // Search pixel_depths, find the bpp that corresponds to screen_bpp, + // then set selected_bpp to match. + + for (i = 0; i < num_depths; ++i) + { + if (pixel_depths[i].bpp == screen_bpp) + { + selected_bpp = GetSupportedBPPIndex(pixel_depths[i].description); + return; + } + } + + // screen_bpp does not match anything in pixel_depths. Set selected_bpp + // to something that is supported, and reset screen_bpp to something + // sensible while we're at it. + + selected_bpp = 0; + screen_bpp = GetSelectedBPP(); +} + static void ModeSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(mode)) { TXT_CAST_ARG(screen_mode_t, mode); @@ -173,6 +320,7 @@ static int GoodFullscreenMode(screen_mode_t *mode) static void BuildFullscreenModesList(void) { + SDL_PixelFormat format; SDL_Rect **modes; screen_mode_t *m1; screen_mode_t *m2; @@ -190,7 +338,10 @@ static void BuildFullscreenModesList(void) // Get a list of fullscreen modes and find out how many // modes are in the list. - modes = SDL_ListModes(NULL, SDL_FULLSCREEN); + format.BitsPerPixel = screen_bpp; + format.BytesPerPixel = (screen_bpp + 7) / 8; + + modes = SDL_ListModes(&format, SDL_FULLSCREEN); if (modes == NULL || modes == (SDL_Rect **) -1) { @@ -313,8 +464,25 @@ static void GenerateModesTable(TXT_UNCAST_ARG(widget), vidmode = FindBestMode(modes); - screen_width = modes[vidmode].w; - screen_height = modes[vidmode].h; + if (vidmode > 0) + { + screen_width = modes[vidmode].w; + screen_height = modes[vidmode].h; + } +} + +// Callback invoked when the BPP selector is changed. + +static void UpdateBPP(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(modes_table)) +{ + TXT_CAST_ARG(txt_table_t, modes_table); + + screen_bpp = GetSelectedBPP(); + + // Rebuild list of fullscreen modes. + + BuildFullscreenModesList(); + GenerateModesTable(NULL, modes_table); } #if defined(_WIN32) && !defined(_WIN32_WCE) @@ -368,6 +536,11 @@ static void UpdateVideoDriver(TXT_UNCAST_ARG(widget), RestartTextscreen(); + // Rebuild the list of supported pixel depths. + + IdentifyPixelDepths(); + SetSelectedBPP(); + // Rebuild the video modes list BuildFullscreenModesList(); @@ -381,8 +554,16 @@ void ConfigDisplay(void) { txt_window_t *window; txt_table_t *modes_table; + txt_table_t *bpp_table; txt_checkbox_t *fs_checkbox; txt_checkbox_t *ar_checkbox; + txt_dropdown_list_t *bpp_selector; + + // What color depths are supported? Generate supported_bpps array + // and set selected_bpp to match the current value of screen_bpp. + + IdentifyPixelDepths(); + SetSelectedBPP(); // First time in? Initialise selected_screen_{width,height} @@ -438,11 +619,21 @@ void ConfigDisplay(void) TXT_AddWidgets(window, TXT_NewSeparator("Screen mode"), + bpp_table = TXT_NewTable(2), modes_table, TXT_NewSeparator("Misc."), TXT_NewCheckBox("Show ENDOOM screen", &show_endoom), NULL); + TXT_AddWidgets(bpp_table, + TXT_NewLabel("Color depth: "), + bpp_selector = TXT_NewDropdownList(&selected_bpp, + supported_bpps, + num_supported_bpps), + NULL); + + + TXT_SignalConnect(bpp_selector, "changed", UpdateBPP, modes_table); TXT_SignalConnect(fs_checkbox, "changed", GenerateModesTable, modes_table); TXT_SignalConnect(ar_checkbox, "changed", GenerateModesTable, modes_table); -- cgit v1.2.3 From 6307e5e2519c165ea0c9496849e8013cd92315e1 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 29 Nov 2010 20:18:10 +0000 Subject: Auto-adjust the screen color depth if the configured color depth is not supported by the hardware. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2174 --- setup/display.c | 41 +++++++++++++++++++++++++++++++++-------- src/i_video.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 12 deletions(-) diff --git a/setup/display.c b/setup/display.c index b20b6667..42a1dced 100644 --- a/setup/display.c +++ b/setup/display.c @@ -243,7 +243,7 @@ static int GetSupportedBPPIndex(char *description) return i; } } - + // Shouldn't happen; fall back to the first in the list. return 0; @@ -251,7 +251,7 @@ static int GetSupportedBPPIndex(char *description) // Set selected_bpp to match screen_bpp. -static void SetSelectedBPP(void) +static int TrySetSelectedBPP(void) { unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); unsigned int i; @@ -264,16 +264,41 @@ static void SetSelectedBPP(void) if (pixel_depths[i].bpp == screen_bpp) { selected_bpp = GetSupportedBPPIndex(pixel_depths[i].description); - return; + return 1; } } - // screen_bpp does not match anything in pixel_depths. Set selected_bpp - // to something that is supported, and reset screen_bpp to something - // sensible while we're at it. + return 0; +} - selected_bpp = 0; - screen_bpp = GetSelectedBPP(); +static void SetSelectedBPP(void) +{ + const SDL_VideoInfo *info; + + if (TrySetSelectedBPP()) + { + return; + } + + // screen_bpp does not match any supported pixel depth. Query SDL + // to find out what it recommends using. + + info = SDL_GetVideoInfo(); + + if (info != NULL && info->vfmt != NULL) + { + screen_bpp = info->vfmt->BitsPerPixel; + } + + // Try again. + + if (!TrySetSelectedBPP()) + { + // Give up and just use the first in the list. + + selected_bpp = 0; + screen_bpp = GetSelectedBPP(); + } } static void ModeSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(mode)) diff --git a/src/i_video.c b/src/i_video.c index 62c74b73..488c08a0 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -1207,15 +1207,61 @@ static void AutoAdjustWindowed(void) } } +// Auto-adjust to a valid color depth. + +static void AutoAdjustColorDepth(void) +{ + SDL_Rect **modes; + SDL_PixelFormat format; + const SDL_VideoInfo *info; + int flags; + + if (fullscreen) + { + flags = SDL_FULLSCREEN; + } + else + { + flags = 0; + } + + format.BitsPerPixel = screen_bpp; + format.BytesPerPixel = (screen_bpp + 7) / 8; + + // Are any screen modes supported at the configured color depth? + + modes = SDL_ListModes(&format, flags); + + // If not, we must autoadjust to something sensible. + + if (modes == NULL) + { + printf("I_InitGraphics: %ibpp color depth not supported.\n", + screen_bpp); + + info = SDL_GetVideoInfo(); + + if (info != NULL && info->vfmt != NULL) + { + screen_bpp = info->vfmt->BitsPerPixel; + } + } +} + // If the video mode set in the configuration file is not available, // try to choose a different mode. static void I_AutoAdjustSettings(void) { - int old_screen_w, old_screen_h; + int old_screen_w, old_screen_h, old_screen_bpp; old_screen_w = screen_width; old_screen_h = screen_height; + old_screen_bpp = screen_bpp; + + // Possibly adjust color depth. + + AutoAdjustColorDepth(); // If we are running fullscreen, try to autoadjust to a valid fullscreen // mode. If this is impossible, switch to windowed. @@ -1234,10 +1280,11 @@ static void I_AutoAdjustSettings(void) // Have the settings changed? Show a message. - if (screen_width != old_screen_w || screen_height != old_screen_h) + if (screen_width != old_screen_w || screen_height != old_screen_h + || screen_bpp != old_screen_bpp) { - printf("I_InitGraphics: Auto-adjusted to %ix%i.\n", - screen_width, screen_height); + printf("I_InitGraphics: Auto-adjusted to %ix%ix%ibpp.\n", + screen_width, screen_height, screen_bpp); printf("NOTE: Your video settings have been adjusted. " "To disable this behavior,\n" -- cgit v1.2.3 From e18391bb0f7b2690d0055fb031caa5fe7d3cdecf Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 30 Nov 2010 01:08:59 +0000 Subject: Add NOT-BUGS file with some common Vanilla gotchas. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2175 --- Makefile.am | 1 + NOT-BUGS | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README | 10 +++-- pkg/config.make.in | 1 + 4 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 NOT-BUGS diff --git a/Makefile.am b/Makefile.am index 13e8bddb..a766d348 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,7 @@ EXTRA_DIST= \ README.OPL \ TODO \ BUGS \ + NOT-BUGS \ rpm.spec MAINTAINERCLEANFILES = $(AUX_DIST_GEN) diff --git a/NOT-BUGS b/NOT-BUGS new file mode 100644 index 00000000..8dbf7262 --- /dev/null +++ b/NOT-BUGS @@ -0,0 +1,112 @@ + +The aim of Chocolate Doom is to behave as closely to Vanilla Doom as +possible. As a result, you may experience problems that you would +also experience when using Vanilla Doom. These are not "bugs" as +Chocolate Doom is behaving as intended. + +This is not intended to be a comprehensive list of Vanilla Doom bugs. +For more information, consult the "engine bugs" page of the Doom Wiki. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits after title screen with message about game version == + +The game may exit after the title screen is shown, with a message like +the following: + + Demo is from a different game version! + (read 106, should be 109) + + *** You may need to upgrade your version of Doom to v1.9. *** + See: http://doomworld.com/files/patches.shtml + This appears to be v1.6/v1.666. + +This usually indicates that your IWAD file that you are using to play +the game (usually named doom.wad or doom2.wad) is out of date. +Chocolate Doom only supports the v1.9 IWAD file. + +To fix the problem, you must upgrade to the v1.9 IWAD file. The URL +in the message has downloadable upgrade patches that you can use to +upgrade. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits when accessing the options menu == + +The game may exit with the message "Bad V_DrawPatch" when accessing +the options menu, if you have your mouse sensitivity set high. + +The Doom options menu has a slider that allows the mouse sensitivity +to be controlled; however, it has only a very limited range. It is +common for experienced players to set a mouse sensitivity that is much +higher than what can be set via the options menu. The setup program +allows a larger range of values to be set. + +However, setting very high sensitivity values causes the game to exit +when accessing the options menu under Vanilla Doom. Because Chocolate +Doom aims to emulate Vanilla Doom as closely as possible, it does the +same thing. + +One solution to the problem is to set a lower mouse sensitivity. +Alternatively, all of the settings in the options menu can be +controlled through Doom's key bindings anyway: + + End game: F7 + Messages on/off: F8 + Graphic detail high/low: F5 + Screen size smaller/larger: -/+ + Sound volume menu: F4 + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits with "Savegame buffer overrun" when saving the game == + +If you are playing on a particularly large level, it is possible that +when you save the game, the game will quit with the message "Savegame +buffer overrun". + +Vanilla Doom has a limited size memory bufferthat it uses for saving +games. If you are playing on a large level, the buffer may be too +small for the entire savegame to fit. Chocolate Doom allows the limit +to be disabled: in the setup tool, go to the "compatibility" menu and +disable the "Vanilla savegame limit" option. + +If this error happens to you, your game has not been lost! A file +named temp.dsg is saved; rename this to doomsav0.dsg to make it appear +in the first slot in the "load game" menu. (On Unix systems, you will +need to look in the .chocolate-doom/savegames directory in your home +directory) + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game ends suddenly when recording a demo == + +If you are recording a very long demo, the game may exit suddenly. +Vanilla Doom has a limited size memory buffer that it uses to save the +demo into. When the buffer is full, the game exits. You can tell if +this happens, as the demo file will be around 131,072 bytes in size. + +You can work around this by using the -maxdemo command line parameter +to specify a larger buffer size. Alternatively, the limit can be +disabled: in the setup tool, go to the compatibility menu and disable +the "Vanilla demo limit" option. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits with a message about "visplanes" == + +The game may exit with one of these messages: + + R_FindPlane: no more visplanes + R_DrawPlanes: visplane overflow (129) + +This is known as the "visplane overflow" limit and is one of the most +well-known Vanilla Doom engine limits. You should only ever experience +this when trying to play an add-on level. The level you are trying to +play is too complex; it was most likely designed to work with a limit +removing source port. + +More information can be found here: + + http://rome.ro/lee_killough/editing/visplane.shtml + diff --git a/README b/README index 0b9eaf7c..06dc1537 100644 --- a/README +++ b/README @@ -65,9 +65,13 @@ Here are some examples: You are encouraged to sign up and contribute any useful information you may have regarding the port! - * Chocolate Doom is not perfect. See the BUGS file for a list of - known issues. New bug reports can be submitted to the Chocolate - Doom bug tracker on Sourceforge. See: + * Chocolate Doom is not perfect. See the BUGS file for a list of + known issues. Because of the nature of the project, you may also + encounter Vanilla Doom bugs; these are intentionally present; see + the NOT-BUGS file for more information. + + New bug reports can be submitted to the Chocolate Doom bug tracker + on Sourceforge. See: http://sourceforge.net/projects/chocolate-doom diff --git a/pkg/config.make.in b/pkg/config.make.in index 3fe757ff..a2bde418 100644 --- a/pkg/config.make.in +++ b/pkg/config.make.in @@ -24,6 +24,7 @@ DOC_FILES = README \ INSTALL \ NEWS \ BUGS \ + NOT-BUGS \ CMDLINE \ TODO -- cgit v1.2.3 From 9e54684b11cf8e8e4ae19ebd2d754ee472c70089 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 30 Nov 2010 20:00:06 +0000 Subject: Add support for HACX v1.2 IWAD file. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2176 --- src/d_iwad.c | 35 ++++++++++----- src/d_main.c | 18 +++++++- src/deh_io.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++---------- src/deh_io.h | 1 + src/deh_main.c | 54 ++++++++++++++++++++-- src/deh_main.h | 2 + src/doomdef.h | 1 + src/m_menu.c | 2 + 8 files changed, 213 insertions(+), 39 deletions(-) diff --git a/src/d_iwad.c b/src/d_iwad.c index ea0d29d0..89a7fba3 100644 --- a/src/d_iwad.c +++ b/src/d_iwad.c @@ -326,16 +326,22 @@ static struct {"doom.wad", doom}, {"doom1.wad", doom}, {"chex.wad", doom}, + {"hacx.wad", doom2}, }; - + // Hack for chex quest mode -static void CheckChex(char *iwad_name) +static void CheckSpecialIWADs(char *iwad_name) { - if (!strcmp(iwad_name, "chex.wad")) + if (!strcasecmp(iwad_name, "chex.wad")) { gameversion = exe_chex; } + + if (!strcasecmp(iwad_name, "hacx.wad")) + { + gameversion = exe_hacx; + } } // Returns true if the specified path is a path to a file @@ -408,7 +414,7 @@ static char *SearchDirectoryForIWAD(char *dir) if (filename != NULL) { - CheckChex(iwads[i].name); + CheckSpecialIWADs(iwads[i].name); gamemission = iwads[i].mission; return filename; @@ -441,7 +447,7 @@ static void IdentifyIWADByName(char *name) if (!strcasecmp(name + strlen(name) - strlen(iwadname), iwadname)) { - CheckChex(iwads[i].name); + CheckSpecialIWADs(iwads[i].name); gamemission = iwads[i].mission; break; } @@ -701,6 +707,13 @@ static char *SaveGameIWADName(void) return "chex.wad"; } + // Hacx hack + + if (gameversion == exe_hacx) + { + return "hacx.wad"; + } + // Find what subdirectory to use for savegames // // They should be stored in something like @@ -770,6 +783,10 @@ void D_SetSaveGameDir(void) static char *banners[] = { + // doom2.wad + " " + "DOOM 2: Hell on Earth v%i.%i" + " ", // doom1.wad " " "DOOM Shareware Startup v%i.%i" @@ -786,10 +803,6 @@ static char *banners[] = " " "The Ultimate DOOM Startup v%i.%i" " ", - // doom2.wad - " " - "DOOM 2: Hell on Earth v%i.%i" - " ", // tnt.wad " " "DOOM 2: TNT - Evilution v%i.%i" @@ -809,13 +822,13 @@ static char *GetGameName(char *gamename) { size_t i; char *deh_sub; - + for (i=0; i #include "i_system.h" +#include "w_wad.h" #include "z_zone.h" #include "deh_defs.h" #include "deh_io.h" +typedef enum +{ + DEH_INPUT_FILE, + DEH_INPUT_LUMP +} deh_input_type_t; + struct deh_context_s { - FILE *stream; + deh_input_type_t type; char *filename; + + // If the input comes from a memory buffer, pointer to the memory + // buffer. + + unsigned char *input_buffer; + size_t input_buffer_len; + unsigned int input_buffer_pos; + int lumpnum; + + // If the input comes from a file, the file stream for reading + // data. + + FILE *stream; + + // Current line number that we have reached: + int linenum; + + // Used by DEH_ReadLine: + boolean last_was_newline; char *readbuffer; int readbuffer_size; }; +static deh_context_t *DEH_NewContext(void) +{ + deh_context_t *context; + + context = Z_Malloc(sizeof(*context), PU_STATIC, NULL); + + // Initial read buffer size of 128 bytes + + context->readbuffer_size = 128; + context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL); + context->linenum = 0; + context->last_was_newline = true; + + return context; +} + // Open a dehacked file for reading // Returns NULL if open failed @@ -52,22 +94,41 @@ deh_context_t *DEH_OpenFile(char *filename) { FILE *fstream; deh_context_t *context; - + fstream = fopen(filename, "r"); if (fstream == NULL) return NULL; - context = Z_Malloc(sizeof(*context), PU_STATIC, NULL); + context = DEH_NewContext(); + + context->type = DEH_INPUT_FILE; context->stream = fstream; - - // Initial read buffer size of 128 bytes + context->filename = strdup(filename); - context->readbuffer_size = 128; - context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL); - context->filename = filename; - context->linenum = 0; - context->last_was_newline = true; + return context; +} + +// Open a WAD lump for reading. + +deh_context_t *DEH_OpenLump(int lumpnum) +{ + deh_context_t *context; + void *lump; + + lump = W_CacheLumpNum(lumpnum, PU_STATIC); + + context = DEH_NewContext(); + + context->type = DEH_INPUT_LUMP; + context->lumpnum = lumpnum; + context->input_buffer = lump; + context->input_buffer_len = W_LumpLength(lumpnum); + context->input_buffer_pos = 0; + + context->filename = malloc(9); + strncpy(context->filename, lumpinfo[lumpnum].name, 8); + context->filename[8] = '\0'; return context; } @@ -76,33 +137,65 @@ deh_context_t *DEH_OpenFile(char *filename) void DEH_CloseFile(deh_context_t *context) { - fclose(context->stream); + if (context->type == DEH_INPUT_FILE) + { + fclose(context->stream); + } + else if (context->type == DEH_INPUT_LUMP) + { + W_ReleaseLumpNum(context->lumpnum); + } + Z_Free(context->readbuffer); Z_Free(context); } +int DEH_GetCharFile(deh_context_t *context) +{ + if (feof(context->stream)) + { + // end of file + + return -1; + } + + return fgetc(context->stream); +} + +int DEH_GetCharLump(deh_context_t *context) +{ + int result; + + if (context->input_buffer_pos >= context->input_buffer_len) + { + return -1; + } + + result = context->input_buffer[context->input_buffer_pos]; + ++context->input_buffer_pos; + + return result; +} + // Reads a single character from a dehacked file int DEH_GetChar(deh_context_t *context) { int result; - + // Read characters, but ignore carriage returns // Essentially this is a DOS->Unix conversion - do + do { - if (feof(context->stream)) + switch (context->type) { - // end of file + case DEH_INPUT_FILE: + result = DEH_GetCharFile(context); - result = -1; + case DEH_INPUT_LUMP: + result = DEH_GetCharLump(context); } - else - { - result = fgetc(context->stream); - } - } while (result == '\r'); // Track the current line number @@ -111,9 +204,9 @@ int DEH_GetChar(deh_context_t *context) { ++context->linenum; } - + context->last_was_newline = result == '\n'; - + return result; } diff --git a/src/deh_io.h b/src/deh_io.h index 061a5a0e..9d22b360 100644 --- a/src/deh_io.h +++ b/src/deh_io.h @@ -30,6 +30,7 @@ #include "deh_defs.h" deh_context_t *DEH_OpenFile(char *filename); +deh_context_t *DEH_OpenLump(int lumpnum); void DEH_CloseFile(deh_context_t *context); int DEH_GetChar(deh_context_t *context); char *DEH_ReadLine(deh_context_t *context); diff --git a/src/deh_main.c b/src/deh_main.c index dcdfb00d..20498375 100644 --- a/src/deh_main.c +++ b/src/deh_main.c @@ -30,6 +30,7 @@ #include "doomtype.h" #include "d_iwad.h" #include "m_argv.h" +#include "w_wad.h" #include "deh_defs.h" #include "deh_io.h" @@ -281,9 +282,6 @@ static void DEH_ParseContext(deh_context_t *context) DEH_Error(context, "This is not a valid dehacked patch file!"); } - deh_allow_long_strings = false; - deh_allow_long_cheats = false; - // Read the file for (;;) @@ -295,7 +293,9 @@ static void DEH_ParseContext(deh_context_t *context) // end of file? if (line == NULL) + { return; + } while (line[0] != '\0' && isspace(line[0])) ++line; @@ -359,6 +359,11 @@ int DEH_LoadFile(char *filename) { deh_context_t *context; + // Vanilla dehacked files don't allow long string or cheat replacements. + + deh_allow_long_strings = false; + deh_allow_long_cheats = false; + printf(" loading %s\n", filename); context = DEH_OpenFile(filename); @@ -376,6 +381,48 @@ int DEH_LoadFile(char *filename) return 1; } +// Load dehacked file from WAD lump. + +int DEH_LoadLump(int lumpnum) +{ + deh_context_t *context; + + // If it's in a lump, it's probably designed for a modern source port, + // so allow it to do long string and cheat replacements. + + deh_allow_long_strings = true; + deh_allow_long_cheats = true; + + context = DEH_OpenLump(lumpnum); + + if (context == NULL) + { + fprintf(stderr, "DEH_LoadFile: Unable to open lump %i\n", lumpnum); + return 0; + } + + DEH_ParseContext(context); + + DEH_CloseFile(context); + + return 1; +} + +int DEH_LoadLumpByName(char *name) +{ + int lumpnum; + + lumpnum = W_CheckNumForName(name); + + if (lumpnum == -1) + { + fprintf(stderr, "DEH_LoadLumpByName: '%s' lump not found\n", name); + return 0; + } + + return DEH_LoadLump(lumpnum); +} + // Checks the command line for -deh argument void DEH_Init(void) @@ -418,4 +465,3 @@ void DEH_Init(void) } } - diff --git a/src/deh_main.h b/src/deh_main.h index 9248e982..4b58a1ad 100644 --- a/src/deh_main.h +++ b/src/deh_main.h @@ -42,6 +42,8 @@ void DEH_Init(void); int DEH_LoadFile(char *filename); +int DEH_LoadLump(int lumpnum); +int DEH_LoadLumpByName(char *name); boolean DEH_ParseAssignment(char *line, char **variable_name, char **value); diff --git a/src/doomdef.h b/src/doomdef.h index ff4d59a9..f9cd4fd9 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -104,6 +104,7 @@ typedef enum typedef enum { exe_doom_1_9, // Doom 1.9: used for shareware, registered and commercial + exe_hacx, // Hacx executable (Doom 1.9 with patch applied) exe_ultimate, // Ultimate Doom (retail) exe_final, // Final Doom exe_chex, // Chex Quest executable (based on Final Doom) diff --git a/src/m_menu.c b/src/m_menu.c index 5fb1ae7c..7b1c5a6e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -784,6 +784,8 @@ void M_DrawReadThis1(void) switch (gameversion) { case exe_doom_1_9: + case exe_hacx: + if (gamemode == commercial) { // Doom 2 -- cgit v1.2.3 From 81170639f96faff3cf512a84341493fe04ec915a Mon Sep 17 00:00:00 2001 From: Russell Rice Date: Tue, 30 Nov 2010 20:09:22 +0000 Subject: - Update codeblocks project Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2177 --- codeblocks/game.cbp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/codeblocks/game.cbp b/codeblocks/game.cbp index d6313bdf..47b8c67e 100644 --- a/codeblocks/game.cbp +++ b/codeblocks/game.cbp @@ -56,10 +56,10 @@ - + - + @@ -72,6 +72,9 @@ + + -- cgit v1.2.3 From 89187a00f3871ae48564cd34057635519f8028e2 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 30 Nov 2010 20:26:37 +0000 Subject: Update NEWS. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2178 --- NEWS | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 8fc37b5f..1296aabf 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,10 @@ * The DOSbox OPL emulator (DBOPL) has been imported to replace the older FMOPL code. The quality of OPL emulation is now therefore much better. + * The game can now run in screen modes at any color depth (not + just 8-bit modes). This is mainly to work around problems with + Windows Vista/7, where 8-bit color modes don't always work + properly. * When running in windowed mode, it is now possible to dynamically resize the window by dragging the window borders. * There are now keyboard, mouse and joystick bindings to cycle @@ -15,19 +19,47 @@ port, for cards that don't use port 0x388. * Up to 8 mouse buttons are now supported (including the mousewheel). + * The Python scripts used for building Chocolate Doom now work + with Python 3 (but also continue to work with Python 2) + (thanks arin). + * There is now a NOT-BUGS file included that lists some common + Vanilla Doom bugs/limitations that you might encounter. + + Compatibility: + * The -timer and -avg options now work the same as Vanilla when + playing back demos (thanks xttl) + * A texture lookup bug was fixed that caused the wrong sky to be + displayed in Spooky01.wad (thanks Porsche Monty). + * The HacX v1.2 IWAD file is now supported, and can be used + standalone without the need for the Doom II IWAD (thanks + atyth). Bugs fixed: + * A workaround has been a bug in old versions of SDL_mixer + (v1.2.8 and earlier) that could cause the game to lock up. + Please upgrade to a newer version if you haven't already. * It is now possible to use OPL emulation at 11025Hz sound - sampling rate (thanks to the new OPL emulator). + sampling rate, due to the new OPL emulator (thanks Porsche + Monty). * The span renderer function (used for drawing floors and ceilings) now behaves the same as Vanilla Doom, so screenshots are pixel-perfect identical to Vanilla Doom (thanks Porsche Monty). * The zone memory system now aligns allocated memory to 8-byte boundaries on 64-bit systems, which may fix crashes on systems - such as sparc64. + such as sparc64 (thanks Ryan Freeman and Edd Barrett). * The configure script now checks for libm, fixing compile - problems on Fedora Linux. + problems on Fedora Linux (thanks Sander van Dijk). + * Sound distortion with certain music files when played back + using OPL (eg. Heretic title screen). + * Error in Windows when reading response files (thanks Porsche + Monty, xttl, Janizdreg). + * Windows Vista/7 8-bit color mode issues (the default is now to + run in 32-bit color depth on these versions) (thanks to + everybody who reported this and helped test the fix). + * Screen borders no longer flash when running on widescreen + monitors, if you choose a true-color screen mode (thanks + exp(x)). 1.4.0 (2010-07-10): -- cgit v1.2.3 From b8db918b1d45aa8124a4953305edba550a52db6e Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 30 Nov 2010 20:44:20 +0000 Subject: Remove "-debugfile" command line option and associated variable. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2179 --- src/d_main.c | 10 ---------- src/d_net.c | 3 --- src/doomstat.h | 1 - src/p_setup.c | 12 +----------- 4 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 10eab2b0..378cc5f3 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -124,8 +124,6 @@ int startmap; boolean autostart; int startloadgame; -FILE* debugfile; - boolean advancedemo; // Store demo, do not accept any inputs @@ -399,14 +397,6 @@ void D_DoomLoop (void) if (demorecording) G_BeginRecording (); - if (M_CheckParm ("-debugfile")) - { - char filename[20]; - sprintf (filename,"debug%i.txt",consoleplayer); - printf ("debug output to: %s\n",filename); - debugfile = fopen (filename,"w"); - } - TryRunTics(); I_InitGraphics (); diff --git a/src/d_net.c b/src/d_net.c index b8e34dec..56f04876 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -405,9 +405,6 @@ void D_CheckNetGame (void) // void D_QuitNetGame (void) { - if (debugfile) - fclose (debugfile); - #ifdef FEATURE_MULTIPLAYER NET_SV_Shutdown(); diff --git a/src/doomstat.h b/src/doomstat.h index 4fc174cd..a0e21a25 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -258,7 +258,6 @@ extern int maxammo[NUMAMMO]; // File handling stuff. extern char * savegamedir; extern char basedefault[1024]; -extern FILE* debugfile; // if true, load all graphics at level load extern boolean precache; diff --git a/src/p_setup.c b/src/p_setup.c index 7d9d4318..3fc95cab 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -755,17 +755,7 @@ P_SetupLevel // Make sure all sounds are stopped before Z_FreeTags. S_Start (); - -#if 0 // UNUSED - if (debugfile) - { - Z_FreeTags (PU_LEVEL, INT_MAX); - Z_FileDumpHeap (debugfile); - } - else -#endif - Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1); - + Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1); // UNUSED W_Profile (); P_InitThinkers (); -- cgit v1.2.3 From 74034c0c1bd68fbc8c57daee922103f69c7ddf6d Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Tue, 30 Nov 2010 21:52:38 +0000 Subject: Oops. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2180 --- src/deh_io.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/deh_io.c b/src/deh_io.c index 12fc7d56..92c81632 100644 --- a/src/deh_io.c +++ b/src/deh_io.c @@ -192,9 +192,11 @@ int DEH_GetChar(deh_context_t *context) { case DEH_INPUT_FILE: result = DEH_GetCharFile(context); + break; case DEH_INPUT_LUMP: result = DEH_GetCharLump(context); + break; } } while (result == '\r'); -- cgit v1.2.3 From f9ab444cc614db3b2380d02750d142f9b17a8b90 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 18:23:09 +0000 Subject: Register servers with Internet master server. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2181 --- src/Makefile.am | 1 + src/d_net.c | 1 + src/net_dedicated.c | 2 +- src/net_defs.h | 8 ++++++ src/net_query.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/net_query.h | 4 +++ src/net_server.c | 55 ++++++++++++++++++++++++++++++++++++++++- src/net_server.h | 4 +++ 8 files changed, 144 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 8b827131..26fe7c7d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ net_dedicated.c net_dedicated.h \ net_io.c net_io.h \ net_packet.c net_packet.h \ net_sdl.c net_sdl.h \ +net_query.c net_query.h \ net_server.c net_server.h \ net_structrw.c net_structrw.h \ z_native.c z_zone.h diff --git a/src/d_net.c b/src/d_net.c index 56f04876..bf9fbf2b 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -270,6 +270,7 @@ void D_CheckNetGame (void) NET_SV_Init(); NET_SV_AddModule(&net_loop_server_module); NET_SV_AddModule(&net_sdl_module); + NET_SV_RegisterWithMaster(); net_loop_client_module.InitClient(); addr = net_loop_client_module.ResolveAddress(NULL); diff --git a/src/net_dedicated.c b/src/net_dedicated.c index 6a153300..82909210 100644 --- a/src/net_dedicated.c +++ b/src/net_dedicated.c @@ -71,8 +71,8 @@ void NET_DedicatedServer(void) CheckForClientOptions(); NET_SV_Init(); - NET_SV_AddModule(&net_sdl_module); + NET_SV_RegisterWithMaster(); while (true) { diff --git a/src/net_defs.h b/src/net_defs.h index 66b17c77..d9e3b920 100644 --- a/src/net_defs.h +++ b/src/net_defs.h @@ -113,6 +113,14 @@ typedef enum NET_PACKET_TYPE_QUERY_RESPONSE, } net_packet_type_t; +typedef enum +{ + NET_MASTER_PACKET_TYPE_ADD, + NET_MASTER_PACKET_TYPE_ADD_RESPONSE, + NET_MASTER_PACKET_TYPE_QUERY, + NET_MASTER_PACKET_TYPE_QUERY_RESPONSE +} net_master_packet_type_t; + typedef struct { int ticdup; diff --git a/src/net_query.c b/src/net_query.c index 72650ac2..deb3744a 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -36,16 +36,86 @@ #include "net_structrw.h" #include "net_sdl.h" +#define MASTER_SERVER_ADDRESS "master.chocolate-doom.org" + typedef struct { net_addr_t *addr; net_querydata_t data; } queryresponse_t; +static boolean registered_with_master = false; + static net_context_t *query_context; static queryresponse_t *responders; static int num_responses; +// Resolve the master server address. + +net_addr_t *NET_Query_ResolveMaster(net_context_t *context) +{ + net_addr_t *addr; + + addr = NET_ResolveAddress(context, MASTER_SERVER_ADDRESS); + + if (addr == NULL) + { + fprintf(stderr, "Warning: Failed to resolve address " + "for master server: %s\n", MASTER_SERVER_ADDRESS); + } + + return addr; +} + +// Send a registration packet to the master server to register +// ourselves with the global list. + +void NET_Query_AddToMaster(net_addr_t *master_addr) +{ + net_packet_t *packet; + + packet = NET_NewPacket(10); + NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_ADD); + NET_SendPacket(master_addr, packet); + NET_FreePacket(packet); +} + +// Process a packet received from the master server. + +void NET_Query_MasterResponse(net_packet_t *packet) +{ + unsigned int packet_type; + unsigned int result; + + if (!NET_ReadInt16(packet, &packet_type) + || !NET_ReadInt16(packet, &result)) + { + return; + } + + if (packet_type == NET_MASTER_PACKET_TYPE_ADD_RESPONSE) + { + if (result != 0) + { + // Only show the message once. + + if (!registered_with_master) + { + printf("Registered with master server at %s\n", + MASTER_SERVER_ADDRESS); + registered_with_master = true; + } + } + else + { + // Always show rejections. + + printf("Failed to register with master server at %s\n", + MASTER_SERVER_ADDRESS); + } + } +} + // Add a new address to the list of hosts that has responded static queryresponse_t *AddResponder(net_addr_t *addr, @@ -319,3 +389,4 @@ void NET_LANQuery(void) exit(0); } + diff --git a/src/net_query.h b/src/net_query.h index f682d320..0ed098f1 100644 --- a/src/net_query.h +++ b/src/net_query.h @@ -31,5 +31,9 @@ extern void NET_QueryAddress(char *addr); extern void NET_LANQuery(void); extern net_addr_t *NET_FindLANServer(void); +net_addr_t *NET_Query_ResolveMaster(net_context_t *context); +void NET_Query_AddToMaster(net_addr_t *master_addr); +void NET_Query_MasterResponse(net_packet_t *packet); + #endif /* #ifndef NET_QUERY_H */ diff --git a/src/net_server.c b/src/net_server.c index 383608be..7b67ea56 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -40,10 +40,15 @@ #include "net_io.h" #include "net_loop.h" #include "net_packet.h" +#include "net_query.h" #include "net_server.h" #include "net_sdl.h" #include "net_structrw.h" +// How often to refresh our registration with the master server. + +#define MASTER_REFRESH_PERIOD 20 * 60 /* 20 minutes */ + typedef enum { // waiting for the game to start @@ -127,6 +132,11 @@ static unsigned int sv_gamemode; static unsigned int sv_gamemission; static net_gamesettings_t sv_settings; +// For registration with master server: + +static net_addr_t *master_server = NULL; +static unsigned int master_refresh_time; + // receive window static unsigned int recvwindow_start; @@ -1108,6 +1118,14 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) net_client_t *client; unsigned int packet_type; + // Response from master server? + + if (addr != NULL && addr == master_server) + { + NET_Query_MasterResponse(packet); + return; + } + // Find which client this packet came from client = NET_SV_FindClient(addr); @@ -1513,6 +1531,32 @@ void NET_SV_Init(void) server_initialized = true; } +void NET_SV_RegisterWithMaster(void) +{ + //! + // When running a server, don't register with the global master server. + // + // @category net + // + + if (!M_CheckParm("-privateserver")) + { + master_server = NET_Query_ResolveMaster(server_context); + } + else + { + master_server = NULL; + } + + // Send request. + + if (master_server != NULL) + { + NET_Query_AddToMaster(master_server); + master_refresh_time = I_GetTimeMS(); + } +} + // Run server code to check for new packets/send packets as the server // requires @@ -1527,12 +1571,21 @@ void NET_SV_Run(void) return; } - while (NET_RecvPacket(server_context, &addr, &packet)) + while (NET_RecvPacket(server_context, &addr, &packet)) { NET_SV_Packet(packet, addr); NET_FreePacket(packet); } + // Possibly refresh our registration with the master server. + + if (master_server != NULL + && I_GetTimeMS() - master_refresh_time > MASTER_REFRESH_PERIOD * 1000) + { + NET_Query_AddToMaster(master_server); + master_refresh_time = I_GetTimeMS(); + } + // "Run" any clients that may have things to do, independent of responses // to received packets diff --git a/src/net_server.h b/src/net_server.h index 93b22fc3..1debbd79 100644 --- a/src/net_server.h +++ b/src/net_server.h @@ -41,5 +41,9 @@ void NET_SV_Shutdown(void); void NET_SV_AddModule(net_module_t *module); +// Register server with master server. + +void NET_SV_RegisterWithMaster(void); + #endif /* #ifndef NET_SERVER_H */ -- cgit v1.2.3 From bfbffcf197a5d78e90d463945d12c84d0f7deadf Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 19:26:05 +0000 Subject: Refactor query code and add a -masterquery command line parameter to query the master server. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2182 --- src/d_main.c | 12 ++ src/net_query.c | 472 ++++++++++++++++++++++++++++++++++++++++++++------------ src/net_query.h | 7 +- 3 files changed, 388 insertions(+), 103 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 378cc5f3..22fdb142 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -843,6 +843,18 @@ void D_DoomMain (void) // Never returns } + //! + // @category net + // + // Query the Internet master server for a global list of active + // servers. + // + + if (M_CheckParm("-masterquery")) + { + NET_MasterQuery(); + } + //! // @arg
// @category net diff --git a/src/net_query.c b/src/net_query.c index deb3744a..681411c2 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -38,17 +38,40 @@ #define MASTER_SERVER_ADDRESS "master.chocolate-doom.org" -typedef struct +typedef enum { + QUERY_TARGET_SERVER, // Normal server target. + QUERY_TARGET_MASTER, // The master server. + QUERY_TARGET_BROADCAST // Send a broadcast query +} query_target_type_t; + +typedef enum +{ + QUERY_TARGET_QUEUED, // Query not yet sent + QUERY_TARGET_QUERIED, // Query sent, waiting response + QUERY_TARGET_RESPONDED, // Response received + QUERY_TARGET_TIMED_OUT +} query_target_state_t; + +typedef struct +{ + query_target_type_t type; + query_target_state_t state; net_addr_t *addr; net_querydata_t data; -} queryresponse_t; + unsigned int query_time; + boolean printed; +} query_target_t; + +// Transmit a query packet static boolean registered_with_master = false; static net_context_t *query_context; -static queryresponse_t *responders; -static int num_responses; +static query_target_t *targets; +static int num_targets; + +static boolean printed_header = false; // Resolve the master server address. @@ -116,40 +139,49 @@ void NET_Query_MasterResponse(net_packet_t *packet) } } -// Add a new address to the list of hosts that has responded +// Send a query to the master server. -static queryresponse_t *AddResponder(net_addr_t *addr, - net_querydata_t *data) +static void NET_Query_SendMasterQuery(net_addr_t *addr) { - queryresponse_t *response; - - responders = realloc(responders, - sizeof(queryresponse_t) * (num_responses + 1)); - - response = &responders[num_responses]; - response->addr = addr; - response->data = *data; - ++num_responses; + net_packet_t *packet; - return response; + packet = NET_NewPacket(10); + NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_QUERY); + NET_SendPacket(addr, packet); + NET_FreePacket(packet); } -// Returns true if the reply is from a host that has not previously -// responded. +// Given the specified address, find the target associated. If no +// target is found, and 'create' is true, a new target is created. -static boolean CheckResponder(net_addr_t *addr) +static query_target_t *GetTargetForAddr(net_addr_t *addr, boolean create) { + query_target_t *target; int i; - for (i=0; itype = QUERY_TARGET_SERVER; + target->state = QUERY_TARGET_QUEUED; + target->printed = false; + target->addr = addr; + ++num_targets; + + return target; } // Transmit a query packet @@ -173,20 +205,225 @@ static void NET_Query_SendQuery(net_addr_t *addr) NET_FreePacket(request); } +static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet) +{ + unsigned int packet_type; + net_querydata_t querydata; + query_target_t *target; + + // Read the header + + if (!NET_ReadInt16(packet, &packet_type) + || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) + { + return; + } + + // Read query data + + if (!NET_ReadQueryData(packet, &querydata)) + { + return; + } + + // Find the target that responded, or potentially add a new target + // if it was not already known (for LAN broadcast search) + + target = GetTargetForAddr(addr, true); + + target->state = QUERY_TARGET_RESPONDED; + memcpy(&target->data, &querydata, sizeof(net_querydata_t)); +} + +// Parse a response packet from the master server. + +static void NET_Query_ParseMasterResponse(net_addr_t *master_addr, + net_packet_t *packet) +{ + unsigned int packet_type; + query_target_t *target; + char *addr_str; + net_addr_t *addr; + + // Read the header. We are only interested in query responses. + + if (!NET_ReadInt16(packet, &packet_type) + || packet_type != NET_MASTER_PACKET_TYPE_QUERY_RESPONSE) + { + return; + } + + // Read a list of strings containing the addresses of servers + // that the master knows about. + + for (;;) + { + addr_str = NET_ReadString(packet); + + if (addr_str == NULL) + { + break; + } + + // Resolve address and add to targets list if it is not already + // there. + + addr = NET_ResolveAddress(query_context, addr_str); + + if (addr != NULL) + { + GetTargetForAddr(addr, true); + } + } + + // Mark the master as having responded. + + target = GetTargetForAddr(master_addr, true); + target->state = QUERY_TARGET_RESPONDED; +} + +static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) +{ + query_target_t *target; + + // This might be the master server responding. + + target = GetTargetForAddr(addr, false); + + if (target != NULL && target->type == QUERY_TARGET_MASTER) + { + NET_Query_ParseMasterResponse(addr, packet); + } + else + { + NET_Query_ParseResponse(addr, packet); + } +} + +static void NET_Query_GetResponse(void) +{ + net_addr_t *addr; + net_packet_t *packet; + + if (NET_RecvPacket(query_context, &addr, &packet)) + { + NET_Query_ParsePacket(addr, packet); + NET_FreePacket(packet); + } +} + +// Find a target we have not yet queried and send a query. + +static void SendOneQuery(void) +{ + unsigned int i; + + for (i = 0; i < num_targets; ++i) + { + if (targets[i].state == QUERY_TARGET_QUEUED) + { + break; + } + } + + if (i >= num_targets) + { + return; + } + + // Found a target to query. Send a query; how to do this depends on + // the target type. + + switch (targets[i].type) + { + case QUERY_TARGET_SERVER: + NET_Query_SendQuery(targets[i].addr); + break; + + case QUERY_TARGET_BROADCAST: + NET_Query_SendQuery(NULL); + break; + + case QUERY_TARGET_MASTER: + NET_Query_SendMasterQuery(targets[i].addr); + break; + } + + //printf("Queried %s\n", NET_AddrToString(targets[i].addr)); + targets[i].state = QUERY_TARGET_QUERIED; + targets[i].query_time = I_GetTimeMS(); +} + +// Search the targets list and find a target that has responded. +// If none have responded yet, returns NULL. + +static query_target_t *FindFirstResponder(void) +{ + unsigned int i; + + for (i = 0; i < num_targets; ++i) + { + if (targets[i].type == QUERY_TARGET_SERVER + && targets[i].state == QUERY_TARGET_RESPONDED) + { + return &targets[i]; + } + } + + return NULL; +} + +// Time out servers that have been queried and not responded. + +static void CheckTargetTimeouts(void) +{ + unsigned int i; + unsigned int now; + + now = I_GetTimeMS(); + + for (i = 0; i < num_targets; ++i) + { + if (targets[i].state == QUERY_TARGET_QUERIED + && now - targets[i].query_time > 5000) + { + targets[i].state = QUERY_TARGET_TIMED_OUT; + } + } +} + +// If all targets have responded or timed out, returns true. + +static boolean AllTargetsDone(void) +{ + unsigned int i; + + for (i = 0; i < num_targets; ++i) + { + if (targets[i].state != QUERY_TARGET_RESPONDED + && targets[i].state != QUERY_TARGET_TIMED_OUT) + { + return false; + } + } + + return true; +} + static void formatted_printf(int wide, char *s, ...) { va_list args; int i; - + va_start(args, s); i = vprintf(s, args); va_end(args); - while (i < wide) + while (i < wide) { putchar(' '); ++i; - } + } } static char *GameDescription(GameMode_t mode, GameMission_t mission) @@ -224,115 +461,104 @@ static void PrintHeader(void) putchar('\n'); } -static void PrintResponse(queryresponse_t *response) +static void PrintResponse(query_target_t *target) { - formatted_printf(18, "%s: ", NET_AddrToString(response->addr)); - formatted_printf(8, "%i/%i", response->data.num_players, - response->data.max_players); + formatted_printf(18, "%s: ", NET_AddrToString(target->addr)); + formatted_printf(8, "%i/%i", target->data.num_players, + target->data.max_players); - if (response->data.gamemode != indetermined) + if (target->data.gamemode != indetermined) { - printf("(%s) ", GameDescription(response->data.gamemode, - response->data.gamemission)); + printf("(%s) ", GameDescription(target->data.gamemode, + target->data.gamemission)); } - if (response->data.server_state) + if (target->data.server_state) { printf("(game running) "); } - NET_SafePuts(response->data.description); + NET_SafePuts(target->data.description); } -static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) -{ - unsigned int packet_type; - net_querydata_t querydata; - queryresponse_t *response; - - // Have we already received a packet from this host? +// Check for printing information about servers that have responded. - if (!CheckResponder(addr)) - { - return; - } - - // Read the header - - if (!NET_ReadInt16(packet, &packet_type) - || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) - { - return; - } - - // Read query data - - if (!NET_ReadQueryData(packet, &querydata)) - { - return; - } +static void CheckPrintOutput(void) +{ + unsigned int i; - if (num_responses <= 0) + for (i = 0; i < num_targets; ++i) { - // If this is the first response, print the table header + if (targets[i].type == QUERY_TARGET_SERVER + && targets[i].state == QUERY_TARGET_RESPONDED + && !targets[i].printed) + { + if (!printed_header) + { + PrintHeader(); + printed_header = true; + } - PrintHeader(); + PrintResponse(&targets[i]); + targets[i].printed = true; + } } - - response = AddResponder(addr, &querydata); - - PrintResponse(response); } -static void NET_Query_GetResponse(void) -{ - net_addr_t *addr; - net_packet_t *packet; +// Loop waiting for responses. - if (NET_RecvPacket(query_context, &addr, &packet)) - { - NET_Query_ParsePacket(addr, packet); - NET_FreePacket(packet); - } -} - -static net_addr_t *NET_Query_QueryLoop(net_addr_t *addr, - boolean find_one) +static net_addr_t *NET_Query_QueryLoop(boolean find_first, + boolean silent) { + query_target_t *responder; int start_time; int last_send_time; last_send_time = -1; start_time = I_GetTimeMS(); - while (I_GetTimeMS() < start_time + 5000) + while (!AllTargetsDone()) { - // Send a query once every second + // Send a query. This will only send a single query. + // Because of the delay below, this is therefore rate limited. - if (last_send_time < 0 || I_GetTimeMS() > last_send_time + 1000) - { - NET_Query_SendQuery(addr); - last_send_time = I_GetTimeMS(); - } + SendOneQuery(); // Check for a response NET_Query_GetResponse(); + // Output the responses + + if (!silent) + { + CheckPrintOutput(); + } + // Found a response? - if (find_one && num_responses > 0) + if (find_first && FindFirstResponder()) + { break; - + } + // Don't thrash the CPU - + I_Sleep(100); + + CheckTargetTimeouts(); } - if (num_responses > 0) - return responders[0].addr; + responder = FindFirstResponder(); + + if (responder != NULL) + { + return responder->addr; + } else + { return NULL; + } } void NET_Query_Init(void) @@ -341,14 +567,16 @@ void NET_Query_Init(void) NET_AddModule(query_context, &net_sdl_module); net_sdl_module.InitClient(); - responders = NULL; - num_responses = 0; + targets = NULL; + num_targets = 0; + + printed_header = false; } void NET_QueryAddress(char *addr) { net_addr_t *net_addr; - + NET_Query_Init(); net_addr = NET_ResolveAddress(query_context, addr); @@ -358,9 +586,13 @@ void NET_QueryAddress(char *addr) I_Error("NET_QueryAddress: Host '%s' not found!", addr); } + // Add the address to the list of targets. + + GetTargetForAddr(net_addr, true); + printf("\nQuerying '%s'...\n\n", addr); - if (!NET_Query_QueryLoop(net_addr, true)) + if (!NET_Query_QueryLoop(true, false)) { I_Error("No response from '%s'", addr); } @@ -370,18 +602,32 @@ void NET_QueryAddress(char *addr) net_addr_t *NET_FindLANServer(void) { + query_target_t *target; + NET_Query_Init(); - return NET_Query_QueryLoop(NULL, true); + // Add a broadcast target to the list. + + target = GetTargetForAddr(NULL, true); + target->type = QUERY_TARGET_BROADCAST; + + return NET_Query_QueryLoop(true, true); } void NET_LANQuery(void) { + query_target_t *target; + NET_Query_Init(); printf("\nSearching for servers on local LAN ...\n\n"); - if (!NET_Query_QueryLoop(NULL, false)) + // Add a broadcast target to the list. + + target = GetTargetForAddr(NULL, true); + target->type = QUERY_TARGET_BROADCAST; + + if (!NET_Query_QueryLoop(false, false)) { I_Error("No servers found"); } @@ -389,4 +635,30 @@ void NET_LANQuery(void) exit(0); } +void NET_MasterQuery(void) +{ + net_addr_t *master; + query_target_t *target; + + NET_Query_Init(); + + printf("\nSearching for servers on Internet ...\n\n"); + + // Resolve master address and add to targets list. + + master = NET_Query_ResolveMaster(query_context); + + if (master == NULL) + { + I_Error("Failed to resolve master server address"); + } + + target = GetTargetForAddr(master, true); + target->type = QUERY_TARGET_MASTER; + + if (!NET_Query_QueryLoop(false, false)) + { + I_Error("No servers found"); + } +} diff --git a/src/net_query.h b/src/net_query.h index 0ed098f1..21c89ecb 100644 --- a/src/net_query.h +++ b/src/net_query.h @@ -30,10 +30,11 @@ extern void NET_QueryAddress(char *addr); extern void NET_LANQuery(void); extern net_addr_t *NET_FindLANServer(void); +extern void NET_MasterQuery(void); -net_addr_t *NET_Query_ResolveMaster(net_context_t *context); -void NET_Query_AddToMaster(net_addr_t *master_addr); -void NET_Query_MasterResponse(net_packet_t *packet); +extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context); +extern void NET_Query_AddToMaster(net_addr_t *master_addr); +extern void NET_Query_MasterResponse(net_packet_t *packet); #endif /* #ifndef NET_QUERY_H */ -- cgit v1.2.3 From b11030cbfee0d4d4a46673001992e94abc146c8c Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 20:11:24 +0000 Subject: More refactoring of querying code, to not be specific to the purpose of printing out a list. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2184 --- src/d_main.c | 13 +- src/net_query.c | 372 ++++++++++++++++++++++++++++++-------------------------- src/net_query.h | 11 +- 3 files changed, 218 insertions(+), 178 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 22fdb142..c0804b5d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -852,7 +852,10 @@ void D_DoomMain (void) if (M_CheckParm("-masterquery")) { - NET_MasterQuery(); + printf("\nSearching for servers on Internet ...\n\n"); + p = NET_MasterQuery(NET_QueryPrintCallback, NULL); + printf("%i server(s) found.\n", p); + exit(0); } //! @@ -868,6 +871,7 @@ void D_DoomMain (void) if (p > 0) { NET_QueryAddress(myargv[p+1]); + exit(0); } //! @@ -877,7 +881,12 @@ void D_DoomMain (void) // if (M_CheckParm("-search")) - NET_LANQuery(); + { + printf("\nSearching for servers on local LAN ...\n"); + p = NET_LANQuery(NET_QueryPrintCallback, NULL); + printf("\n%i server(s) found.\n", p); + exit(0); + } #endif diff --git a/src/net_query.c b/src/net_query.c index 681411c2..3dee1b00 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -71,6 +71,7 @@ static net_context_t *query_context; static query_target_t *targets; static int num_targets; +static boolean query_loop_running = false; static boolean printed_header = false; // Resolve the master server address. @@ -205,7 +206,9 @@ static void NET_Query_SendQuery(net_addr_t *addr) NET_FreePacket(request); } -static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet) +static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet, + net_query_callback_t callback, + void *user_data) { unsigned int packet_type; net_querydata_t querydata; @@ -231,8 +234,15 @@ static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet) target = GetTargetForAddr(addr, true); - target->state = QUERY_TARGET_RESPONDED; - memcpy(&target->data, &querydata, sizeof(net_querydata_t)); + if (target->state != QUERY_TARGET_RESPONDED) + { + target->state = QUERY_TARGET_RESPONDED; + memcpy(&target->data, &querydata, sizeof(net_querydata_t)); + + // Invoke callback to signal that we have a new address. + + callback(addr, &target->data, user_data); + } } // Parse a response packet from the master server. @@ -282,7 +292,9 @@ static void NET_Query_ParseMasterResponse(net_addr_t *master_addr, target->state = QUERY_TARGET_RESPONDED; } -static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) +static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet, + net_query_callback_t callback, + void *user_data) { query_target_t *target; @@ -296,18 +308,19 @@ static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) } else { - NET_Query_ParseResponse(addr, packet); + NET_Query_ParseResponse(addr, packet, callback, user_data); } } -static void NET_Query_GetResponse(void) +static void NET_Query_GetResponse(net_query_callback_t callback, + void *user_data) { net_addr_t *addr; net_packet_t *packet; if (NET_RecvPacket(query_context, &addr, &packet)) { - NET_Query_ParsePacket(addr, packet); + NET_Query_ParsePacket(addr, packet, callback, user_data); NET_FreePacket(packet); } } @@ -354,25 +367,6 @@ static void SendOneQuery(void) targets[i].query_time = I_GetTimeMS(); } -// Search the targets list and find a target that has responded. -// If none have responded yet, returns NULL. - -static query_target_t *FindFirstResponder(void) -{ - unsigned int i; - - for (i = 0; i < num_targets; ++i) - { - if (targets[i].type == QUERY_TARGET_SERVER - && targets[i].state == QUERY_TARGET_RESPONDED) - { - return &targets[i]; - } - } - - return NULL; -} - // Time out servers that have been queried and not responded. static void CheckTargetTimeouts(void) @@ -410,197 +404,165 @@ static boolean AllTargetsDone(void) return true; } -static void formatted_printf(int wide, char *s, ...) -{ - va_list args; - int i; - - va_start(args, s); - i = vprintf(s, args); - va_end(args); +// Stop the query loop - while (i < wide) - { - putchar(' '); - ++i; - } +static void NET_Query_ExitLoop(void) +{ + query_loop_running = false; } -static char *GameDescription(GameMode_t mode, GameMission_t mission) +// Loop waiting for responses. +// The specified callback is invoked when a new server responds. + +static void NET_Query_QueryLoop(net_query_callback_t callback, + void *user_data) { - switch (mode) + query_loop_running = true; + + while (query_loop_running && !AllTargetsDone()) { - case shareware: - return "shareware"; - case registered: - return "registered"; - case retail: - return "ultimate"; - case commercial: - if (mission == doom2) - return "doom2"; - else if (mission == pack_tnt) - return "tnt"; - else if (mission == pack_plut) - return "plutonia"; - default: - return "unknown"; - } -} + // Send a query. This will only send a single query. + // Because of the delay below, this is therefore rate limited. -static void PrintHeader(void) -{ - int i; + SendOneQuery(); - formatted_printf(18, "Address"); - formatted_printf(8, "Players"); - puts("Description"); + // Check for a response - for (i=0; i<70; ++i) - putchar('='); - putchar('\n'); + NET_Query_GetResponse(callback, user_data); + + // Don't thrash the CPU + + I_Sleep(100); + + CheckTargetTimeouts(); + } } -static void PrintResponse(query_target_t *target) +void NET_Query_Init(void) { - formatted_printf(18, "%s: ", NET_AddrToString(target->addr)); - formatted_printf(8, "%i/%i", target->data.num_players, - target->data.max_players); + query_context = NET_NewContext(); + NET_AddModule(query_context, &net_sdl_module); + net_sdl_module.InitClient(); - if (target->data.gamemode != indetermined) - { - printf("(%s) ", GameDescription(target->data.gamemode, - target->data.gamemission)); - } + targets = NULL; + num_targets = 0; - if (target->data.server_state) - { - printf("(game running) "); - } + printed_header = false; +} + +// Callback that exits the query loop when the first server is found. - NET_SafePuts(target->data.description); +static void NET_Query_ExitCallback(net_addr_t *addr, net_querydata_t *data, + void *user_data) +{ + NET_Query_ExitLoop(); } -// Check for printing information about servers that have responded. +// Search the targets list and find a target that has responded. +// If none have responded, returns NULL. -static void CheckPrintOutput(void) +static query_target_t *FindFirstResponder(void) { unsigned int i; for (i = 0; i < num_targets; ++i) { if (targets[i].type == QUERY_TARGET_SERVER - && targets[i].state == QUERY_TARGET_RESPONDED - && !targets[i].printed) + && targets[i].state == QUERY_TARGET_RESPONDED) { - if (!printed_header) - { - PrintHeader(); - printed_header = true; - } - - PrintResponse(&targets[i]); - targets[i].printed = true; + return &targets[i]; } } + + return NULL; } -// Loop waiting for responses. +// Return a count of the number of responses. -static net_addr_t *NET_Query_QueryLoop(boolean find_first, - boolean silent) +static int GetNumResponses(void) { - query_target_t *responder; - int start_time; - int last_send_time; + unsigned int i; + int result; - last_send_time = -1; - start_time = I_GetTimeMS(); + result = 0; - while (!AllTargetsDone()) + for (i = 0; i < num_targets; ++i) { - // Send a query. This will only send a single query. - // Because of the delay below, this is therefore rate limited. + if (targets[i].type == QUERY_TARGET_SERVER + && targets[i].state == QUERY_TARGET_RESPONDED) + { + ++result; + } + } - SendOneQuery(); + return result; +} - // Check for a response +void NET_QueryAddress(char *addr_str) +{ + net_addr_t *addr; + query_target_t *target; - NET_Query_GetResponse(); + NET_Query_Init(); - // Output the responses + addr = NET_ResolveAddress(query_context, addr_str); - if (!silent) - { - CheckPrintOutput(); - } + if (addr == NULL) + { + I_Error("NET_QueryAddress: Host '%s' not found!", addr_str); + } - // Found a response? + // Add the address to the list of targets. - if (find_first && FindFirstResponder()) - { - break; - } + target = GetTargetForAddr(addr, true); - // Don't thrash the CPU + printf("\nQuerying '%s'...\n", addr_str); - I_Sleep(100); + // Run query loop. - CheckTargetTimeouts(); - } + NET_Query_QueryLoop(NET_Query_ExitCallback, NULL); - responder = FindFirstResponder(); + // Check if the target responded. - if (responder != NULL) + if (target->state == QUERY_TARGET_RESPONDED) { - return responder->addr; + NET_QueryPrintCallback(addr, &target->data, NULL); } else { - return NULL; + I_Error("No response from '%s'", addr_str); } } -void NET_Query_Init(void) -{ - query_context = NET_NewContext(); - NET_AddModule(query_context, &net_sdl_module); - net_sdl_module.InitClient(); - - targets = NULL; - num_targets = 0; - - printed_header = false; -} - -void NET_QueryAddress(char *addr) +net_addr_t *NET_FindLANServer(void) { - net_addr_t *net_addr; + query_target_t *target; + query_target_t *responder; NET_Query_Init(); - net_addr = NET_ResolveAddress(query_context, addr); + // Add a broadcast target to the list. - if (net_addr == NULL) - { - I_Error("NET_QueryAddress: Host '%s' not found!", addr); - } + target = GetTargetForAddr(NULL, true); + target->type = QUERY_TARGET_BROADCAST; - // Add the address to the list of targets. + // Run the query loop, and stop at the first target found. - GetTargetForAddr(net_addr, true); + NET_Query_QueryLoop(NET_Query_ExitCallback, NULL); - printf("\nQuerying '%s'...\n\n", addr); + responder = FindFirstResponder(); - if (!NET_Query_QueryLoop(true, false)) + if (responder != NULL) { - I_Error("No response from '%s'", addr); + return responder->addr; + } + else + { + return NULL; } - - exit(0); } -net_addr_t *NET_FindLANServer(void) +int NET_LANQuery(net_query_callback_t callback, void *user_data) { query_target_t *target; @@ -611,54 +573,116 @@ net_addr_t *NET_FindLANServer(void) target = GetTargetForAddr(NULL, true); target->type = QUERY_TARGET_BROADCAST; - return NET_Query_QueryLoop(true, true); + NET_Query_QueryLoop(callback, user_data); + + return GetNumResponses(); } -void NET_LANQuery(void) +int NET_MasterQuery(net_query_callback_t callback, void *user_data) { + net_addr_t *master; query_target_t *target; NET_Query_Init(); - printf("\nSearching for servers on local LAN ...\n\n"); + // Resolve master address and add to targets list. - // Add a broadcast target to the list. + master = NET_Query_ResolveMaster(query_context); - target = GetTargetForAddr(NULL, true); - target->type = QUERY_TARGET_BROADCAST; + if (master == NULL) + { + return 0; + } + + target = GetTargetForAddr(master, true); + target->type = QUERY_TARGET_MASTER; - if (!NET_Query_QueryLoop(false, false)) + NET_Query_QueryLoop(callback, user_data); + + return GetNumResponses(); +} + +static void formatted_printf(int wide, char *s, ...) +{ + va_list args; + int i; + + va_start(args, s); + i = vprintf(s, args); + va_end(args); + + while (i < wide) { - I_Error("No servers found"); + putchar(' '); + ++i; } +} - exit(0); +static char *GameDescription(GameMode_t mode, GameMission_t mission) +{ + switch (mode) + { + case shareware: + return "shareware"; + case registered: + return "registered"; + case retail: + return "ultimate"; + case commercial: + if (mission == doom2) + return "doom2"; + else if (mission == pack_tnt) + return "tnt"; + else if (mission == pack_plut) + return "plutonia"; + default: + return "unknown"; + } } -void NET_MasterQuery(void) +static void PrintHeader(void) { - net_addr_t *master; - query_target_t *target; + int i; - NET_Query_Init(); + putchar('\n'); + formatted_printf(18, "Address"); + formatted_printf(8, "Players"); + puts("Description"); - printf("\nSearching for servers on Internet ...\n\n"); + for (i=0; i<70; ++i) + putchar('='); + putchar('\n'); +} - // Resolve master address and add to targets list. +// Callback function that just prints information in a table. - master = NET_Query_ResolveMaster(query_context); +void NET_QueryPrintCallback(net_addr_t *addr, + net_querydata_t *data, + void *user_data) +{ + // If this is the first server, print the header. - if (master == NULL) + if (!printed_header) { - I_Error("Failed to resolve master server address"); + PrintHeader(); + printed_header = true; } - target = GetTargetForAddr(master, true); - target->type = QUERY_TARGET_MASTER; + formatted_printf(18, "%s: ", NET_AddrToString(addr)); + formatted_printf(8, "%i/%i", data->num_players, + data->max_players); - if (!NET_Query_QueryLoop(false, false)) + if (data->gamemode != indetermined) { - I_Error("No servers found"); + printf("(%s) ", GameDescription(data->gamemode, + data->gamemission)); } + + if (data->server_state) + { + printf("(game running) "); + } + + NET_SafePuts(data->description); } diff --git a/src/net_query.h b/src/net_query.h index 21c89ecb..98931593 100644 --- a/src/net_query.h +++ b/src/net_query.h @@ -27,10 +27,17 @@ #include "net_defs.h" +typedef void (*net_query_callback_t)(net_addr_t *addr, + net_querydata_t *querydata, + void *user_data); + +extern int NET_LANQuery(net_query_callback_t callback, void *user_data); +extern int NET_MasterQuery(net_query_callback_t callback, void *user_data); extern void NET_QueryAddress(char *addr); -extern void NET_LANQuery(void); extern net_addr_t *NET_FindLANServer(void); -extern void NET_MasterQuery(void); + +extern void NET_QueryPrintCallback(net_addr_t *addr, net_querydata_t *data, + void *user_data); extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context); extern void NET_Query_AddToMaster(net_addr_t *master_addr); -- cgit v1.2.3 From 59d2ed0f2de6b2156142c87d48b0f55fa56b2acf Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 20:32:52 +0000 Subject: Add -servername parameter to allow the owner to change the name returned in response to queries (thanks AlexMax). Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2185 --- src/net_server.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/net_server.c b/src/net_server.c index 7b67ea56..43584170 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -1079,6 +1079,7 @@ void NET_SV_SendQueryResponse(net_addr_t *addr) { net_packet_t *reply; net_querydata_t querydata; + int p; // Version @@ -1098,9 +1099,22 @@ void NET_SV_SendQueryResponse(net_addr_t *addr) querydata.gamemode = sv_gamemode; querydata.gamemission = sv_gamemission; - // Server description. This is currently hard-coded. + //! + // @arg + // + // When starting a network server, specify a name for the server. + // - querydata.description = "Chocolate Doom server"; + p = M_CheckParm("-servername"); + + if (p > 0 && p + 1 < myargc) + { + querydata.description = myargv[p + 1]; + } + else + { + querydata.description = "Unnamed server"; + } // Send it and we're done. -- cgit v1.2.3 From 0ff67f43d6d13d9675e305abc652188ea95a88fe Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 21:34:51 +0000 Subject: Make multiple query attempts to servers before giving up. Display a warning if the master server does not respond. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2187 --- src/net_query.c | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/net_query.c b/src/net_query.c index 3dee1b00..6a934413 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -36,8 +36,18 @@ #include "net_structrw.h" #include "net_sdl.h" +// DNS address of the Internet master server. + #define MASTER_SERVER_ADDRESS "master.chocolate-doom.org" +// Time to wait for a response before declaring a timeout. + +#define QUERY_TIMEOUT_SECS 1 + +// Number of query attempts to make before giving up on a server. + +#define QUERY_MAX_ATTEMPTS 5 + typedef enum { QUERY_TARGET_SERVER, // Normal server target. @@ -50,7 +60,7 @@ typedef enum QUERY_TARGET_QUEUED, // Query not yet sent QUERY_TARGET_QUERIED, // Query sent, waiting response QUERY_TARGET_RESPONDED, // Response received - QUERY_TARGET_TIMED_OUT + QUERY_TARGET_NO_RESPONSE } query_target_state_t; typedef struct @@ -60,6 +70,7 @@ typedef struct net_addr_t *addr; net_querydata_t data; unsigned int query_time; + unsigned int query_attempts; boolean printed; } query_target_t; @@ -179,6 +190,7 @@ static query_target_t *GetTargetForAddr(net_addr_t *addr, boolean create) target->type = QUERY_TARGET_SERVER; target->state = QUERY_TARGET_QUEUED; target->printed = false; + target->query_attempts = 0; target->addr = addr; ++num_targets; @@ -329,11 +341,19 @@ static void NET_Query_GetResponse(net_query_callback_t callback, static void SendOneQuery(void) { + unsigned int now; unsigned int i; + now = I_GetTimeMS(); + for (i = 0; i < num_targets; ++i) { - if (targets[i].state == QUERY_TARGET_QUEUED) + // Not queried yet? + // Or last query timed out without a response? + + if (targets[i].state == QUERY_TARGET_QUEUED + || (targets[i].state == QUERY_TARGET_QUERIED + && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000)) { break; } @@ -365,6 +385,7 @@ static void SendOneQuery(void) //printf("Queried %s\n", NET_AddrToString(targets[i].addr)); targets[i].state = QUERY_TARGET_QUERIED; targets[i].query_time = I_GetTimeMS(); + ++targets[i].query_attempts; } // Time out servers that have been queried and not responded. @@ -378,10 +399,15 @@ static void CheckTargetTimeouts(void) for (i = 0; i < num_targets; ++i) { + // We declare a target to be "no response" when we've sent + // multiple query packets to it (QUERY_MAX_ATTEMPTS) and + // received no response to any of them. + if (targets[i].state == QUERY_TARGET_QUERIED - && now - targets[i].query_time > 5000) + && targets[i].query_attempts >= QUERY_MAX_ATTEMPTS + && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000) { - targets[i].state = QUERY_TARGET_TIMED_OUT; + targets[i].state = QUERY_TARGET_NO_RESPONSE; } } } @@ -395,7 +421,7 @@ static boolean AllTargetsDone(void) for (i = 0; i < num_targets; ++i) { if (targets[i].state != QUERY_TARGET_RESPONDED - && targets[i].state != QUERY_TARGET_TIMED_OUT) + && targets[i].state != QUERY_TARGET_NO_RESPONSE) { return false; } @@ -432,7 +458,7 @@ static void NET_Query_QueryLoop(net_query_callback_t callback, // Don't thrash the CPU - I_Sleep(100); + I_Sleep(50); CheckTargetTimeouts(); } @@ -599,6 +625,14 @@ int NET_MasterQuery(net_query_callback_t callback, void *user_data) NET_Query_QueryLoop(callback, user_data); + // Check that we got a response from the master, and display + // a warning if we didn't. + + if (target->state == QUERY_TARGET_NO_RESPONSE) + { + fprintf(stderr, "NET_MasterQuery: no response from master server.\n"); + } + return GetNumResponses(); } -- cgit v1.2.3 From 863afa816738407f639618fb43659b97dcc3430d Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 4 Dec 2010 20:34:39 +0000 Subject: Fix bug when running with -server option. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2190 --- src/net_loop.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/net_loop.c b/src/net_loop.c index abba96e0..b8387794 100644 --- a/src/net_loop.c +++ b/src/net_loop.c @@ -137,9 +137,16 @@ static void NET_CL_FreeAddress(net_addr_t *addr) static net_addr_t *NET_CL_ResolveAddress(char *address) { - client_addr.module = &net_loop_client_module; + if (address == NULL) + { + client_addr.module = &net_loop_client_module; - return &client_addr; + return &client_addr; + } + else + { + return NULL; + } } net_module_t net_loop_client_module = @@ -206,8 +213,15 @@ static void NET_SV_FreeAddress(net_addr_t *addr) static net_addr_t *NET_SV_ResolveAddress(char *address) { - server_addr.module = &net_loop_server_module; - return &server_addr; + if (address == NULL) + { + server_addr.module = &net_loop_server_module; + return &server_addr; + } + else + { + return NULL; + } } net_module_t net_loop_server_module = -- cgit v1.2.3 From 0194038cac0092499668d849a300eaffaa448421 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 4 Dec 2010 20:40:10 +0000 Subject: Fix formatting for -masterquery to match -search. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2191 --- src/d_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index c0804b5d..2f787694 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -852,9 +852,9 @@ void D_DoomMain (void) if (M_CheckParm("-masterquery")) { - printf("\nSearching for servers on Internet ...\n\n"); + printf("\nSearching for servers on Internet ...\n"); p = NET_MasterQuery(NET_QueryPrintCallback, NULL); - printf("%i server(s) found.\n", p); + printf("\n%i server(s) found.\n", p); exit(0); } -- cgit v1.2.3 From 3c57887b0a5352da1c7c4fe7f149c94bb6d70c31 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 4 Dec 2010 20:48:07 +0000 Subject: Add ping time to query output. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2192 --- src/net_query.c | 18 +++++++++++++----- src/net_query.h | 3 ++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/net_query.c b/src/net_query.c index 6a934413..265e3804 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -42,11 +42,11 @@ // Time to wait for a response before declaring a timeout. -#define QUERY_TIMEOUT_SECS 1 +#define QUERY_TIMEOUT_SECS 2 // Number of query attempts to make before giving up on a server. -#define QUERY_MAX_ATTEMPTS 5 +#define QUERY_MAX_ATTEMPTS 3 typedef enum { @@ -69,6 +69,7 @@ typedef struct query_target_state_t state; net_addr_t *addr; net_querydata_t data; + unsigned int ping_time; unsigned int query_time; unsigned int query_attempts; boolean printed; @@ -251,9 +252,13 @@ static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet, target->state = QUERY_TARGET_RESPONDED; memcpy(&target->data, &querydata, sizeof(net_querydata_t)); + // Calculate RTT. + + target->ping_time = I_GetTimeMS() - target->query_time; + // Invoke callback to signal that we have a new address. - callback(addr, &target->data, user_data); + callback(addr, &target->data, target->ping_time, user_data); } } @@ -479,7 +484,7 @@ void NET_Query_Init(void) // Callback that exits the query loop when the first server is found. static void NET_Query_ExitCallback(net_addr_t *addr, net_querydata_t *data, - void *user_data) + unsigned int ping_time, void *user_data) { NET_Query_ExitLoop(); } @@ -552,7 +557,7 @@ void NET_QueryAddress(char *addr_str) if (target->state == QUERY_TARGET_RESPONDED) { - NET_QueryPrintCallback(addr, &target->data, NULL); + NET_QueryPrintCallback(addr, &target->data, target->ping_time, NULL); } else { @@ -679,6 +684,7 @@ static void PrintHeader(void) int i; putchar('\n'); + formatted_printf(5, "Ping"); formatted_printf(18, "Address"); formatted_printf(8, "Players"); puts("Description"); @@ -692,6 +698,7 @@ static void PrintHeader(void) void NET_QueryPrintCallback(net_addr_t *addr, net_querydata_t *data, + unsigned int ping_time, void *user_data) { // If this is the first server, print the header. @@ -702,6 +709,7 @@ void NET_QueryPrintCallback(net_addr_t *addr, printed_header = true; } + formatted_printf(5, "%4i", ping_time); formatted_printf(18, "%s: ", NET_AddrToString(addr)); formatted_printf(8, "%i/%i", data->num_players, data->max_players); diff --git a/src/net_query.h b/src/net_query.h index 98931593..01e059cb 100644 --- a/src/net_query.h +++ b/src/net_query.h @@ -29,6 +29,7 @@ typedef void (*net_query_callback_t)(net_addr_t *addr, net_querydata_t *querydata, + unsigned int ping_time, void *user_data); extern int NET_LANQuery(net_query_callback_t callback, void *user_data); @@ -37,7 +38,7 @@ extern void NET_QueryAddress(char *addr); extern net_addr_t *NET_FindLANServer(void); extern void NET_QueryPrintCallback(net_addr_t *addr, net_querydata_t *data, - void *user_data); + unsigned int ping_time, void *user_data); extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context); extern void NET_Query_AddToMaster(net_addr_t *master_addr); -- cgit v1.2.3 From d3c8d42bc4edf892557875a83c3f5ae65880e074 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 4 Dec 2010 20:56:04 +0000 Subject: Rename search command line options: -search to search the Internet, -localsearch to search local LAN. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2193 --- src/d_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 2f787694..032c5caa 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -850,7 +850,7 @@ void D_DoomMain (void) // servers. // - if (M_CheckParm("-masterquery")) + if (M_CheckParm("-search")) { printf("\nSearching for servers on Internet ...\n"); p = NET_MasterQuery(NET_QueryPrintCallback, NULL); @@ -880,7 +880,7 @@ void D_DoomMain (void) // Search the local LAN for running servers. // - if (M_CheckParm("-search")) + if (M_CheckParm("-localsearch")) { printf("\nSearching for servers on local LAN ...\n"); p = NET_LANQuery(NET_QueryPrintCallback, NULL); -- cgit v1.2.3 From 2a786cc67e1cfb7472b117f05e1f9962d7d3da39 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 5 Dec 2010 14:42:09 +0000 Subject: Allow textscreen font to be overridden using the TEXTSCREEN_FONT command line variable. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2195 --- textscreen/txt_sdl.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c index 0df9fc93..315d2762 100644 --- a/textscreen/txt_sdl.c +++ b/textscreen/txt_sdl.c @@ -119,6 +119,22 @@ static SDL_Color ega_colors[] = #endif +static txt_font_t *FontForName(char *name) +{ + if (!strcmp(name, "small")) + { + return &small_font; + } + else if (!strcmp(name, "normal")) + { + return &main_font; + } + else + { + return NULL; + } +} + // // Select the font to use, based on screen resolution // @@ -129,9 +145,22 @@ static SDL_Color ega_colors[] = static void ChooseFont(void) { SDL_Rect **modes; + char *env; int i; - font = &main_font; + // Allow normal selection to be overridden from an environment variable: + + env = getenv("TEXTSCREEN_FONT"); + + if (env != NULL) + { + font = FontForName(env); + + if (font != NULL) + { + return; + } + } // Check all modes @@ -140,6 +169,8 @@ static void ChooseFont(void) // If in doubt and we can't get a list, always prefer to // fall back to the normal font: + font = &main_font; + if (modes == NULL || modes == (SDL_Rect **) -1 || *modes == NULL) { #ifdef _WIN32_WCE -- cgit v1.2.3 From 678a8f9aeea9fa1966b3e8a94974688fda4d8fe1 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 6 Dec 2010 00:04:08 +0000 Subject: Update NEWS. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2196 --- NEWS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/NEWS b/NEWS index 1296aabf..7ce747ec 100644 --- a/NEWS +++ b/NEWS @@ -8,8 +8,15 @@ just 8-bit modes). This is mainly to work around problems with Windows Vista/7, where 8-bit color modes don't always work properly. + * Multiplayer servers now register themselves with an Internet + master server. Use the -search command line parameter to + find servers on the Internet to play on. You can also use + DoomSeeker (http://skulltag.net/doomseeker/) which supports + this functionality. * When running in windowed mode, it is now possible to dynamically resize the window by dragging the window borders. + * Names can be specified for servers with the -servername command + line parameter. * There are now keyboard, mouse and joystick bindings to cycle through available weapons, making play with joypads or mobile devices (ie. without a proper keyboard) much more practical. @@ -22,6 +29,9 @@ * The Python scripts used for building Chocolate Doom now work with Python 3 (but also continue to work with Python 2) (thanks arin). + * The font used for the textscreen library can be forced by + setting the TEXTSCREEN_FONT environment variable to "small" or + "normal". * There is now a NOT-BUGS file included that lists some common Vanilla Doom bugs/limitations that you might encounter. -- cgit v1.2.3