From 253731b66d4a70d5040d11e4b1acf8aa58230a46 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sun, 19 Sep 2010 20:09:36 +0000 Subject: Read response file in binary mode, to fix incomplete response file bug. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2122 --- src/m_argv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/m_argv.c b/src/m_argv.c index 7fc15863..99295c6d 100644 --- a/src/m_argv.c +++ b/src/m_argv.c @@ -74,9 +74,9 @@ static void LoadResponseFile(int argv_index) int i, k; response_filename = myargv[argv_index] + 1; - + // Read the response file into memory - handle = fopen(response_filename, "r"); + handle = fopen(response_filename, "rb"); if (handle == NULL) { -- 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(-) (limited to 'src') 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(-) (limited to 'src') 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 --- src/i_video.c | 42 ++++++++++++++++++++++++++++++++++-------- src/i_video.h | 1 + src/m_config.c | 6 ++++++ 3 files changed, 41 insertions(+), 8 deletions(-) (limited to 'src') 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 --- src/m_config.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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 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 --- src/i_video.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) (limited to 'src') 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 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(-) (limited to 'src') 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 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(-) (limited to 'src') 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(+) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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(-) (limited to 'src') 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