From 9fdcb553aa18960ad1c1bb9d158172a3c17cb10b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 30 Jun 2006 02:13:26 +0000 Subject: [PATCH] - Added some hackery at the start of MouseRead_Win32() that prevents it from yanking the mouse around if they keys haven't been read yet to combat the same situation that causes the keyboard to return DIERR_NOTACQUIRED in KeyRead(): The window is sort of in focus and sort of not. User.dll considers it to be focused and it's drawn as such, but another focused window is on top of it, and DirectInput doesn't see it as focused. - Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it handles DIERR_INPUTLOST errors. This can happen if our window had the focus stolen away from it before we tried to acquire the keyboard in DI_Init2(). Strangely, MouseRead_DI() already did this. - When a stack overflow occurs, report.txt now only includes the first and last 16KB of the stack to make it more manageable. - Limited StreamEditBinary() to the first 64KB of the file to keep it from taking too long on large dumps. - And now I know why gathering crash information in the same process that crashed can be bad: Stack overflows. You get one spare page to play with when the stack overflows. MiniDumpWriteDump() needs more than that and causes an access violation when it runs out of leftover stack, silently terminating the application. Windows XP x64 offers SetThreadStackGuarantee() to increase this, but that isn't available on anything older, including 32-bit XP. To get around this, a new thread is created to write the mini dump when the stack overflows. - Changed A_Burnination() to be closer to Strife's. - Fixed: When playing back demos, DoAddBot() can be called without an associated call to SpawnBot(). So if the bot can't spawn, botnum can go negative, which will cause problems later in DCajunMaster::Main() when it sees that wanted_botnum (0) is higher than botnum (-1). - Fixed: Stopping demo recording in multiplayer games should not abruptly drop the recorder out of the game without notifying the other players. In fact, there's no reason why it should drop them out of multiplayer at all. - Fixed: Earthquakes were unreliable in multiplayer games because P_PredictPlayer() did not preserve the player's xviewshift. - Fixed: PlayerIsGone() needs to stop any scripts that belong to the player who left, in addition to executing disconnect scripts. - Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo in case the player left but somebody still has a reference to their actor. - Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior and set Buffer to NULL. - Improved feedback for network game initialization with the console ticker. - Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source directory. They are identical, so keeping two copies of them is bad. - Fixed: (At least with Creative's driver's,) EAX settings are global and not per-application. So if you play a multiplayer ZDoom game on one computer (or even another EAX-using application), ZDoom needs to restore the environment when it regains focus. - Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently, PacketGet can receive ECONNRESET from nodes that aren't in the game. It should be safe to just ignore these packets. - Fixed: PlayerIsGone() should set the gone player's camera to NULL in case the player who left was player 0. This is because if a remaining player receives a "recoverable" error, they will become player 0. Once that happens, they game will try to update sounds through their camera and crash in FMODSoundRenderer::UpdateListener() because the zones array is now NULL. G_NewInit() should also clear all the player structures. SVN r233 (trunk) --- docs/rh-log.txt | 57 +++ src/b_game.cpp | 5 +- src/c_console.cpp | 14 +- src/c_console.h | 2 +- src/d_main.cpp | 6 +- src/d_net.cpp | 2 + src/g_game.cpp | 5 +- src/g_level.cpp | 5 +- src/g_shared/hudmessages.cpp | 5 +- src/g_strife/a_strifeweapons.cpp | 25 +- src/{sdl => }/i_net.cpp | 160 ++++-- src/{sdl => }/i_net.h | 0 src/m_options.cpp | 2 +- src/p_acs.cpp | 31 ++ src/p_acs.h | 2 + src/p_user.cpp | 5 +- src/sound/fmodsound.cpp | 6 + src/sound/fmodsound.h | 1 + src/sound/i_sound.cpp | 5 + src/sound/i_sound.h | 1 + src/win32/i_crash.cpp | 94 +++- src/win32/i_input.cpp | 18 +- src/win32/i_main.cpp | 32 +- src/win32/i_net.cpp | 837 ------------------------------- src/win32/i_net.h | 30 -- src/win32/win32video.cpp | 1 + zdoom.vcproj | 124 +---- 27 files changed, 390 insertions(+), 1085 deletions(-) rename src/{sdl => }/i_net.cpp (85%) rename src/{sdl => }/i_net.h (100%) delete mode 100644 src/win32/i_net.cpp delete mode 100644 src/win32/i_net.h diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 968ee717a6..f569d14842 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,60 @@ +June 29, 2006 +- Added some hackery at the start of MouseRead_Win32() that prevents it from + yanking the mouse around if they keys haven't been read yet to combat the + same situation that causes the keyboard to return DIERR_NOTACQUIRED in + KeyRead(): The window is sort of in focus and sort of not. User.dll + considers it to be focused and it's drawn as such, but another focused + window is on top of it, and DirectInput doesn't see it as focused. +- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it + handles DIERR_INPUTLOST errors. This can happen if our window had the + focus stolen away from it before we tried to acquire the keyboard in + DI_Init2(). Strangely, MouseRead_DI() already did this. +- When a stack overflow occurs, report.txt now only includes the first and + last 16KB of the stack to make it more manageable. +- Limited StreamEditBinary() to the first 64KB of the file to keep it from + taking too long on large dumps. +- And now I know why gathering crash information in the same process that + crashed can be bad: Stack overflows. You get one spare page to play with + when the stack overflows. MiniDumpWriteDump() needs more than that and + causes an access violation when it runs out of leftover stack, silently + terminating the application. Windows XP x64 offers SetThreadStackGuarantee() + to increase this, but that isn't available on anything older, including + 32-bit XP. To get around this, a new thread is created to write the mini + dump when the stack overflows. +- Changed A_Burnination() to be closer to Strife's. +- Fixed: When playing back demos, DoAddBot() can be called without an + associated call to SpawnBot(). So if the bot can't spawn, botnum can + go negative, which will cause problems later in DCajunMaster::Main() + when it sees that wanted_botnum (0) is higher than botnum (-1). +- Fixed: Stopping demo recording in multiplayer games should not abruptly + drop the recorder out of the game without notifying the other players. + In fact, there's no reason why it should drop them out of multiplayer at + all. +- Fixed: Earthquakes were unreliable in multiplayer games because + P_PredictPlayer() did not preserve the player's xviewshift. +- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player + who left, in addition to executing disconnect scripts. +- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo + in case the player left but somebody still has a reference to their actor. +- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior + and set Buffer to NULL. +- Improved feedback for network game initialization with the console ticker. +- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source + directory. They are identical, so keeping two copies of them is bad. +- Fixed: (At least with Creative's driver's,) EAX settings are global and not + per-application. So if you play a multiplayer ZDoom game on one computer + (or even another EAX-using application), ZDoom needs to restore the + environment when it regains focus. +- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently, + PacketGet can receive ECONNRESET from nodes that aren't in the game. It + should be safe to just ignore these packets. +- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case + the player who left was player 0. This is because if a remaining player + receives a "recoverable" error, they will become player 0. Once that happens, + they game will try to update sounds through their camera and crash in + FMODSoundRenderer::UpdateListener() because the zones array is now NULL. + G_NewInit() should also clear all the player structures. + June 29, 2006 (Changes by Graf Zahl) - Added a 'default' setting to all color selection menu items that leaves the font untranslated. diff --git a/src/b_game.cpp b/src/b_game.cpp index 5a58a2f03a..ae02d136ee 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -361,7 +361,10 @@ void DCajunMaster::DoAddBot (int bnum, char *info) Printf ("%s tried to join, but there was no player %d start\n", players[bnum].userinfo.netname, bnum+1); ClearPlayer (bnum, false); // Make the bot inactive again - botnum--; + if (botnum > 0) + { + botnum--; + } } else { diff --git a/src/c_console.cpp b/src/c_console.cpp index 18463d4f18..3b19518376 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -121,6 +121,7 @@ static GameAtExit *ExitCmdList; EXTERN_CVAR (Bool, show_messages) static unsigned int TickerAt, TickerMax; +static bool TickerPercent; static const char *TickerLabel; static bool TickerVisible; @@ -1079,8 +1080,9 @@ static void C_DrawNotifyText () } } -void C_InitTicker (const char *label, unsigned int max) +void C_InitTicker (const char *label, unsigned int max, bool showpercent) { + TickerPercent = showpercent; TickerMax = max; TickerLabel = label; TickerAt = 0; @@ -1170,7 +1172,14 @@ void C_DrawConsole () memset (tickstr + tickbegin + 1, 0x11, tickend - tickbegin); tickstr[tickend + 1] = 0x12; tickstr[tickend + 2] = ' '; - sprintf (tickstr + tickend + 3, "%lu%%", Scale (TickerAt, 100, TickerMax)); + if (TickerPercent) + { + sprintf (tickstr + tickend + 3, "%lu%%", Scale (TickerAt, 100, TickerMax)); + } + else + { + tickstr[tickend+3] = 0; + } screen->DrawText (CR_BROWN, LEFTMARGIN, tickerY, tickstr, TAG_DONE); // Draw the marker @@ -1268,6 +1277,7 @@ void C_FullConsole () { if (demoplayback) G_CheckDemoStatus (); + D_QuitNetGame (); advancedemo = false; ConsoleState = c_down; HistPos = NULL; diff --git a/src/c_console.h b/src/c_console.h index d2b8ec545b..4a6fc01521 100644 --- a/src/c_console.h +++ b/src/c_console.h @@ -69,7 +69,7 @@ void C_HideConsole (void); void C_AdjustBottom (void); void C_FlushDisplay (void); -void C_InitTicker (const char *label, unsigned int max); +void C_InitTicker (const char *label, unsigned int max, bool showpercent=true); void C_SetTicker (unsigned int at, bool forceUpdate=false); void C_MidPrint (const char *message); diff --git a/src/d_main.cpp b/src/d_main.cpp index 252726b54c..97f5e48d27 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -633,16 +633,16 @@ void D_ErrorCleanup () screen->Unlock (); bglobal.RemoveAllBots (true); D_QuitNetGame (); + if (demorecording || demoplayback) + G_CheckDemoStatus (); Net_ClearBuffers (); G_NewInit (); singletics = false; - if (demorecording || demoplayback) - G_CheckDemoStatus (); playeringame[0] = 1; players[0].playerstate = PST_LIVE; gameaction = ga_fullconsole; menuactive = MENU_Off; - insave=false; + insave = false; } //========================================================================== diff --git a/src/d_net.cpp b/src/d_net.cpp index a48efe3578..0e581b4b11 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -621,11 +621,13 @@ void PlayerIsGone (int netnode, int netconsole) } // [RH] Make the player disappear + FBehavior::StaticStopMyScripts (players[netconsole].mo); if (players[netconsole].mo != NULL) { P_DisconnectEffect (players[netconsole].mo); players[netconsole].mo->Destroy (); players[netconsole].mo = NULL; + players[netconsole].camera = NULL; } // [RH] Let the scripts know the player left FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, NULL, true, netconsole); diff --git a/src/g_game.cpp b/src/g_game.cpp index ed25a30704..9be81fb918 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2101,7 +2101,10 @@ void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf) if (stoprecording) { // use "stop" console command to end demo recording G_CheckDemoStatus (); - gameaction = ga_fullconsole; + if (!netgame) + { + gameaction = ga_fullconsole; + } return; } diff --git a/src/g_level.cpp b/src/g_level.cpp index 6ed6d115f4..eee6199015 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1369,10 +1369,13 @@ void G_NewInit () demoplayback = false; D_SetupUserInfo (); } - memset (playeringame, 0, sizeof(playeringame)); for (i = 0; i < MAXPLAYERS; ++i) { + player_t *p = &players[i]; + p->~player_t(); + ::new(p) player_t; players[i].playerstate = PST_DEAD; + playeringame[i] = 0; } BackupSaveName = ""; consoleplayer = 0; diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 6cd8cf630a..78b5acdcd3 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -142,7 +142,10 @@ DHUDMessage::~DHUDMessage () { V_FreeBrokenLines (Lines); Lines = NULL; - BorderNeedRefresh = screen->GetPageCount (); + if (screen != NULL) + { + BorderNeedRefresh = screen->GetPageCount (); + } } if (SourceText != NULL) { diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index d8d5c42e32..3e1614fc29 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -1598,27 +1598,20 @@ void A_Burnination (AActor *self) // x + (((pr_phburn() + 12) & 31) << FRACBITS); // // But that creates a lop-sided burn because it won't use negative offsets. - int xofs = pr_phburn(); - int yofs = pr_phburn(); + int xofs, xrand = pr_phburn(); + int yofs, yrand = pr_phburn(); - xofs = (xofs - 128); - if (xofs < 0) + // Adding 12 is pointless if you're going to mask it afterward. + xofs = xrand & 31; + if (xrand & 128) { - xofs = clamp (xofs, -31, -12); - } - else - { - xofs = clamp (xofs, 12, 31); + xofs = -xofs; } - yofs = (yofs - 128); - if (yofs < 0) + yofs = yrand & 31; + if (yrand & 128) { - yofs = clamp (yofs, -31, -12); - } - else - { - yofs = clamp (yofs, 12, 31); + yofs = -yofs; } fixed_t x = self->x + (xofs << FRACBITS); diff --git a/src/sdl/i_net.cpp b/src/i_net.cpp similarity index 85% rename from src/sdl/i_net.cpp rename to src/i_net.cpp index 32dbcb0677..6456cf282a 100644 --- a/src/sdl/i_net.cpp +++ b/src/i_net.cpp @@ -57,6 +57,7 @@ #include "m_crc32.h" #include "d_player.h" #include "templates.h" +#include "c_console.h" #include "doomstat.h" @@ -215,11 +216,11 @@ void PacketGet (void) , (sockaddr *)&fromaddress, &fromlen); node = FindNode (&fromaddress); - if (c == SOCKET_ERROR) + if (node >= 0 && c == SOCKET_ERROR) { int err = WSAGetLastError(); - if (err == WSAECONNRESET && node >= 0) + if (err == WSAECONNRESET) { // The remote node aborted unexpectedly, so pretend it sent an exit packet Printf (PRINT_BOLD, "The connection from %s was dropped\n", @@ -435,11 +436,15 @@ void HostGame (int i) atterm (SendAbort); + C_InitTicker ("Waiting for players", numplayers); + C_SetTicker (1, true); + // Wait for numplayers-1 different connections while (doomcom.numnodes < numplayers) { while (doomcom.numnodes < numplayers) { + C_SetTicker (doomcom.numnodes, true); if (CheckAbort ()) { SendAbort (); @@ -510,6 +515,8 @@ void HostGame (int i) ackcount = 0; memset (gotack, 0, sizeof(gotack)); Printf ("Sending all here\n"); + C_InitTicker ("Done waiting", 1); + C_SetTicker (1, true); while (ackcount < doomcom.numnodes - 1) { packet.fake = PRE_FAKE; @@ -585,13 +592,32 @@ void HostGame (int i) { sendplayer[i] = i; } + C_SetTicker (1, true); + C_InitTicker (NULL, 0); } -void SendToHost (BYTE message, BYTE ackmess, bool abortable) +// This routine is used by a guest to notify the host of its presence. +// Once that host acknowledges receipt of the notification, this routine +// is never called again. + +static const int bouncerfps = 10; +static const int bouncerdelay = 1000 / bouncerfps; +static const int updateperiod = 300 / bouncerdelay; + +int SendToHost (BYTE message, BYTE ackmess, bool abortable) { sockaddr_in *from; bool waiting = true; PreGamePacket packet; + int bouncer = 0; + + C_InitTicker ("Waiting for host", 8, false); + C_SetTicker (0, true); + + // Let host know we are here + packet.fake = PRE_FAKE; + packet.message = message; + PreSend (&packet, 2, &sendaddress[1]); while (waiting) { @@ -601,25 +627,41 @@ void SendToHost (BYTE message, BYTE ackmess, bool abortable) I_FatalError ("Network game synchronization aborted."); } - // Let host know we are here - packet.fake = PRE_FAKE; - packet.message = message; - PreSend (&packet, 2, &sendaddress[1]); + Sleep (bouncerdelay); - Sleep (300); // Listen for acknowledgement - while ( (from = PreGet (&packet, sizeof(packet), true)) ) + if (bouncer % updateperiod == 0) { - if (packet.fake == PRE_FAKE && packet.message == ackmess) + while ( (from = PreGet (&packet, sizeof(packet), true)) ) { - waiting = false; + if (packet.fake == PRE_FAKE && packet.message == ackmess) + { + waiting = false; - doomcom.consoleplayer = packet.consolenum; - sendplayer[0] = packet.consolenum; - Printf ("Console player number: %d\n", doomcom.consoleplayer); + doomcom.consoleplayer = packet.consolenum; + sendplayer[0] = packet.consolenum; + Printf ("Console player number: %d\n", doomcom.consoleplayer); + } + } + if (waiting) + { + // Let host know we are here + packet.fake = PRE_FAKE; + packet.message = message; + PreSend (&packet, 2, &sendaddress[1]); } } + if (waiting) + { + int tickpos = ++bouncer & 15; + if (tickpos > 8) + { + tickpos = 16 - tickpos; + } + C_SetTicker (tickpos, true); + } } + return bouncer; } void JoinGame (int i) @@ -627,6 +669,7 @@ void JoinGame (int i) sockaddr_in *from; bool waiting; PreGamePacket packet; + int bouncer; if ((i == Args.NumArgs() - 1) || (Args.GetArg(i+1)[0] == '-') || @@ -640,9 +683,10 @@ void JoinGame (int i) sendplayer[1] = 0; // Let host know we are here - SendToHost (PRE_CONNECT, PRE_CONACK, true); + bouncer = SendToHost (PRE_CONNECT, PRE_CONACK, true); // Wait for everyone else to connect + C_InitTicker ("Waiting for players", 8, false); waiting = true; //doomcom.numnodes = 2; atterm (SendAbort); @@ -655,54 +699,68 @@ void JoinGame (int i) I_FatalError ("Network game synchronization aborted."); } - Sleep (300); - while (waiting && (from = PreGet (&packet, sizeof(packet), false)) ) + Sleep (bouncerdelay); + + if (bouncer % updateperiod == 0) { - if (packet.fake != PRE_FAKE) + while (waiting && (from = PreGet (&packet, sizeof(packet), false)) ) { - continue; - } - switch (packet.message) - { - case PRE_ALLHERE: - if (doomcom.numnodes == 0) + if (packet.fake != PRE_FAKE) { - int node; - - packet.numnodes = packet.numnodes; - doomcom.numnodes = packet.numnodes + 2; - for (node = 0; node < packet.numnodes; node++) - { - sendaddress[node+2].sin_addr.s_addr = packet.machines[node].address; - sendaddress[node+2].sin_port = packet.machines[node].port; - sendplayer[node+2] = packet.machines[node].player; - - // [JC] - fixes problem of games not starting due to - // no address family being assigned to nodes stored in - // sendaddress[] from the All Here packet. - sendaddress[node+2].sin_family = AF_INET; - } + continue; } + switch (packet.message) + { + case PRE_ALLHERE: + if (doomcom.numnodes == 0) + { + int node; - Printf ("Received All Here, sending ACK\n"); - packet.fake = PRE_FAKE; - packet.message = PRE_ALLHEREACK; - PreSend (&packet, 2, &sendaddress[1]); - break; - case PRE_GO: - Printf ("Go\n"); - waiting = false; - break; - case PRE_DISCONNECT: - I_FatalError ("Host cancelled the game"); - break; + packet.numnodes = packet.numnodes; + doomcom.numnodes = packet.numnodes + 2; + for (node = 0; node < packet.numnodes; node++) + { + sendaddress[node+2].sin_addr.s_addr = packet.machines[node].address; + sendaddress[node+2].sin_port = packet.machines[node].port; + sendplayer[node+2] = packet.machines[node].player; + + // [JC] - fixes problem of games not starting due to + // no address family being assigned to nodes stored in + // sendaddress[] from the All Here packet. + sendaddress[node+2].sin_family = AF_INET; + } + } + + Printf ("Received All Here, sending ACK\n"); + packet.fake = PRE_FAKE; + packet.message = PRE_ALLHEREACK; + PreSend (&packet, 2, &sendaddress[1]); + break; + case PRE_GO: + Printf ("Go\n"); + waiting = false; + break; + case PRE_DISCONNECT: + I_FatalError ("Host cancelled the game"); + break; + } } } + if (waiting) + { + int tickpos = ++bouncer & 15; + if (tickpos > 8) + { + tickpos = 16 - tickpos; + } + C_SetTicker (tickpos, true); + } } popterm (); Printf ("Total players: %d\n", doomcom.numnodes); + C_InitTicker (NULL, 0); doomcom.id = DOOMCOM_ID; doomcom.numplayers = doomcom.numnodes; diff --git a/src/sdl/i_net.h b/src/i_net.h similarity index 100% rename from src/sdl/i_net.h rename to src/i_net.h diff --git a/src/m_options.cpp b/src/m_options.cpp index 322769acf9..d46b3fc9fc 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -753,7 +753,7 @@ static value_t TextColors[] = { 7.0, "blue" }, { 8.0, "orange" }, { 9.0, "white" }, - { 10.0, "yellow" } + { 10.0, "yellow" }, { 11.0, "default" } }; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 6ec8971edf..9afa41b277 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1434,6 +1434,22 @@ void FBehavior::StartTypedScripts (WORD type, AActor *activator, bool always, in } } +// FBehavior :: StaticStopMyScripts +// +// Stops any scripts started by the specified actor. Used by the net code +// when a player disconnects. Should this be used in general whenever an +// actor is destroyed? + +void FBehavior::StaticStopMyScripts (AActor *actor) +{ + DACSThinker *controller = DACSThinker::ActiveThinker; + + if (controller != NULL) + { + controller->StopScriptsFor (actor); + } +} + //---- The ACS Interpreter ----// void strbin (char *str); @@ -1512,6 +1528,21 @@ void DACSThinker::Tick () } } +void DACSThinker::StopScriptsFor (AActor *actor) +{ + DLevelScript *script = Scripts; + + while (script != NULL) + { + DLevelScript *next = script->next; + if (script->activator == actor) + { + script->SetState (DLevelScript::SCRIPT_PleaseRemove); + } + script = next; + } +} + IMPLEMENT_POINTY_CLASS (DLevelScript) DECLARE_POINTER (activator) END_POINTERS diff --git a/src/p_acs.h b/src/p_acs.h index fcdca7712d..72146d22d1 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -156,6 +156,7 @@ public: static const ScriptPtr *StaticFindScript (int script, FBehavior *&module); static const char *StaticLookupString (DWORD index); static void StaticStartTypedScripts (WORD type, AActor *activator, bool always, int arg1=0, bool runNow=false); + static void StaticStopMyScripts (AActor *actor); private: struct ArrayInfo; @@ -632,6 +633,7 @@ public: static DACSThinker *ActiveThinker; void DumpScriptStatus(); + void StopScriptsFor (AActor *actor); private: DLevelScript *LastScript; diff --git a/src/p_user.cpp b/src/p_user.cpp index 0566b7b311..16d934be30 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -278,7 +278,7 @@ void APlayerPawn::Tick() void APlayerPawn::AddInventory (AInventory *item) { // Adding inventory to a voodoo doll should add it to the real player instead. - if (player != NULL && player->mo != this) + if (player != NULL && player->mo != this && player->mo != NULL) { player->mo->AddInventory (item); return; @@ -1728,13 +1728,14 @@ void P_PredictPlayer (player_t *player) } act->BlockNode = NULL; - + int xviewshift = player->xviewshift; for (int i = gametic; i < maxtic; ++i) { player->cmd = localcmds[i % LOCALCMDTICS]; P_PlayerThink (player); player->mo->Tick (); } + player->xviewshift = xviewshift; } extern msecnode_t *P_AddSecnode (sector_t *s, AActor *thing, msecnode_t *nextnode); diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 9b8ca9c9d7..bccdc9a548 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -857,6 +857,11 @@ void FMODSoundRenderer::UpdateSoundParams3D (long handle, float pos[3], float ve FSOUND_3D_SetAttributes (ChannelMap[handle].channelID, pos, vel); } +void FMODSoundRenderer::ResetEnvironment () +{ + PrevEnvironment = NULL; +} + void FMODSoundRenderer::UpdateListener (AActor *listener) { float angle; @@ -908,6 +913,7 @@ void FMODSoundRenderer::UpdateListener (AActor *listener) else { underwater = (listener->waterlevel == 3 && snd_waterreverb); + assert (zones != NULL); env = zones[listener->Sector->ZoneNumber].Environment; if (env == NULL) { diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 10178012eb..fca3d671c1 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -51,6 +51,7 @@ public: void PrintStatus (); void PrintDriversList (); void GatherStats (char *outstring); + void ResetEnvironment (); private: // Maps sfx channels onto FMOD channels diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index ac1550a5b7..b24329a27e 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -332,6 +332,10 @@ void SoundRenderer::GatherStats (char *outstring) sprintf (outstring, "No stats for this sound renderer."); } +void SoundRenderer::ResetEnvironment () +{ +} + SoundStream::~SoundStream () { } @@ -339,3 +343,4 @@ SoundStream::~SoundStream () SoundTrackerModule::~SoundTrackerModule () { } + diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index eecb31f0cb..300e8ce2d3 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -120,6 +120,7 @@ public: virtual void PrintStatus () = 0; virtual void PrintDriversList () = 0; virtual void GatherStats (char *outstring); + virtual void ResetEnvironment (); bool Sound3D; }; diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp index 6a3803c904..c7e8ddc23b 100644 --- a/src/win32/i_crash.cpp +++ b/src/win32/i_crash.cpp @@ -175,6 +175,13 @@ typedef BOOL (WINAPI *WRITEDUMP) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION); +struct MiniDumpThreadData +{ + HANDLE File; + WRITEDUMP pMiniDumpWriteDump; + MINIDUMP_EXCEPTION_INFORMATION *Exceptor; +}; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -188,11 +195,12 @@ static void AddZipFile (HANDLE ziphandle, TarFile *whichfile, short dosdate, sho static HANDLE CreateTempFile (); static void DumpBytes (HANDLE file, BYTE *address); -static void AddStackInfo (HANDLE file, void *dumpaddress); -static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack); +static void AddStackInfo (HANDLE file, void *dumpaddress, DWORD code); +static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack, DWORD *jump); static void AddToolHelp (HANDLE file); static HANDLE WriteTextReport (); +static DWORD WINAPI WriteMiniDumpInAnotherThread (LPVOID lpParam); static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); static void SetEditControl (HWND control, HWND sizedisplay, int filenum); @@ -379,8 +387,23 @@ static HANDLE WriteMyMiniDump (void) file = CreateTempFile (); if (file != INVALID_HANDLE_VALUE) { - good = pMiniDumpWriteDump (DbgProcess, DbgProcessID, file, - MiniDumpNormal, &exceptor, NULL, NULL); + if (CrashPointers.ExceptionRecord->ExceptionCode != EXCEPTION_STACK_OVERFLOW) + { + good = pMiniDumpWriteDump (DbgProcess, DbgProcessID, file, + MiniDumpNormal, &exceptor, NULL, NULL); + } + else + { + MiniDumpThreadData dumpdata = { file, pMiniDumpWriteDump, &exceptor }; + DWORD id; + HANDLE thread = CreateThread (NULL, 0, WriteMiniDumpInAnotherThread, + &dumpdata, 0, &id); + WaitForSingleObject (thread, INFINITE); + if (GetExitCodeThread (thread, &id)) + { + good = id; + } + } } } else @@ -390,6 +413,23 @@ static HANDLE WriteMyMiniDump (void) return good ? file : INVALID_HANDLE_VALUE; } +//========================================================================== +// +// WriteMiniDumpInAnotherThread +// +// When a stack overflow occurs, there isn't enough room left on the stack +// for MiniDumpWriteDump to do its thing, so we create a new thread with +// a new stack to do the work. +// +//========================================================================== + +static DWORD WINAPI WriteMiniDumpInAnotherThread (LPVOID lpParam) +{ + MiniDumpThreadData *dumpdata = (MiniDumpThreadData *)lpParam; + return dumpdata->pMiniDumpWriteDump (DbgProcess, DbgProcessID, + dumpdata->File, MiniDumpNormal, dumpdata->Exceptor, NULL, NULL); +} + //========================================================================== // // Writef @@ -634,7 +674,8 @@ HANDLE WriteTextReport () if (ctxt->ContextFlags & CONTEXT_CONTROL) { - AddStackInfo (file, (void *)(size_t)CrashPointers.ContextRecord->Esp); + AddStackInfo (file, (void *)(size_t)CrashPointers.ContextRecord->Esp, + CrashPointers.ExceptionRecord->ExceptionCode); } return file; @@ -731,14 +772,24 @@ static void AddToolHelp (HANDLE file) // //========================================================================== -static void AddStackInfo (HANDLE file, void *dumpaddress) +static void AddStackInfo (HANDLE file, void *dumpaddress, DWORD code) { - DWORD *addr = (DWORD *)dumpaddress; + DWORD *addr = (DWORD *)dumpaddress, *jump; DWORD *topOfStack = GetTopOfStack (dumpaddress); BYTE peekb; DWORD peekd; - StackWalk (file, dumpaddress, topOfStack); + jump = topOfStack; + if (code == EXCEPTION_STACK_OVERFLOW) + { + // If the stack overflowed, only dump the first and last 16KB of it. + if (topOfStack - addr > 32768/4) + { + jump = addr + 16384/4; + } + } + + StackWalk (file, dumpaddress, topOfStack, jump); Writef (file, "\r\nStack Contents:\r\n"); DWORD *scan; @@ -747,6 +798,12 @@ static void AddStackInfo (HANDLE file, void *dumpaddress) int i; ptrdiff_t max; + if (scan == jump) + { + scan = topOfStack - 16384/4; + Writef (file, "\r\n . . . Snip . . .\r\n\r\n"); + } + if (topOfStack - scan < 4) { max = topOfStack - scan; @@ -792,7 +849,7 @@ static void AddStackInfo (HANDLE file, void *dumpaddress) // //========================================================================== -static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack) +static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack, DWORD *jump) { DWORD *addr = (DWORD *)dumpaddress; @@ -809,6 +866,12 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack) { DWORD_PTR code; + if (scan == jump) + { + scan = topOfStack - 16384/4; + Writef (file, "\r\n\r\n . . . . Snip . . . .\r\n"); + } + if (SafeReadMemory (scan, &code, sizeof(code)) && code >= codeStart && code < codeEnd) { @@ -1793,9 +1856,9 @@ repeat: while (cb - ((LPBYTE)buff_p - buffer) > 150) { ReadFile (info->File, buf16, 16, &read, NULL); - if (read == 0) + if (read == 0 || info->Pointer >= 65536) { - info->Stage++; + info->Stage = read == 0 ? 2 : 3; goto repeat; } char *linestart = buff_p; @@ -1833,10 +1896,15 @@ repeat: case 2: // Write epilogue buff_p += sprintf (buff_p, "\\cf0 }"); - info->Stage++; + info->Stage = 4; break; - case 3: // We're done + case 3: // Write epilogue for truncated file + buff_p += sprintf (buff_p, "--- Rest of file truncated ---\\cf0 }"); + info->Stage = 4; + break; + + case 4: // We're done return TRUE; } diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index 1cdecc1bc5..f314682ac7 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -357,6 +357,7 @@ CUSTOM_CVAR (Int, in_mouse, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) static BYTE KeyState[256]; static BYTE DIKState[2][NUM_KEYS]; +static int KeysReadCount; static int ActiveDIKState; static void SetSoundPaused (int state); @@ -744,6 +745,10 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (wParam) { SetPriorityClass (GetCurrentProcess (), INGAME_PRIORITY_CLASS); + if (GSnd != NULL) + { + GSnd->ResetEnvironment(); + } } else if (!noidle && !netgame) { @@ -1686,8 +1691,18 @@ static void MouseRead_Win32 () POINT pt; int x, y; + if (KeysReadCount == 0) + { + UngrabMouse_Win32(); + } + else if (KeysReadCount == 1 && HaveFocus && !MakeMouseEvents) + { + GrabMouse_Win32(); + } if (!HaveFocus || !MakeMouseEvents || !GetCursorPos (&pt)) + { return; + } x = pt.x - PrevX; y = PrevY - pt.y; @@ -1829,7 +1844,7 @@ static void KeyRead () toState = DIKState[ActiveDIKState ^ 1]; hr = g_pKey->GetDeviceState (256, toState); - if (hr == DIERR_INPUTLOST) + if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) { hr = g_pKey->Acquire (); if (hr != DI_OK) @@ -1844,6 +1859,7 @@ static void KeyRead () } // Successfully got the buffer + KeysReadCount++; ActiveDIKState ^= 1; // Copy key states not handled here from the old to the new buffer diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 66c9ece9b0..18aeb6d542 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -519,6 +519,14 @@ LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info) return EXCEPTION_CONTINUE_EXECUTION; } +static void infiniterecursion(int foo) +{ + if (foo) + { + infiniterecursion(foo); + } +} + int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int nCmdShow) { g_hInst = hInstance; @@ -539,6 +547,19 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n DisplayCrashLog (); exit (0); } + if (__argc == 2 && strcmp (__argv[1], "TestStackCrash") == 0) + { + __try + { + infiniterecursion(1); + } + __except(CrashPointers = *GetExceptionInformation(), + CreateCrashLog (__argv[1], 14), EXCEPTION_EXECUTE_HANDLER) + { + } + DisplayCrashLog (); + exit (0); + } #endif #ifdef REGEXEPEEK @@ -550,17 +571,12 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n 0, FALSE, DUPLICATE_SAME_ACCESS); MainThreadID = GetCurrentThreadId(); +#ifndef _DEBUG if (MainThread != INVALID_HANDLE_VALUE) { - // SetUnhandledExceptionFilter is not supposed to do anything if a debugger - // is attached to the process, but one time I did see my exception filter - // used instead of breaking into the debugger. (Or maybe I just forgot to - // run it in the debugger. Whatever. It doesn't hurt to check for one.) -#ifdef _DEBUG - if (!IsDebuggerPresent ()) -#endif - SetUnhandledExceptionFilter (CatchAllExceptions); + SetUnhandledExceptionFilter (CatchAllExceptions); } +#endif #if defined(_DEBUG) && defined(_MSC_VER) // Uncomment this line to make the Visual C++ CRT check the heap before diff --git a/src/win32/i_net.cpp b/src/win32/i_net.cpp deleted file mode 100644 index 32dbcb0677..0000000000 --- a/src/win32/i_net.cpp +++ /dev/null @@ -1,837 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id: i_net.c,v 1.2 1997/12/29 19:50:54 pekangas Exp $ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// Low-level networking code. Uses BSD sockets for UDP networking. -// -//----------------------------------------------------------------------------- - - -/* [Petteri] Check if compiling for Win32: */ -#if defined(__WINDOWS__) || defined(__NT__) || defined(_MSC_VER) || defined(_WIN32) -#ifndef __WIN32__ -# define __WIN32__ -#endif -#endif -/* Follow #ifdef __WIN32__ marks */ - -#include -#include -#include - -/* [Petteri] Use Winsock for Win32: */ -#ifdef __WIN32__ -# define WIN32_LEAN_AND_MEAN -# include -# include -#else -# include -# include -# include -# include -# include -# include -# include -#endif - -#include "doomtype.h" -#include "i_system.h" -#include "d_event.h" -#include "d_net.h" -#include "m_argv.h" -#include "m_alloc.h" -#include "m_swap.h" -#include "m_crc32.h" -#include "d_player.h" -#include "templates.h" - -#include "doomstat.h" - -#include "i_net.h" - - - -/* [Petteri] Get more portable: */ -#ifndef __WIN32__ -typedef int SOCKET; -#define SOCKET_ERROR -1 -#define INVALID_SOCKET -1 -#define closesocket close -#define ioctlsocket ioctl -#define Sleep(x) usleep (x * 1000) -#define WSAEWOULDBLOCK EWOULDBLOCK -#define WSAECONNRESET ECONNRESET -#define WSAGetLastError() errno -#endif - -#ifdef __WIN32__ -#define IPPORT_USERRESERVED 5000 -typedef int socklen_t; -#endif - -extern BOOL CheckAbort (void); - - -// -// NETWORKING -// - -static u_short DOOMPORT = (IPPORT_USERRESERVED + 29); -static SOCKET mysocket = INVALID_SOCKET; -static sockaddr_in sendaddress[MAXNETNODES]; -static BYTE sendplayer[MAXNETNODES]; - -void (*netget) (void); -void (*netsend) (void); - -#ifdef __WIN32__ -char *neterror (void); -#else -#define neterror() strerror(errno) -#endif - -enum -{ - PRE_CONNECT, - PRE_DISCONNECT, - PRE_ALLHERE, - PRE_CONACK, - PRE_ALLHEREACK, - PRE_GO -}; - -// Set PreGamePacket.fake to this so that the game rejects any pregame packets -// after it starts. This translates to NCMD_SETUP|NCMD_MULTI. -#define PRE_FAKE 0x30 - -struct PreGamePacket -{ - BYTE fake; - BYTE message; - BYTE numnodes; - BYTE consolenum; - struct - { - u_long address; - u_short port; - BYTE player; - BYTE pad; - } machines[MAXNETNODES]; -}; - -// -// UDPsocket -// -SOCKET UDPsocket (void) -{ - SOCKET s; - - // allocate a socket - s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (s == INVALID_SOCKET) - I_FatalError ("can't create socket: %s", neterror ()); - - return s; -} - -// -// BindToLocalPort -// -void BindToLocalPort (SOCKET s, u_short port) -{ - int v; - sockaddr_in address; - - memset (&address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons(port); - - v = bind (s, (sockaddr *)&address, sizeof(address)); - if (v == SOCKET_ERROR) - I_FatalError ("BindToPort: %s", neterror ()); -} - -int FindNode (sockaddr_in *address) -{ - int i; - - // find remote node number - for (i = 0; isin_addr.s_addr == sendaddress[i].sin_addr.s_addr - && address->sin_port == sendaddress[i].sin_port) - break; - - if (i == doomcom.numnodes) - { - // packet is not from one of the players (new game broadcast?) - i = -1; - } - return i; -} - -// -// PacketSend -// -void PacketSend (void) -{ - int c; - - //printf ("sending %i\n",gametic); - c = sendto (mysocket , (const char*)doomcom.data, doomcom.datalength - ,0,(sockaddr *)&sendaddress[doomcom.remotenode] - ,sizeof(sendaddress[doomcom.remotenode])); - - // if (c == -1) - // I_Error ("SendPacket error: %s",strerror(errno)); -} - - -// -// PacketGet -// -void PacketGet (void) -{ - int c; - socklen_t fromlen; - sockaddr_in fromaddress; - int node; - - fromlen = sizeof(fromaddress); - c = recvfrom (mysocket, (char*)doomcom.data, MAX_MSGLEN, 0 - , (sockaddr *)&fromaddress, &fromlen); - node = FindNode (&fromaddress); - - if (c == SOCKET_ERROR) - { - int err = WSAGetLastError(); - - if (err == WSAECONNRESET && node >= 0) - { // The remote node aborted unexpectedly, so pretend it sent an exit packet - - Printf (PRINT_BOLD, "The connection from %s was dropped\n", - players[sendplayer[node]].userinfo.netname); - - doomcom.data[0] = 0x80; // NCMD_EXIT - c = 1; - } - else if (err != WSAEWOULDBLOCK) - { - I_Error ("GetPacket: %s", neterror ()); - } - else - { - doomcom.remotenode = -1; // no packet - return; - } - } - - doomcom.remotenode = node; - doomcom.datalength = (short)c; -} - -sockaddr_in *PreGet (void *buffer, int bufferlen, bool noabort) -{ - static sockaddr_in fromaddress; - socklen_t fromlen; - int c; - - fromlen = sizeof(fromaddress); - c = recvfrom (mysocket, (char *)buffer, bufferlen, 0, - (sockaddr *)&fromaddress, &fromlen); - - if (c == SOCKET_ERROR) - { - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK || (noabort && err == WSAECONNRESET)) - return NULL; // no packet - I_Error ("PreGet: %s", neterror ()); - } - return &fromaddress; -} - -void PreSend (const void *buffer, int bufferlen, sockaddr_in *to) -{ - sendto (mysocket, (const char *)buffer, bufferlen, 0, (sockaddr *)to, sizeof(*to)); -} - -void BuildAddress (sockaddr_in *address, char *name) -{ - hostent *hostentry; // host information entry - u_short port; - char *portpart; - bool isnamed = false; - int curchar; - char c; - - address->sin_family = AF_INET; - - if ( (portpart = strchr (name, ':')) ) - { - *portpart = 0; - port = atoi (portpart + 1); - if (!port) - { - Printf ("Weird port: %s (using %d)\n", portpart + 1, DOOMPORT); - port = DOOMPORT; - } - } - else - { - port = DOOMPORT; - } - address->sin_port = htons(port); - - for (curchar = 0; (c = name[curchar]) ; curchar++) - { - if ((c < '0' || c > '9') && c != '.') - { - isnamed = true; - break; - } - } - - if (!isnamed) - { - address->sin_addr.s_addr = inet_addr (name); - Printf ("Node number %d address %s\n", doomcom.numnodes, name); - } - else - { - hostentry = gethostbyname (name); - if (!hostentry) - I_FatalError ("gethostbyname: couldn't find %s\n%s", name, neterror()); - address->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; - Printf ("Node number %d hostname %s\n", - doomcom.numnodes, hostentry->h_name); - } - - if (portpart) - *portpart = ':'; -} - -void CloseNetwork (void) -{ - if (mysocket != INVALID_SOCKET) - { - closesocket (mysocket); - mysocket = INVALID_SOCKET; - } -#ifdef __WIN32__ - WSACleanup (); -#endif -} - -void StartNetwork (bool autoPort) -{ - u_long trueval = 1; -#ifdef __WIN32__ - WSADATA wsad; - - if (WSAStartup (0x0101, &wsad)) - { - I_FatalError ("Could not initialize Windows Sockets"); - } -#endif - - atterm (CloseNetwork); - - netsend = PacketSend; - netget = PacketGet; - netgame = true; - multiplayer = true; - - // create communication socket - mysocket = UDPsocket (); - BindToLocalPort (mysocket, autoPort ? 0 : DOOMPORT); - ioctlsocket (mysocket, FIONBIO, &trueval); -} - -void WaitForPlayers (int i) -{ - if (i == Args.NumArgs() - 1) - I_FatalError ("Not enough parameters after -net"); - - StartNetwork (false); - - // parse player number and host list - doomcom.consoleplayer = (short)(Args.GetArg (i+1)[0]-'1'); - Printf ("Console player number: %d\n", doomcom.consoleplayer); - - doomcom.numnodes = 1; // this node for sure - - i++; - while (++i < Args.NumArgs() && Args.GetArg (i)[0] != '-' && Args.GetArg (i)[0] != '+') - { - BuildAddress (&sendaddress[doomcom.numnodes], Args.GetArg (i)); - doomcom.numnodes++; - } - - Printf ("Total players: %d\n", doomcom.numnodes); - - doomcom.id = DOOMCOM_ID; - doomcom.numplayers = doomcom.numnodes; -} - -void SendAbort (void) -{ - BYTE dis[2] = { PRE_FAKE, PRE_DISCONNECT }; - - while (--doomcom.numnodes > 0) - { - PreSend (dis, 2, &sendaddress[doomcom.numnodes]); - PreSend (dis, 2, &sendaddress[doomcom.numnodes]); - PreSend (dis, 2, &sendaddress[doomcom.numnodes]); - PreSend (dis, 2, &sendaddress[doomcom.numnodes]); - } -} - -void HostGame (int i) -{ - PreGamePacket packet; - int numplayers; - bool gotack[MAXNETNODES]; - int ackcount; - sockaddr_in *from; - int node; - - if ((i == Args.NumArgs() - 1) || !(numplayers = atoi (Args.GetArg(i+1)))) - { // No player count specified, assume 2 - numplayers = 2; - } - - if (numplayers == 1) - { // Special case: Only 1 player, so don't bother starting the network - netgame = false; - multiplayer = true; - doomcom.id = DOOMCOM_ID; - doomcom.numplayers = doomcom.numnodes = 1; - doomcom.consoleplayer = 0; - return; - } - - StartNetwork (false); - - // [JC] - this computer is starting the game, therefore it should - // be the Net Arbitrator. - doomcom.consoleplayer = 0; - Printf ("Console player number: %d\n", doomcom.consoleplayer); - - doomcom.numnodes = 1; - Printf ("Waiting for players...\n"); - - atterm (SendAbort); - - // Wait for numplayers-1 different connections - while (doomcom.numnodes < numplayers) - { - while (doomcom.numnodes < numplayers) - { - if (CheckAbort ()) - { - SendAbort (); - I_FatalError ("Network game synchronization aborted."); - } - - while ( (from = PreGet (&packet, sizeof(packet), false)) ) - { - if (packet.fake != PRE_FAKE) - { - continue; - } - switch (packet.message) - { - case PRE_CONNECT: - node = FindNode (from); - if (node == -1) - { - node = doomcom.numnodes++; - sendaddress[node] = *from; - } - Printf ("Got connect from node %d\n", node); - packet.message = PRE_CONACK; - packet.consolenum = node; - PreSend (&packet, 4, from); - break; - - case PRE_DISCONNECT: - node = FindNode (from); - if (node >= 0) - { - Printf ("Got disconnect from node %d\n", node); - doomcom.numnodes--; - while (node < doomcom.numnodes) - { - sendaddress[node] = sendaddress[node+1]; - node++; - } - } - break; - } - } - } - - // It's possible somebody bailed out after all players were found. - // Unfortunately, this isn't guaranteed to catch all of them. - // Oh well. Better than nothing. - while ( (from = PreGet (&packet, sizeof(packet), false)) ) - { - if (packet.fake == PRE_FAKE && packet.message == PRE_DISCONNECT) - { - node = FindNode (from); - if (node >= 0) - { - doomcom.numnodes--; - while (node < doomcom.numnodes) - { - sendaddress[node] = sendaddress[node+1]; - node++; - } - } - break; - } - } - } - - // Now inform everyone of all machines involved in the game - ackcount = 0; - memset (gotack, 0, sizeof(gotack)); - Printf ("Sending all here\n"); - while (ackcount < doomcom.numnodes - 1) - { - packet.fake = PRE_FAKE; - packet.message = PRE_ALLHERE; - packet.numnodes = doomcom.numnodes - 2; - for (node = 1; node < doomcom.numnodes; node++) - { - int machine, spot = 0; - - if (!gotack[node]) - { - for (spot = 0, machine = 1; machine < doomcom.numnodes; machine++) - { - if (node != machine) - { - packet.machines[spot].address = sendaddress[machine].sin_addr.s_addr; - packet.machines[spot].port = sendaddress[machine].sin_port; - packet.machines[spot].player = node; - - spot++; // fixes problem of new address replacing existing address in - // array, it's supposed to increment the index before getting - // and storing in the packet the next address. - } - } - } - PreSend (&packet, 4 + spot*8, &sendaddress[node]); - } - if (CheckAbort ()) - { - SendAbort (); - I_FatalError ("Network game synchronization aborted."); - } - - while ( (from = PreGet (&packet, sizeof(packet), false)) ) - { - if (packet.fake == PRE_FAKE && packet.message == PRE_ALLHEREACK) - { - node = FindNode (from); - if (node >= 0) - { - if (!gotack[node]) - { - gotack[node] = true; - ackcount++; - } - } - PreSend (&packet, 2, from); - } - } - } - - popterm (); - - // Now go - Printf ("Go\n"); - packet.fake = PRE_FAKE; - packet.message = PRE_GO; - for (node = 1; node < doomcom.numnodes; node++) - { - for (int i = 8; i != 0; --i) - { - PreSend (&packet, 2, &sendaddress[node]); - } - } - - Printf ("Total players: %d\n", doomcom.numnodes); - - doomcom.id = DOOMCOM_ID; - doomcom.numplayers = doomcom.numnodes; - - // On the host, each player's number is the same as its node number - for (i = 0; i < doomcom.numnodes; ++i) - { - sendplayer[i] = i; - } -} - -void SendToHost (BYTE message, BYTE ackmess, bool abortable) -{ - sockaddr_in *from; - bool waiting = true; - PreGamePacket packet; - - while (waiting) - { - if (abortable && CheckAbort ()) - { - SendAbort (); - I_FatalError ("Network game synchronization aborted."); - } - - // Let host know we are here - packet.fake = PRE_FAKE; - packet.message = message; - PreSend (&packet, 2, &sendaddress[1]); - - Sleep (300); - // Listen for acknowledgement - while ( (from = PreGet (&packet, sizeof(packet), true)) ) - { - if (packet.fake == PRE_FAKE && packet.message == ackmess) - { - waiting = false; - - doomcom.consoleplayer = packet.consolenum; - sendplayer[0] = packet.consolenum; - Printf ("Console player number: %d\n", doomcom.consoleplayer); - } - } - } -} - -void JoinGame (int i) -{ - sockaddr_in *from; - bool waiting; - PreGamePacket packet; - - if ((i == Args.NumArgs() - 1) || - (Args.GetArg(i+1)[0] == '-') || - (Args.GetArg(i+1)[0] == '+')) - I_FatalError ("You need to specify the host machine's address"); - - StartNetwork (true); - - // Host is always node 1 - BuildAddress (&sendaddress[1], Args.GetArg(i+1)); - sendplayer[1] = 0; - - // Let host know we are here - SendToHost (PRE_CONNECT, PRE_CONACK, true); - - // Wait for everyone else to connect - waiting = true; - //doomcom.numnodes = 2; - atterm (SendAbort); - - while (waiting) - { - if (CheckAbort ()) - { - SendAbort (); - I_FatalError ("Network game synchronization aborted."); - } - - Sleep (300); - while (waiting && (from = PreGet (&packet, sizeof(packet), false)) ) - { - if (packet.fake != PRE_FAKE) - { - continue; - } - switch (packet.message) - { - case PRE_ALLHERE: - if (doomcom.numnodes == 0) - { - int node; - - packet.numnodes = packet.numnodes; - doomcom.numnodes = packet.numnodes + 2; - for (node = 0; node < packet.numnodes; node++) - { - sendaddress[node+2].sin_addr.s_addr = packet.machines[node].address; - sendaddress[node+2].sin_port = packet.machines[node].port; - sendplayer[node+2] = packet.machines[node].player; - - // [JC] - fixes problem of games not starting due to - // no address family being assigned to nodes stored in - // sendaddress[] from the All Here packet. - sendaddress[node+2].sin_family = AF_INET; - } - } - - Printf ("Received All Here, sending ACK\n"); - packet.fake = PRE_FAKE; - packet.message = PRE_ALLHEREACK; - PreSend (&packet, 2, &sendaddress[1]); - break; - case PRE_GO: - Printf ("Go\n"); - waiting = false; - break; - case PRE_DISCONNECT: - I_FatalError ("Host cancelled the game"); - break; - } - } - } - - popterm (); - - Printf ("Total players: %d\n", doomcom.numnodes); - - doomcom.id = DOOMCOM_ID; - doomcom.numplayers = doomcom.numnodes; -} - -// -// I_InitNetwork -// -void I_InitNetwork (void) -{ - int i; - char *v; - - memset (&doomcom, 0, sizeof(doomcom)); - - // set up for network - v = Args.CheckValue ("-dup"); - if (v) - { - doomcom.ticdup = clamp (atoi (v), 1, MAXTICDUP); - } - else - { - doomcom.ticdup = 1; - } - - if (Args.CheckParm ("-extratic")) - doomcom.extratics = 1; - else - doomcom.extratics = 0; - - v = Args.CheckValue ("-port"); - if (v) - { - DOOMPORT = atoi (v); - Printf ("using alternate port %i\n", DOOMPORT); - } - - // parse network game options, - // -net ... - // -or- - // player 1: -host - // player x: -join - if ( (i = Args.CheckParm ("-net")) ) - WaitForPlayers (i); - else if ( (i = Args.CheckParm ("-host")) ) - HostGame (i); - else if ( (i = Args.CheckParm ("-join")) ) - JoinGame (i); - else - { - // single player game - netgame = false; - multiplayer = false; - doomcom.id = DOOMCOM_ID; - doomcom.numplayers = doomcom.numnodes = 1; - doomcom.consoleplayer = 0; - return; - } -} - - -void I_NetCmd (void) -{ - if (doomcom.command == CMD_SEND) - { - netsend (); - } - else if (doomcom.command == CMD_GET) - { - netget (); - } - else - I_Error ("Bad net cmd: %i\n",doomcom.command); -} - -#ifdef __WIN32__ -char *neterror (void) -{ - static char neterr[16]; - int code; - - switch (code = WSAGetLastError ()) { - case WSAEACCES: return "EACCES"; - case WSAEADDRINUSE: return "EADDRINUSE"; - case WSAEADDRNOTAVAIL: return "EADDRNOTAVAIL"; - case WSAEAFNOSUPPORT: return "EAFNOSUPPORT"; - case WSAEALREADY: return "EALREADY"; - case WSAECONNABORTED: return "ECONNABORTED"; - case WSAECONNREFUSED: return "ECONNREFUSED"; - case WSAECONNRESET: return "ECONNRESET"; - case WSAEDESTADDRREQ: return "EDESTADDRREQ"; - case WSAEFAULT: return "EFAULT"; - case WSAEHOSTDOWN: return "EHOSTDOWN"; - case WSAEHOSTUNREACH: return "EHOSTUNREACH"; - case WSAEINPROGRESS: return "EINPROGRESS"; - case WSAEINTR: return "EINTR"; - case WSAEINVAL: return "EINVAL"; - case WSAEISCONN: return "EISCONN"; - case WSAEMFILE: return "EMFILE"; - case WSAEMSGSIZE: return "EMSGSIZE"; - case WSAENETDOWN: return "ENETDOWN"; - case WSAENETRESET: return "ENETRESET"; - case WSAENETUNREACH: return "ENETUNREACH"; - case WSAENOBUFS: return "ENOBUFS"; - case WSAENOPROTOOPT: return "ENOPROTOOPT"; - case WSAENOTCONN: return "ENOTCONN"; - case WSAENOTSOCK: return "ENOTSOCK"; - case WSAEOPNOTSUPP: return "EOPNOTSUPP"; - case WSAEPFNOSUPPORT: return "EPFNOSUPPORT"; - case WSAEPROCLIM: return "EPROCLIM"; - case WSAEPROTONOSUPPORT: return "EPROTONOSUPPORT"; - case WSAEPROTOTYPE: return "EPROTOTYPE"; - case WSAESHUTDOWN: return "ESHUTDOWN"; - case WSAESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT"; - case WSAETIMEDOUT: return "ETIMEDOUT"; - case WSAEWOULDBLOCK: return "EWOULDBLOCK"; - case WSAHOST_NOT_FOUND: return "HOST_NOT_FOUND"; - case WSANOTINITIALISED: return "NOTINITIALISED"; - case WSANO_DATA: return "NO_DATA"; - case WSANO_RECOVERY: return "NO_RECOVERY"; - case WSASYSNOTREADY: return "SYSNOTREADY"; - case WSATRY_AGAIN: return "TRY_AGAIN"; - case WSAVERNOTSUPPORTED: return "VERNOTSUPPORTED"; - case WSAEDISCON: return "EDISCON"; - - default: - sprintf (neterr, "%d", code); - return neterr; - } -} -#endif diff --git a/src/win32/i_net.h b/src/win32/i_net.h deleted file mode 100644 index 5b8496cb05..0000000000 --- a/src/win32/i_net.h +++ /dev/null @@ -1,30 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id: i_net.h,v 1.1.1.1 1997/12/28 12:59:02 pekangas Exp $ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// System specific network interface stuff. -// -//----------------------------------------------------------------------------- - - -#ifndef __I_NET_H__ -#define __I_NET_H__ - -// Called by D_DoomMain. -void I_InitNetwork (void); -void I_NetCmd (void); - -#endif diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 2850a9d750..9c069d0051 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -1599,6 +1599,7 @@ bool DDrawFB::PaintToWindow () PrimarySurf->Blt (&rect, BackSurf, NULL, DDBLT_WAIT, NULL); } } + Buffer = NULL; LOG ("Did paint to window\n"); } return true; diff --git a/zdoom.vcproj b/zdoom.vcproj index c48aa9e0c5..49669e3bb7 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1847,6 +1847,10 @@ /> + + @@ -4526,6 +4530,10 @@ RelativePath=".\src\i_movie.h" > + + @@ -5271,46 +5279,6 @@ /> - - - - - - - - - - - - - - - - @@ -10080,82 +10048,6 @@ /> - - - - - - - - - - - - - - - - - - - - - - - - - - - -