From 0df692bfec1ff90195f98eac3f4be384cf8d4905 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 24 Mar 2018 00:31:08 +0100 Subject: [PATCH 01/17] - Create a Network class and a network global for d_net - Remove old DOS stuff from doomcom_t and clarify the interface by adding a NetPacket class - Remove all calls to NetUpdate from the software renderers --- src/b_bot.cpp | 6 +- src/b_game.cpp | 14 +- src/b_think.cpp | 10 +- src/c_cmds.cpp | 136 ++--- src/c_console.cpp | 2 +- src/c_dispatch.cpp | 2 +- src/ct_chat.cpp | 8 +- src/d_main.cpp | 33 +- src/d_net.cpp | 622 ++++++++------------ src/d_net.h | 208 ++++--- src/d_netinfo.cpp | 26 +- src/d_protocol.cpp | 17 +- src/events.cpp | 14 +- src/g_game.cpp | 53 +- src/g_inventory/a_weapons.cpp | 30 +- src/g_level.cpp | 2 +- src/g_shared/a_decals.cpp | 4 +- src/g_shared/shared_hud.cpp | 10 +- src/g_statusbar/shared_sbar.cpp | 2 +- src/hu_scores.cpp | 4 +- src/i_net.cpp | 327 +++++----- src/i_net.h | 45 +- src/info.cpp | 12 +- src/intermission/intermission.cpp | 2 +- src/m_cheat.cpp | 4 +- src/p_conversation.cpp | 10 +- src/p_interaction.cpp | 19 +- src/p_lnspec.cpp | 2 +- src/p_user.cpp | 18 +- src/polyrenderer/poly_renderer.cpp | 4 - src/posix/cocoa/st_start.mm | 6 +- src/posix/sdl/st_start.cpp | 6 +- src/st_start.h | 4 +- src/st_stuff.cpp | 4 +- src/statistics.cpp | 2 +- src/swrenderer/line/r_renderdrawsegment.cpp | 3 - src/swrenderer/line/r_walldraw.cpp | 3 - src/swrenderer/plane/r_visibleplane.cpp | 2 - src/swrenderer/scene/r_portal.cpp | 6 - src/swrenderer/scene/r_scene.cpp | 11 - src/swrenderer/things/r_playersprite.cpp | 3 - src/swrenderer/things/r_sprite.cpp | 3 - src/v_draw.cpp | 5 - src/win32/st_start.cpp | 6 +- 44 files changed, 768 insertions(+), 942 deletions(-) diff --git a/src/b_bot.cpp b/src/b_bot.cpp index d1848fc6a0..616c923c2e 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -213,7 +213,7 @@ CCMD (removebots) return; } - Net_WriteByte (DEM_KILLBOTS); + network.Net_WriteByte (DEM_KILLBOTS); } CCMD (freeze) @@ -227,8 +227,8 @@ CCMD (freeze) return; } - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_FREEZE); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_FREEZE); } CCMD (listbots) diff --git a/src/b_game.cpp b/src/b_game.cpp index 661d09c6ee..b44a386cc5 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -319,8 +319,8 @@ bool FCajunMaster::SpawnBot (const char *name, int color) thebot->inuse = BOTINUSE_Waiting; - Net_WriteByte (DEM_ADDBOT); - Net_WriteByte (botshift); + network.Net_WriteByte (DEM_ADDBOT); + network.Net_WriteByte (botshift); { //Set color. char concat[512]; @@ -334,12 +334,12 @@ bool FCajunMaster::SpawnBot (const char *name, int color) mysnprintf (concat + strlen(concat), countof(concat) - strlen(concat), "\\team\\%d\n", thebot->lastteam); } - Net_WriteString (concat); + network.Net_WriteString (concat); } - Net_WriteByte(thebot->skill.aiming); - Net_WriteByte(thebot->skill.perfection); - Net_WriteByte(thebot->skill.reaction); - Net_WriteByte(thebot->skill.isp); + network.Net_WriteByte(thebot->skill.aiming); + network.Net_WriteByte(thebot->skill.perfection); + network.Net_WriteByte(thebot->skill.reaction); + network.Net_WriteByte(thebot->skill.isp); return true; } diff --git a/src/b_think.cpp b/src/b_think.cpp index 696af9c15f..a80c32c77d 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -63,7 +63,7 @@ static FRandom pr_botmove ("BotMove"); //so this is what the bot does. void DBot::Think () { - ticcmd_t *cmd = &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS]; + ticcmd_t *cmd = &network.netcmds[player - players][((gametic + 1)/ network.ticdup)%BACKUPTICS]; memset (cmd, 0, sizeof(*cmd)); @@ -83,13 +83,13 @@ void DBot::Think () ThinkForMove (cmd); TurnToAng (); - cmd->ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees * (65536 / 360.f)) / ticdup; + cmd->ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees * (65536 / 360.f)) / network.ticdup; cmd->ucmd.pitch = (short)((oldpitch - actor->Angles.Pitch).Degrees * (65536 / 360.f)); if (cmd->ucmd.pitch == -32768) cmd->ucmd.pitch = -32767; - cmd->ucmd.pitch /= ticdup; - actor->Angles.Yaw = oldyaw + DAngle(cmd->ucmd.yaw * ticdup * (360 / 65536.f)); - actor->Angles.Pitch = oldpitch - DAngle(cmd->ucmd.pitch * ticdup * (360 / 65536.f)); + cmd->ucmd.pitch /= network.ticdup; + actor->Angles.Yaw = oldyaw + DAngle(cmd->ucmd.yaw * network.ticdup * (360 / 65536.f)); + actor->Angles.Pitch = oldpitch - DAngle(cmd->ucmd.pitch * network.ticdup * (360 / 65536.f)); } if (t_active) t_active--; diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index f74eae569b..f77fd044af 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -122,8 +122,8 @@ CCMD (god) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_GOD); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_GOD); } CCMD(god2) @@ -131,8 +131,8 @@ CCMD(god2) if (CheckCheatmode()) return; - Net_WriteByte(DEM_GENERICCHEAT); - Net_WriteByte(CHT_GOD2); + network.Net_WriteByte(DEM_GENERICCHEAT); + network.Net_WriteByte(CHT_GOD2); } CCMD (iddqd) @@ -140,8 +140,8 @@ CCMD (iddqd) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_IDDQD); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_IDDQD); } CCMD (buddha) @@ -149,8 +149,8 @@ CCMD (buddha) if (CheckCheatmode()) return; - Net_WriteByte(DEM_GENERICCHEAT); - Net_WriteByte(CHT_BUDDHA); + network.Net_WriteByte(DEM_GENERICCHEAT); + network.Net_WriteByte(CHT_BUDDHA); } CCMD(buddha2) @@ -158,8 +158,8 @@ CCMD(buddha2) if (CheckCheatmode()) return; - Net_WriteByte(DEM_GENERICCHEAT); - Net_WriteByte(CHT_BUDDHA2); + network.Net_WriteByte(DEM_GENERICCHEAT); + network.Net_WriteByte(CHT_BUDDHA2); } CCMD (notarget) @@ -167,8 +167,8 @@ CCMD (notarget) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_NOTARGET); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_NOTARGET); } CCMD (fly) @@ -176,8 +176,8 @@ CCMD (fly) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_FLY); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_FLY); } /* @@ -192,8 +192,8 @@ CCMD (noclip) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_NOCLIP); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_NOCLIP); } CCMD (noclip2) @@ -201,8 +201,8 @@ CCMD (noclip2) if (CheckCheatmode()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_NOCLIP2); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_NOCLIP2); } CCMD (powerup) @@ -210,8 +210,8 @@ CCMD (powerup) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_POWER); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_POWER); } CCMD (morphme) @@ -221,13 +221,13 @@ CCMD (morphme) if (argv.argc() == 1) { - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_MORPH); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_MORPH); } else { - Net_WriteByte (DEM_MORPHEX); - Net_WriteString (argv[1]); + network.Net_WriteByte (DEM_MORPHEX); + network.Net_WriteString (argv[1]); } } @@ -236,8 +236,8 @@ CCMD (anubis) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_ANUBIS); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_ANUBIS); } // [GRB] @@ -246,8 +246,8 @@ CCMD (resurrect) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_RESSURECT); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_RESSURECT); } EXTERN_CVAR (Bool, chasedemo) @@ -278,8 +278,8 @@ CCMD (chase) if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && deathmatch && CheckCheatmode ())) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_CHASECAM); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_CHASECAM); } } @@ -377,14 +377,14 @@ CCMD (changemap) { if (argv.argc() > 2) { - Net_WriteByte (DEM_CHANGEMAP2); - Net_WriteByte (atoi(argv[2])); + network.Net_WriteByte (DEM_CHANGEMAP2); + network.Net_WriteByte (atoi(argv[2])); } else { - Net_WriteByte (DEM_CHANGEMAP); + network.Net_WriteByte (DEM_CHANGEMAP); } - Net_WriteString (mapname); + network.Net_WriteString (mapname); } } catch(CRecoverableError &error) @@ -404,12 +404,12 @@ CCMD (give) if (CheckCheatmode () || argv.argc() < 2) return; - Net_WriteByte (DEM_GIVECHEAT); - Net_WriteString (argv[1]); + network.Net_WriteByte (DEM_GIVECHEAT); + network.Net_WriteString (argv[1]); if (argv.argc() > 2) - Net_WriteLong(atoi(argv[2])); + network.Net_WriteLong(atoi(argv[2])); else - Net_WriteLong(0); + network.Net_WriteLong(0); } CCMD (take) @@ -417,12 +417,12 @@ CCMD (take) if (CheckCheatmode () || argv.argc() < 2) return; - Net_WriteByte (DEM_TAKECHEAT); - Net_WriteString (argv[1]); + network.Net_WriteByte (DEM_TAKECHEAT); + network.Net_WriteString (argv[1]); if (argv.argc() > 2) - Net_WriteLong(atoi (argv[2])); + network.Net_WriteLong(atoi (argv[2])); else - Net_WriteLong (0); + network.Net_WriteLong (0); } CCMD(setinv) @@ -430,17 +430,17 @@ CCMD(setinv) if (CheckCheatmode() || argv.argc() < 2) return; - Net_WriteByte(DEM_SETINV); - Net_WriteString(argv[1]); + network.Net_WriteByte(DEM_SETINV); + network.Net_WriteString(argv[1]); if (argv.argc() > 2) - Net_WriteLong(atoi(argv[2])); + network.Net_WriteLong(atoi(argv[2])); else - Net_WriteLong(0); + network.Net_WriteLong(0); if (argv.argc() > 3) - Net_WriteByte(!!atoi(argv[3])); + network.Net_WriteByte(!!atoi(argv[3])); else - Net_WriteByte(0); + network.Net_WriteByte(0); } @@ -538,18 +538,18 @@ CCMD (puke) if (script > 0) { - Net_WriteByte (DEM_RUNSCRIPT); - Net_WriteWord (script); + network.Net_WriteByte (DEM_RUNSCRIPT); + network.Net_WriteWord (script); } else { - Net_WriteByte (DEM_RUNSCRIPT2); - Net_WriteWord (-script); + network.Net_WriteByte (DEM_RUNSCRIPT2); + network.Net_WriteWord (-script); } - Net_WriteByte (argn); + network.Net_WriteByte (argn); for (i = 0; i < argn; ++i) { - Net_WriteLong (arg[i]); + network.Net_WriteLong (arg[i]); } } } @@ -582,12 +582,12 @@ CCMD (pukename) arg[i] = atoi(argv[argstart + i]); } } - Net_WriteByte(DEM_RUNNAMEDSCRIPT); - Net_WriteString(argv[1]); - Net_WriteByte(argn | (always << 7)); + network.Net_WriteByte(DEM_RUNNAMEDSCRIPT); + network.Net_WriteString(argv[1]); + network.Net_WriteByte(argn | (always << 7)); for (i = 0; i < argn; ++i) { - Net_WriteLong(arg[i]); + network.Net_WriteLong(arg[i]); } } } @@ -628,12 +628,12 @@ CCMD (special) return; } } - Net_WriteByte(DEM_RUNSPECIAL); - Net_WriteWord(specnum); - Net_WriteByte(argc - 2); + network.Net_WriteByte(DEM_RUNSPECIAL); + network.Net_WriteWord(specnum); + network.Net_WriteByte(argc - 2); for (int i = 2; i < argc; ++i) { - Net_WriteLong(atoi(argv[i])); + network.Net_WriteLong(atoi(argv[i])); } } } @@ -779,10 +779,10 @@ CCMD (warp) } else { - Net_WriteByte (DEM_WARPCHEAT); - Net_WriteWord (atoi (argv[1])); - Net_WriteWord (atoi (argv[2])); - Net_WriteWord (argv.argc() == 3 ? ONFLOORZ/65536 : atoi (argv[3])); + network.Net_WriteByte (DEM_WARPCHEAT); + network.Net_WriteWord (atoi (argv[1])); + network.Net_WriteWord (atoi (argv[2])); + network.Net_WriteWord (argv.argc() == 3 ? ONFLOORZ/65536 : atoi (argv[3])); } } @@ -1083,8 +1083,8 @@ CCMD(thaw) if (CheckCheatmode()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_CLEARFROZENPROPS); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_CLEARFROZENPROPS); } //----------------------------------------------------------------------------- diff --git a/src/c_console.cpp b/src/c_console.cpp index 9cbb5623fe..2707234d9f 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1300,7 +1300,7 @@ void C_FullConsole () { if (demoplayback) G_CheckDemoStatus (); - D_QuitNetGame (); + network.D_QuitNetGame (); advancedemo = false; ConsoleState = c_down; HistPos = NULL; diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index cb1fb47e1d..26de411086 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -623,7 +623,7 @@ void C_DoCommand (const char *cmd, int keynum) button->ReleaseKey (keynum); if (button == &Button_Mlook && lookspring) { - Net_WriteByte (DEM_CENTERVIEW); + network.Net_WriteByte (DEM_CENTERVIEW); } } return; diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index 34a5ee9703..b54cd3b0cd 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -356,16 +356,16 @@ static void ShoveChatStr (const char *str, uint8_t who) who |= 2; } - Net_WriteByte (DEM_SAY); - Net_WriteByte (who); + network.Net_WriteByte (DEM_SAY); + network.Net_WriteByte (who); if (!chat_substitution || !DoSubstitution (substBuff, str)) { - Net_WriteString (str); + network.Net_WriteString (str); } else { - Net_WriteString (substBuff); + network.Net_WriteString (substBuff); } } diff --git a/src/d_main.cpp b/src/d_main.cpp index 007af39d51..3efdf79662 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -143,7 +143,6 @@ const FIWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const c // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- -void D_CheckNetGame (); void D_ProcessEvents (); void G_BuildTiccmd (ticcmd_t* cmd); void D_DoAdvanceDemo (); @@ -399,14 +398,14 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO) if (self & DF_NO_FREELOOK) { - Net_WriteByte (DEM_CENTERVIEW); + network.Net_WriteByte (DEM_CENTERVIEW); } // If nofov is set, force everybody to the arbitrator's FOV. if ((self & DF_NO_FOV) && consoleplayer == Net_Arbitrator) { float fov; - Net_WriteByte (DEM_FOV); + network.Net_WriteByte (DEM_FOV); // If the game is started with DF_NO_FOV set, the arbitrator's // DesiredFOV will not be set when this callback is run, so @@ -416,7 +415,7 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO) { fov = 90; } - Net_WriteFloat (fov); + network.Net_WriteFloat (fov); } } @@ -937,7 +936,7 @@ void D_Display () if (!wipe || NoWipe < 0) { - NetUpdate (); // send out any new accumulation + network.NetUpdate (); // send out any new accumulation // normal update // draw ZScript UI stuff C_DrawConsole (hw2d); // draw console @@ -956,7 +955,7 @@ void D_Display () screen->WipeEndScreen (); wipestart = I_msTime(); - NetUpdate(); // send out any new accumulation + network.NetUpdate(); // send out any new accumulation do { @@ -971,7 +970,7 @@ void D_Display () C_DrawConsole (hw2d); // console and M_Drawer (); // menu are drawn even on top of wipes screen->Update (); // page flip or blit buffer - NetUpdate (); // [RH] not sure this is needed anymore + network.NetUpdate (); // [RH] not sure this is needed anymore } while (!done); screen->WipeCleanup(); I_FreezeTime(false); @@ -994,10 +993,10 @@ void D_ErrorCleanup () savegamerestore = false; screen->Unlock (); bglobal.RemoveAllBots (true); - D_QuitNetGame (); + network.D_QuitNetGame (); if (demorecording || demoplayback) G_CheckDemoStatus (); - Net_ClearBuffers (); + network.Net_ClearBuffers (); G_NewInit (); M_ClearMenus (); singletics = false; @@ -1048,7 +1047,7 @@ void D_DoomLoop () { I_StartTic (); D_ProcessEvents (); - G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); + G_BuildTiccmd (&network.netcmds[consoleplayer][network.maketic%BACKUPTICS]); if (advancedemo) D_DoAdvanceDemo (); C_Ticker (); @@ -1057,13 +1056,13 @@ void D_DoomLoop () // [RH] Use the consoleplayer's camera to update sounds S_UpdateSounds (players[consoleplayer].camera); // move positional sounds gametic++; - maketic++; + network.maketic++; GC::CheckGC (); - Net_NewMakeTic (); + network.Net_NewMakeTic (); } else { - TryRunTics (); // will run at least one tic + network.TryRunTics (); // will run at least one tic } // Update display, next frame, with current state. I_StartTic (); @@ -2635,7 +2634,7 @@ void D_DoomMain (void) { if (!batchrun) Printf ("D_CheckNetGame: Checking network game status.\n"); StartScreen->LoadingStatus ("Checking network game status.", 0x3f); - D_CheckNetGame (); + network.D_CheckNetGame (); } // [SP] Force vanilla transparency auto-detection to re-detect our game lumps now @@ -2650,7 +2649,7 @@ void D_DoomMain (void) // [RH] Run any saved commands from the command line or autoexec.cfg now. gamestate = GS_FULLCONSOLE; - Net_NewMakeTic (); + network.Net_NewMakeTic (); DThinker::RunThinkers (); gamestate = GS_STARTUP; @@ -2733,7 +2732,7 @@ void D_DoomMain (void) G_BeginRecording(NULL); } - atterm(D_QuitNetGame); // killough + atterm([] { network.D_QuitNetGame(); }); // killough } } } @@ -2903,7 +2902,7 @@ void FStartupScreen::NetInit(char const *,int) {} void FStartupScreen::NetProgress(int) {} void FStartupScreen::NetMessage(char const *,...) {} void FStartupScreen::NetDone(void) {} -bool FStartupScreen::NetLoop(bool (*)(void *),void *) { return false; } +bool FStartupScreen::NetLoop(std::function callback) { return false; } DEFINE_FIELD_X(InputEventData, event_t, type) DEFINE_FIELD_X(InputEventData, event_t, subtype) diff --git a/src/d_net.cpp b/src/d_net.cpp index 7681626d0e..f5df285582 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -74,6 +74,8 @@ EXTERN_CVAR (Int, disableautosave) EXTERN_CVAR (Int, autosavecount) +Network network; + //#define SIMULATEERRORS (RAND_MAX/3) #define SIMULATEERRORS 0 @@ -81,16 +83,6 @@ extern uint8_t *demo_p; // [RH] Special "ticcmds" get recorded in demos extern FString savedescription; extern FString savegamefile; -extern short consistancy[MAXPLAYERS][BACKUPTICS]; - -doomcom_t doomcom; -#define netbuffer (doomcom.data) - -enum { NET_PeerToPeer, NET_PacketServer }; -uint8_t NetMode = NET_PeerToPeer; - - - // // NETWORKING // @@ -103,49 +95,12 @@ uint8_t NetMode = NET_PeerToPeer; #define RESENDCOUNT 10 #define PL_DRONE 0x80 // bit flag in doomdata->player -ticcmd_t localcmds[LOCALCMDTICS]; - -FDynamicBuffer NetSpecs[MAXPLAYERS][BACKUPTICS]; -ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; -int nettics[MAXNETNODES]; -bool nodeingame[MAXNETNODES]; // set false as nodes leave game -bool nodejustleft[MAXNETNODES]; // set when a node just left -bool remoteresend[MAXNETNODES]; // set when local needs tics -int resendto[MAXNETNODES]; // set when remote needs tics -int resendcount[MAXNETNODES]; - -uint64_t lastrecvtime[MAXPLAYERS]; // [RH] Used for pings -uint64_t currrecvtime[MAXPLAYERS]; -uint64_t lastglobalrecvtime; // Identify the last time a packet was received. -bool hadlate; -int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times. -int lastaverage; - -int nodeforplayer[MAXPLAYERS]; -int playerfornode[MAXNETNODES]; - -int maketic; -int skiptics; -int ticdup; - void D_ProcessEvents (void); void G_BuildTiccmd (ticcmd_t *cmd); void D_DoAdvanceDemo (void); -static void SendSetup (uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[MAXNETNODES], int len); static void RunScript(uint8_t **stream, APlayerPawn *pawn, int snum, int argn, int always); -int reboundpacket; -uint8_t reboundstore[MAX_MSGLEN]; - -int frameon; -int frameskip[4]; -int oldnettics; -int mastertics; - -static int entertic; -static int oldentertics; - extern bool advancedemo; CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -180,7 +135,7 @@ CVAR(Int, net_fakelatency, 0, 0); struct PacketStore { int timer; - doomcom_t message; + NetPacket message; }; static TArray InBuffer; @@ -188,17 +143,7 @@ static TArray OutBuffer; #endif // [RH] Special "ticcmds" get stored in here -static struct TicSpecial -{ - uint8_t *streams[BACKUPTICS]; - size_t used[BACKUPTICS]; - uint8_t *streamptr; - size_t streamoffs; - size_t specialsize; - int lastmaketic; - bool okay; - - TicSpecial () +TicSpecial::TicSpecial () { int i; @@ -216,116 +161,112 @@ static struct TicSpecial okay = true; } - ~TicSpecial () - { - int i; - - for (i = 0; i < BACKUPTICS; i++) - { - if (streams[i]) - { - M_Free (streams[i]); - streams[i] = NULL; - used[i] = 0; - } - } - okay = false; - } - - // Make more room for special commands. - void GetMoreSpace (size_t needed) - { - int i; - - specialsize = MAX(specialsize * 2, needed + 30); - - DPrintf (DMSG_NOTIFY, "Expanding special size to %zu\n", specialsize); - - for (i = 0; i < BACKUPTICS; i++) - streams[i] = (uint8_t *)M_Realloc (streams[i], specialsize); - - streamptr = streams[(maketic/ticdup)%BACKUPTICS] + streamoffs; - } - - void CheckSpace (size_t needed) - { - if (streamoffs + needed >= specialsize) - GetMoreSpace (streamoffs + needed); - - streamoffs += needed; - } - - void NewMakeTic () - { - int mt = maketic / ticdup; - if (lastmaketic != -1) - { - if (lastmaketic == mt) - return; - used[lastmaketic%BACKUPTICS] = streamoffs; - } - - lastmaketic = mt; - streamptr = streams[mt%BACKUPTICS]; - streamoffs = 0; - } - - TicSpecial &operator << (uint8_t it) - { - if (streamptr) - { - CheckSpace (1); - WriteByte (it, &streamptr); - } - return *this; - } - - TicSpecial &operator << (short it) - { - if (streamptr) - { - CheckSpace (2); - WriteWord (it, &streamptr); - } - return *this; - } - - TicSpecial &operator << (int it) - { - if (streamptr) - { - CheckSpace (4); - WriteLong (it, &streamptr); - } - return *this; - } - - TicSpecial &operator << (float it) - { - if (streamptr) - { - CheckSpace (4); - WriteFloat (it, &streamptr); - } - return *this; - } - - TicSpecial &operator << (const char *it) - { - if (streamptr) - { - CheckSpace (strlen (it) + 1); - WriteString (it, &streamptr); - } - return *this; - } - -} specials; - -void Net_ClearBuffers () +TicSpecial::~TicSpecial () { - int i, j; + int i; + for (i = 0; i < BACKUPTICS; i++) + { + if (streams[i]) + { + M_Free (streams[i]); + streams[i] = NULL; + used[i] = 0; + } + } + okay = false; +} + +// Make more room for special commands. +void TicSpecial::GetMoreSpace (size_t needed) +{ + int i; + + specialsize = MAX(specialsize * 2, needed + 30); + + DPrintf (DMSG_NOTIFY, "Expanding special size to %zu\n", specialsize); + + for (i = 0; i < BACKUPTICS; i++) + streams[i] = (uint8_t *)M_Realloc (streams[i], specialsize); + + streamptr = streams[(network.maketic/network.ticdup)%BACKUPTICS] + streamoffs; +} + +void TicSpecial::CheckSpace (size_t needed) +{ + if (streamoffs + needed >= specialsize) + GetMoreSpace (streamoffs + needed); + + streamoffs += needed; +} + +void TicSpecial::NewMakeTic () +{ + int mt = network.maketic / network.ticdup; + if (lastmaketic != -1) + { + if (lastmaketic == mt) + return; + used[lastmaketic%BACKUPTICS] = streamoffs; + } + + lastmaketic = mt; + streamptr = streams[mt%BACKUPTICS]; + streamoffs = 0; +} + +TicSpecial &TicSpecial::operator << (uint8_t it) +{ + if (streamptr) + { + CheckSpace (1); + WriteByte (it, &streamptr); + } + return *this; +} + +TicSpecial &TicSpecial::operator << (short it) +{ + if (streamptr) + { + CheckSpace (2); + WriteWord (it, &streamptr); + } + return *this; +} + +TicSpecial &TicSpecial::operator << (int it) +{ + if (streamptr) + { + CheckSpace (4); + WriteLong (it, &streamptr); + } + return *this; +} + +TicSpecial &TicSpecial::operator << (float it) +{ + if (streamptr) + { + CheckSpace (4); + WriteFloat (it, &streamptr); + } + return *this; +} + +TicSpecial &TicSpecial::operator << (const char *it) +{ + if (streamptr) + { + CheckSpace (strlen (it) + 1); + WriteString (it, &streamptr); + } + return *this; +} + +void Network::Net_ClearBuffers() +{ memset (localcmds, 0, sizeof(localcmds)); memset (netcmds, 0, sizeof(netcmds)); memset (nettics, 0, sizeof(nettics)); @@ -340,9 +281,9 @@ void Net_ClearBuffers () memset (consistancy, 0, sizeof(consistancy)); nodeingame[0] = true; - for (i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAXPLAYERS; i++) { - for (j = 0; j < BACKUPTICS; j++) + for (int j = 0; j < BACKUPTICS; j++) { NetSpecs[i][j].SetData (NULL, 0); } @@ -355,15 +296,11 @@ void Net_ClearBuffers () lastglobalrecvtime = 0; } -// -// [RH] Rewritten to properly calculate the packet size -// with our variable length commands. -// -int NetbufferSize () +int Network::NetbufferSize() { if (netbuffer[0] & (NCMD_EXIT | NCMD_SETUP)) { - return doomcom.datalength; + return netbuffer.datalength; } int k = 2, count, numtics; @@ -371,7 +308,7 @@ int NetbufferSize () if (netbuffer[0] & NCMD_RETRANSMIT) k++; - if (NetMode == NET_PacketServer && doomcom.remotenode == nodeforplayer[Net_Arbitrator]) + if (NetMode == NET_PacketServer && netbuffer.remotenode == nodeforplayer[Net_Arbitrator]) k++; numtics = netbuffer[0] & NCMD_XTICS; @@ -399,7 +336,7 @@ int NetbufferSize () } // Need at least 3 bytes per tic per player - if (doomcom.datalength < k + 3 * count * numtics) + if (netbuffer.datalength < k + 3 * count * numtics) { return k + 3 * count * numtics; } @@ -412,13 +349,10 @@ int NetbufferSize () SkipTicCmd (&skipper, numtics); } } - return int(skipper - netbuffer); + return int(skipper - &netbuffer[0]); } -// -// -// -int ExpandTics (int low) +int Network::ExpandTics(int low) { int delta; int mt = maketic / ticdup; @@ -436,12 +370,7 @@ int ExpandTics (int low) return 0; } - - -// -// HSendPacket -// -void HSendPacket (int node, int len) +void Network::HSendPacket (int node, int len) { if (debugfile && node != 0) { @@ -451,13 +380,13 @@ void HSendPacket (int node, int len) { fprintf (debugfile,"%i/%i send %i = SETUP [%3i]", gametic, maketic, node, len); for (i = 0; i < len; i++) - fprintf (debugfile," %2x", ((uint8_t *)netbuffer)[i]); + fprintf (debugfile," %2x", ((uint8_t *)netbuffer.data)[i]); } else if (netbuffer[0] & NCMD_EXIT) { fprintf (debugfile,"%i/%i send %i = EXIT [%3i]", gametic, maketic, node, len); for (i = 0; i < len; i++) - fprintf (debugfile," %2x", ((uint8_t *)netbuffer)[i]); + fprintf (debugfile," %2x", ((uint8_t *)netbuffer.data)[i]); } else { @@ -485,10 +414,10 @@ void HSendPacket (int node, int len) numtics, realretrans, len); for (i = 0; i < len; i++) - fprintf (debugfile, "%c%2x", i==k?'|':' ', ((uint8_t *)netbuffer)[i]); + fprintf (debugfile, "%c%2x", i==k?'|':' ', ((uint8_t *)netbuffer.data)[i]); } fprintf (debugfile, " [[ "); - for (i = 0; i < doomcom.numnodes; ++i) + for (i = 0; i < doomcom->numnodes; ++i) { if (nodeingame[i]) { @@ -504,7 +433,7 @@ void HSendPacket (int node, int len) if (node == 0) { - memcpy (reboundstore, netbuffer, len); + memcpy (reboundstore, netbuffer.data, len); reboundpacket = len; return; } @@ -524,46 +453,42 @@ void HSendPacket (int node, int len) } #endif - doomcom.command = CMD_SEND; - doomcom.remotenode = node; - doomcom.datalength = len; + netbuffer.remotenode = node; + netbuffer.datalength = len; #ifdef _DEBUG if (net_fakelatency / 2 > 0) { PacketStore store; - store.message = doomcom; + store.message = netbuffer; store.timer = I_GetTime() + ((net_fakelatency / 2) / (1000 / TICRATE)); OutBuffer.Push(store); } else - I_NetCmd(); + doomcom->PacketSend(netbuffer); for (unsigned int i = 0; i < OutBuffer.Size(); i++) { if (OutBuffer[i].timer <= I_GetTime()) { - doomcom = OutBuffer[i].message; - I_NetCmd(); + netbuffer = OutBuffer[i].message; + doomcom->PacketSend(netbuffer); OutBuffer.Delete(i); i = -1; } } #else - I_NetCmd(); + doomcom->PacketSend(netbuffer); #endif } -// -// HGetPacket // Returns false if no packet is waiting -// -bool HGetPacket (void) +bool Network::HGetPacket() { if (reboundpacket) { - memcpy (netbuffer, reboundstore, reboundpacket); - doomcom.remotenode = 0; + memcpy (netbuffer.data, reboundstore, reboundpacket); + netbuffer.remotenode = 0; reboundpacket = 0; return true; } @@ -574,27 +499,26 @@ bool HGetPacket (void) if (demoplayback) return false; - doomcom.command = CMD_GET; - I_NetCmd (); + doomcom->PacketGet(netbuffer); #ifdef _DEBUG - if (net_fakelatency / 2 > 0 && doomcom.remotenode != -1) + if (net_fakelatency / 2 > 0 && netbuffer.remotenode != -1) { PacketStore store; - store.message = doomcom; + store.message = netbuffer; store.timer = I_GetTime() + ((net_fakelatency / 2) / (1000 / TICRATE)); InBuffer.Push(store); - doomcom.remotenode = -1; + netbuffer.remotenode = -1; } - if (doomcom.remotenode == -1) + if (netbuffer.remotenode == -1) { bool gotmessage = false; for (unsigned int i = 0; i < InBuffer.Size(); i++) { if (InBuffer[i].timer <= I_GetTime()) { - doomcom = InBuffer[i].message; + netbuffer = InBuffer[i].message; InBuffer.Delete(i); gotmessage = true; break; @@ -604,7 +528,7 @@ bool HGetPacket (void) return false; } #else - if (doomcom.remotenode == -1) + if (netbuffer.remotenode == -1) { return false; } @@ -616,23 +540,23 @@ bool HGetPacket (void) if (netbuffer[0] & NCMD_SETUP) { - fprintf (debugfile,"%i/%i get %i = SETUP [%3i]", gametic, maketic, doomcom.remotenode, doomcom.datalength); - for (i = 0; i < doomcom.datalength; i++) - fprintf (debugfile, " %2x", ((uint8_t *)netbuffer)[i]); + fprintf (debugfile,"%i/%i get %i = SETUP [%3i]", gametic, maketic, netbuffer.remotenode, netbuffer.datalength); + for (i = 0; i < netbuffer.datalength; i++) + fprintf (debugfile, " %2x", ((uint8_t *)netbuffer.data)[i]); fprintf (debugfile, "\n"); } else if (netbuffer[0] & NCMD_EXIT) { - fprintf (debugfile,"%i/%i get %i = EXIT [%3i]", gametic, maketic, doomcom.remotenode, doomcom.datalength); - for (i = 0; i < doomcom.datalength; i++) - fprintf (debugfile, " %2x", ((uint8_t *)netbuffer)[i]); + fprintf (debugfile,"%i/%i get %i = EXIT [%3i]", gametic, maketic, netbuffer.remotenode, netbuffer.datalength); + for (i = 0; i < netbuffer.datalength; i++) + fprintf (debugfile, " %2x", ((uint8_t *)netbuffer.data)[i]); fprintf (debugfile, "\n"); } - else { + else + { k = 2; - if (NetMode == NET_PacketServer && - doomcom.remotenode == nodeforplayer[Net_Arbitrator]) + if (NetMode == NET_PacketServer && netbuffer.remotenode == nodeforplayer[Net_Arbitrator]) { k++; } @@ -648,48 +572,46 @@ bool HGetPacket (void) fprintf (debugfile,"%i/%i get %i = (%i + %i, R %i) [%3i]", gametic, maketic, - doomcom.remotenode, + netbuffer.remotenode, ExpandTics(netbuffer[1]), - numtics, realretrans, doomcom.datalength); + numtics, realretrans, netbuffer.datalength); - for (i = 0; i < doomcom.datalength; i++) - fprintf (debugfile, "%c%2x", i==k?'|':' ', ((uint8_t *)netbuffer)[i]); + for (i = 0; i < netbuffer.datalength; i++) + fprintf (debugfile, "%c%2x", i==k?'|':' ', ((uint8_t *)netbuffer.data)[i]); if (numtics) fprintf (debugfile, " <<%4x>>\n", - consistancy[playerfornode[doomcom.remotenode]][nettics[doomcom.remotenode]%BACKUPTICS] & 0xFFFF); + consistancy[playerfornode[netbuffer.remotenode]][nettics[netbuffer.remotenode]%BACKUPTICS] & 0xFFFF); else fprintf (debugfile, "\n"); } } - if (doomcom.datalength != NetbufferSize ()) + if (netbuffer.datalength != NetbufferSize ()) { - Printf("Bad packet length %i (calculated %i)\n", - doomcom.datalength, NetbufferSize()); + Printf("Bad packet length %i (calculated %i)\n", netbuffer.datalength, NetbufferSize()); if (debugfile) - fprintf (debugfile,"---bad packet length %i (calculated %i)\n", - doomcom.datalength, NetbufferSize()); + fprintf (debugfile,"---bad packet length %i (calculated %i)\n", netbuffer.datalength, NetbufferSize()); return false; } return true; } -void PlayerIsGone (int netnode, int netconsole) +void Network::PlayerIsGone(int netnode, int netconsole) { int i; if (nodeingame[netnode]) { - for (i = netnode + 1; i < doomcom.numnodes; ++i) + for (i = netnode + 1; i < doomcom->numnodes; ++i) { if (nodeingame[i]) break; } - if (i == doomcom.numnodes) + if (i == doomcom->numnodes) { - doomcom.numnodes = netnode; + doomcom->numnodes = netnode; } if (playeringame[netconsole]) @@ -701,9 +623,9 @@ void PlayerIsGone (int netnode, int netconsole) } else if (nodejustleft[netnode]) // Packet Server { - if (netnode + 1 == doomcom.numnodes) + if (netnode + 1 == doomcom->numnodes) { - doomcom.numnodes = netnode; + doomcom->numnodes = netnode; } if (playeringame[netconsole]) { @@ -749,11 +671,7 @@ void PlayerIsGone (int netnode, int netconsole) } } -// -// GetPackets -// - -void GetPackets (void) +void Network::GetPackets() { int netconsole; int netnode; @@ -773,12 +691,12 @@ void GetPackets (void) { // This player apparantly doesn't realise the game has started netbuffer[0] = NCMD_SETUP+3; - HSendPacket (doomcom.remotenode, 1); + HSendPacket (netbuffer.remotenode, 1); } continue; // extra setup packet } - netnode = doomcom.remotenode; + netnode = netbuffer.remotenode; netconsole = playerfornode[netnode] & ~PL_DRONE; // [RH] Get "ping" times - totally useless, since it's bound to the frequency @@ -933,14 +851,8 @@ void GetPackets (void) } } -// -// NetUpdate -// Builds ticcmds for console player, -// sends out a packet -// -int gametime; - -void NetUpdate (void) +// Builds ticcmds for console player, sends out a packet +void Network::NetUpdate() { int lowtic; int nowtime; @@ -1101,7 +1013,7 @@ void NetUpdate (void) // and it also added the player being sent the packet to the count. count -= 2; - for (j = 0; j < doomcom.numnodes; ++j) + for (j = 0; j < doomcom->numnodes; ++j) { if (nodejustleft[j]) { @@ -1123,7 +1035,7 @@ void NetUpdate (void) } } - for (i = 0; i < doomcom.numnodes; i++) + for (i = 0; i < doomcom->numnodes; i++) { uint8_t playerbytes[MAXPLAYERS]; @@ -1156,7 +1068,7 @@ void NetUpdate (void) consoleplayer == Net_Arbitrator && i != 0) { - for (j = 1; j < doomcom.numnodes; ++j) + for (j = 1; j < doomcom->numnodes; ++j) { if (nodeingame[j] && nettics[j] < lowtic && j != i) { @@ -1204,7 +1116,7 @@ void NetUpdate (void) { netbuffer[0] |= NCMD_QUITTERS; netbuffer[k++] = quitcount; - for (int l = 0; l < doomcom.numnodes; ++l) + for (int l = 0; l < doomcom->numnodes; ++l) { if (nodejustleft[l]) { @@ -1285,7 +1197,7 @@ void NetUpdate (void) } } } - HSendPacket (i, int(cmddata - netbuffer)); + HSendPacket (i, int(cmddata - netbuffer.data)); } else { @@ -1408,15 +1320,8 @@ void NetUpdate (void) // Negotiation is done when all the guests have reported to the host that // they know about the other nodes. -struct ArbitrateData +bool Network::DoArbitrate (ArbitrateData *data) { - uint32_t playersdetected[MAXNETNODES]; - uint8_t gotsetup[MAXNETNODES]; -}; - -bool DoArbitrate (void *userdata) -{ - ArbitrateData *data = (ArbitrateData *)userdata; char *s; uint8_t *stream; int version; @@ -1430,14 +1335,14 @@ bool DoArbitrate (void *userdata) I_FatalError ("The game was aborted."); } - if (doomcom.remotenode == 0) + if (netbuffer.remotenode == 0) { continue; } if (netbuffer[0] == NCMD_SETUP || netbuffer[0] == NCMD_SETUP+1) // got user info { - node = (netbuffer[0] == NCMD_SETUP) ? doomcom.remotenode : nodeforplayer[netbuffer[1]]; + node = (netbuffer[0] == NCMD_SETUP) ? netbuffer.remotenode : nodeforplayer[netbuffer[1]]; data->playersdetected[node] = (netbuffer[5] << 24) | (netbuffer[6] << 16) | (netbuffer[7] << 8) | netbuffer[8]; @@ -1475,7 +1380,7 @@ bool DoArbitrate (void *userdata) { data->gotsetup[0] = 0x80; - ticdup = doomcom.ticdup = netbuffer[1]; + ticdup = netbuffer[1]; NetMode = netbuffer[2]; stream = &netbuffer[3]; @@ -1494,11 +1399,11 @@ bool DoArbitrate (void *userdata) // If everybody already knows everything, it's time to go if (consoleplayer == Net_Arbitrator) { - for (i = 0; i < doomcom.numnodes; ++i) - if (data->playersdetected[i] != uint32_t(1 << doomcom.numnodes) - 1 || !data->gotsetup[i]) + for (i = 0; i < doomcom->numnodes; ++i) + if (data->playersdetected[i] != uint32_t(1 << doomcom->numnodes) - 1 || !data->gotsetup[i]) break; - if (i == doomcom.numnodes) + if (i == doomcom->numnodes) return true; } @@ -1517,14 +1422,14 @@ bool DoArbitrate (void *userdata) netbuffer[9] = data->gotsetup[0]; stream = &netbuffer[10]; D_WriteUserInfoStrings (consoleplayer, &stream, true); - SendSetup (data->playersdetected, data->gotsetup, int(stream - netbuffer)); + SendSetup (data->playersdetected, data->gotsetup, int(stream - netbuffer.data)); } else { // Send user info for all nodes netbuffer[0] = NCMD_SETUP+1; - for (i = 1; i < doomcom.numnodes; ++i) + for (i = 1; i < doomcom->numnodes; ++i) { - for (j = 0; j < doomcom.numnodes; ++j) + for (j = 0; j < doomcom->numnodes; ++j) { // Send info about player j to player i? if ((data->playersdetected[0] & (1<playersdetected[i] & (1<playersdetected, data->gotsetup, int(stream - netbuffer)); + SendSetup (data->playersdetected, data->gotsetup, int(stream - netbuffer.data)); } return false; } -void D_ArbitrateNetStart (void) +void Network::D_ArbitrateNetStart() { ArbitrateData data; int i; // Return right away if we're just playing with ourselves. - if (doomcom.numnodes == 1) + if (doomcom->numnodes == 1) return; autostart = true; @@ -1584,7 +1489,7 @@ void D_ArbitrateNetStart (void) nodeforplayer[consoleplayer] = 0; if (consoleplayer == Net_Arbitrator) { - for (i = 1; i < doomcom.numnodes; ++i) + for (i = 1; i < doomcom->numnodes; ++i) { playerfornode[i] = i; nodeforplayer[i] = i; @@ -1594,7 +1499,7 @@ void D_ArbitrateNetStart (void) { playerfornode[1] = 0; nodeforplayer[0] = 1; - for (i = 1; i < doomcom.numnodes; ++i) + for (i = 1; i < doomcom->numnodes; ++i) { if (i < consoleplayer) { @@ -1615,7 +1520,7 @@ void D_ArbitrateNetStart (void) } StartScreen->NetInit ("Exchanging game information", 1); - if (!StartScreen->NetLoop (DoArbitrate, &data)) + if (!StartScreen->NetLoop([&] { return DoArbitrate(&data); })) { exit (0); } @@ -1628,7 +1533,7 @@ void D_ArbitrateNetStart (void) if (debugfile) { - for (i = 0; i < doomcom.numnodes; ++i) + for (i = 0; i < doomcom->numnodes; ++i) { fprintf (debugfile, "player %d is on node %d\n", i, nodeforplayer[i]); } @@ -1636,7 +1541,7 @@ void D_ArbitrateNetStart (void) StartScreen->NetDone(); } -static void SendSetup (uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[MAXNETNODES], int len) +void Network::SendSetup (uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[MAXNETNODES], int len) { if (consoleplayer != Net_Arbitrator) { @@ -1651,7 +1556,7 @@ static void SendSetup (uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[M } else { - for (int i = 1; i < doomcom.numnodes; ++i) + for (int i = 1; i < doomcom->numnodes; ++i) { if (!gotsetup[i] || netbuffer[0] == NCMD_SETUP+3) { @@ -1661,12 +1566,8 @@ static void SendSetup (uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[M } } -// -// D_CheckNetGame // Works out player numbers among the net participants -// - -void D_CheckNetGame (void) +void Network::D_CheckNetGame() { const char *v; int i; @@ -1688,18 +1589,21 @@ void D_CheckNetGame (void) } // I_InitNetwork sets doomcom and netgame - if (I_InitNetwork ()) + doomcom = I_InitNetwork(); + + v = Args->CheckValue("-dup"); + if (v) { - // For now, stop auto selecting PacketServer, as it's more likely to cause confusion. - //NetMode = NET_PacketServer; + ticdup = clamp(atoi(v), 1, MAXTICDUP); } - if (doomcom.id != DOOMCOM_ID) + else { - I_FatalError ("Doomcom buffer invalid!"); + ticdup = 1; } + players[0].settings_controller = true; - consoleplayer = doomcom.consoleplayer; + consoleplayer = doomcom->consoleplayer; if (consoleplayer == Net_Arbitrator) { @@ -1708,7 +1612,7 @@ void D_CheckNetGame (void) { NetMode = atoi(v) != 0 ? NET_PacketServer : NET_PeerToPeer; } - if (doomcom.numnodes > 1) + if (doomcom->numnodes > 1) { Printf("Selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode. (%s)\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server", v != NULL ? "forced" : "auto"); @@ -1737,30 +1641,23 @@ void D_CheckNetGame (void) D_ArbitrateNetStart (); } - // read values out of doomcom - ticdup = doomcom.ticdup; - - for (i = 0; i < doomcom.numplayers; i++) + for (i = 0; i < doomcom->numplayers; i++) playeringame[i] = true; - for (i = 0; i < doomcom.numnodes; i++) + for (i = 0; i < doomcom->numnodes; i++) nodeingame[i] = true; - if (consoleplayer != Net_Arbitrator && doomcom.numnodes > 1) + if (consoleplayer != Net_Arbitrator && doomcom->numnodes > 1) { Printf("Arbitrator selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode.\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server"); } if (!batchrun) Printf ("player %i of %i (%i nodes)\n", - consoleplayer+1, doomcom.numplayers, doomcom.numnodes); + consoleplayer+1, doomcom->numplayers, doomcom->numnodes); } -// -// D_QuitNetGame -// Called before quitting to leave a net game -// without hanging the other players -// -void D_QuitNetGame (void) +// Called before quitting to leave a net game without hanging the other players +void Network::D_QuitNetGame() { int i, j, k; @@ -1783,7 +1680,7 @@ void D_QuitNetGame (void) if (playeringame[i] && i != consoleplayer) WriteLong (resendto[nodeforplayer[i]], &foo); } - k = int(foo - netbuffer); + k = int(foo - netbuffer.data); } for (i = 0; i < 4; i++) @@ -1794,7 +1691,7 @@ void D_QuitNetGame (void) } else { - for (j = 1; j < doomcom.numnodes; j++) + for (j = 1; j < doomcom->numnodes; j++) if (nodeingame[j]) HSendPacket (j, k); } @@ -1805,12 +1702,7 @@ void D_QuitNetGame (void) fclose (debugfile); } - - -// -// TryRunTics -// -void TryRunTics (void) +void Network::TryRunTics() { int i; int lowtic; @@ -1845,7 +1737,7 @@ void TryRunTics (void) lowtic = INT_MAX; numplaying = 0; - for (i = 0; i < doomcom.numnodes; i++) + for (i = 0; i < doomcom->numnodes; i++) { if (nodeingame[i]) { @@ -1902,7 +1794,7 @@ void TryRunTics (void) NetUpdate (); lowtic = INT_MAX; - for (i = 0; i < doomcom.numnodes; i++) + for (i = 0; i < doomcom->numnodes; i++) if (nodeingame[i] && nettics[i] < lowtic) lowtic = nettics[i]; @@ -1963,7 +1855,7 @@ void TryRunTics (void) } } -void Net_CheckLastReceived (int counts) +void Network::Net_CheckLastReceived(int counts) { // [Ed850] Check to see the last time a packet was received. // If it's longer then 3 seconds, a node has likely stalled. @@ -1975,7 +1867,7 @@ void Net_CheckLastReceived (int counts) { //Keep the local node in the for loop so we can still log any cases where the local node is /somehow/ late. //However, we don't send a resend request for sanity reasons. - for (int i = 0; i < doomcom.numnodes; i++) + for (int i = 0; i < doomcom->numnodes; i++) { if (nodeingame[i] && nettics[i] <= gametic + counts) { @@ -2001,37 +1893,37 @@ void Net_CheckLastReceived (int counts) } } -void Net_NewMakeTic (void) +void Network::Net_NewMakeTic() { specials.NewMakeTic (); } -void Net_WriteByte (uint8_t it) +void Network::Net_WriteByte(uint8_t it) { specials << it; } -void Net_WriteWord (short it) +void Network::Net_WriteWord(short it) { specials << it; } -void Net_WriteLong (int it) +void Network::Net_WriteLong(int it) { specials << it; } -void Net_WriteFloat (float it) +void Network::Net_WriteFloat(float it) { specials << it; } -void Net_WriteString (const char *it) +void Network::Net_WriteString(const char *it) { specials << it; } -void Net_WriteBytes (const uint8_t *block, int len) +void Network::Net_WriteBytes(const uint8_t *block, int len) { while (len--) specials << *block++; @@ -2460,7 +2352,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) { break; } - Net_WriteByte (DEM_DOAUTOSAVE); + network.Net_WriteByte (DEM_DOAUTOSAVE); break; case DEM_DOAUTOSAVE: @@ -2870,76 +2762,64 @@ void Net_SkipCommand (int type, uint8_t **stream) *stream += skip; } -// [RH] List "ping" times -CCMD (pings) +void Network::ListPingTimes() { - int i; - for (i = 0; i < MAXPLAYERS; i++) + for (int i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) - Printf ("% 4" PRId64 " %s\n", currrecvtime[i] - lastrecvtime[i], - players[i].userinfo.GetName()); + Printf("% 4" PRId64 " %s\n", currrecvtime[i] - lastrecvtime[i], players[i].userinfo.GetName()); } -//========================================================================== -// -// Network_Controller -// -// Implement players who have the ability to change settings in a network -// game. -// -//========================================================================== - -static void Network_Controller (int playernum, bool add) +// Implement players who have the ability to change settings in a network game. +void Network::Network_Controller(int playernum, bool add) { if (consoleplayer != Net_Arbitrator) { - Printf ("This command is only accessible to the net arbitrator.\n"); + Printf("This command is only accessible to the net arbitrator.\n"); return; } if (players[playernum].settings_controller && add) { - Printf ("%s is already on the setting controller list.\n", players[playernum].userinfo.GetName()); + Printf("%s is already on the setting controller list.\n", players[playernum].userinfo.GetName()); return; } if (!players[playernum].settings_controller && !add) { - Printf ("%s is not on the setting controller list.\n", players[playernum].userinfo.GetName()); + Printf("%s is not on the setting controller list.\n", players[playernum].userinfo.GetName()); return; } if (!playeringame[playernum]) { - Printf ("Player (%d) not found!\n", playernum); + Printf("Player (%d) not found!\n", playernum); return; } if (players[playernum].Bot != NULL) { - Printf ("Bots cannot be added to the controller list.\n"); + Printf("Bots cannot be added to the controller list.\n"); return; } if (playernum == Net_Arbitrator) { - Printf ("The net arbitrator cannot have their status changed on this list.\n"); + Printf("The net arbitrator cannot have their status changed on this list.\n"); return; } if (add) - Net_WriteByte (DEM_ADDCONTROLLER); + Net_WriteByte(DEM_ADDCONTROLLER); else - Net_WriteByte (DEM_DELCONTROLLER); + Net_WriteByte(DEM_DELCONTROLLER); - Net_WriteByte (playernum); + Net_WriteByte(playernum); } -//========================================================================== -// -// CCMD net_addcontroller -// -//========================================================================== +CCMD (pings) +{ + network.ListPingTimes(); +} CCMD (net_addcontroller) { @@ -2955,15 +2835,9 @@ CCMD (net_addcontroller) return; } - Network_Controller (atoi (argv[1]), true); + network.Network_Controller (atoi (argv[1]), true); } -//========================================================================== -// -// CCMD net_removecontroller -// -//========================================================================== - CCMD (net_removecontroller) { if (!netgame) @@ -2978,15 +2852,9 @@ CCMD (net_removecontroller) return; } - Network_Controller (atoi (argv[1]), false); + network.Network_Controller (atoi (argv[1]), false); } -//========================================================================== -// -// CCMD net_listcontrollers -// -//========================================================================== - CCMD (net_listcontrollers) { if (!netgame) diff --git a/src/d_net.h b/src/d_net.h index 352a01eb28..2e9856187e 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -17,21 +17,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see http://www.gnu.org/licenses/ // -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// Networking stuff. -// -//----------------------------------------------------------------------------- - -#ifndef __D_NET__ -#define __D_NET__ +#pragma once #include "doomtype.h" #include "doomdef.h" #include "d_protocol.h" - +#include "i_net.h" +#include // // Network play related stuff. @@ -41,58 +34,11 @@ // be transmitted. // -#define DOOMCOM_ID 0x12345678l #define MAXNETNODES 8 // max computers in a game #define BACKUPTICS 36 // number of tics to remember #define MAXTICDUP 5 #define LOCALCMDTICS (BACKUPTICS*MAXTICDUP) - -#ifdef DJGPP -// The DOS drivers provide a pretty skimpy buffer. -// Probably not enough. -#define MAX_MSGLEN (BACKUPTICS*10) -#else -#define MAX_MSGLEN 14000 -#endif - -#define CMD_SEND 1 -#define CMD_GET 2 - -// -// Network packet data. -// -struct doomcom_t -{ - uint32_t id; // should be DOOMCOM_ID - int16_t intnum; // DOOM executes an int to execute commands - -// communication between DOOM and the driver - int16_t command; // CMD_SEND or CMD_GET - int16_t remotenode; // dest for send, set by get (-1 = no packet). - int16_t datalength; // bytes in doomdata to be sent - -// info common to all nodes - int16_t numnodes; // console is always node 0. - int16_t ticdup; // 1 = no duplication, 2-5 = dup for slow nets -#ifdef DJGPP - int16_t pad[5]; // keep things aligned for DOS drivers -#endif - -// info specific to this node - int16_t consoleplayer; - int16_t numplayers; -#ifdef DJGPP - int16_t angleoffset; // does not work, but needed to preserve - int16_t drone; // alignment for DOS drivers -#endif - -// packet data to be sent - uint8_t data[MAX_MSGLEN]; - -}; - - class FDynamicBuffer { public: @@ -107,52 +53,124 @@ private: int m_Len, m_BufferLen; }; -extern FDynamicBuffer NetSpecs[MAXPLAYERS][BACKUPTICS]; +struct TicSpecial +{ + uint8_t *streams[BACKUPTICS]; + size_t used[BACKUPTICS]; + uint8_t *streamptr; + size_t streamoffs; + size_t specialsize; + int lastmaketic; + bool okay; -// Create any new ticcmds and broadcast to other players. -void NetUpdate (void); + TicSpecial(); + ~TicSpecial(); -// Broadcasts special packets to other players -// to notify of game exit -void D_QuitNetGame (void); + void GetMoreSpace(size_t needed); + void CheckSpace(size_t needed); + void NewMakeTic(); -//? how many ticks to run? -void TryRunTics (void); + TicSpecial &operator << (uint8_t it); + TicSpecial &operator << (short it); + TicSpecial &operator << (int it); + TicSpecial &operator << (float it); + TicSpecial &operator << (const char *it); +}; -//Use for checking to see if the netgame has stalled -void Net_CheckLastReceived(int); +struct ArbitrateData +{ + uint32_t playersdetected[MAXNETNODES]; + uint8_t gotsetup[MAXNETNODES]; +}; -// [RH] Functions for making and using special "ticcmds" -void Net_NewMakeTic (); -void Net_WriteByte (uint8_t); -void Net_WriteWord (short); -void Net_WriteLong (int); -void Net_WriteFloat (float); -void Net_WriteString (const char *); -void Net_WriteBytes (const uint8_t *, int len); +struct Network +{ +public: + void D_CheckNetGame(); + void ListPingTimes(); + void Network_Controller(int playernum, bool add); + void Net_ClearBuffers(); + void NetUpdate(); + void D_QuitNetGame(); + void TryRunTics(); + void Net_NewMakeTic(); + + void Net_WriteByte(uint8_t it); + void Net_WriteWord(short it); + void Net_WriteLong(int it); + void Net_WriteFloat(float it); + void Net_WriteString(const char *it); + void Net_WriteBytes(const uint8_t *block, int len); + + short consistancy[MAXPLAYERS][BACKUPTICS]; + + FDynamicBuffer NetSpecs[MAXPLAYERS][BACKUPTICS]; + ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; + ticcmd_t localcmds[LOCALCMDTICS]; + + int maketic; + int ticdup; // 1 = no duplication, 2-5 = dup for slow nets + + int nodeforplayer[MAXPLAYERS]; + int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times. + +private: + int NetbufferSize(); + int ExpandTics(int low); + void HSendPacket(int node, int len); + bool HGetPacket(); + void PlayerIsGone(int netnode, int netconsole); + void GetPackets(); + bool DoArbitrate(ArbitrateData *data); + void D_ArbitrateNetStart(); + void Net_CheckLastReceived(int counts); + + void SendSetup(uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[MAXNETNODES], int len); + + std::unique_ptr doomcom; + NetPacket netbuffer; + + int gametime; + + enum { NET_PeerToPeer, NET_PacketServer }; + uint8_t NetMode = NET_PeerToPeer; + + int nettics[MAXNETNODES]; + bool nodeingame[MAXNETNODES]; // set false as nodes leave game + bool nodejustleft[MAXNETNODES]; // set when a node just left + bool remoteresend[MAXNETNODES]; // set when local needs tics + int resendto[MAXNETNODES]; // set when remote needs tics + int resendcount[MAXNETNODES]; + + uint64_t lastrecvtime[MAXPLAYERS]; // [RH] Used for pings + uint64_t currrecvtime[MAXPLAYERS]; + uint64_t lastglobalrecvtime; // Identify the last time a packet was received. + bool hadlate; + int lastaverage; + + int playerfornode[MAXNETNODES]; + + int skiptics; + + int reboundpacket; + uint8_t reboundstore[MAX_MSGLEN]; + + int frameon; + int frameskip[4]; + int oldnettics; + int mastertics; + + int entertic; + int oldentertics; + + TicSpecial specials; +}; + +extern Network network; void Net_DoCommand (int type, uint8_t **stream, int player); void Net_SkipCommand (int type, uint8_t **stream); -void Net_ClearBuffers (); - - -// Netgame stuff (buffers and pointers, i.e. indices). - -// This is the interface to the packet driver, a separate program -// in DOS, but just an abstraction here. -extern doomcom_t doomcom; - -extern struct ticcmd_t localcmds[LOCALCMDTICS]; - -extern int maketic; -extern int nettics[MAXNETNODES]; -extern int netdelay[MAXNETNODES][BACKUPTICS]; -extern int nodeforplayer[MAXPLAYERS]; - -extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; -extern int ticdup; - // [RH] // New generic packet structure: // @@ -182,5 +200,3 @@ extern int ticdup; #define NCMD_2TICS 0x02 // packet contains 2 tics #define NCMD_1TICS 0x01 // packet contains 1 tic #define NCMD_0TICS 0x00 // packet contains 0 tics - -#endif diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 2928568d0d..fa218b616e 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -549,8 +549,8 @@ void D_UserInfoChanged (FBaseCVar *cvar) mysnprintf (foo, countof(foo), "\\%s\\%s", cvar->GetName(), escaped_val.GetChars()); - Net_WriteByte (DEM_UINFCHANGED); - Net_WriteString (foo); + network.Net_WriteByte (DEM_UINFCHANGED); + network.Net_WriteString (foo); } static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, bool singlebit) @@ -633,15 +633,15 @@ void D_SendServerInfoChange (const FBaseCVar *cvar, UCVarValue value, ECVarType namelen = strlen (cvar->GetName ()); - Net_WriteByte (DEM_SINFCHANGED); - Net_WriteByte ((uint8_t)(namelen | (type << 6))); - Net_WriteBytes ((uint8_t *)cvar->GetName (), (int)namelen); + network.Net_WriteByte (DEM_SINFCHANGED); + network.Net_WriteByte ((uint8_t)(namelen | (type << 6))); + network.Net_WriteBytes ((uint8_t *)cvar->GetName (), (int)namelen); switch (type) { - case CVAR_Bool: Net_WriteByte (value.Bool); break; - case CVAR_Int: Net_WriteLong (value.Int); break; - case CVAR_Float: Net_WriteFloat (value.Float); break; - case CVAR_String: Net_WriteString (value.String); break; + case CVAR_Bool: network.Net_WriteByte (value.Bool); break; + case CVAR_Int: network.Net_WriteLong (value.Int); break; + case CVAR_Float: network.Net_WriteFloat (value.Float); break; + case CVAR_String: network.Net_WriteString (value.String); break; default: break; // Silence GCC } } @@ -652,10 +652,10 @@ void D_SendServerFlagChange (const FBaseCVar *cvar, int bitnum, bool set) namelen = (int)strlen (cvar->GetName ()); - Net_WriteByte (DEM_SINFCHANGEDXOR); - Net_WriteByte ((uint8_t)namelen); - Net_WriteBytes ((uint8_t *)cvar->GetName (), namelen); - Net_WriteByte (uint8_t(bitnum | (set << 5))); + network.Net_WriteByte (DEM_SINFCHANGEDXOR); + network.Net_WriteByte ((uint8_t)namelen); + network.Net_WriteBytes ((uint8_t *)cvar->GetName (), namelen); + network.Net_WriteByte (uint8_t(bitnum | (set << 5))); } void D_DoServerInfoChange (uint8_t **stream, bool singlebit) diff --git a/src/d_protocol.cpp b/src/d_protocol.cpp index 06caca46cd..4542c4c43a 100644 --- a/src/d_protocol.cpp +++ b/src/d_protocol.cpp @@ -409,7 +409,6 @@ int SkipTicCmd (uint8_t **stream, int count) } #include -extern short consistancy[MAXPLAYERS][BACKUPTICS]; void ReadTicCmd (uint8_t **stream, int player, int tic) { int type; @@ -418,7 +417,7 @@ void ReadTicCmd (uint8_t **stream, int player, int tic) int ticmod = tic % BACKUPTICS; - tcmd = &netcmds[player][ticmod]; + tcmd = &network.netcmds[player][ticmod]; tcmd->consistancy = ReadWord (stream); start = *stream; @@ -426,18 +425,18 @@ void ReadTicCmd (uint8_t **stream, int player, int tic) while ((type = ReadByte (stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD) Net_SkipCommand (type, stream); - NetSpecs[player][ticmod].SetData (start, int(*stream - start - 1)); + network.NetSpecs[player][ticmod].SetData (start, int(*stream - start - 1)); if (type == DEM_USERCMD) { UnpackUserCmd (&tcmd->ucmd, - tic ? &netcmds[player][(tic-1)%BACKUPTICS].ucmd : NULL, stream); + tic ? &network.netcmds[player][(tic-1)%BACKUPTICS].ucmd : NULL, stream); } else { if (tic) { - memcpy (&tcmd->ucmd, &netcmds[player][(tic-1)%BACKUPTICS].ucmd, sizeof(tcmd->ucmd)); + memcpy (&tcmd->ucmd, &network.netcmds[player][(tic-1)%BACKUPTICS].ucmd, sizeof(tcmd->ucmd)); } else { @@ -446,7 +445,7 @@ void ReadTicCmd (uint8_t **stream, int player, int tic) } if (player==consoleplayer&&tic>BACKUPTICS) - assert(consistancy[player][ticmod] == tcmd->consistancy); + assert(network.consistancy[player][ticmod] == tcmd->consistancy); } void RunNetSpecs (int player, int buf) @@ -454,9 +453,9 @@ void RunNetSpecs (int player, int buf) uint8_t *stream; int len; - if (gametic % ticdup == 0) + if (gametic % network.ticdup == 0) { - stream = NetSpecs[player][buf].GetData (&len); + stream = network.NetSpecs[player][buf].GetData (&len); if (stream) { uint8_t *end = stream + len; @@ -466,7 +465,7 @@ void RunNetSpecs (int player, int buf) Net_DoCommand (type, &stream, player); } if (!demorecording) - NetSpecs[player][buf].SetData (NULL, 0); + network.NetSpecs[player][buf].SetData (NULL, 0); } } } diff --git a/src/events.cpp b/src/events.cpp index ec8b07af95..b8760072ee 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -154,13 +154,13 @@ bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual) if (gamestate != GS_LEVEL) return false; - Net_WriteByte(DEM_NETEVENT); - Net_WriteString(name); - Net_WriteByte(3); - Net_WriteLong(arg1); - Net_WriteLong(arg2); - Net_WriteLong(arg3); - Net_WriteByte(manual); + network.Net_WriteByte(DEM_NETEVENT); + network.Net_WriteString(name); + network.Net_WriteByte(3); + network.Net_WriteLong(arg1); + network.Net_WriteLong(arg2); + network.Net_WriteLong(arg3); + network.Net_WriteByte(manual); return true; } diff --git a/src/g_game.cpp b/src/g_game.cpp index b2f58990c4..8ff13e9254 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -196,9 +196,6 @@ bool precache = true; // if true, load all graphics at start wbstartstruct_t wminfo; // parms for world map / intermission -short consistancy[MAXPLAYERS][BACKUPTICS]; - - #define MAXPLMOVE (forwardmove[1]) #define TURBOTHRESHOLD 12800 @@ -316,12 +313,12 @@ CCMD (slot) CCMD (centerview) { - Net_WriteByte (DEM_CENTERVIEW); + network.Net_WriteByte (DEM_CENTERVIEW); } CCMD(crouch) { - Net_WriteByte(DEM_CROUCH); + network.Net_WriteByte(DEM_CROUCH); } CCMD (land) @@ -577,7 +574,7 @@ void G_BuildTiccmd (ticcmd_t *cmd) base = I_BaseTiccmd (); // empty, or external driver *cmd = *base; - cmd->consistancy = consistancy[consoleplayer][(maketic/ticdup)%BACKUPTICS]; + cmd->consistancy = network.consistancy[consoleplayer][(network.maketic/network.ticdup)%BACKUPTICS]; strafe = Button_Strafe.bDown; speed = Button_Speed.bDown ^ (int)cl_run; @@ -588,7 +585,7 @@ void G_BuildTiccmd (ticcmd_t *cmd) // and not the joystick, since we treat the joystick as // the analog device it is. if (Button_Left.bDown || Button_Right.bDown) - turnheld += ticdup; + turnheld += network.ticdup; else turnheld = 0; @@ -754,32 +751,32 @@ void G_BuildTiccmd (ticcmd_t *cmd) if (sendpause) { sendpause = false; - Net_WriteByte (DEM_PAUSE); + network.Net_WriteByte (DEM_PAUSE); } if (sendsave) { sendsave = false; - Net_WriteByte (DEM_SAVEGAME); - Net_WriteString (savegamefile); - Net_WriteString (savedescription); + network.Net_WriteByte (DEM_SAVEGAME); + network.Net_WriteString (savegamefile); + network.Net_WriteString (savedescription); savegamefile = ""; } if (SendItemUse == (const AInventory *)1) { - Net_WriteByte (DEM_INVUSEALL); + network.Net_WriteByte (DEM_INVUSEALL); SendItemUse = NULL; } else if (SendItemUse != NULL) { - Net_WriteByte (DEM_INVUSE); - Net_WriteLong (SendItemUse->InventoryID); + network.Net_WriteByte (DEM_INVUSE); + network.Net_WriteLong (SendItemUse->InventoryID); SendItemUse = NULL; } if (SendItemDrop != NULL) { - Net_WriteByte (DEM_INVDROP); - Net_WriteLong (SendItemDrop->InventoryID); - Net_WriteLong(SendItemDropAmount); + network.Net_WriteByte (DEM_INVDROP); + network.Net_WriteLong (SendItemDrop->InventoryID); + network.Net_WriteLong(SendItemDropAmount); SendItemDrop = NULL; } @@ -883,7 +880,7 @@ static void ChangeSpy (int changespy) // has done this for you, since it could desync otherwise. if (!demoplayback) { - Net_WriteByte(DEM_REVERTCAMERA); + network.Net_WriteByte(DEM_REVERTCAMERA); } return; } @@ -1153,7 +1150,7 @@ void G_Ticker () } // get commands, check consistancy, and build new consistancy check - int buf = (gametic/ticdup)%BACKUPTICS; + int buf = (gametic/network.ticdup)%BACKUPTICS; // [RH] Include some random seeds and player stuff in the consistancy // check, not just the player's x position like BOOM. @@ -1167,9 +1164,9 @@ void G_Ticker () if (playeringame[i]) { ticcmd_t *cmd = &players[i].cmd; - ticcmd_t *newcmd = &netcmds[i][buf]; + ticcmd_t *newcmd = &network.netcmds[i][buf]; - if ((gametic % ticdup) == 0) + if ((gametic % network.ticdup) == 0) { RunNetSpecs (i, buf); } @@ -1197,22 +1194,22 @@ void G_Ticker () Printf ("%s is turbo!\n", players[i].userinfo.GetName()); } - if (netgame && players[i].Bot == NULL && !demoplayback && (gametic%ticdup) == 0) + if (netgame && players[i].Bot == NULL && !demoplayback && (gametic%network.ticdup) == 0) { //players[i].inconsistant = 0; - if (gametic > BACKUPTICS*ticdup && consistancy[i][buf] != cmd->consistancy) + if (gametic > BACKUPTICS*network.ticdup && network.consistancy[i][buf] != cmd->consistancy) { - players[i].inconsistant = gametic - BACKUPTICS*ticdup; + players[i].inconsistant = gametic - BACKUPTICS*network.ticdup; } if (players[i].mo) { uint32_t sum = rngsum + int((players[i].mo->X() + players[i].mo->Y() + players[i].mo->Z())*257) + players[i].mo->Angles.Yaw.BAMs() + players[i].mo->Angles.Pitch.BAMs(); sum ^= players[i].health; - consistancy[i][buf] = sum; + network.consistancy[i][buf] = sum; } else { - consistancy[i][buf] = rngsum; + network.consistancy[i][buf] = rngsum; } } } @@ -2472,11 +2469,11 @@ void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf) } // [RH] Write any special "ticcmds" for this player to the demo - if ((specdata = NetSpecs[player][buf].GetData (&speclen)) && gametic % ticdup == 0) + if ((specdata = network.NetSpecs[player][buf].GetData (&speclen)) && gametic % network.ticdup == 0) { memcpy (demo_p, specdata, speclen); demo_p += speclen; - NetSpecs[player][buf].SetData (NULL, 0); + network.NetSpecs[player][buf].SetData (NULL, 0); } // [RH] Now write out a "normal" ticcmd. diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index e0d98529be..b7e82182e7 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1110,15 +1110,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) // The slots differ. Send mine. if (playernum == consoleplayer) { - Net_WriteByte(DEM_SETSLOT); + network.Net_WriteByte(DEM_SETSLOT); } else { - Net_WriteByte(DEM_SETSLOTPNUM); - Net_WriteByte(playernum); + network.Net_WriteByte(DEM_SETSLOTPNUM); + network.Net_WriteByte(playernum); } - Net_WriteByte(i); - Net_WriteByte(Slots[i].Size()); + network.Net_WriteByte(i); + network.Net_WriteByte(Slots[i].Size()); for (j = 0; j < Slots[i].Size(); ++j) { Net_WriteWeapon(Slots[i].GetWeapon(j)); @@ -1248,9 +1248,9 @@ CCMD (setslot) Printf ("Slot %d cleared\n", slot); } - Net_WriteByte(DEM_SETSLOT); - Net_WriteByte(slot); - Net_WriteByte(argv.argc()-2); + network.Net_WriteByte(DEM_SETSLOT); + network.Net_WriteByte(slot); + network.Net_WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { Net_WriteWeapon(PClass::FindActor(argv[i])); @@ -1299,8 +1299,8 @@ CCMD (addslot) } else { - Net_WriteByte(DEM_ADDSLOT); - Net_WriteByte(slot); + network.Net_WriteByte(DEM_ADDSLOT); + network.Net_WriteByte(slot); Net_WriteWeapon(type); } } @@ -1375,8 +1375,8 @@ CCMD (addslotdefault) } else { - Net_WriteByte(DEM_ADDSLOTDEFAULT); - Net_WriteByte(slot); + network.Net_WriteByte(DEM_ADDSLOTDEFAULT); + network.Net_WriteByte(slot); Net_WriteWeapon(type); } } @@ -1541,12 +1541,12 @@ void Net_WriteWeapon(PClassActor *type) assert(index >= 0 && index <= 32767); if (index < 128) { - Net_WriteByte(index); + network.Net_WriteByte(index); } else { - Net_WriteByte(0x80 | index); - Net_WriteByte(index >> 7); + network.Net_WriteByte(0x80 | index); + network.Net_WriteByte(index >> 7); } } diff --git a/src/g_level.cpp b/src/g_level.cpp index d6c712b241..29c1fc5de5 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -890,7 +890,7 @@ IMPLEMENT_CLASS(DAutosaver, false, false) void DAutosaver::Tick () { - Net_WriteByte (DEM_CHECKAUTOSAVE); + network.Net_WriteByte (DEM_CHECKAUTOSAVE); Destroy (); } diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index edc170294a..be72f9f502 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -700,8 +700,8 @@ CCMD (spray) return; } - Net_WriteByte (DEM_SPRAY); - Net_WriteString (argv[1]); + network.Net_WriteByte (DEM_SPRAY); + network.Net_WriteString (argv[1]); } void SprayDecal(AActor *shooter, const char *name, double distance) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 9dc90d908a..faac5610dd 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -1054,10 +1054,10 @@ static void DrawLatency() return; } int i, localdelay = 0, arbitratordelay = 0; - for (i = 0; i < BACKUPTICS; i++) localdelay += netdelay[0][i]; - for (i = 0; i < BACKUPTICS; i++) arbitratordelay += netdelay[nodeforplayer[Net_Arbitrator]][i]; - localdelay = ((localdelay / BACKUPTICS) * ticdup) * (1000 / TICRATE); - arbitratordelay = ((arbitratordelay / BACKUPTICS) * ticdup) * (1000 / TICRATE); + for (i = 0; i < BACKUPTICS; i++) localdelay += network.netdelay[0][i]; + for (i = 0; i < BACKUPTICS; i++) arbitratordelay += network.netdelay[network.nodeforplayer[Net_Arbitrator]][i]; + localdelay = ((localdelay / BACKUPTICS) * network.ticdup) * (1000 / TICRATE); + arbitratordelay = ((arbitratordelay / BACKUPTICS) * network.ticdup) * (1000 / TICRATE); int color = CR_GREEN; if (MAX(localdelay, arbitratordelay) > 200) { @@ -1067,7 +1067,7 @@ static void DrawLatency() { color = CR_ORANGE; } - if (MAX(localdelay, arbitratordelay) >= ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE)) + if (MAX(localdelay, arbitratordelay) >= ((BACKUPTICS / 2 - 1) * network.ticdup) * (1000 / TICRATE)) { color = CR_RED; } diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index d95cca8881..a5ed763e74 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1255,7 +1255,7 @@ void DBaseStatusBar::DrawConsistancy () const { fprintf (debugfile, "%s as of tic %d (%d)\n", conbuff, players[1-consoleplayer].inconsistant, - players[1-consoleplayer].inconsistant/ticdup); + players[1-consoleplayer].inconsistant/network.ticdup); } } screen->DrawText (SmallFont, CR_GREEN, diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index a399011812..8a384c4bf2 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -437,11 +437,11 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int avgdelay = 0; for (int i = 0; i < BACKUPTICS; i++) { - avgdelay += netdelay[nodeforplayer[(int)(player - players)]][i]; + avgdelay += network.netdelay[network.nodeforplayer[(int)(player - players)]][i]; } avgdelay /= BACKUPTICS; - mysnprintf(str, countof(str), "%d", (avgdelay * ticdup) * (1000 / TICRATE)); + mysnprintf(str, countof(str), "%d", (avgdelay * network.ticdup) * (1000 / TICRATE)); screen->DrawText(SmallFont, color, col5, y + ypadding, str, DTA_CleanNoMove, true, TAG_DONE); diff --git a/src/i_net.cpp b/src/i_net.cpp index 48160373cf..8bef2e1cb5 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -95,15 +95,6 @@ typedef int SOCKET; typedef int socklen_t; #endif -// -// NETWORKING -// - -static u_short DOOMPORT = (IPPORT_USERRESERVED + 29); -static SOCKET mysocket = INVALID_SOCKET; -static sockaddr_in sendaddress[MAXNETNODES]; -static uint8_t sendplayer[MAXNETNODES]; - #ifdef __WIN32__ const char *neterror (void); #else @@ -145,12 +136,50 @@ struct PreGamePacket } machines[MAXNETNODES]; }; -uint8_t TransmitBuffer[TRANSMIT_SIZE]; +class DoomComImpl : public doomcom_t +{ +public: + DoomComImpl(); + ~DoomComImpl() { CloseNetwork(); } -// -// UDPsocket -// -SOCKET UDPsocket (void) + void PacketSend(const NetPacket &packet) override; + void PacketGet(NetPacket &packet) override; + +private: + u_short DOOMPORT = (IPPORT_USERRESERVED + 29); + SOCKET mysocket = INVALID_SOCKET; + sockaddr_in sendaddress[MAXNETNODES]; + uint8_t sendplayer[MAXNETNODES]; + + uint8_t TransmitBuffer[TRANSMIT_SIZE]; + + SOCKET UDPsocket(); + void BindToLocalPort(SOCKET s, u_short port); + int FindNode(const sockaddr_in *address); + sockaddr_in *PreGet(void *buffer, int bufferlen, bool noabort); + void PreSend(const void *buffer, int bufferlen, const sockaddr_in *to); + void BuildAddress(sockaddr_in *address, const char *name); + void CloseNetwork(); + void StartNetwork(bool autoPort); + void SendAbort(); + void SendConAck(int num_connected, int num_needed); + bool Host_CheckForConnects(); + bool Host_SendAllHere(int *gotack); + void HostGame(int i); + bool Guest_ContactHost(); + bool Guest_WaitForOthers(); + void JoinGame(int i); + + static int PrivateNetOf(in_addr in); + bool NodesOnSameNetwork(); +}; + +std::unique_ptr I_InitNetwork() +{ + return std::unique_ptr(new DoomComImpl()); +} + +SOCKET DoomComImpl::UDPsocket() { SOCKET s; @@ -162,10 +191,7 @@ SOCKET UDPsocket (void) return s; } -// -// BindToLocalPort -// -void BindToLocalPort (SOCKET s, u_short port) +void DoomComImpl::BindToLocalPort(SOCKET s, u_short port) { int v; sockaddr_in address; @@ -180,17 +206,17 @@ void BindToLocalPort (SOCKET s, u_short port) I_FatalError ("BindToPort: %s", neterror ()); } -int FindNode (const sockaddr_in *address) +int DoomComImpl::FindNode(const 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) + if (i == numnodes) { // packet is not from one of the players (new game broadcast?) i = -1; @@ -198,63 +224,52 @@ int FindNode (const sockaddr_in *address) return i; } -// -// PacketSend -// -void PacketSend (void) +void DoomComImpl::PacketSend(const NetPacket &packet) { int c; // FIXME: Catch this before we've overflown the buffer. With long chat // text and lots of backup tics, it could conceivably happen. (Though // apparently it hasn't yet, which is good.) - if (doomcom.datalength > MAX_MSGLEN) + if (packet.datalength > MAX_MSGLEN) { I_FatalError("Netbuffer overflow!"); } - assert(!(doomcom.data[0] & NCMD_COMPRESSED)); + assert(!(packet.data[0] & NCMD_COMPRESSED)); uLong size = TRANSMIT_SIZE - 1; - if (doomcom.datalength >= 10) + if (packet.datalength >= 10) { - TransmitBuffer[0] = doomcom.data[0] | NCMD_COMPRESSED; - c = compress2(TransmitBuffer + 1, &size, doomcom.data + 1, doomcom.datalength - 1, 9); + TransmitBuffer[0] = packet.data[0] | NCMD_COMPRESSED; + c = compress2(TransmitBuffer + 1, &size, packet.data + 1, packet.datalength - 1, 9); size += 1; } else { c = -1; // Just some random error code to avoid sending the compressed buffer. } - if (c == Z_OK && size < (uLong)doomcom.datalength) + if (c == Z_OK && size < (uLong)packet.datalength) { -// Printf("send %lu/%d\n", size, doomcom.datalength); - c = sendto(mysocket, (char *)TransmitBuffer, size, - 0, (sockaddr *)&sendaddress[doomcom.remotenode], - sizeof(sendaddress[doomcom.remotenode])); +// Printf("send %lu/%d\n", size, datalength); + c = sendto(mysocket, (char *)TransmitBuffer, size, 0, (sockaddr *)&sendaddress[packet.remotenode], sizeof(sendaddress[packet.remotenode])); } else { - if (doomcom.datalength > TRANSMIT_SIZE) + if (packet.datalength > TRANSMIT_SIZE) { I_Error("Net compression failed (zlib error %d)", c); } else { -// Printf("send %d\n", doomcom.datalength); - c = sendto(mysocket, (char *)doomcom.data, doomcom.datalength, - 0, (sockaddr *)&sendaddress[doomcom.remotenode], - sizeof(sendaddress[doomcom.remotenode])); +// Printf("send %d\n", datalength); + c = sendto(mysocket, (char *)packet.data, packet.datalength, 0, (sockaddr *)&sendaddress[packet.remotenode], sizeof(sendaddress[packet.remotenode])); } } // if (c == -1) // I_Error ("SendPacket error: %s",strerror(errno)); } - -// -// PacketGet -// -void PacketGet (void) +void DoomComImpl::PacketGet(NetPacket &packet) { int c; socklen_t fromlen; @@ -262,8 +277,7 @@ void PacketGet (void) int node; fromlen = sizeof(fromaddress); - c = recvfrom (mysocket, (char*)TransmitBuffer, TRANSMIT_SIZE, 0, - (sockaddr *)&fromaddress, &fromlen); + c = recvfrom (mysocket, (char*)TransmitBuffer, TRANSMIT_SIZE, 0, (sockaddr *)&fromaddress, &fromlen); node = FindNode (&fromaddress); if (node >= 0 && c == SOCKET_ERROR) @@ -284,7 +298,7 @@ void PacketGet (void) players[sendplayer[node]].userinfo.GetName()); } - doomcom.data[0] = 0x80; // NCMD_EXIT + packet.data[0] = 0x80; // NCMD_EXIT c = 1; } else if (err != WSAEWOULDBLOCK) @@ -293,23 +307,23 @@ void PacketGet (void) } else { - doomcom.remotenode = -1; // no packet + packet.remotenode = -1; // no packet return; } } else if (node >= 0 && c > 0) { - doomcom.data[0] = TransmitBuffer[0] & ~NCMD_COMPRESSED; + packet.data[0] = TransmitBuffer[0] & ~NCMD_COMPRESSED; if (TransmitBuffer[0] & NCMD_COMPRESSED) { uLongf msgsize = MAX_MSGLEN - 1; - int err = uncompress(doomcom.data + 1, &msgsize, TransmitBuffer + 1, c - 1); + int err = uncompress(packet.data + 1, &msgsize, TransmitBuffer + 1, c - 1); // Printf("recv %d/%lu\n", c, msgsize + 1); if (err != Z_OK) { Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars()); // Pretend no packet - doomcom.remotenode = -1; + packet.remotenode = -1; return; } c = msgsize + 1; @@ -317,7 +331,7 @@ void PacketGet (void) else { // Printf("recv %d\n", c); - memcpy(doomcom.data + 1, TransmitBuffer + 1, c - 1); + memcpy(packet.data + 1, TransmitBuffer + 1, c - 1); } } else if (c > 0) @@ -327,23 +341,22 @@ void PacketGet (void) { DPrintf(DMSG_WARNING, "Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port); } - doomcom.remotenode = -1; + packet.remotenode = -1; return; } - doomcom.remotenode = node; - doomcom.datalength = (short)c; + packet.remotenode = node; + packet.datalength = (short)c; } -sockaddr_in *PreGet (void *buffer, int bufferlen, bool noabort) +sockaddr_in *DoomComImpl::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); + c = recvfrom (mysocket, (char *)buffer, bufferlen, 0, (sockaddr *)&fromaddress, &fromlen); if (c == SOCKET_ERROR) { @@ -355,12 +368,12 @@ sockaddr_in *PreGet (void *buffer, int bufferlen, bool noabort) return &fromaddress; } -void PreSend (const void *buffer, int bufferlen, const sockaddr_in *to) +void DoomComImpl::PreSend(const void *buffer, int bufferlen, const sockaddr_in *to) { sendto (mysocket, (const char *)buffer, bufferlen, 0, (const sockaddr *)to, sizeof(*to)); } -void BuildAddress (sockaddr_in *address, const char *name) +void DoomComImpl::BuildAddress(sockaddr_in *address, const char *name) { hostent *hostentry; // host information entry u_short port; @@ -401,7 +414,7 @@ void BuildAddress (sockaddr_in *address, const char *name) if (!isnamed) { address->sin_addr.s_addr = inet_addr (target); - Printf ("Node number %d, address %s\n", doomcom.numnodes, target.GetChars()); + Printf ("Node number %d, address %s\n", numnodes, target.GetChars()); } else { @@ -409,12 +422,11 @@ void BuildAddress (sockaddr_in *address, const char *name) if (!hostentry) I_FatalError ("gethostbyname: couldn't find %s\n%s", target.GetChars(), neterror()); address->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; - Printf ("Node number %d, hostname %s\n", - doomcom.numnodes, hostentry->h_name); + Printf ("Node number %d, hostname %s\n", numnodes, hostentry->h_name); } } -void CloseNetwork (void) +void DoomComImpl::CloseNetwork() { if (mysocket != INVALID_SOCKET) { @@ -426,7 +438,7 @@ void CloseNetwork (void) #endif } -void StartNetwork (bool autoPort) +void DoomComImpl::StartNetwork(bool autoPort) { u_long trueval = 1; #ifdef __WIN32__ @@ -438,8 +450,6 @@ void StartNetwork (bool autoPort) } #endif - atterm (CloseNetwork); - netgame = true; multiplayer = true; @@ -453,17 +463,17 @@ void StartNetwork (bool autoPort) #endif } -void SendAbort (void) +void DoomComImpl::SendAbort() { uint8_t dis[2] = { PRE_FAKE, PRE_DISCONNECT }; int i, j; - if (doomcom.numnodes > 1) + if (numnodes > 1) { if (consoleplayer == 0) { // The host needs to let everyone know - for (i = 1; i < doomcom.numnodes; ++i) + for (i = 1; i < numnodes; ++i) { for (j = 4; j > 0; --j) { @@ -482,7 +492,7 @@ void SendAbort (void) } } -static void SendConAck (int num_connected, int num_needed) +void DoomComImpl::SendConAck (int num_connected, int num_needed) { PreGamePacket packet; @@ -490,17 +500,16 @@ static void SendConAck (int num_connected, int num_needed) packet.Message = PRE_CONACK; packet.NumNodes = num_needed; packet.NumPresent = num_connected; - for (int node = 1; node < doomcom.numnodes; ++node) + for (int node = 1; node < numnodes; ++node) { PreSend (&packet, 4, &sendaddress[node]); } - StartScreen->NetProgress (doomcom.numnodes); + StartScreen->NetProgress (numnodes); } -bool Host_CheckForConnects (void *userdata) +bool DoomComImpl::Host_CheckForConnects() { PreGamePacket packet; - int numplayers = (int)(intptr_t)userdata; sockaddr_in *from; int node; @@ -514,7 +523,7 @@ bool Host_CheckForConnects (void *userdata) { case PRE_CONNECT: node = FindNode (from); - if (doomcom.numnodes == numplayers) + if (numnodes == numplayers) { if (node == -1) { @@ -530,13 +539,13 @@ bool Host_CheckForConnects (void *userdata) { if (node == -1) { - node = doomcom.numnodes++; + node = numnodes++; sendaddress[node] = *from; StartScreen->NetMessage ("Got connect from node %d.", node); } // Let the new guest (and everyone else) know we got their message. - SendConAck (doomcom.numnodes, numplayers); + SendConAck (numnodes, numplayers); } break; @@ -545,15 +554,15 @@ bool Host_CheckForConnects (void *userdata) if (node >= 0) { StartScreen->NetMessage ("Got disconnect from node %d.", node); - doomcom.numnodes--; - while (node < doomcom.numnodes) + numnodes--; + while (node < numnodes) { sendaddress[node] = sendaddress[node+1]; node++; } // Let remaining guests know that somebody left. - SendConAck (doomcom.numnodes, numplayers); + SendConAck (numnodes, numplayers); } break; @@ -561,10 +570,10 @@ bool Host_CheckForConnects (void *userdata) break; } } - if (doomcom.numnodes < numplayers) + if (numnodes < numplayers) { // Send message to everyone as a keepalive - SendConAck(doomcom.numnodes, numplayers); + SendConAck(numnodes, numplayers); return false; } @@ -578,24 +587,23 @@ bool Host_CheckForConnects (void *userdata) node = FindNode (from); if (node >= 0) { - doomcom.numnodes--; - while (node < doomcom.numnodes) + numnodes--; + while (node < numnodes) { sendaddress[node] = sendaddress[node+1]; node++; } // Let remaining guests know that somebody left. - SendConAck (doomcom.numnodes, numplayers); + SendConAck (numnodes, numplayers); } break; } } - return doomcom.numnodes >= numplayers; + return numnodes >= numplayers; } -bool Host_SendAllHere (void *userdata) +bool DoomComImpl::Host_SendAllHere(int *gotack) { - int *gotack = (int *)userdata; // ackcount is at gotack[MAXNETNODES] PreGamePacket packet; int node; sockaddr_in *from; @@ -604,14 +612,14 @@ bool Host_SendAllHere (void *userdata) // acknowledged receipt effectively get just a heartbeat packet. packet.Fake = PRE_FAKE; packet.Message = PRE_ALLHERE; - for (node = 1; node < doomcom.numnodes; node++) + for (node = 1; node < numnodes; node++) { int machine, spot = 0; packet.ConsoleNum = node; if (!gotack[node]) { - for (spot = 0, machine = 1; machine < doomcom.numnodes; machine++) + for (spot = 0, machine = 1; machine < numnodes; machine++) { if (node != machine) { @@ -624,7 +632,7 @@ bool Host_SendAllHere (void *userdata) // and storing in the packet the next address. } } - packet.NumNodes = doomcom.numnodes - 2; + packet.NumNodes = numnodes - 2; } else { @@ -652,13 +660,12 @@ bool Host_SendAllHere (void *userdata) } // If everybody has replied, then this loop can end. - return gotack[MAXNETNODES] == doomcom.numnodes - 1; + return gotack[MAXNETNODES] == numnodes - 1; } -void HostGame (int i) +void DoomComImpl::HostGame(int i) { PreGamePacket packet; - int numplayers; int node; int gotack[MAXNETNODES+1]; @@ -677,9 +684,8 @@ void HostGame (int i) { // 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; + numnodes = 1; + consoleplayer = 0; return; } @@ -687,18 +693,17 @@ void HostGame (int i) // [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); + consoleplayer = 0; + Printf ("Console player number: %d\n", consoleplayer); - doomcom.numnodes = 1; - - atterm (SendAbort); + numnodes = 1; StartScreen->NetInit ("Waiting for players", numplayers); // Wait for numplayers-1 different connections - if (!StartScreen->NetLoop (Host_CheckForConnects, (void *)(intptr_t)numplayers)) + if (!StartScreen->NetLoop([&] { return Host_CheckForConnects(); })) { + SendAbort(); exit (0); } @@ -707,18 +712,17 @@ void HostGame (int i) StartScreen->NetMessage ("Sending all here."); StartScreen->NetInit ("Done waiting", 1); - if (!StartScreen->NetLoop (Host_SendAllHere, (void *)gotack)) + if (!StartScreen->NetLoop([&] { return Host_SendAllHere(gotack); })) { + SendAbort(); exit (0); } - popterm (); - // Now go StartScreen->NetMessage ("Go"); packet.Fake = PRE_FAKE; packet.Message = PRE_GO; - for (node = 1; node < doomcom.numnodes; node++) + for (node = 1; node < numnodes; node++) { // If we send the packets eight times to each guest, // hopefully at least one of them will get through. @@ -728,13 +732,12 @@ void HostGame (int i) } } - StartScreen->NetMessage ("Total players: %d", doomcom.numnodes); + StartScreen->NetMessage ("Total players: %d", numnodes); - doomcom.id = DOOMCOM_ID; - doomcom.numplayers = doomcom.numnodes; + numplayers = numnodes; // On the host, each player's number is the same as its node number - for (i = 0; i < doomcom.numnodes; ++i) + for (i = 0; i < numnodes; ++i) { sendplayer[i] = i; } @@ -744,7 +747,7 @@ void HostGame (int i) // Once that host acknowledges receipt of the notification, this routine // is never called again. -bool Guest_ContactHost (void *userdata) +bool DoomComImpl::Guest_ContactHost() { sockaddr_in *from; PreGamePacket packet; @@ -768,12 +771,12 @@ bool Guest_ContactHost (void *userdata) } else if (packet.Message == PRE_DISCONNECT) { - doomcom.numnodes = 0; + numnodes = 0; I_FatalError ("The host cancelled the game."); } else if (packet.Message == PRE_ALLFULL) { - doomcom.numnodes = 0; + numnodes = 0; I_FatalError ("The game is full."); } } @@ -785,7 +788,7 @@ bool Guest_ContactHost (void *userdata) return false; } -bool Guest_WaitForOthers (void *userdata) +bool DoomComImpl::Guest_WaitForOthers() { sockaddr_in *from; PreGamePacket packet; @@ -803,14 +806,14 @@ bool Guest_WaitForOthers (void *userdata) break; case PRE_ALLHERE: - if (doomcom.numnodes == 2) + if (numnodes == 2) { int node; - doomcom.numnodes = packet.NumNodes + 2; + numnodes = packet.NumNodes + 2; sendplayer[0] = packet.ConsoleNum; // My player number - doomcom.consoleplayer = packet.ConsoleNum; - StartScreen->NetMessage ("Console player number: %d", doomcom.consoleplayer); + consoleplayer = packet.ConsoleNum; + StartScreen->NetMessage ("Console player number: %d", consoleplayer); for (node = 0; node < packet.NumNodes; node++) { sendaddress[node+2].sin_addr.s_addr = packet.machines[node].address; @@ -847,7 +850,7 @@ bool Guest_WaitForOthers (void *userdata) return false; } -void JoinGame (int i) +void DoomComImpl::JoinGame(int i) { if ((i == Args->NumArgs() - 1) || (Args->GetArg(i+1)[0] == '-') || @@ -859,36 +862,33 @@ void JoinGame (int i) // Host is always node 1 BuildAddress (&sendaddress[1], Args->GetArg(i+1)); sendplayer[1] = 0; - doomcom.numnodes = 2; - - atterm (SendAbort); + numnodes = 2; // Let host know we are here StartScreen->NetInit ("Contacting host", 0); - if (!StartScreen->NetLoop (Guest_ContactHost, NULL)) + if (!StartScreen->NetLoop([&] { return Guest_ContactHost(); })) { + SendAbort(); exit (0); } // Wait for everyone else to connect - if (!StartScreen->NetLoop (Guest_WaitForOthers, 0)) + if (!StartScreen->NetLoop([&] { return Guest_WaitForOthers(); })) { + SendAbort(); exit (0); } - popterm (); + StartScreen->NetMessage ("Total players: %d", numnodes); - StartScreen->NetMessage ("Total players: %d", doomcom.numnodes); - - doomcom.id = DOOMCOM_ID; - doomcom.numplayers = doomcom.numnodes; + numplayers = numnodes; } -static int PrivateNetOf(in_addr in) +int DoomComImpl::PrivateNetOf(in_addr in) { int addr = ntohl(in.s_addr); - if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0 + if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0 { return 0xC0A80000; } @@ -908,14 +908,8 @@ static int PrivateNetOf(in_addr in) return 0; } -// -// NodesOnSameNetwork -// -// The best I can really do here is check if the others are on the same -// private network, since that means we (probably) are too. -// - -static bool NodesOnSameNetwork() +// The best I can really do here is check if the others are on the same private network, since that means we (probably) are too. +bool DoomComImpl::NodesOnSameNetwork() { int net1; @@ -925,7 +919,7 @@ static bool NodesOnSameNetwork() { return false; } - for (int i = 2; i < doomcom.numnodes; ++i) + for (int i = 2; i < numnodes; ++i) { int net = PrivateNetOf(sendaddress[i].sin_addr); // Printf("Net[%d] = %08x\n", i, net); @@ -937,29 +931,11 @@ static bool NodesOnSameNetwork() return true; } -// -// I_InitNetwork -// -// Returns true if packet server mode might be a good idea. -// -bool I_InitNetwork (void) +DoomComImpl::DoomComImpl() { int i; const 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; - } - v = Args->CheckValue ("-port"); if (v) { @@ -983,32 +959,9 @@ bool I_InitNetwork (void) // single player game netgame = false; multiplayer = false; - doomcom.id = DOOMCOM_ID; - doomcom.numplayers = doomcom.numnodes = 1; - doomcom.consoleplayer = 0; - return false; + numplayers = numnodes = 1; + consoleplayer = 0; } - if (doomcom.numnodes < 3) - { // Packet server mode with only two players is effectively the same as - // peer-to-peer but with some slightly larger packets. - return false; - } - return doomcom.numnodes > 3 || !NodesOnSameNetwork(); -} - - -void I_NetCmd (void) -{ - if (doomcom.command == CMD_SEND) - { - PacketSend (); - } - else if (doomcom.command == CMD_GET) - { - PacketGet (); - } - else - I_Error ("Bad net cmd: %i\n",doomcom.command); } #ifdef __WIN32__ diff --git a/src/i_net.h b/src/i_net.h index 124116cf5c..e3402425d1 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -1,8 +1,41 @@ -#ifndef __I_NET_H__ -#define __I_NET_H__ -// Called by D_DoomMain. -bool I_InitNetwork (void); -void I_NetCmd (void); +#pragma once -#endif +#include + +#define MAX_MSGLEN 14000 + +struct NetPacket +{ + NetPacket() { memset(data, 0, sizeof(data)); } + + // packet data to be sent + uint8_t data[MAX_MSGLEN]; + + // bytes in data to be sent + int16_t datalength = 0; + + // dest for send, set by get (-1 = no packet). + int16_t remotenode = 0; + + uint8_t &operator[](int i) { return data[i]; } + const uint8_t &operator[](int i) const { return data[i]; } +}; + +// Network packet data. +struct doomcom_t +{ + virtual ~doomcom_t() { } + + virtual void PacketSend(const NetPacket &packet) = 0; + virtual void PacketGet(NetPacket &packet) = 0; + + // info common to all nodes + int16_t numnodes = 0; // console is always node 0. + + // info specific to this node + int16_t consoleplayer = 0; + int16_t numplayers = 0; +}; + +std::unique_ptr I_InitNetwork(); diff --git a/src/info.cpp b/src/info.cpp index 28feeb826e..73c9713bd1 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -594,17 +594,17 @@ static void SummonActor (int command, int command2, FCommandLine argv) Printf ("Unknown actor '%s'\n", argv[1]); return; } - Net_WriteByte (argv.argc() > 2 ? command2 : command); - Net_WriteString (type->TypeName.GetChars()); + network.Net_WriteByte (argv.argc() > 2 ? command2 : command); + network.Net_WriteString (type->TypeName.GetChars()); if (argv.argc () > 2) { - Net_WriteWord (atoi (argv[2])); // angle - Net_WriteWord ((argv.argc() > 3) ? atoi(argv[3]) : 0); // TID - Net_WriteByte ((argv.argc() > 4) ? atoi(argv[4]) : 0); // special + network.Net_WriteWord (atoi (argv[2])); // angle + network.Net_WriteWord ((argv.argc() > 3) ? atoi(argv[3]) : 0); // TID + network.Net_WriteByte ((argv.argc() > 4) ? atoi(argv[4]) : 0); // special for (int i = 5; i < 10; i++) { // args[5] - Net_WriteLong((i < argv.argc()) ? atoi(argv[i]) : 0); + network.Net_WriteLong((i < argv.argc()) ? atoi(argv[i]) : 0); } } } diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index bc052b5dde..d921e2569e 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -809,7 +809,7 @@ bool DIntermissionController::Responder (event_t *ev) int res = mScreen->Responder(ev); if (res == -1 && !mSentAdvance) { - Net_WriteByte(DEM_ADVANCEINTER); + network.Net_WriteByte(DEM_ADVANCEINTER); mSentAdvance = true; } return !!res; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index ffba7a806d..dd08f492a1 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -701,6 +701,6 @@ CCMD (mdk) return; const char *name = argv.argc() > 1 ? argv[1] : ""; - Net_WriteByte (DEM_MDK); - Net_WriteString(name); + network.Net_WriteByte (DEM_MDK); + network.Net_WriteString(name); } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 37903021ea..f0f17bedbb 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -695,17 +695,17 @@ DEFINE_ACTION_FUNCTION(DConversationMenu, SendConversationReply) switch (node) { case -1: - Net_WriteByte(DEM_CONVNULL); + network.Net_WriteByte(DEM_CONVNULL); break; case -2: - Net_WriteByte(DEM_CONVCLOSE); + network.Net_WriteByte(DEM_CONVCLOSE); break; default: - Net_WriteByte(DEM_CONVREPLY); - Net_WriteWord(node); - Net_WriteByte(reply); + network.Net_WriteByte(DEM_CONVREPLY); + network.Net_WriteWord(node); + network.Net_WriteByte(reply); break; } StaticLastReply = reply; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 4de850900d..760dbd4676 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1981,8 +1981,8 @@ CCMD (kill) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_MASSACRE); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_MASSACRE); } else if (!stricmp (argv[1], "baddies")) { @@ -1990,13 +1990,13 @@ CCMD (kill) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_MASSACRE2); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (CHT_MASSACRE2); } else { - Net_WriteByte (DEM_KILLCLASSCHEAT); - Net_WriteString (argv[1]); + network.Net_WriteByte (DEM_KILLCLASSCHEAT); + network.Net_WriteString (argv[1]); } } else @@ -2006,7 +2006,7 @@ CCMD (kill) return; // Kill the player - Net_WriteByte (DEM_SUICIDE); + network.Net_WriteByte (DEM_SUICIDE); } C_HideConsole (); } @@ -2018,8 +2018,8 @@ CCMD(remove) if (CheckCheatmode()) return; - Net_WriteByte(DEM_REMOVE); - Net_WriteString(argv[1]); + network.Net_WriteByte(DEM_REMOVE); + network.Net_WriteString(argv[1]); C_HideConsole(); } else @@ -2027,5 +2027,4 @@ CCMD(remove) Printf("Usage: remove \n"); return; } - } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 001b39be83..a6e6b56c3c 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3088,7 +3088,7 @@ FUNC(LS_Autosave) if (gameaction != ga_savegame) { level.flags2 &= ~LEVEL2_NOAUTOSAVEHINT; - Net_WriteByte (DEM_CHECKAUTOSAVE); + network.Net_WriteByte (DEM_CHECKAUTOSAVE); } return true; } diff --git a/src/p_user.cpp b/src/p_user.cpp index d622827bae..830462c9db 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -602,7 +602,7 @@ void player_t::SetFOV(float fov) { if (consoleplayer == Net_Arbitrator) { - Net_WriteByte(DEM_MYFOV); + network.Net_WriteByte(DEM_MYFOV); } else { @@ -612,9 +612,9 @@ void player_t::SetFOV(float fov) } else { - Net_WriteByte(DEM_MYFOV); + network.Net_WriteByte(DEM_MYFOV); } - Net_WriteFloat(clamp(fov, 5.f, 179.f)); + network.Net_WriteFloat(clamp(fov, 5.f, 179.f)); } } @@ -734,9 +734,9 @@ void player_t::SendPitchLimits() const { if (this - players == consoleplayer) { - Net_WriteByte(DEM_SETPITCHLIMIT); - Net_WriteByte(Renderer->GetMaxViewPitch(false)); // up - Net_WriteByte(Renderer->GetMaxViewPitch(true)); // down + network.Net_WriteByte(DEM_SETPITCHLIMIT); + network.Net_WriteByte(Renderer->GetMaxViewPitch(false)); // up + network.Net_WriteByte(Renderer->GetMaxViewPitch(true)); // down } } @@ -2453,7 +2453,7 @@ void P_PredictPlayer (player_t *player) return; } - maxtic = maketic; + maxtic = network.maketic; if (gametic == maxtic) { @@ -2504,13 +2504,13 @@ void P_PredictPlayer (player_t *player) act->BlockNode = NULL; // Values too small to be usable for lerping can be considered "off". - bool CanLerp = (!(cl_predict_lerpscale < 0.01f) && (ticdup == 1)), DoLerp = false, NoInterpolateOld = R_GetViewInterpolationStatus(); + bool CanLerp = (!(cl_predict_lerpscale < 0.01f) && (network.ticdup == 1)), DoLerp = false, NoInterpolateOld = R_GetViewInterpolationStatus(); for (int i = gametic; i < maxtic; ++i) { if (!NoInterpolateOld) R_RebuildViewInterpolation(player); - player->cmd = localcmds[i % LOCALCMDTICS]; + player->cmd = network.localcmds[i % LOCALCMDTICS]; P_PlayerThink (player); player->mo->Tick (); diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp index 7517083c5e..f7a23a77ac 100644 --- a/src/polyrenderer/poly_renderer.cpp +++ b/src/polyrenderer/poly_renderer.cpp @@ -111,8 +111,6 @@ void PolyRenderer::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int void PolyRenderer::RenderActorView(AActor *actor, bool dontmaplines) { - NetUpdate(); - DontMapLines = dontmaplines; R_SetupFrame(Viewpoint, Viewwindow, actor); @@ -147,8 +145,6 @@ void PolyRenderer::RenderActorView(AActor *actor, bool dontmaplines) Viewpoint.camera->renderflags = savedflags; interpolator.RestoreInterpolations (); - - NetUpdate(); } void PolyRenderer::RenderRemainingPlayerSprites() diff --git a/src/posix/cocoa/st_start.mm b/src/posix/cocoa/st_start.mm index 6ce48e8071..97a9e6188c 100644 --- a/src/posix/cocoa/st_start.mm +++ b/src/posix/cocoa/st_start.mm @@ -72,7 +72,7 @@ public: virtual void NetProgress(int count); virtual void NetMessage(const char *format, ...); virtual void NetDone(); - virtual bool NetLoop(bool (*timerCallback)(void*), void* userData); + virtual bool NetLoop(std::function callback); }; @@ -154,11 +154,11 @@ void FBasicStartupScreen::NetDone() FConsoleWindow::GetInstance().NetDone(); } -bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData) +bool FBasicStartupScreen::NetLoop(std::function callback) { while (true) { - if (timerCallback(userData)) + if (callback()) { break; } diff --git a/src/posix/sdl/st_start.cpp b/src/posix/sdl/st_start.cpp index 060548b53b..7ea591b3cf 100644 --- a/src/posix/sdl/st_start.cpp +++ b/src/posix/sdl/st_start.cpp @@ -59,7 +59,7 @@ class FTTYStartupScreen : public FStartupScreen void NetProgress(int count); void NetMessage(const char *format, ...); // cover for printf void NetDone(); - bool NetLoop(bool (*timer_callback)(void *), void *userdata); + bool NetLoop(std::function callback); protected: bool DidNetInit; int NetMaxPos, NetCurPos; @@ -305,7 +305,7 @@ void FTTYStartupScreen::NetProgress(int count) // //=========================================================================== -bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) +bool FTTYStartupScreen::NetLoop(std::function callback) { fd_set rfds; struct timeval tv; @@ -329,7 +329,7 @@ bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) } else if (retval == 0) { - if (timer_callback (userdata)) + if (callback()) { fputc ('\n', stderr); return true; diff --git a/src/st_start.h b/src/st_start.h index a55b471977..f542b4af51 100644 --- a/src/st_start.h +++ b/src/st_start.h @@ -35,6 +35,8 @@ ** Actual implementation is system-specific. */ +#include + class FStartupScreen { public: @@ -51,7 +53,7 @@ public: virtual void NetProgress(int count); virtual void NetMessage(const char *format, ...); // cover for printf virtual void NetDone(); - virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata); + virtual bool NetLoop(std::function callback); protected: int MaxPos, CurPos, NotchPos; }; diff --git a/src/st_stuff.cpp b/src/st_stuff.cpp index fe96d62655..aed2681c20 100644 --- a/src/st_stuff.cpp +++ b/src/st_stuff.cpp @@ -433,8 +433,8 @@ static bool CheatAddKey (cheatseq_t *cheat, uint8_t key, bool *eat) static bool Cht_Generic (cheatseq_t *cheat) { - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (cheat->Args[0]); + network.Net_WriteByte (DEM_GENERICCHEAT); + network.Net_WriteByte (cheat->Args[0]); return true; } diff --git a/src/statistics.cpp b/src/statistics.cpp index 447352f862..e701f33ca0 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -599,7 +599,7 @@ CCMD(finishgame) return; } // This CCMD simulates an end-of-game action and exists to end mods that never exit their last level. - Net_WriteByte(DEM_FINISHGAME); + network.Net_WriteByte(DEM_FINISHGAME); } ADD_STAT(statistics) diff --git a/src/swrenderer/line/r_renderdrawsegment.cpp b/src/swrenderer/line/r_renderdrawsegment.cpp index f46fbc1331..0000b25432 100644 --- a/src/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/swrenderer/line/r_renderdrawsegment.cpp @@ -85,9 +85,6 @@ namespace swrenderer return; } - if (Thread->MainThread) - NetUpdate(); - frontsector = curline->frontsector; backsector = curline->backsector; diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index 0b9c9131d9..f65db302d4 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -373,9 +373,6 @@ namespace swrenderer WallSampler sampler(Thread->Viewport.get(), y1, texturemid, swal[x], yrepeat, lwal[x] + xoffset, xmagnitude, rw_pic); Draw1Column(x, y1, y2, sampler); } - - if (Thread->MainThread) - NetUpdate(); } void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal) diff --git a/src/swrenderer/plane/r_visibleplane.cpp b/src/swrenderer/plane/r_visibleplane.cpp index 185b567109..37298ec6ac 100644 --- a/src/swrenderer/plane/r_visibleplane.cpp +++ b/src/swrenderer/plane/r_visibleplane.cpp @@ -142,7 +142,5 @@ namespace swrenderer renderer.Render(this, xscale, yscale, alpha, additive, masked, colormap, tex); } } - if (thread->MainThread) - NetUpdate(); } } diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index a22232dbf7..68ca20f2ac 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -451,14 +451,8 @@ namespace swrenderer int prevuniq2 = CurrentPortalUniq; CurrentPortalUniq = prevuniq; - if (Thread->MainThread) - NetUpdate(); - Thread->TranslucentPass->Render(); // this is required since with portals there often will be cases when more than 80% of the view is inside a portal. - if (Thread->MainThread) - NetUpdate(); - Thread->Clip3D->LeaveSkybox(); // pop 3D floor height map CurrentPortalUniq = prevuniq2; diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 8c0b81cefc..3c83783712 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -145,8 +145,6 @@ namespace swrenderer CameraLight::Instance()->SetCamera(MainThread()->Viewport->viewpoint, MainThread()->Viewport->RenderTarget, actor); MainThread()->Viewport->SetupFreelook(); - NetUpdate(); - this->dontmaplines = dontmaplines; // [RH] Setup particles for this frame @@ -277,9 +275,6 @@ namespace swrenderer thread->OpaquePass->RenderScene(); thread->Clip3D->ResetClip(); // reset clips (floor/ceiling) - if (thread->MainThread) - NetUpdate(); - if (viewactive) { thread->PlaneList->Render(); @@ -287,13 +282,7 @@ namespace swrenderer thread->Portal->RenderPlanePortals(); thread->Portal->RenderLinePortals(); - if (thread->MainThread) - NetUpdate(); - thread->TranslucentPass->Render(); - - if (thread->MainThread) - NetUpdate(); } DrawerThreads::Execute(thread->DrawQueue); diff --git a/src/swrenderer/things/r_playersprite.cpp b/src/swrenderer/things/r_playersprite.cpp index 924c7a7d82..970385e32d 100644 --- a/src/swrenderer/things/r_playersprite.cpp +++ b/src/swrenderer/things/r_playersprite.cpp @@ -551,8 +551,5 @@ namespace swrenderer drawerargs.DrawMaskedColumn(thread, x, iscale, pic, frac + xiscale / 2, spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, RenderStyle, false); frac += xiscale; } - - if (thread->MainThread) - NetUpdate(); } } diff --git a/src/swrenderer/things/r_sprite.cpp b/src/swrenderer/things/r_sprite.cpp index be26ad7c2e..0d926a20c6 100644 --- a/src/swrenderer/things/r_sprite.cpp +++ b/src/swrenderer/things/r_sprite.cpp @@ -371,8 +371,5 @@ namespace swrenderer } } } - - if (thread->MainThread) - NetUpdate(); } } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 32f908d034..59f8c6ccf3 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -177,11 +177,6 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) #ifndef NO_SWRENDER SWCanvas::DrawTexture(this, img, parms); #endif - - if (ticdup != 0 && menuactive == MENU_Off) - { - NetUpdate(); - } } void DCanvas::SetClipRect(int x, int y, int w, int h) diff --git a/src/win32/st_start.cpp b/src/win32/st_start.cpp index 98034f002a..6e0e95393d 100644 --- a/src/win32/st_start.cpp +++ b/src/win32/st_start.cpp @@ -124,7 +124,7 @@ public: void NetProgress(int count); void NetMessage(const char *format, ...); // cover for printf void NetDone(); - bool NetLoop(bool (*timer_callback)(void *), void *userdata); + bool NetLoop(std::function callback); protected: LRESULT NetMarqueeMode; int NetMaxPos, NetCurPos; @@ -531,7 +531,7 @@ void FBasicStartupScreen :: NetProgress(int count) // //========================================================================== -bool FBasicStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) +bool FBasicStartupScreen::NetLoop(std::function callback) { BOOL bRet; MSG msg; @@ -552,7 +552,7 @@ bool FBasicStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata { if (msg.message == WM_TIMER && msg.hwnd == Window && msg.wParam == 1337) { - if (timer_callback (userdata)) + if (callback()) { KillTimer (NetStartPane, 1); return true; From 6ae64a866bb2de8e4a8be195ae82f894965c9985 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 24 Mar 2018 00:35:27 +0100 Subject: [PATCH 02/17] - Rename consistancy to consistency --- src/d_net.cpp | 8 ++++---- src/d_net.h | 4 ++-- src/d_protocol.cpp | 8 ++++---- src/d_protocol.h | 2 +- src/g_game.cpp | 12 ++++++------ src/hu_scores.cpp | 2 +- src/m_random.cpp | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index f5df285582..fd730e1589 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -278,7 +278,7 @@ void Network::Net_ClearBuffers() memset (resendcount, 0, sizeof(resendcount)); memset (lastrecvtime, 0, sizeof(lastrecvtime)); memset (currrecvtime, 0, sizeof(currrecvtime)); - memset (consistancy, 0, sizeof(consistancy)); + memset (consistency, 0, sizeof(consistency)); nodeingame[0] = true; for (int i = 0; i < MAXPLAYERS; i++) @@ -580,7 +580,7 @@ bool Network::HGetPacket() fprintf (debugfile, "%c%2x", i==k?'|':' ', ((uint8_t *)netbuffer.data)[i]); if (numtics) fprintf (debugfile, " <<%4x>>\n", - consistancy[playerfornode[netbuffer.remotenode]][nettics[netbuffer.remotenode]%BACKUPTICS] & 0xFFFF); + consistency[playerfornode[netbuffer.remotenode]][nettics[netbuffer.remotenode]%BACKUPTICS] & 0xFFFF); else fprintf (debugfile, "\n"); } @@ -1169,7 +1169,7 @@ void Network::NetUpdate() // the other players. if (l == 0) { - WriteWord (localcmds[localstart].consistancy, &cmddata); + WriteWord (localcmds[localstart].consistency, &cmddata); // [RH] Write out special "ticcmds" before real ticcmd if (specials.used[start]) { @@ -1184,7 +1184,7 @@ void Network::NetUpdate() int len; uint8_t *spec; - WriteWord (netcmds[playerbytes[l]][start].consistancy, &cmddata); + WriteWord (netcmds[playerbytes[l]][start].consistency, &cmddata); spec = NetSpecs[playerbytes[l]][start].GetData (&len); if (spec != NULL) { diff --git a/src/d_net.h b/src/d_net.h index 2e9856187e..6738f98d86 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -102,7 +102,7 @@ public: void Net_WriteString(const char *it); void Net_WriteBytes(const uint8_t *block, int len); - short consistancy[MAXPLAYERS][BACKUPTICS]; + short consistency[MAXPLAYERS][BACKUPTICS]; FDynamicBuffer NetSpecs[MAXPLAYERS][BACKUPTICS]; ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; @@ -185,7 +185,7 @@ void Net_SkipCommand (int type, uint8_t **stream); // - The first player's consolenum is not included in this list, because it always matches the sender // // For each tic: -// Two bytes with consistancy check, followed by tic data +// Two bytes with consistency check, followed by tic data // // Setup packets are different, and are described just before D_ArbitrateNetStart(). diff --git a/src/d_protocol.cpp b/src/d_protocol.cpp index 4542c4c43a..2bb1d4764c 100644 --- a/src/d_protocol.cpp +++ b/src/d_protocol.cpp @@ -291,7 +291,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, ticcmd_t &cmd, ticcmd_ { if (arc.BeginObject(key)) { - arc("consistency", cmd.consistancy) + arc("consistency", cmd.consistency) ("ucmd", cmd.ucmd) .EndObject(); } @@ -361,7 +361,7 @@ int SkipTicCmd (uint8_t **stream, int count) { bool moreticdata = true; - flow += 2; // Skip consistancy marker + flow += 2; // Skip consistency marker while (moreticdata) { uint8_t type = *flow++; @@ -418,7 +418,7 @@ void ReadTicCmd (uint8_t **stream, int player, int tic) int ticmod = tic % BACKUPTICS; tcmd = &network.netcmds[player][ticmod]; - tcmd->consistancy = ReadWord (stream); + tcmd->consistency = ReadWord (stream); start = *stream; @@ -445,7 +445,7 @@ void ReadTicCmd (uint8_t **stream, int player, int tic) } if (player==consoleplayer&&tic>BACKUPTICS) - assert(network.consistancy[player][ticmod] == tcmd->consistancy); + assert(network.consistency[player][ticmod] == tcmd->consistency); } void RunNetSpecs (int player, int buf) diff --git a/src/d_protocol.h b/src/d_protocol.h index ddae331a60..30853d435d 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -238,7 +238,7 @@ int WriteUserCmdMessage (usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stre struct ticcmd_t { usercmd_t ucmd; - int16_t consistancy; // checks for net game + int16_t consistency; // checks for net game }; int SkipTicCmd (uint8_t **stream, int count); diff --git a/src/g_game.cpp b/src/g_game.cpp index 8ff13e9254..cedd793668 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -574,7 +574,7 @@ void G_BuildTiccmd (ticcmd_t *cmd) base = I_BaseTiccmd (); // empty, or external driver *cmd = *base; - cmd->consistancy = network.consistancy[consoleplayer][(network.maketic/network.ticdup)%BACKUPTICS]; + cmd->consistency = network.consistency[consoleplayer][(network.maketic/network.ticdup)%BACKUPTICS]; strafe = Button_Strafe.bDown; speed = Button_Speed.bDown ^ (int)cl_run; @@ -1149,10 +1149,10 @@ void G_Ticker () } } - // get commands, check consistancy, and build new consistancy check + // get commands, check consistency, and build new consistency check int buf = (gametic/network.ticdup)%BACKUPTICS; - // [RH] Include some random seeds and player stuff in the consistancy + // [RH] Include some random seeds and player stuff in the consistency // check, not just the player's x position like BOOM. uint32_t rngsum = FRandom::StaticSumSeeds (); @@ -1197,7 +1197,7 @@ void G_Ticker () if (netgame && players[i].Bot == NULL && !demoplayback && (gametic%network.ticdup) == 0) { //players[i].inconsistant = 0; - if (gametic > BACKUPTICS*network.ticdup && network.consistancy[i][buf] != cmd->consistancy) + if (gametic > BACKUPTICS*network.ticdup && network.consistency[i][buf] != cmd->consistency) { players[i].inconsistant = gametic - BACKUPTICS*network.ticdup; } @@ -1205,11 +1205,11 @@ void G_Ticker () { uint32_t sum = rngsum + int((players[i].mo->X() + players[i].mo->Y() + players[i].mo->Z())*257) + players[i].mo->Angles.Yaw.BAMs() + players[i].mo->Angles.Pitch.BAMs(); sum ^= players[i].health; - network.consistancy[i][buf] = sum; + network.consistency[i][buf] = sum; } else { - network.consistancy[i][buf] = rngsum; + network.consistency[i][buf] = rngsum; } } } diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index 8a384c4bf2..c9c3c1116c 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -407,7 +407,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, { // The teamplay mode uses colors to show teams, so we need some // other way to do highlighting. And it may as well be used for - // all modes for the sake of consistancy. + // all modes for the sake of consistency. screen->Dim(MAKERGB(200,245,255), 0.125f, col1 - 12*CleanXfac, y - 1, col5 + (maxnamewidth + 24)*CleanXfac, height + 2); } diff --git a/src/m_random.cpp b/src/m_random.cpp index ecb2bfe9e7..24d4e34d23 100644 --- a/src/m_random.cpp +++ b/src/m_random.cpp @@ -270,7 +270,7 @@ void FRandom::Init(uint32_t seed) // // FRandom :: StaticSumSeeds // -// This function produces a uint32_t that can be used to check the consistancy +// This function produces a uint32_t that can be used to check the consistency // of network games between different machines. Only a select few RNGs are // used for the sum, because not all RNGs are important to network sync. // From 8f1bc32d1284fd1c302ee1d0237a96cd8468f0fb Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 24 Mar 2018 16:00:45 +0100 Subject: [PATCH 03/17] - Isolate network buffer access to the Network class and make the buffers private --- src/b_think.cpp | 24 +++--- src/d_main.cpp | 26 +----- src/d_net.cpp | 163 ++++++++++++++++++++++++++++++++++-- src/d_net.h | 44 +++++++--- src/d_protocol.cpp | 62 -------------- src/d_protocol.h | 18 ++-- src/g_game.cpp | 111 +++++++++++------------- src/g_shared/shared_hud.cpp | 9 +- src/hu_scores.cpp | 9 +- src/p_user.cpp | 2 +- src/posix/cocoa/i_system.mm | 10 --- src/posix/i_system.h | 11 --- src/posix/sdl/i_system.cpp | 6 -- src/win32/i_system.cpp | 15 ---- src/win32/i_system.h | 10 --- 15 files changed, 263 insertions(+), 257 deletions(-) diff --git a/src/b_think.cpp b/src/b_think.cpp index a80c32c77d..c77a20cb70 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -63,9 +63,7 @@ static FRandom pr_botmove ("BotMove"); //so this is what the bot does. void DBot::Think () { - ticcmd_t *cmd = &network.netcmds[player - players][((gametic + 1)/ network.ticdup)%BACKUPTICS]; - - memset (cmd, 0, sizeof(*cmd)); + ticcmd_t cmd; if (enemy && enemy->health <= 0) enemy = NULL; @@ -80,16 +78,16 @@ void DBot::Think () DAngle oldpitch = actor->Angles.Pitch; Set_enemy (); - ThinkForMove (cmd); + ThinkForMove (&cmd); TurnToAng (); - cmd->ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees * (65536 / 360.f)) / network.ticdup; - cmd->ucmd.pitch = (short)((oldpitch - actor->Angles.Pitch).Degrees * (65536 / 360.f)); - if (cmd->ucmd.pitch == -32768) - cmd->ucmd.pitch = -32767; - cmd->ucmd.pitch /= network.ticdup; - actor->Angles.Yaw = oldyaw + DAngle(cmd->ucmd.yaw * network.ticdup * (360 / 65536.f)); - actor->Angles.Pitch = oldpitch - DAngle(cmd->ucmd.pitch * network.ticdup * (360 / 65536.f)); + cmd.ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees * (65536 / 360.f)) / network.ticdup; + cmd.ucmd.pitch = (short)((oldpitch - actor->Angles.Pitch).Degrees * (65536 / 360.f)); + if (cmd.ucmd.pitch == -32768) + cmd.ucmd.pitch = -32767; + cmd.ucmd.pitch /= network.ticdup; + actor->Angles.Yaw = oldyaw + DAngle(cmd.ucmd.yaw * network.ticdup * (360 / 65536.f)); + actor->Angles.Pitch = oldpitch - DAngle(cmd.ucmd.pitch * network.ticdup * (360 / 65536.f)); } if (t_active) t_active--; @@ -106,8 +104,10 @@ void DBot::Think () } else if (player->mo->health <= 0) { // Time to respawn - cmd->ucmd.buttons |= BT_USE; + cmd.ucmd.buttons |= BT_USE; } + + network.SetBotCommand((int)(player - players), cmd); } #define THINKDISTSQ (50000.*50000./(65536.*65536.)) diff --git a/src/d_main.cpp b/src/d_main.cpp index 3efdf79662..f0518be6d4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -144,7 +144,7 @@ const FIWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const c // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- void D_ProcessEvents (); -void G_BuildTiccmd (ticcmd_t* cmd); +ticcmd_t G_BuildTiccmd (); void D_DoAdvanceDemo (); void D_AddWildFile (TArray &wadfiles, const char *pattern); void D_LoadWadSettings (); @@ -1042,28 +1042,8 @@ void D_DoomLoop () } I_SetFrameTime(); - // process one or more tics - if (singletics) - { - I_StartTic (); - D_ProcessEvents (); - G_BuildTiccmd (&network.netcmds[consoleplayer][network.maketic%BACKUPTICS]); - if (advancedemo) - D_DoAdvanceDemo (); - C_Ticker (); - M_Ticker (); - G_Ticker (); - // [RH] Use the consoleplayer's camera to update sounds - S_UpdateSounds (players[consoleplayer].camera); // move positional sounds - gametic++; - network.maketic++; - GC::CheckGC (); - network.Net_NewMakeTic (); - } - else - { - network.TryRunTics (); // will run at least one tic - } + network.TryRunTics(); + // Update display, next frame, with current state. I_StartTic (); D_Display (); diff --git a/src/d_net.cpp b/src/d_net.cpp index fd730e1589..59e9f26d1c 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -96,7 +96,7 @@ extern FString savegamefile; #define PL_DRONE 0x80 // bit flag in doomdata->player void D_ProcessEvents (void); -void G_BuildTiccmd (ticcmd_t *cmd); +ticcmd_t G_BuildTiccmd (); void D_DoAdvanceDemo (void); static void RunScript(uint8_t **stream, APlayerPawn *pawn, int snum, int argn, int always); @@ -831,19 +831,20 @@ void Network::GetPackets() // update command store from the packet { - uint8_t *start; - int i, tics; remoteresend[netnode] = false; - start = &netbuffer[k]; + uint8_t *start = &netbuffer[k]; - for (i = 0; i < numplayers; ++i) + for (int i = 0; i < numplayers; ++i) { int node = nodeforplayer[playerbytes[i]]; SkipTicCmd (&start, nettics[node] - realstart); - for (tics = nettics[node]; tics < realend; tics++) - ReadTicCmd (&start, playerbytes[i], tics); + + for (int tic = nettics[node]; tic < realend; tic++) + { + ReadTicCmd(&start, playerbytes[i], tic); + } nettics[nodeforplayer[playerbytes[i]]] = realend; } @@ -851,6 +852,77 @@ void Network::GetPackets() } } +void Network::ReadTicCmd(uint8_t **stream, int player, int tic) +{ + int type; + uint8_t *start; + ticcmd_t *tcmd; + + int ticmod = tic % BACKUPTICS; + + tcmd = &netcmds[player][ticmod]; + tcmd->consistency = ReadWord(stream); + + start = *stream; + + while ((type = ReadByte(stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD) + Net_SkipCommand(type, stream); + + NetSpecs[player][ticmod].SetData(start, int(*stream - start - 1)); + + if (type == DEM_USERCMD) + { + UnpackUserCmd(&tcmd->ucmd, tic ? &netcmds[player][(tic - 1) % BACKUPTICS].ucmd : NULL, stream); + } + else + { + if (tic) + { + memcpy(&tcmd->ucmd, &netcmds[player][(tic - 1) % BACKUPTICS].ucmd, sizeof(tcmd->ucmd)); + } + else + { + memset(&tcmd->ucmd, 0, sizeof(tcmd->ucmd)); + } + } + + if (player == consoleplayer && tic>BACKUPTICS) + assert(consistency[player][ticmod] == tcmd->consistency); +} + +void Network::RunNetSpecs(int player) +{ + if (gametic % ticdup == 0) + { + int buf = (gametic / network.ticdup) % BACKUPTICS; + + int len = 0; + uint8_t *stream = NetSpecs[player][buf].GetData(&len); + if (stream) + { + uint8_t *end = stream + len; + while (stream < end) + { + int type = ReadByte(&stream); + Net_DoCommand(type, &stream, player); + } + if (!demorecording) + NetSpecs[player][buf].SetData(nullptr, 0); + } + } +} + +void Network::SetBotCommand(int player, const ticcmd_t &cmd) +{ + netcmds[player][((gametic + 1) / network.ticdup) % BACKUPTICS] = cmd; +} + +ticcmd_t Network::GetPlayerCommand(int player) const +{ + int buf = (gametic / network.ticdup) % BACKUPTICS; + return netcmds[player][buf]; +} + // Builds ticcmds for console player, sends out a packet void Network::NetUpdate() { @@ -900,7 +972,7 @@ void Network::NetUpdate() break; // can't hold any more //Printf ("mk:%i ",maketic); - G_BuildTiccmd (&localcmds[maketic % LOCALCMDTICS]); + localcmds[maketic % LOCALCMDTICS] = G_BuildTiccmd(); maketic++; if (ticdup == 1 || maketic == 0) @@ -1711,6 +1783,25 @@ void Network::TryRunTics() int counts; int numplaying; + if (singletics) + { + I_StartTic(); + D_ProcessEvents(); + netcmds[consoleplayer][maketic%BACKUPTICS] = G_BuildTiccmd(); + if (advancedemo) + D_DoAdvanceDemo(); + C_Ticker(); + M_Ticker(); + G_Ticker(); + // [RH] Use the consoleplayer's camera to update sounds + S_UpdateSounds(players[consoleplayer].camera); // move positional sounds + gametic++; + maketic++; + GC::CheckGC(); + Net_NewMakeTic(); + return; + } + // If paused, do not eat more CPU time than we need, because it // will all be wasted anyway. if (pauseext) @@ -1929,6 +2020,62 @@ void Network::Net_WriteBytes(const uint8_t *block, int len) specials << *block++; } +bool Network::IsInconsistent(int player, int16_t checkvalue) const +{ + int buf = (gametic / ticdup) % BACKUPTICS; + return gametic > BACKUPTICS*ticdup && consistency[player][buf] != checkvalue; +} + +void Network::SetConsistency(int player, int16_t checkvalue) +{ + int buf = (gametic / ticdup) % BACKUPTICS; + consistency[player][buf] = checkvalue; +} + +int16_t Network::GetConsoleConsistency() const +{ + return consistency[consoleplayer][(maketic / ticdup) % BACKUPTICS]; +} + +size_t Network::CopySpecData(int player, uint8_t *dest, size_t dest_size) +{ + if (gametic % ticdup != 0) + return 0; + + int buf = (gametic / ticdup) % BACKUPTICS; + + int speclen = 0; + uint8_t *specdata = NetSpecs[player][buf].GetData(&speclen); + if (!specdata) + return 0; + + if (dest_size < speclen) + I_FatalError("Demo buffer too small for CopySpecData"); + + memcpy(dest, specdata, speclen); + NetSpecs[player][buf].SetData(nullptr, 0); // Why is this needed? + return speclen; +} + +int Network::GetPing(int player) const +{ + int node = nodeforplayer[player]; + int avgdelay = 0; + for (int i = 0; i < BACKUPTICS; i++) + avgdelay += netdelay[node][i]; + return avgdelay * ticdup * 1000 / TICRATE / BACKUPTICS; +} + +int Network::GetServerPing() const +{ + return GetPing(Net_Arbitrator); +} + +int Network::GetHighPingThreshold() const +{ + return ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE); +} + //========================================================================== // // Dynamic buffer interface diff --git a/src/d_net.h b/src/d_net.h index 6738f98d86..c9f1e2a156 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -86,15 +86,17 @@ struct ArbitrateData struct Network { public: + void TryRunTics(); + void NetUpdate(); + void D_CheckNetGame(); + void Net_ClearBuffers(); + void D_QuitNetGame(); + void ListPingTimes(); void Network_Controller(int playernum, bool add); - void Net_ClearBuffers(); - void NetUpdate(); - void D_QuitNetGame(); - void TryRunTics(); - void Net_NewMakeTic(); + void Net_NewMakeTic(); // Only public because DoomMain calls it. Really really shouldn't be public. void Net_WriteByte(uint8_t it); void Net_WriteWord(short it); void Net_WriteLong(int it); @@ -102,18 +104,26 @@ public: void Net_WriteString(const char *it); void Net_WriteBytes(const uint8_t *block, int len); - short consistency[MAXPLAYERS][BACKUPTICS]; + size_t CopySpecData(int player, uint8_t *dest, size_t dest_size); - FDynamicBuffer NetSpecs[MAXPLAYERS][BACKUPTICS]; - ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; - ticcmd_t localcmds[LOCALCMDTICS]; + void SetBotCommand(int player, const ticcmd_t &cmd); + ticcmd_t GetPlayerCommand(int player) const; + + bool IsInconsistent(int player, int16_t checkvalue) const; + void SetConsistency(int player, int16_t checkvalue); + int16_t GetConsoleConsistency() const; + + void RunNetSpecs(int player); + + ticcmd_t GetLocalCommand(int tic) const { return localcmds[tic % LOCALCMDTICS]; } + + int GetPing(int player) const; + int GetServerPing() const; + int GetHighPingThreshold() const; int maketic; int ticdup; // 1 = no duplication, 2-5 = dup for slow nets - int nodeforplayer[MAXPLAYERS]; - int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times. - private: int NetbufferSize(); int ExpandTics(int low); @@ -127,9 +137,19 @@ private: void SendSetup(uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[MAXNETNODES], int len); + void ReadTicCmd(uint8_t **stream, int player, int tic); + std::unique_ptr doomcom; NetPacket netbuffer; + int nodeforplayer[MAXPLAYERS]; + int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times. + + short consistency[MAXPLAYERS][BACKUPTICS]; + ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; + FDynamicBuffer NetSpecs[MAXPLAYERS][BACKUPTICS]; + ticcmd_t localcmds[LOCALCMDTICS]; + int gametime; enum { NET_PeerToPeer, NET_PacketServer }; diff --git a/src/d_protocol.cpp b/src/d_protocol.cpp index 2bb1d4764c..1b32a26a63 100644 --- a/src/d_protocol.cpp +++ b/src/d_protocol.cpp @@ -408,68 +408,6 @@ int SkipTicCmd (uint8_t **stream, int count) return skip; } -#include -void ReadTicCmd (uint8_t **stream, int player, int tic) -{ - int type; - uint8_t *start; - ticcmd_t *tcmd; - - int ticmod = tic % BACKUPTICS; - - tcmd = &network.netcmds[player][ticmod]; - tcmd->consistency = ReadWord (stream); - - start = *stream; - - while ((type = ReadByte (stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD) - Net_SkipCommand (type, stream); - - network.NetSpecs[player][ticmod].SetData (start, int(*stream - start - 1)); - - if (type == DEM_USERCMD) - { - UnpackUserCmd (&tcmd->ucmd, - tic ? &network.netcmds[player][(tic-1)%BACKUPTICS].ucmd : NULL, stream); - } - else - { - if (tic) - { - memcpy (&tcmd->ucmd, &network.netcmds[player][(tic-1)%BACKUPTICS].ucmd, sizeof(tcmd->ucmd)); - } - else - { - memset (&tcmd->ucmd, 0, sizeof(tcmd->ucmd)); - } - } - - if (player==consoleplayer&&tic>BACKUPTICS) - assert(network.consistency[player][ticmod] == tcmd->consistency); -} - -void RunNetSpecs (int player, int buf) -{ - uint8_t *stream; - int len; - - if (gametic % network.ticdup == 0) - { - stream = network.NetSpecs[player][buf].GetData (&len); - if (stream) - { - uint8_t *end = stream + len; - while (stream < end) - { - int type = ReadByte (&stream); - Net_DoCommand (type, &stream, player); - } - if (!demorecording) - network.NetSpecs[player][buf].SetData (NULL, 0); - } - } -} - uint8_t *lenspot; // Write the header of an IFF chunk and leave space diff --git a/src/d_protocol.h b/src/d_protocol.h index 30853d435d..db95352692 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -63,13 +63,13 @@ struct zdemoheader_s { struct usercmd_t { - uint32_t buttons; - short pitch; // up/down - short yaw; // left/right - short roll; // "tilt" - short forwardmove; - short sidemove; - short upmove; + uint32_t buttons = 0; + short pitch = 0; // up/down + short yaw = 0; // left/right + short roll = 0; // "tilt" + short forwardmove = 0; + short sidemove = 0; + short upmove = 0; }; // When transmitted, the above message is preceded by a byte @@ -238,12 +238,10 @@ int WriteUserCmdMessage (usercmd_t *ucmd, const usercmd_t *basis, uint8_t **stre struct ticcmd_t { usercmd_t ucmd; - int16_t consistency; // checks for net game + int16_t consistency = 0; // checks for net game }; int SkipTicCmd (uint8_t **stream, int count); -void ReadTicCmd (uint8_t **stream, int player, int tic); -void RunNetSpecs (int player, int buf); int ReadByte (uint8_t **stream); int ReadWord (uint8_t **stream); diff --git a/src/g_game.cpp b/src/g_game.cpp index cedd793668..797b95fd4f 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -104,7 +104,7 @@ const int SAVEPICHEIGHT = 162; bool G_CheckDemoStatus (void); void G_ReadDemoTiccmd (ticcmd_t *cmd, int player); -void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf); +void G_WriteDemoTiccmd (ticcmd_t *cmd, int player); void G_PlayerReborn (int player); void G_DoNewGame (void); @@ -561,7 +561,7 @@ static inline int joyint(double val) // or reads it from the demo buffer. // If recording a demo, write it out // -void G_BuildTiccmd (ticcmd_t *cmd) +ticcmd_t G_BuildTiccmd () { int strafe; int speed; @@ -569,12 +569,9 @@ void G_BuildTiccmd (ticcmd_t *cmd) int side; int fly; - ticcmd_t *base; + ticcmd_t cmd; - base = I_BaseTiccmd (); // empty, or external driver - *cmd = *base; - - cmd->consistency = network.consistency[consoleplayer][(network.maketic/network.ticdup)%BACKUPTICS]; + cmd.consistency = network.GetConsoleConsistency(); strafe = Button_Strafe.bDown; speed = Button_Speed.bDown ^ (int)cl_run; @@ -649,32 +646,32 @@ void G_BuildTiccmd (ticcmd_t *cmd) side -= sidemove[speed]; // buttons - if (Button_Attack.bDown) cmd->ucmd.buttons |= BT_ATTACK; - if (Button_AltAttack.bDown) cmd->ucmd.buttons |= BT_ALTATTACK; - if (Button_Use.bDown) cmd->ucmd.buttons |= BT_USE; - if (Button_Jump.bDown) cmd->ucmd.buttons |= BT_JUMP; - if (Button_Crouch.bDown) cmd->ucmd.buttons |= BT_CROUCH; - if (Button_Zoom.bDown) cmd->ucmd.buttons |= BT_ZOOM; - if (Button_Reload.bDown) cmd->ucmd.buttons |= BT_RELOAD; + if (Button_Attack.bDown) cmd.ucmd.buttons |= BT_ATTACK; + if (Button_AltAttack.bDown) cmd.ucmd.buttons |= BT_ALTATTACK; + if (Button_Use.bDown) cmd.ucmd.buttons |= BT_USE; + if (Button_Jump.bDown) cmd.ucmd.buttons |= BT_JUMP; + if (Button_Crouch.bDown) cmd.ucmd.buttons |= BT_CROUCH; + if (Button_Zoom.bDown) cmd.ucmd.buttons |= BT_ZOOM; + if (Button_Reload.bDown) cmd.ucmd.buttons |= BT_RELOAD; - if (Button_User1.bDown) cmd->ucmd.buttons |= BT_USER1; - if (Button_User2.bDown) cmd->ucmd.buttons |= BT_USER2; - if (Button_User3.bDown) cmd->ucmd.buttons |= BT_USER3; - if (Button_User4.bDown) cmd->ucmd.buttons |= BT_USER4; + if (Button_User1.bDown) cmd.ucmd.buttons |= BT_USER1; + if (Button_User2.bDown) cmd.ucmd.buttons |= BT_USER2; + if (Button_User3.bDown) cmd.ucmd.buttons |= BT_USER3; + if (Button_User4.bDown) cmd.ucmd.buttons |= BT_USER4; - if (Button_Speed.bDown) cmd->ucmd.buttons |= BT_SPEED; - if (Button_Strafe.bDown) cmd->ucmd.buttons |= BT_STRAFE; - if (Button_MoveRight.bDown) cmd->ucmd.buttons |= BT_MOVERIGHT; - if (Button_MoveLeft.bDown) cmd->ucmd.buttons |= BT_MOVELEFT; - if (Button_LookDown.bDown) cmd->ucmd.buttons |= BT_LOOKDOWN; - if (Button_LookUp.bDown) cmd->ucmd.buttons |= BT_LOOKUP; - if (Button_Back.bDown) cmd->ucmd.buttons |= BT_BACK; - if (Button_Forward.bDown) cmd->ucmd.buttons |= BT_FORWARD; - if (Button_Right.bDown) cmd->ucmd.buttons |= BT_RIGHT; - if (Button_Left.bDown) cmd->ucmd.buttons |= BT_LEFT; - if (Button_MoveDown.bDown) cmd->ucmd.buttons |= BT_MOVEDOWN; - if (Button_MoveUp.bDown) cmd->ucmd.buttons |= BT_MOVEUP; - if (Button_ShowScores.bDown) cmd->ucmd.buttons |= BT_SHOWSCORES; + if (Button_Speed.bDown) cmd.ucmd.buttons |= BT_SPEED; + if (Button_Strafe.bDown) cmd.ucmd.buttons |= BT_STRAFE; + if (Button_MoveRight.bDown) cmd.ucmd.buttons |= BT_MOVERIGHT; + if (Button_MoveLeft.bDown) cmd.ucmd.buttons |= BT_MOVELEFT; + if (Button_LookDown.bDown) cmd.ucmd.buttons |= BT_LOOKDOWN; + if (Button_LookUp.bDown) cmd.ucmd.buttons |= BT_LOOKUP; + if (Button_Back.bDown) cmd.ucmd.buttons |= BT_BACK; + if (Button_Forward.bDown) cmd.ucmd.buttons |= BT_FORWARD; + if (Button_Right.bDown) cmd.ucmd.buttons |= BT_RIGHT; + if (Button_Left.bDown) cmd.ucmd.buttons |= BT_LEFT; + if (Button_MoveDown.bDown) cmd.ucmd.buttons |= BT_MOVEDOWN; + if (Button_MoveUp.bDown) cmd.ucmd.buttons |= BT_MOVEUP; + if (Button_ShowScores.bDown) cmd.ucmd.buttons |= BT_SHOWSCORES; // Handle joysticks/game controllers. float joyaxes[NUM_JOYAXIS]; @@ -712,7 +709,7 @@ void G_BuildTiccmd (ticcmd_t *cmd) forward += (int)((float)mousey * m_forward); } - cmd->ucmd.pitch = LocalViewPitch >> 16; + cmd.ucmd.pitch = LocalViewPitch >> 16; if (SendLand) { @@ -735,10 +732,10 @@ void G_BuildTiccmd (ticcmd_t *cmd) else if (side < -MAXPLMOVE) side = -MAXPLMOVE; - cmd->ucmd.forwardmove += forward; - cmd->ucmd.sidemove += side; - cmd->ucmd.yaw = LocalViewAngle >> 16; - cmd->ucmd.upmove = fly; + cmd.ucmd.forwardmove += forward; + cmd.ucmd.sidemove += side; + cmd.ucmd.yaw = LocalViewAngle >> 16; + cmd.ucmd.upmove = fly; LocalViewAngle = 0; LocalViewPitch = 0; @@ -746,7 +743,7 @@ void G_BuildTiccmd (ticcmd_t *cmd) if (sendturn180) { sendturn180 = false; - cmd->ucmd.buttons |= BT_TURN180; + cmd.ucmd.buttons |= BT_TURN180; } if (sendpause) { @@ -780,8 +777,10 @@ void G_BuildTiccmd (ticcmd_t *cmd) SendItemDrop = NULL; } - cmd->ucmd.forwardmove <<= 8; - cmd->ucmd.sidemove <<= 8; + cmd.ucmd.forwardmove <<= 8; + cmd.ucmd.sidemove <<= 8; + + return cmd; } //[Graf Zahl] This really helps if the mouse update rate can't be increased! @@ -1149,9 +1148,6 @@ void G_Ticker () } } - // get commands, check consistency, and build new consistency check - int buf = (gametic/network.ticdup)%BACKUPTICS; - // [RH] Include some random seeds and player stuff in the consistency // check, not just the player's x position like BOOM. uint32_t rngsum = FRandom::StaticSumSeeds (); @@ -1164,15 +1160,13 @@ void G_Ticker () if (playeringame[i]) { ticcmd_t *cmd = &players[i].cmd; - ticcmd_t *newcmd = &network.netcmds[i][buf]; + ticcmd_t newcmd = network.GetPlayerCommand(i); + + network.RunNetSpecs(i); - if ((gametic % network.ticdup) == 0) - { - RunNetSpecs (i, buf); - } if (demorecording) { - G_WriteDemoTiccmd (newcmd, i, buf); + G_WriteDemoTiccmd (&newcmd, i); } players[i].oldbuttons = cmd->ucmd.buttons; // If the user alt-tabbed away, paused gets set to -1. In this case, @@ -1184,7 +1178,7 @@ void G_Ticker () } else { - memcpy(cmd, newcmd, sizeof(ticcmd_t)); + *cmd = newcmd; } // check for turbo cheats @@ -1196,8 +1190,7 @@ void G_Ticker () if (netgame && players[i].Bot == NULL && !demoplayback && (gametic%network.ticdup) == 0) { - //players[i].inconsistant = 0; - if (gametic > BACKUPTICS*network.ticdup && network.consistency[i][buf] != cmd->consistency) + if (network.IsInconsistent(i, cmd->consistency)) { players[i].inconsistant = gametic - BACKUPTICS*network.ticdup; } @@ -1205,11 +1198,11 @@ void G_Ticker () { uint32_t sum = rngsum + int((players[i].mo->X() + players[i].mo->Y() + players[i].mo->Z())*257) + players[i].mo->Angles.Yaw.BAMs() + players[i].mo->Angles.Pitch.BAMs(); sum ^= players[i].health; - network.consistency[i][buf] = sum; + network.SetConsistency(i, sum); } else { - network.consistency[i][buf] = rngsum; + network.SetConsistency(i, rngsum); } } } @@ -2453,11 +2446,8 @@ CCMD (stop) extern uint8_t *lenspot; -void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf) +void G_WriteDemoTiccmd (ticcmd_t *cmd, int player) { - uint8_t *specdata; - int speclen; - if (stoprecording) { // use "stop" console command to end demo recording G_CheckDemoStatus (); @@ -2469,12 +2459,7 @@ void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf) } // [RH] Write any special "ticcmds" for this player to the demo - if ((specdata = network.NetSpecs[player][buf].GetData (&speclen)) && gametic % network.ticdup == 0) - { - memcpy (demo_p, specdata, speclen); - demo_p += speclen; - network.NetSpecs[player][buf].SetData (NULL, 0); - } + demo_p += network.CopySpecData(player, demo_p, maxdemosize - (demo_p - demobuffer)); // [RH] Now write out a "normal" ticcmd. WriteUserCmdMessage (&cmd->ucmd, &players[player].cmd.ucmd, &demo_p); diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index faac5610dd..f1c71e69e3 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -1053,11 +1053,8 @@ static void DrawLatency() { return; } - int i, localdelay = 0, arbitratordelay = 0; - for (i = 0; i < BACKUPTICS; i++) localdelay += network.netdelay[0][i]; - for (i = 0; i < BACKUPTICS; i++) arbitratordelay += network.netdelay[network.nodeforplayer[Net_Arbitrator]][i]; - localdelay = ((localdelay / BACKUPTICS) * network.ticdup) * (1000 / TICRATE); - arbitratordelay = ((arbitratordelay / BACKUPTICS) * network.ticdup) * (1000 / TICRATE); + int localdelay = network.GetPing(0); + int arbitratordelay = network.GetServerPing(); int color = CR_GREEN; if (MAX(localdelay, arbitratordelay) > 200) { @@ -1067,7 +1064,7 @@ static void DrawLatency() { color = CR_ORANGE; } - if (MAX(localdelay, arbitratordelay) >= ((BACKUPTICS / 2 - 1) * network.ticdup) * (1000 / TICRATE)) + if (MAX(localdelay, arbitratordelay) >= network.GetHighPingThreshold()) { color = CR_RED; } diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index c9c3c1116c..7a351a5c7f 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -434,14 +434,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); - int avgdelay = 0; - for (int i = 0; i < BACKUPTICS; i++) - { - avgdelay += network.netdelay[network.nodeforplayer[(int)(player - players)]][i]; - } - avgdelay /= BACKUPTICS; - - mysnprintf(str, countof(str), "%d", (avgdelay * network.ticdup) * (1000 / TICRATE)); + mysnprintf(str, countof(str), "%d", network.GetPing((int)(player - players))); screen->DrawText(SmallFont, color, col5, y + ypadding, str, DTA_CleanNoMove, true, TAG_DONE); diff --git a/src/p_user.cpp b/src/p_user.cpp index 830462c9db..6c42807e3e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2510,7 +2510,7 @@ void P_PredictPlayer (player_t *player) if (!NoInterpolateOld) R_RebuildViewInterpolation(player); - player->cmd = network.localcmds[i % LOCALCMDTICS]; + player->cmd = network.GetLocalCommand(i); P_PlayerThink (player); player->mo->Tick (); diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm index c8f066be5b..2379fff3a2 100644 --- a/src/posix/cocoa/i_system.mm +++ b/src/posix/cocoa/i_system.mm @@ -56,20 +56,10 @@ EXTERN_CVAR(String, language) uint32_t LanguageIDs[4]; - void I_Tactile(int /*on*/, int /*off*/, int /*total*/) { } - -ticcmd_t* I_BaseTiccmd() -{ - static ticcmd_t emptycmd; - return &emptycmd; -} - - - // // SetLanguageIDs // diff --git a/src/posix/i_system.h b/src/posix/i_system.h index 7f468f1432..3bcb7b70e6 100644 --- a/src/posix/i_system.h +++ b/src/posix/i_system.h @@ -79,17 +79,6 @@ void I_StartFrame (void); // Can call D_PostEvent. void I_StartTic (void); -// Asynchronous interrupt functions should maintain private queues -// that are read by the synchronous functions -// to be converted into events. - -// Either returns a null ticcmd, -// or calls a loadable driver to build it. -// This ticcmd will then be modified by the gameloop -// for normal input. -ticcmd_t *I_BaseTiccmd (void); - - // Called by M_Responder when quit is selected. // Clean exit, displays sell blurb. void I_Quit (void); diff --git a/src/posix/sdl/i_system.cpp b/src/posix/sdl/i_system.cpp index 1f41788a04..30668935a0 100644 --- a/src/posix/sdl/i_system.cpp +++ b/src/posix/sdl/i_system.cpp @@ -91,12 +91,6 @@ void I_Tactile (int /*on*/, int /*off*/, int /*total*/) { } -ticcmd_t emptycmd; -ticcmd_t *I_BaseTiccmd(void) -{ - return &emptycmd; -} - void I_BeginRead(void) { } diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 50bc7d8d0f..dab5f81906 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -158,7 +158,6 @@ int sys_ostype = 0; // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static ticcmd_t emptycmd; static bool HasExited; static WadStuff *WadList; @@ -182,20 +181,6 @@ void I_Tactile(int on, int off, int total) on = off = total = 0; } -//========================================================================== -// -// I_BaseTiccmd -// -// Returns an empty ticcmd. I have no idea why this should be system- -// specific. -// -//========================================================================== - -ticcmd_t *I_BaseTiccmd() -{ - return &emptycmd; -} - //========================================================================== // // I_DetectOS diff --git a/src/win32/i_system.h b/src/win32/i_system.h index a5f7b5d0ba..b070364122 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -72,16 +72,6 @@ void I_StartFrame (void); // Can call D_PostEvent. void I_StartTic (void); -// Asynchronous interrupt functions should maintain private queues -// that are read by the synchronous functions -// to be converted into events. - -// Either returns a null ticcmd, -// or calls a loadable driver to build it. -// This ticcmd will then be modified by the gameloop -// for normal input. -ticcmd_t *I_BaseTiccmd (void); - // Called by M_Responder when quit is selected. // Clean exit, displays sell blurb. From 1d35a2320b030dc5d81f398ff18cfa1b66832ca2 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 25 Mar 2018 01:40:09 +0100 Subject: [PATCH 04/17] - Improve mouse movement interpolation by recording input events at the beginning of a frame --- src/d_event.h | 6 +--- src/d_main.cpp | 83 +++++++++++++++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/d_event.h b/src/d_event.h index 22988cda54..0d5059a6bc 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -119,17 +119,13 @@ typedef enum // Called by IO functions when input is detected. void D_PostEvent (const event_t* ev); void D_RemoveNextCharEvent(); - +void D_AddPostedEvents(); // // GLOBAL VARIABLES // #define MAXEVENTS 128 -extern event_t events[MAXEVENTS]; -extern int eventhead; -extern int eventtail; - extern gameaction_t gameaction; diff --git a/src/d_main.cpp b/src/d_main.cpp index f0518be6d4..45c9737098 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -144,7 +144,6 @@ const FIWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const c // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- void D_ProcessEvents (); -ticcmd_t G_BuildTiccmd (); void D_DoAdvanceDemo (); void D_AddWildFile (TArray &wadfiles, const char *pattern); void D_LoadWadSettings (); @@ -237,9 +236,10 @@ FString StoredWarp; bool advancedemo; FILE *debugfile; FILE *hashfile; -event_t events[MAXEVENTS]; -int eventhead; -int eventtail; +static TArray FrameStartInputEvents; +static event_t events[MAXEVENTS]; +static int eventhead; +static int eventtail; gamestate_t wipegamestate = GS_DEMOSCREEN; // can be -1 to force a wipe bool PageBlank; FTexture *Page; @@ -319,33 +319,46 @@ void D_ProcessEvents (void) void D_PostEvent (const event_t *ev) { - // Do not post duplicate consecutive EV_DeviceChange events. - if (ev->type == EV_DeviceChange && events[eventhead].type == EV_DeviceChange) + FrameStartInputEvents.Push(*ev); +} + +void D_AddPostedEvents() +{ + unsigned int c = FrameStartInputEvents.Size(); + for (unsigned int i = 0; i < c; i++) { - return; + const event_t *ev = &FrameStartInputEvents[i]; + + // Do not post duplicate consecutive EV_DeviceChange events. + if (ev->type == EV_DeviceChange && events[eventhead].type == EV_DeviceChange) + { + continue; + } + events[eventhead] = *ev; + if (ev->type == EV_Mouse && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !E_Responder(ev) && !paused) + { + if (Button_Mlook.bDown || freelook) + { + int look = int(ev->y * m_pitch * mouse_sensitivity * 16.0); + if (invertmouse) + look = -look; + G_AddViewPitch(look, true); + events[eventhead].y = 0; + } + if (!Button_Strafe.bDown && !lookstrafe) + { + G_AddViewAngle(int(ev->x * m_yaw * mouse_sensitivity * 8.0), true); + events[eventhead].x = 0; + } + if ((events[eventhead].x | events[eventhead].y) == 0) + { + continue; + } + } + eventhead = (eventhead + 1)&(MAXEVENTS - 1); } - events[eventhead] = *ev; - if (ev->type == EV_Mouse && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !E_Responder(ev) && !paused) - { - if (Button_Mlook.bDown || freelook) - { - int look = int(ev->y * m_pitch * mouse_sensitivity * 16.0); - if (invertmouse) - look = -look; - G_AddViewPitch (look, true); - events[eventhead].y = 0; - } - if (!Button_Strafe.bDown && !lookstrafe) - { - G_AddViewAngle (int(ev->x * m_yaw * mouse_sensitivity * 8.0), true); - events[eventhead].x = 0; - } - if ((events[eventhead].x | events[eventhead].y) == 0) - { - return; - } - } - eventhead = (eventhead+1)&(MAXEVENTS-1); + + FrameStartInputEvents.Clear(); } //========================================================================== @@ -1042,11 +1055,19 @@ void D_DoomLoop () } I_SetFrameTime(); + // Grab input events at the beginning of the frame. + // This ensures the mouse movement matches I_GetTimeFrac precisely. + I_StartTic(); + + // Tick the playsim network.TryRunTics(); - // Update display, next frame, with current state. - I_StartTic (); + // Apply the events we recorded in I_StartTic as the events for the next frame. + D_AddPostedEvents(); + + // Render frame and present D_Display (); + if (wantToRestart) { wantToRestart = false; From 97f19f3b840e66846fad49a37b9f76016aa0cb9a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 26 Mar 2018 22:13:44 +0200 Subject: [PATCH 05/17] - Replace the old D_DoomLoop with a simplified version while d_net and i_net gets refactored --- src/d_main.cpp | 145 +++++++++++++++++++++++++++++++++++++++++++++++++ src/d_net.cpp | 32 ++++++++++- src/d_net.h | 12 +++- 3 files changed, 186 insertions(+), 3 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 4643b184a2..e338aa156f 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1033,6 +1033,150 @@ void D_ErrorCleanup () // //========================================================================== +class GameTime +{ +public: + void Update() + { + LastTic = CurrentTic; + I_SetFrameTime(); + CurrentTic = I_GetTime(); + } + + int TicsElapsed() const + { + return CurrentTic - LastTic; + } + + int BaseGameTic() const + { + return LastTic; + } + + int BaseMakeTic() const + { + return LastTic + 1; + } + +private: + int LastTic = 0; + int CurrentTic = 0; +} gametime; + +class GameInput +{ +public: + void Update() + { + // Not sure why the joystick can't be updated every frame.. + bool updateJoystick = gametime.TicsElapsed() > 0; + if (updateJoystick) + { + I_StartFrame(); // To do: rename this silly function to I_UpdateJoystick + } + + // Grab input events at the beginning of the frame. + // This ensures the mouse movement matches I_GetTimeFrac precisely. + I_StartTic(); // To do: rename this to I_ProcessWindowMessages + } + + void BeforeDisplayUpdate() + { + // Apply the events we recorded in I_StartTic as the events for the next frame. + D_AddPostedEvents(); + } + +} input; + +ticcmd_t G_BuildTiccmd(); + +class PlaySim +{ +public: + void Update() + { + int tics = gametime.TicsElapsed(); + if (tics == 0) + return; + + P_UnPredictPlayer(); + + D_ProcessEvents(); + + for (int i = 0; i < tics; i++) + { + gametic = gametime.BaseGameTic() + i; + network.maketic = gametime.BaseMakeTic() + i; + network.Net_NewMakeTic(); + network.SetPlayerCommand(consoleplayer, G_BuildTiccmd()); + + if (advancedemo) + D_DoAdvanceDemo(); + + network.DispatchEvents(gametic); + + C_Ticker(); + M_Ticker(); + G_Ticker(); + } + + P_PredictPlayer(&players[consoleplayer]); + + S_UpdateSounds(players[consoleplayer].camera); // move positional sounds + } + +} playsim; + +class GameDisplay +{ +public: + void Update() + { + // Render frame and present + D_Display(); + } + +} display; + +void D_DoomLoop() +{ + while (true) + { + try + { + gametime.Update(); + network.Update(); + input.Update(); + playsim.Update(); + input.BeforeDisplayUpdate(); + display.Update(); + + GC::CheckGC(); + + if (wantToRestart) + { + wantToRestart = false; + return; + } + } + catch (CRecoverableError &error) + { + if (error.GetMessage()) + { + Printf(PRINT_BOLD, "\n%s\n", error.GetMessage()); + } + D_ErrorCleanup(); + } + catch (CVMAbortException &error) + { + error.MaybePrintMessage(); + Printf("%s", error.stacktrace.GetChars()); + D_ErrorCleanup(); + } + } +} + +#if 0 void D_DoomLoop () { int lasttic = 0; @@ -1090,6 +1234,7 @@ void D_DoomLoop () } } } +#endif //========================================================================== // diff --git a/src/d_net.cpp b/src/d_net.cpp index 59e9f26d1c..875040fb5d 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -917,12 +917,42 @@ void Network::SetBotCommand(int player, const ticcmd_t &cmd) netcmds[player][((gametic + 1) / network.ticdup) % BACKUPTICS] = cmd; } +ticcmd_t Network::GetLocalCommand(int tic) const +{ + int buf = tic % BACKUPTICS; + return netcmds[consoleplayer][buf]; +} + ticcmd_t Network::GetPlayerCommand(int player) const { int buf = (gametic / network.ticdup) % BACKUPTICS; return netcmds[player][buf]; } +void Network::SetPlayerCommand(int player, ticcmd_t cmd) +{ + int buf = (gametic / ticdup) % BACKUPTICS; + netcmds[player][buf] = cmd; +} + +void Network::DispatchEvents(int tic) +{ + int player = consoleplayer; + int ticmod = tic % BACKUPTICS; + + if (specials.used[ticmod]) + { + NetSpecs[player][ticmod].SetData(specials.streams[ticmod], (int)specials.used[ticmod]); + specials.used[ticmod] = 0; + } + else + { + NetSpecs[player][ticmod].SetData(nullptr, 0); + } +} + + +#if 0 // Builds ticcmds for console player, sends out a packet void Network::NetUpdate() { @@ -1357,7 +1387,7 @@ void Network::NetUpdate() } } } - +#endif // // D_ArbitrateNetStart diff --git a/src/d_net.h b/src/d_net.h index c9f1e2a156..11961dc1ee 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -63,6 +63,7 @@ struct TicSpecial int lastmaketic; bool okay; +public: TicSpecial(); ~TicSpecial(); @@ -86,8 +87,14 @@ struct ArbitrateData struct Network { public: + void Update() { } + void DispatchEvents(int tic); + void SetPlayerCommand(int player, ticcmd_t cmd); + +private: void TryRunTics(); - void NetUpdate(); +public: + void NetUpdate() { } void D_CheckNetGame(); void Net_ClearBuffers(); @@ -115,7 +122,8 @@ public: void RunNetSpecs(int player); - ticcmd_t GetLocalCommand(int tic) const { return localcmds[tic % LOCALCMDTICS]; } + ticcmd_t GetLocalCommand(int tic) const; + //ticcmd_t GetLocalCommand(int tic) const { return localcmds[tic % LOCALCMDTICS]; } int GetPing(int player) const; int GetServerPing() const; From 04a91e586e1c0c6845a043ad22448daa9ce0bcf1 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 27 Mar 2018 00:55:10 +0200 Subject: [PATCH 06/17] - Removed old network implementation - Rewrote doomcom_t to handle nodes joining and leaving during a game and removed initial game handshake from it --- src/d_main.cpp | 69 +- src/d_net.cpp | 1813 ++++-------------------------------------------- src/d_net.h | 35 +- src/i_net.cpp | 875 ++++------------------- src/i_net.h | 11 +- 5 files changed, 308 insertions(+), 2495 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index e338aa156f..0994073ade 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -949,7 +949,6 @@ void D_Display () if (!wipe || NoWipe < 0) { - network.NetUpdate (); // send out any new accumulation // normal update // draw ZScript UI stuff C_DrawConsole (hw2d); // draw console @@ -968,7 +967,6 @@ void D_Display () screen->WipeEndScreen (); wipestart = I_msTime(); - network.NetUpdate(); // send out any new accumulation do { @@ -983,7 +981,6 @@ void D_Display () C_DrawConsole (hw2d); // console and M_Drawer (); // menu are drawn even on top of wipes screen->Update (); // page flip or blit buffer - network.NetUpdate (); // [RH] not sure this is needed anymore } while (!done); screen->WipeCleanup(); I_FreezeTime(false); @@ -1140,6 +1137,12 @@ public: void D_DoomLoop() { + // Clamp the timer to TICRATE until the playloop has been entered. + r_NoInterpolate = true; + Page = Advisory = NULL; + + vid_cursor.Callback(); + while (true) { try @@ -1176,66 +1179,6 @@ void D_DoomLoop() } } -#if 0 -void D_DoomLoop () -{ - int lasttic = 0; - - // Clamp the timer to TICRATE until the playloop has been entered. - r_NoInterpolate = true; - Page = Advisory = NULL; - - vid_cursor.Callback(); - - for (;;) - { - try - { - // frame syncronous IO operations - if (gametic > lasttic) - { - lasttic = gametic; - I_StartFrame (); - } - I_SetFrameTime(); - - // Grab input events at the beginning of the frame. - // This ensures the mouse movement matches I_GetTimeFrac precisely. - I_StartTic(); - - // Tick the playsim - network.TryRunTics(); - - // Apply the events we recorded in I_StartTic as the events for the next frame. - D_AddPostedEvents(); - - // Render frame and present - D_Display (); - - if (wantToRestart) - { - wantToRestart = false; - return; - } - } - catch (CRecoverableError &error) - { - if (error.GetMessage ()) - { - Printf (PRINT_BOLD, "\n%s\n", error.GetMessage()); - } - D_ErrorCleanup (); - } - catch (CVMAbortException &error) - { - error.MaybePrintMessage(); - Printf("%s", error.stacktrace.GetChars()); - D_ErrorCleanup(); - } - } -} -#endif - //========================================================================== // // D_PageTicker diff --git a/src/d_net.cpp b/src/d_net.cpp index 875040fb5d..ba895b474a 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -265,591 +265,102 @@ TicSpecial &TicSpecial::operator << (const char *it) return *this; } -void Network::Net_ClearBuffers() +///////////////////////////////////////////////////////////////////////////// + +void Network::D_QuitNetGame() { - memset (localcmds, 0, sizeof(localcmds)); - memset (netcmds, 0, sizeof(netcmds)); - memset (nettics, 0, sizeof(nettics)); - memset (nodeingame, 0, sizeof(nodeingame)); - memset (nodeforplayer, 0, sizeof(nodeforplayer)); - memset (playerfornode, 0, sizeof(playerfornode)); - memset (remoteresend, 0, sizeof(remoteresend)); - memset (resendto, 0, sizeof(resendto)); - memset (resendcount, 0, sizeof(resendcount)); - memset (lastrecvtime, 0, sizeof(lastrecvtime)); - memset (currrecvtime, 0, sizeof(currrecvtime)); - memset (consistency, 0, sizeof(consistency)); - nodeingame[0] = true; - - for (int i = 0; i < MAXPLAYERS; i++) - { - for (int j = 0; j < BACKUPTICS; j++) - { - NetSpecs[i][j].SetData (NULL, 0); - } - } - - oldentertics = entertic; - gametic = 0; - maketic = 0; - - lastglobalrecvtime = 0; } -int Network::NetbufferSize() +void Network::Net_NewMakeTic() { - if (netbuffer[0] & (NCMD_EXIT | NCMD_SETUP)) - { - return netbuffer.datalength; - } - - int k = 2, count, numtics; - - if (netbuffer[0] & NCMD_RETRANSMIT) - k++; - - if (NetMode == NET_PacketServer && netbuffer.remotenode == nodeforplayer[Net_Arbitrator]) - k++; - - numtics = netbuffer[0] & NCMD_XTICS; - if (numtics == 3) - { - numtics += netbuffer[k++]; - } - - if (netbuffer[0] & NCMD_QUITTERS) - { - k += netbuffer[k] + 1; - } - - // Network delay byte - k++; - - if (netbuffer[0] & NCMD_MULTI) - { - count = netbuffer[k]; - k += count; - } - else - { - count = 1; - } - - // Need at least 3 bytes per tic per player - if (netbuffer.datalength < k + 3 * count * numtics) - { - return k + 3 * count * numtics; - } - - uint8_t *skipper = &netbuffer[k]; - if ((netbuffer[0] & NCMD_EXIT) == 0) - { - while (count-- > 0) - { - SkipTicCmd (&skipper, numtics); - } - } - return int(skipper - &netbuffer[0]); + specials.NewMakeTic(); } -int Network::ExpandTics(int low) +void Network::Net_WriteByte(uint8_t it) { - int delta; - int mt = maketic / ticdup; - - delta = low - (mt&0xff); - - if (delta >= -64 && delta <= 64) - return (mt&~0xff) + low; - if (delta > 64) - return (mt&~0xff) - 256 + low; - if (delta < -64) - return (mt&~0xff) + 256 + low; - - I_Error ("ExpandTics: strange value %i at maketic %i", low, maketic); - return 0; + specials << it; } -void Network::HSendPacket (int node, int len) +void Network::Net_WriteWord(short it) { - if (debugfile && node != 0) - { - int i, k, realretrans; - - if (netbuffer[0] & NCMD_SETUP) - { - fprintf (debugfile,"%i/%i send %i = SETUP [%3i]", gametic, maketic, node, len); - for (i = 0; i < len; i++) - fprintf (debugfile," %2x", ((uint8_t *)netbuffer.data)[i]); - } - else if (netbuffer[0] & NCMD_EXIT) - { - fprintf (debugfile,"%i/%i send %i = EXIT [%3i]", gametic, maketic, node, len); - for (i = 0; i < len; i++) - fprintf (debugfile," %2x", ((uint8_t *)netbuffer.data)[i]); - } - else - { - k = 2; - - if (NetMode == NET_PacketServer && consoleplayer == Net_Arbitrator && - node != 0) - { - k++; - } - - if (netbuffer[0] & NCMD_RETRANSMIT) - realretrans = ExpandTics (netbuffer[k++]); - else - realretrans = -1; - - int numtics = netbuffer[0] & 3; - if (numtics == 3) - numtics += netbuffer[k++]; - - fprintf (debugfile,"%i/%i send %i = (%i + %i, R %i) [%3i]", - gametic, maketic, - node, - ExpandTics(netbuffer[1]), - numtics, realretrans, len); - - for (i = 0; i < len; i++) - fprintf (debugfile, "%c%2x", i==k?'|':' ', ((uint8_t *)netbuffer.data)[i]); - } - fprintf (debugfile, " [[ "); - for (i = 0; i < doomcom->numnodes; ++i) - { - if (nodeingame[i]) - { - fprintf (debugfile, "%d ", nettics[i]); - } - else - { - fprintf (debugfile, "--- "); - } - } - fprintf (debugfile, "]]\n"); - } - - if (node == 0) - { - memcpy (reboundstore, netbuffer.data, len); - reboundpacket = len; - return; - } - - if (demoplayback) - return; - - if (!netgame) - I_Error ("Tried to transmit to another node"); - -#if SIMULATEERRORS - if (rand() < SIMULATEERRORS) - { - if (debugfile) - fprintf (debugfile, "Drop!\n"); - return; - } -#endif - - netbuffer.remotenode = node; - netbuffer.datalength = len; - -#ifdef _DEBUG - if (net_fakelatency / 2 > 0) - { - PacketStore store; - store.message = netbuffer; - store.timer = I_GetTime() + ((net_fakelatency / 2) / (1000 / TICRATE)); - OutBuffer.Push(store); - } - else - doomcom->PacketSend(netbuffer); - - for (unsigned int i = 0; i < OutBuffer.Size(); i++) - { - if (OutBuffer[i].timer <= I_GetTime()) - { - netbuffer = OutBuffer[i].message; - doomcom->PacketSend(netbuffer); - OutBuffer.Delete(i); - i = -1; - } - } -#else - doomcom->PacketSend(netbuffer); -#endif + specials << it; } -// Returns false if no packet is waiting -bool Network::HGetPacket() +void Network::Net_WriteLong(int it) { - if (reboundpacket) - { - memcpy (netbuffer.data, reboundstore, reboundpacket); - netbuffer.remotenode = 0; - reboundpacket = 0; - return true; - } - - if (!netgame) - return false; - - if (demoplayback) - return false; - - doomcom->PacketGet(netbuffer); - -#ifdef _DEBUG - if (net_fakelatency / 2 > 0 && netbuffer.remotenode != -1) - { - PacketStore store; - store.message = netbuffer; - store.timer = I_GetTime() + ((net_fakelatency / 2) / (1000 / TICRATE)); - InBuffer.Push(store); - netbuffer.remotenode = -1; - } - - if (netbuffer.remotenode == -1) - { - bool gotmessage = false; - for (unsigned int i = 0; i < InBuffer.Size(); i++) - { - if (InBuffer[i].timer <= I_GetTime()) - { - netbuffer = InBuffer[i].message; - InBuffer.Delete(i); - gotmessage = true; - break; - } - } - if (!gotmessage) - return false; - } -#else - if (netbuffer.remotenode == -1) - { - return false; - } -#endif - - if (debugfile) - { - int i, k, realretrans; - - if (netbuffer[0] & NCMD_SETUP) - { - fprintf (debugfile,"%i/%i get %i = SETUP [%3i]", gametic, maketic, netbuffer.remotenode, netbuffer.datalength); - for (i = 0; i < netbuffer.datalength; i++) - fprintf (debugfile, " %2x", ((uint8_t *)netbuffer.data)[i]); - fprintf (debugfile, "\n"); - } - else if (netbuffer[0] & NCMD_EXIT) - { - fprintf (debugfile,"%i/%i get %i = EXIT [%3i]", gametic, maketic, netbuffer.remotenode, netbuffer.datalength); - for (i = 0; i < netbuffer.datalength; i++) - fprintf (debugfile, " %2x", ((uint8_t *)netbuffer.data)[i]); - fprintf (debugfile, "\n"); - } - else - { - k = 2; - - if (NetMode == NET_PacketServer && netbuffer.remotenode == nodeforplayer[Net_Arbitrator]) - { - k++; - } - - if (netbuffer[0] & NCMD_RETRANSMIT) - realretrans = ExpandTics (netbuffer[k++]); - else - realretrans = -1; - - int numtics = netbuffer[0] & 3; - if (numtics == 3) - numtics += netbuffer[k++]; - - fprintf (debugfile,"%i/%i get %i = (%i + %i, R %i) [%3i]", - gametic, maketic, - netbuffer.remotenode, - ExpandTics(netbuffer[1]), - numtics, realretrans, netbuffer.datalength); - - for (i = 0; i < netbuffer.datalength; i++) - fprintf (debugfile, "%c%2x", i==k?'|':' ', ((uint8_t *)netbuffer.data)[i]); - if (numtics) - fprintf (debugfile, " <<%4x>>\n", - consistency[playerfornode[netbuffer.remotenode]][nettics[netbuffer.remotenode]%BACKUPTICS] & 0xFFFF); - else - fprintf (debugfile, "\n"); - } - } - - if (netbuffer.datalength != NetbufferSize ()) - { - Printf("Bad packet length %i (calculated %i)\n", netbuffer.datalength, NetbufferSize()); - - if (debugfile) - fprintf (debugfile,"---bad packet length %i (calculated %i)\n", netbuffer.datalength, NetbufferSize()); - return false; - } - - return true; + specials << it; } -void Network::PlayerIsGone(int netnode, int netconsole) +void Network::Net_WriteFloat(float it) { - int i; - - if (nodeingame[netnode]) - { - for (i = netnode + 1; i < doomcom->numnodes; ++i) - { - if (nodeingame[i]) - break; - } - if (i == doomcom->numnodes) - { - doomcom->numnodes = netnode; - } - - if (playeringame[netconsole]) - { - players[netconsole].playerstate = PST_GONE; - } - nodeingame[netnode] = false; - nodejustleft[netnode] = false; - } - else if (nodejustleft[netnode]) // Packet Server - { - if (netnode + 1 == doomcom->numnodes) - { - doomcom->numnodes = netnode; - } - if (playeringame[netconsole]) - { - players[netconsole].playerstate = PST_GONE; - } - nodejustleft[netnode] = false; - } - else return; - - if (netconsole == Net_Arbitrator) - { - // Pick a new network arbitrator - for (int i = 0; i < MAXPLAYERS; i++) - { - if (i != netconsole && playeringame[i] && players[i].Bot == NULL) - { - Net_Arbitrator = i; - players[i].settings_controller = true; - Printf("%s is the new arbitrator\n", players[i].userinfo.GetName()); - break; - } - } - } - - if (debugfile && NetMode == NET_PacketServer) - { - if (Net_Arbitrator == consoleplayer) - { - fprintf(debugfile, "I am the new master!\n"); - } - else - { - fprintf(debugfile, "Node %d is the new master!\n", nodeforplayer[Net_Arbitrator]); - } - } - - if (demorecording) - { - G_CheckDemoStatus (); - - //WriteByte (DEM_DROPPLAYER, &demo_p); - //WriteByte ((uint8_t)netconsole, &demo_p); - } + specials << it; } -void Network::GetPackets() +void Network::Net_WriteString(const char *it) { - int netconsole; - int netnode; - int realend; - int realstart; - int numtics; - int retransmitfrom; - int k; - uint8_t playerbytes[MAXNETNODES]; - int numplayers; - - while ( HGetPacket() ) - { - if (netbuffer[0] & NCMD_SETUP) - { - if (consoleplayer == Net_Arbitrator) - { - // This player apparantly doesn't realise the game has started - netbuffer[0] = NCMD_SETUP+3; - HSendPacket (netbuffer.remotenode, 1); - } - continue; // extra setup packet - } - - netnode = netbuffer.remotenode; - netconsole = playerfornode[netnode] & ~PL_DRONE; + specials << it; +} - // [RH] Get "ping" times - totally useless, since it's bound to the frequency - // packets go out at. - lastrecvtime[netconsole] = currrecvtime[netconsole]; - currrecvtime[netconsole] = I_msTime (); +void Network::Net_WriteBytes(const uint8_t *block, int len) +{ + while (len--) + specials << *block++; +} - // check for exiting the game - if (netbuffer[0] & NCMD_EXIT) - { - if (!nodeingame[netnode]) - continue; +bool Network::IsInconsistent(int player, int16_t checkvalue) const +{ + int buf = (gametic / ticdup) % BACKUPTICS; + return gametic > BACKUPTICS*ticdup && consistency[player][buf] != checkvalue; +} - if (NetMode != NET_PacketServer || netconsole == Net_Arbitrator) - { - PlayerIsGone (netnode, netconsole); - if (NetMode == NET_PacketServer) - { - uint8_t *foo = &netbuffer[2]; - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i]) - { - int resend = ReadLong (&foo); - if (i != consoleplayer) - { - resendto[nodeforplayer[i]] = resend; - } - } - } - } - } - else - { - nodeingame[netnode] = false; - nodejustleft[netnode] = true; - } - continue; - } +void Network::SetConsistency(int player, int16_t checkvalue) +{ + int buf = (gametic / ticdup) % BACKUPTICS; + consistency[player][buf] = checkvalue; +} - k = 2; +int16_t Network::GetConsoleConsistency() const +{ + return consistency[consoleplayer][(maketic / ticdup) % BACKUPTICS]; +} - if (NetMode == NET_PacketServer && - netconsole == Net_Arbitrator && - netconsole != consoleplayer) - { - mastertics = ExpandTics (netbuffer[k++]); - } +size_t Network::CopySpecData(int player, uint8_t *dest, size_t dest_size) +{ + if (gametic % ticdup != 0) + return 0; - if (netbuffer[0] & NCMD_RETRANSMIT) - { - retransmitfrom = netbuffer[k++]; - } - else - { - retransmitfrom = 0; - } + int buf = (gametic / ticdup) % BACKUPTICS; - numtics = (netbuffer[0] & NCMD_XTICS); - if (numtics == 3) - { - numtics += netbuffer[k++]; - } + int speclen = 0; + uint8_t *specdata = NetSpecs[player][buf].GetData(&speclen); + if (!specdata) + return 0; - if (netbuffer[0] & NCMD_QUITTERS) - { - numplayers = netbuffer[k++]; - for (int i = 0; i < numplayers; ++i) - { - PlayerIsGone (nodeforplayer[netbuffer[k]], netbuffer[k]); - k++; - } - } + if (dest_size < speclen) + I_FatalError("Demo buffer too small for CopySpecData"); - // Pull current network delay from node - netdelay[netnode][(nettics[netnode]+1) % BACKUPTICS] = netbuffer[k++]; + memcpy(dest, specdata, speclen); + NetSpecs[player][buf].SetData(nullptr, 0); // Why is this needed? + return speclen; +} - playerbytes[0] = netconsole; - if (netbuffer[0] & NCMD_MULTI) - { - numplayers = netbuffer[k++]; - memcpy (playerbytes+1, &netbuffer[k], numplayers - 1); - k += numplayers - 1; - } - else - { - numplayers = 1; - } +int Network::GetPing(int player) const +{ + int node = nodeforplayer[player]; + int avgdelay = 0; + for (int i = 0; i < BACKUPTICS; i++) + avgdelay += netdelay[node][i]; + return avgdelay * ticdup * 1000 / TICRATE / BACKUPTICS; +} - // to save bytes, only the low byte of tic numbers are sent - // Figure out what the rest of the bytes are - realstart = ExpandTics (netbuffer[1]); - realend = (realstart + numtics); - - nodeforplayer[netconsole] = netnode; - - // check for retransmit request - if (resendcount[netnode] <= 0 && (netbuffer[0] & NCMD_RETRANSMIT)) - { - resendto[netnode] = ExpandTics (retransmitfrom); - if (debugfile) - fprintf (debugfile,"retransmit from %i\n", resendto[netnode]); - resendcount[netnode] = RESENDCOUNT; - } - else - { - resendcount[netnode]--; - } - - // check for out of order / duplicated packet - if (realend == nettics[netnode]) - continue; - - if (realend < nettics[netnode]) - { - if (debugfile) - fprintf (debugfile, "out of order packet (%i + %i)\n" , - realstart, numtics); - continue; - } - - // check for a missed packet - if (realstart > nettics[netnode]) - { - // stop processing until the other system resends the missed tics - if (debugfile) - fprintf (debugfile, "missed tics from %i (%i to %i)\n", - netnode, nettics[netnode], realstart); - remoteresend[netnode] = true; - continue; - } +int Network::GetServerPing() const +{ + return GetPing(Net_Arbitrator); +} - // update command store from the packet - { - remoteresend[netnode] = false; - - uint8_t *start = &netbuffer[k]; - - for (int i = 0; i < numplayers; ++i) - { - int node = nodeforplayer[playerbytes[i]]; - - SkipTicCmd (&start, nettics[node] - realstart); - - for (int tic = nettics[node]; tic < realend; tic++) - { - ReadTicCmd(&start, playerbytes[i], tic); - } - - nettics[nodeforplayer[playerbytes[i]]] = realend; - } - } - } +int Network::GetHighPingThreshold() const +{ + return ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE); } void Network::ReadTicCmd(uint8_t **stream, int player, int tic) @@ -951,721 +462,35 @@ void Network::DispatchEvents(int tic) } } - -#if 0 -// Builds ticcmds for console player, sends out a packet -void Network::NetUpdate() +void Network::Net_ClearBuffers() { - int lowtic; - int nowtime; - int newtics; - int i,j; - int realstart; - uint8_t *cmddata; - bool resendOnly; + memset(localcmds, 0, sizeof(localcmds)); + memset(netcmds, 0, sizeof(netcmds)); + memset(nettics, 0, sizeof(nettics)); + memset(nodeingame, 0, sizeof(nodeingame)); + memset(nodeforplayer, 0, sizeof(nodeforplayer)); + memset(playerfornode, 0, sizeof(playerfornode)); + memset(remoteresend, 0, sizeof(remoteresend)); + memset(resendto, 0, sizeof(resendto)); + memset(resendcount, 0, sizeof(resendcount)); + memset(lastrecvtime, 0, sizeof(lastrecvtime)); + memset(currrecvtime, 0, sizeof(currrecvtime)); + memset(consistency, 0, sizeof(consistency)); + nodeingame[0] = true; - GC::CheckGC(); - - if (ticdup == 0) + for (int i = 0; i < MAXPLAYERS; i++) { - return; - } - - // check time - nowtime = I_GetTime (); - newtics = nowtime - gametime; - gametime = nowtime; - - if (newtics <= 0) // nothing new to update - { - GetPackets (); - return; - } - - if (skiptics <= newtics) - { - newtics -= skiptics; - skiptics = 0; - } - else - { - skiptics -= newtics; - newtics = 0; - } - - // build new ticcmds for console player - for (i = 0; i < newtics; i++) - { - I_StartTic (); - D_ProcessEvents (); - if (pauseext || (maketic - gametic) / ticdup >= BACKUPTICS/2-1) - break; // can't hold any more - - //Printf ("mk:%i ",maketic); - localcmds[maketic % LOCALCMDTICS] = G_BuildTiccmd(); - maketic++; - - if (ticdup == 1 || maketic == 0) + for (int j = 0; j < BACKUPTICS; j++) { - Net_NewMakeTic (); - } - else - { - // Once ticdup tics have been collected, average their movements - // and combine their buttons, since they will all be sent as a - // single tic that gets duplicated ticdup times. Even with ticdup, - // tics are still collected at the normal rate so that, with the - // help of prediction, the game seems as responsive as normal. - if (maketic % ticdup != 0) - { - int mod = maketic - maketic % ticdup; - int j; - - // Update the buttons for all tics in this ticdup set as soon as - // possible so that the prediction shows jumping as correctly as - // possible. (If you press +jump in the middle of a ticdup set, - // the jump will actually begin at the beginning of the set, not - // in the middle.) - for (j = maketic-2; j >= mod; --j) - { - localcmds[j % LOCALCMDTICS].ucmd.buttons |= - localcmds[(j + 1) % LOCALCMDTICS].ucmd.buttons; - } - } - else - { - // Average the ticcmds between these tics to get the - // movement that is actually sent across the network. We - // need to update them in all the localcmds slots that - // are dupped so that prediction works properly. - int mod = maketic - ticdup; - int modp, j; - - int pitch = 0; - int yaw = 0; - int roll = 0; - int forwardmove = 0; - int sidemove = 0; - int upmove = 0; - - for (j = 0; j < ticdup; ++j) - { - modp = (mod + j) % LOCALCMDTICS; - pitch += localcmds[modp].ucmd.pitch; - yaw += localcmds[modp].ucmd.yaw; - roll += localcmds[modp].ucmd.roll; - forwardmove += localcmds[modp].ucmd.forwardmove; - sidemove += localcmds[modp].ucmd.sidemove; - upmove += localcmds[modp].ucmd.upmove; - } - - pitch /= ticdup; - yaw /= ticdup; - roll /= ticdup; - forwardmove /= ticdup; - sidemove /= ticdup; - upmove /= ticdup; - - for (j = 0; j < ticdup; ++j) - { - modp = (mod + j) % LOCALCMDTICS; - localcmds[modp].ucmd.pitch = pitch; - localcmds[modp].ucmd.yaw = yaw; - localcmds[modp].ucmd.roll = roll; - localcmds[modp].ucmd.forwardmove = forwardmove; - localcmds[modp].ucmd.sidemove = sidemove; - localcmds[modp].ucmd.upmove = upmove; - } - - Net_NewMakeTic (); - } + NetSpecs[i][j].SetData(NULL, 0); } } - if (singletics) - return; // singletic update is synchronous + oldentertics = entertic; + gametic = 0; + maketic = 0; - if (demoplayback) - { - resendto[0] = nettics[0] = (maketic / ticdup); - return; // Don't touch netcmd data while playing a demo, as it'll already exist. - } - - // If maketic didn't cross a ticdup boundary, only send packets - // to players waiting for resends. - resendOnly = (maketic / ticdup) == (maketic - i) / ticdup; - - // send the packet to the other nodes - int count = 1; - int quitcount = 0; - - if (consoleplayer == Net_Arbitrator) - { - if (NetMode == NET_PacketServer) - { - for (j = 0; j < MAXPLAYERS; j++) - { - if (playeringame[j] && players[j].Bot == NULL) - { - count++; - } - } - - // The loop above added the local player to the count a second time, - // and it also added the player being sent the packet to the count. - count -= 2; - - for (j = 0; j < doomcom->numnodes; ++j) - { - if (nodejustleft[j]) - { - if (count == 0) - { - PlayerIsGone (j, playerfornode[j]); - } - else - { - quitcount++; - } - } - } - - if (count == 0) - { - count = 1; - } - } - } - - for (i = 0; i < doomcom->numnodes; i++) - { - uint8_t playerbytes[MAXPLAYERS]; - - if (!nodeingame[i]) - { - continue; - } - if (NetMode == NET_PacketServer && - consoleplayer != Net_Arbitrator && - i != nodeforplayer[Net_Arbitrator] && - i != 0) - { - continue; - } - if (resendOnly && resendcount[i] <= 0 && !remoteresend[i] && nettics[i]) - { - continue; - } - - int numtics; - int k; - - lowtic = maketic / ticdup; - - netbuffer[0] = 0; - netbuffer[1] = realstart = resendto[i]; - k = 2; - - if (NetMode == NET_PacketServer && - consoleplayer == Net_Arbitrator && - i != 0) - { - for (j = 1; j < doomcom->numnodes; ++j) - { - if (nodeingame[j] && nettics[j] < lowtic && j != i) - { - lowtic = nettics[j]; - } - } - netbuffer[k++] = lowtic; - } - - numtics = MAX(0, lowtic - realstart); - if (numtics > BACKUPTICS) - I_Error ("NetUpdate: Node %d missed too many tics", i); - - switch (net_extratic) - { - case 0: - default: - resendto[i] = lowtic; break; - case 1: resendto[i] = MAX(0, lowtic - 1); break; - case 2: resendto[i] = nettics[i]; break; - } - - if (numtics == 0 && resendOnly && !remoteresend[i] && nettics[i]) - { - continue; - } - - if (remoteresend[i]) - { - netbuffer[0] |= NCMD_RETRANSMIT; - netbuffer[k++] = nettics[i]; - } - - if (numtics < 3) - { - netbuffer[0] |= numtics; - } - else - { - netbuffer[0] |= NCMD_XTICS; - netbuffer[k++] = numtics - 3; - } - - if (quitcount > 0) - { - netbuffer[0] |= NCMD_QUITTERS; - netbuffer[k++] = quitcount; - for (int l = 0; l < doomcom->numnodes; ++l) - { - if (nodejustleft[l]) - { - netbuffer[k++] = playerfornode[l]; - } - } - } - - // Send current network delay - // The number of tics we just made should be removed from the count. - netbuffer[k++] = ((maketic - numtics - gametic) / ticdup); - - if (numtics > 0) - { - int l; - - if (count > 1 && i != 0 && consoleplayer == Net_Arbitrator) - { - netbuffer[0] |= NCMD_MULTI; - netbuffer[k++] = count; - - if (NetMode == NET_PacketServer) - { - for (l = 1, j = 0; j < MAXPLAYERS; j++) - { - if (playeringame[j] && players[j].Bot == NULL && j != playerfornode[i] && j != consoleplayer) - { - playerbytes[l++] = j; - netbuffer[k++] = j; - } - } - } - } - - cmddata = &netbuffer[k]; - - for (l = 0; l < count; ++l) - { - for (j = 0; j < numtics; j++) - { - int start = realstart + j, prev = start - 1; - int localstart, localprev; - - localstart = (start * ticdup) % LOCALCMDTICS; - localprev = (prev * ticdup) % LOCALCMDTICS; - start %= BACKUPTICS; - prev %= BACKUPTICS; - - // The local player has their tics sent first, followed by - // the other players. - if (l == 0) - { - WriteWord (localcmds[localstart].consistency, &cmddata); - // [RH] Write out special "ticcmds" before real ticcmd - if (specials.used[start]) - { - memcpy (cmddata, specials.streams[start], specials.used[start]); - cmddata += specials.used[start]; - } - WriteUserCmdMessage (&localcmds[localstart].ucmd, - localprev >= 0 ? &localcmds[localprev].ucmd : NULL, &cmddata); - } - else if (i != 0) - { - int len; - uint8_t *spec; - - WriteWord (netcmds[playerbytes[l]][start].consistency, &cmddata); - spec = NetSpecs[playerbytes[l]][start].GetData (&len); - if (spec != NULL) - { - memcpy (cmddata, spec, len); - cmddata += len; - } - - WriteUserCmdMessage (&netcmds[playerbytes[l]][start].ucmd, - prev >= 0 ? &netcmds[playerbytes[l]][prev].ucmd : NULL, &cmddata); - } - } - } - HSendPacket (i, int(cmddata - netbuffer.data)); - } - else - { - HSendPacket (i, k); - } - } - - // listen for other packets - GetPackets (); - - if (!resendOnly) - { - // ideally nettics[0] should be 1 - 3 tics above lowtic - // if we are consistantly slower, speed up time - - // [RH] I had erroneously assumed frameskip[] had 4 entries - // because there were 4 players, but that's not the case at - // all. The game is comparing the lag behind the master for - // four runs of TryRunTics. If our tic count is ahead of the - // master all 4 times, the next run of NetUpdate will not - // process any new input. If we have less input than the - // master, the next run of NetUpdate will process extra tics - // (because gametime gets decremented here). - - // the key player does not adapt - if (consoleplayer != Net_Arbitrator) - { - // I'm not sure about this when using a packet server, because - // if left unmodified from the P2P version, it can make the game - // very jerky. The way I have it written right now basically means - // that it won't adapt. Fortunately, player prediction helps - // alleviate the lag somewhat. - - if (NetMode == NET_PeerToPeer) - { - int totalavg = 0; - if (net_ticbalance) - { - // Try to guess ahead the time it takes to send responses to the slowest node - int nodeavg = 0, arbavg = 0; - - for (j = 0; j < BACKUPTICS; j++) - { - arbavg += netdelay[nodeforplayer[Net_Arbitrator]][j]; - nodeavg += netdelay[0][j]; - } - arbavg /= BACKUPTICS; - nodeavg /= BACKUPTICS; - - // We shouldn't adapt if we are already the arbitrator isn't what we are waiting for, otherwise it just adds more latency - if (arbavg > nodeavg) - { - lastaverage = totalavg = ((arbavg + nodeavg) / 2); - } - else - { - // Allow room to guess two tics ahead - if (nodeavg > (arbavg + 2) && lastaverage > 0) - lastaverage--; - totalavg = lastaverage; - } - } - - mastertics = nettics[nodeforplayer[Net_Arbitrator]] + totalavg; - } - if (nettics[0] <= mastertics) - { - gametime--; - if (debugfile) fprintf(debugfile, "-"); - } - if (NetMode != NET_PacketServer) - { - frameskip[(maketic / ticdup) & 3] = (oldnettics > mastertics); - } - else - { - frameskip[(maketic / ticdup) & 3] = (oldnettics - mastertics) > 3; - } - if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3]) - { - skiptics = 1; - if (debugfile) fprintf(debugfile, "+"); - } - oldnettics = nettics[0]; - } - } -} -#endif - -// -// D_ArbitrateNetStart -// -// User info packets look like this: -// -// 0 One byte set to NCMD_SETUP or NCMD_SETUP+1; if NCMD_SETUP+1, omit byte 9 -// 1 One byte for the player's number -//2-4 Three bytes for the game version (255,high byte,low byte) -//5-8 A bit mask for each player the sender knows about -// 9 The high bit is set if the sender got the game info -// 10 A stream of bytes with the user info -// -// The guests always send NCMD_SETUP packets, and the host always -// sends NCMD_SETUP+1 packets. -// -// Game info packets look like this: -// -// 0 One byte set to NCMD_SETUP+2 -// 1 One byte for ticdup setting -// 2 One byte for NetMode setting -// 3 String with starting map's name -// . Four bytes for the RNG seed -// . Stream containing remaining game info -// -// Finished packet looks like this: -// -// 0 One byte set to NCMD_SETUP+3 -// -// Each machine sends user info packets to the host. The host sends user -// info packets back to the other machines as well as game info packets. -// Negotiation is done when all the guests have reported to the host that -// they know about the other nodes. - -bool Network::DoArbitrate (ArbitrateData *data) -{ - char *s; - uint8_t *stream; - int version; - int node; - int i, j; - - while (HGetPacket ()) - { - if (netbuffer[0] == NCMD_EXIT) - { - I_FatalError ("The game was aborted."); - } - - if (netbuffer.remotenode == 0) - { - continue; - } - - if (netbuffer[0] == NCMD_SETUP || netbuffer[0] == NCMD_SETUP+1) // got user info - { - node = (netbuffer[0] == NCMD_SETUP) ? netbuffer.remotenode : nodeforplayer[netbuffer[1]]; - - data->playersdetected[node] = - (netbuffer[5] << 24) | (netbuffer[6] << 16) | (netbuffer[7] << 8) | netbuffer[8]; - - if (netbuffer[0] == NCMD_SETUP) - { // Sent to host - data->gotsetup[node] = netbuffer[9] & 0x80; - stream = &netbuffer[10]; - } - else - { // Sent from host - stream = &netbuffer[9]; - } - - D_ReadUserInfoStrings (netbuffer[1], &stream, false); - if (!nodeingame[node]) - { - version = (netbuffer[2] << 16) | (netbuffer[3] << 8) | netbuffer[4]; - if (version != (0xFF0000 | NETGAMEVERSION)) - { - I_Error ("Different " GAMENAME " versions cannot play a net game"); - } - - playeringame[netbuffer[1]] = true; - nodeingame[node] = true; - - data->playersdetected[0] |= 1 << netbuffer[1]; - - StartScreen->NetMessage ("Found %s (node %d, player %d)", - players[netbuffer[1]].userinfo.GetName(), - node, netbuffer[1]+1); - } - } - else if (netbuffer[0] == NCMD_SETUP+2) // got game info - { - data->gotsetup[0] = 0x80; - - ticdup = netbuffer[1]; - NetMode = netbuffer[2]; - - stream = &netbuffer[3]; - s = ReadString (&stream); - startmap = s; - delete[] s; - rngseed = ReadLong (&stream); - C_ReadCVars (&stream); - } - else if (netbuffer[0] == NCMD_SETUP+3) - { - return true; - } - } - - // If everybody already knows everything, it's time to go - if (consoleplayer == Net_Arbitrator) - { - for (i = 0; i < doomcom->numnodes; ++i) - if (data->playersdetected[i] != uint32_t(1 << doomcom->numnodes) - 1 || !data->gotsetup[i]) - break; - - if (i == doomcom->numnodes) - return true; - } - - netbuffer[2] = 255; - netbuffer[3] = (NETGAMEVERSION >> 8) & 255; - netbuffer[4] = NETGAMEVERSION & 255; - netbuffer[5] = data->playersdetected[0] >> 24; - netbuffer[6] = data->playersdetected[0] >> 16; - netbuffer[7] = data->playersdetected[0] >> 8; - netbuffer[8] = data->playersdetected[0]; - - if (consoleplayer != Net_Arbitrator) - { // Send user info for the local node - netbuffer[0] = NCMD_SETUP; - netbuffer[1] = consoleplayer; - netbuffer[9] = data->gotsetup[0]; - stream = &netbuffer[10]; - D_WriteUserInfoStrings (consoleplayer, &stream, true); - SendSetup (data->playersdetected, data->gotsetup, int(stream - netbuffer.data)); - } - else - { // Send user info for all nodes - netbuffer[0] = NCMD_SETUP+1; - for (i = 1; i < doomcom->numnodes; ++i) - { - for (j = 0; j < doomcom->numnodes; ++j) - { - // Send info about player j to player i? - if ((data->playersdetected[0] & (1<playersdetected[i] & (1<playersdetected, data->gotsetup, int(stream - netbuffer.data)); - } - return false; -} - -void Network::D_ArbitrateNetStart() -{ - ArbitrateData data; - int i; - - // Return right away if we're just playing with ourselves. - if (doomcom->numnodes == 1) - return; - - autostart = true; - - memset (data.playersdetected, 0, sizeof(data.playersdetected)); - memset (data.gotsetup, 0, sizeof(data.gotsetup)); - - // The arbitrator knows about himself, but the other players must - // be told about themselves, in case the host had to adjust their - // userinfo (e.g. assign them to a different team). - if (consoleplayer == Net_Arbitrator) - { - data.playersdetected[0] = 1 << consoleplayer; - } - - // Assign nodes to players. The local player is always node 0. - // If the local player is not the host, then the host is node 1. - // Any remaining players are assigned node numbers in the order - // they were detected. - playerfornode[0] = consoleplayer; - nodeforplayer[consoleplayer] = 0; - if (consoleplayer == Net_Arbitrator) - { - for (i = 1; i < doomcom->numnodes; ++i) - { - playerfornode[i] = i; - nodeforplayer[i] = i; - } - } - else - { - playerfornode[1] = 0; - nodeforplayer[0] = 1; - for (i = 1; i < doomcom->numnodes; ++i) - { - if (i < consoleplayer) - { - playerfornode[i+1] = i; - nodeforplayer[i] = i+1; - } - else if (i > consoleplayer) - { - playerfornode[i] = i; - nodeforplayer[i] = i; - } - } - } - - if (consoleplayer == Net_Arbitrator) - { - data.gotsetup[0] = 0x80; - } - - StartScreen->NetInit ("Exchanging game information", 1); - if (!StartScreen->NetLoop([&] { return DoArbitrate(&data); })) - { - exit (0); - } - - if (consoleplayer == Net_Arbitrator) - { - netbuffer[0] = NCMD_SETUP+3; - SendSetup (data.playersdetected, data.gotsetup, 1); - } - - if (debugfile) - { - for (i = 0; i < doomcom->numnodes; ++i) - { - fprintf (debugfile, "player %d is on node %d\n", i, nodeforplayer[i]); - } - } - StartScreen->NetDone(); -} - -void Network::SendSetup (uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[MAXNETNODES], int len) -{ - if (consoleplayer != Net_Arbitrator) - { - if (playersdetected[1] & (1 << consoleplayer)) - { - HSendPacket (1, 10); - } - else - { - HSendPacket (1, len); - } - } - else - { - for (int i = 1; i < doomcom->numnodes; ++i) - { - if (!gotsetup[i] || netbuffer[0] == NCMD_SETUP+3) - { - HSendPacket (i, len); - } - } - } + lastglobalrecvtime = 0; } // Works out player numbers among the net participants @@ -1690,8 +515,41 @@ void Network::D_CheckNetGame() "\nIf the game is running well below expected speeds, use netmode 0 (P2P) instead.\n"); } - // I_InitNetwork sets doomcom and netgame - doomcom = I_InitNetwork(); + int port = DOOMPORT; + v = Args->CheckValue("-port"); + if (v) + { + port = atoi(v); + Printf("using alternate port %i\n", port); + } + + // parse network game options, + // player 1: -host + // player x: -join + if ((i = Args->CheckParm("-host"))) + { + doomcom = I_InitNetwork(port); + //HostGame(i); + } + else if ((i = Args->CheckParm("-join"))) + { + 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"); + + doomcom = I_InitNetwork(0); + doomcom->Connect(Args->GetArg(i + 1)); + //JoinGame(i); + } + else + { + // single player game + netgame = false; + multiplayer = false; + //numplayers = numnodes = 1; + consoleplayer = 0; + } v = Args->CheckValue("-dup"); if (v) @@ -1705,6 +563,7 @@ void Network::D_CheckNetGame() players[0].settings_controller = true; + /* consoleplayer = doomcom->consoleplayer; if (consoleplayer == Net_Arbitrator) @@ -1725,24 +584,30 @@ void Network::D_CheckNetGame() net_extratic = 1; } } + */ // [RH] Setup user info - D_SetupUserInfo (); + D_SetupUserInfo(); - if (Args->CheckParm ("-debugfile")) + if (Args->CheckParm("-debugfile")) { char filename[20]; - mysnprintf (filename, countof(filename), "debug%i.txt", consoleplayer); - Printf ("debug output to: %s\n", filename); - debugfile = fopen (filename, "w"); + mysnprintf(filename, countof(filename), "debug%i.txt", consoleplayer); + Printf("debug output to: %s\n", filename); + debugfile = fopen(filename, "w"); } if (netgame) { - GameConfig->ReadNetVars (); // [RH] Read network ServerInfo cvars - D_ArbitrateNetStart (); + GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars + //D_ArbitrateNetStart(); } + consoleplayer = 0; + playeringame[0] = true; + nodeingame[0] = true; + + /* for (i = 0; i < doomcom->numplayers; i++) playeringame[i] = true; for (i = 0; i < doomcom->numnodes; i++) @@ -1753,357 +618,21 @@ void Network::D_CheckNetGame() Printf("Arbitrator selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode.\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server"); } - if (!batchrun) Printf ("player %i of %i (%i nodes)\n", - consoleplayer+1, doomcom->numplayers, doomcom->numnodes); + if (!batchrun) Printf("player %i of %i (%i nodes)\n", + consoleplayer + 1, doomcom->numplayers, doomcom->numnodes); + */ } - -// Called before quitting to leave a net game without hanging the other players -void Network::D_QuitNetGame() +void Network::ListPingTimes() { - int i, j, k; - - if (!netgame || !usergame || consoleplayer == -1 || demoplayback) - return; - - // send a bunch of packets for security - netbuffer[0] = NCMD_EXIT; - netbuffer[1] = 0; - - k = 2; - if (NetMode == NET_PacketServer && consoleplayer == Net_Arbitrator) - { - uint8_t *foo = &netbuffer[2]; - - // Let the new arbitrator know what resendto counts to use - - for (i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && i != consoleplayer) - WriteLong (resendto[nodeforplayer[i]], &foo); - } - k = int(foo - netbuffer.data); - } - - for (i = 0; i < 4; i++) - { - if (NetMode == NET_PacketServer && consoleplayer != Net_Arbitrator) - { - HSendPacket (nodeforplayer[Net_Arbitrator], 2); - } - else - { - for (j = 1; j < doomcom->numnodes; j++) - if (nodeingame[j]) - HSendPacket (j, k); - } - I_WaitVBL (1); - } - - if (debugfile) - fclose (debugfile); + for (int i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + Printf("% 4" PRId64 " %s\n", currrecvtime[i] - lastrecvtime[i], players[i].userinfo.GetName()); } -void Network::TryRunTics() +// Implement players who have the ability to change settings in a network game. +void Network::Network_Controller(int playernum, bool add) { - int i; - int lowtic; - int realtics; - int availabletics; - int counts; - int numplaying; - - if (singletics) - { - I_StartTic(); - D_ProcessEvents(); - netcmds[consoleplayer][maketic%BACKUPTICS] = G_BuildTiccmd(); - if (advancedemo) - D_DoAdvanceDemo(); - C_Ticker(); - M_Ticker(); - G_Ticker(); - // [RH] Use the consoleplayer's camera to update sounds - S_UpdateSounds(players[consoleplayer].camera); // move positional sounds - gametic++; - maketic++; - GC::CheckGC(); - Net_NewMakeTic(); - return; - } - - // If paused, do not eat more CPU time than we need, because it - // will all be wasted anyway. - if (pauseext) - r_NoInterpolate = true; - bool doWait = cl_capfps || r_NoInterpolate /*|| netgame*/; - - // get real tics - if (doWait) - { - entertic = I_WaitForTic (oldentertics); - } - else - { - entertic = I_GetTime (); - } - realtics = entertic - oldentertics; - oldentertics = entertic; - - // get available tics - NetUpdate (); - - if (pauseext) - return; - - lowtic = INT_MAX; - numplaying = 0; - for (i = 0; i < doomcom->numnodes; i++) - { - if (nodeingame[i]) - { - numplaying++; - if (nettics[i] < lowtic) - lowtic = nettics[i]; - } - } - - if (ticdup == 1) - { - availabletics = lowtic - gametic; - } - else - { - availabletics = lowtic - gametic / ticdup; - } - - // decide how many tics to run - if (realtics < availabletics-1) - counts = realtics+1; - else if (realtics < availabletics) - counts = realtics; - else - counts = availabletics; - - // Uncapped framerate needs seprate checks - if (counts == 0 && !doWait) - { - // Check possible stall conditions - Net_CheckLastReceived(counts); - if (realtics >= 1) - { - C_Ticker(); - M_Ticker(); - // Repredict the player for new buffered movement - P_UnPredictPlayer(); - P_PredictPlayer(&players[consoleplayer]); - } - return; - } - - if (counts < 1) - counts = 1; - - if (debugfile) - fprintf (debugfile, - "=======real: %i avail: %i game: %i\n", - realtics, availabletics, counts); - - // wait for new tics if needed - while (lowtic < gametic + counts) - { - NetUpdate (); - lowtic = INT_MAX; - - for (i = 0; i < doomcom->numnodes; i++) - if (nodeingame[i] && nettics[i] < lowtic) - lowtic = nettics[i]; - - lowtic = lowtic * ticdup; - - if (lowtic < gametic) - I_Error ("TryRunTics: lowtic < gametic"); - - // Check possible stall conditions - Net_CheckLastReceived (counts); - - // Update time returned by I_GetTime, but only if we are stuck in this loop - if (lowtic < gametic + counts) - I_SetFrameTime(); - - // don't stay in here forever -- give the menu a chance to work - if (I_GetTime () - entertic >= 1) - { - C_Ticker (); - M_Ticker (); - // Repredict the player for new buffered movement - P_UnPredictPlayer(); - P_PredictPlayer(&players[consoleplayer]); - return; - } - } - - //Tic lowtic is high enough to process this gametic. Clear all possible waiting info - hadlate = false; - for (i = 0; i < MAXPLAYERS; i++) - players[i].waiting = false; - lastglobalrecvtime = I_GetTime (); //Update the last time the game tic'd over - - // run the count tics - if (counts > 0) - { - P_UnPredictPlayer(); - while (counts--) - { - if (gametic > lowtic) - { - I_Error ("gametic>lowtic"); - } - if (advancedemo) - { - D_DoAdvanceDemo (); - } - if (debugfile) fprintf (debugfile, "run tic %d\n", gametic); - C_Ticker (); - M_Ticker (); - G_Ticker(); - gametic++; - - NetUpdate (); // check for new console commands - } - P_PredictPlayer(&players[consoleplayer]); - S_UpdateSounds (players[consoleplayer].camera); // move positional sounds - } -} - -void Network::Net_CheckLastReceived(int counts) -{ - // [Ed850] Check to see the last time a packet was received. - // If it's longer then 3 seconds, a node has likely stalled. - if (I_GetTime() - lastglobalrecvtime >= TICRATE * 3) - { - lastglobalrecvtime = I_GetTime(); //Bump the count - - if (NetMode == NET_PeerToPeer || consoleplayer == Net_Arbitrator) - { - //Keep the local node in the for loop so we can still log any cases where the local node is /somehow/ late. - //However, we don't send a resend request for sanity reasons. - for (int i = 0; i < doomcom->numnodes; i++) - { - if (nodeingame[i] && nettics[i] <= gametic + counts) - { - if (debugfile && !players[playerfornode[i]].waiting) - fprintf(debugfile, "%i is slow (%i to %i)\n", - i, nettics[i], gametic + counts); - //Send resend request to the late node. Also mark the node as waiting to display it in the hud. - if (i != 0) - remoteresend[i] = players[playerfornode[i]].waiting = hadlate = true; - } - else - players[playerfornode[i]].waiting = false; - } - } - else - { //Send a resend request to the Arbitrator, as it's obvious we are stuck here. - if (debugfile && !players[Net_Arbitrator].waiting) - fprintf(debugfile, "Arbitrator is slow (%i to %i)\n", - nettics[nodeforplayer[Net_Arbitrator]], gametic + counts); - //Send resend request to the Arbitrator. Also mark the Arbitrator as waiting to display it in the hud. - remoteresend[nodeforplayer[Net_Arbitrator]] = players[Net_Arbitrator].waiting = hadlate = true; - } - } -} - -void Network::Net_NewMakeTic() -{ - specials.NewMakeTic (); -} - -void Network::Net_WriteByte(uint8_t it) -{ - specials << it; -} - -void Network::Net_WriteWord(short it) -{ - specials << it; -} - -void Network::Net_WriteLong(int it) -{ - specials << it; -} - -void Network::Net_WriteFloat(float it) -{ - specials << it; -} - -void Network::Net_WriteString(const char *it) -{ - specials << it; -} - -void Network::Net_WriteBytes(const uint8_t *block, int len) -{ - while (len--) - specials << *block++; -} - -bool Network::IsInconsistent(int player, int16_t checkvalue) const -{ - int buf = (gametic / ticdup) % BACKUPTICS; - return gametic > BACKUPTICS*ticdup && consistency[player][buf] != checkvalue; -} - -void Network::SetConsistency(int player, int16_t checkvalue) -{ - int buf = (gametic / ticdup) % BACKUPTICS; - consistency[player][buf] = checkvalue; -} - -int16_t Network::GetConsoleConsistency() const -{ - return consistency[consoleplayer][(maketic / ticdup) % BACKUPTICS]; -} - -size_t Network::CopySpecData(int player, uint8_t *dest, size_t dest_size) -{ - if (gametic % ticdup != 0) - return 0; - - int buf = (gametic / ticdup) % BACKUPTICS; - - int speclen = 0; - uint8_t *specdata = NetSpecs[player][buf].GetData(&speclen); - if (!specdata) - return 0; - - if (dest_size < speclen) - I_FatalError("Demo buffer too small for CopySpecData"); - - memcpy(dest, specdata, speclen); - NetSpecs[player][buf].SetData(nullptr, 0); // Why is this needed? - return speclen; -} - -int Network::GetPing(int player) const -{ - int node = nodeforplayer[player]; - int avgdelay = 0; - for (int i = 0; i < BACKUPTICS; i++) - avgdelay += netdelay[node][i]; - return avgdelay * ticdup * 1000 / TICRATE / BACKUPTICS; -} - -int Network::GetServerPing() const -{ - return GetPing(Net_Arbitrator); -} - -int Network::GetHighPingThreshold() const -{ - return ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE); } //========================================================================== @@ -2939,60 +1468,6 @@ void Net_SkipCommand (int type, uint8_t **stream) *stream += skip; } -void Network::ListPingTimes() -{ - for (int i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - Printf("% 4" PRId64 " %s\n", currrecvtime[i] - lastrecvtime[i], players[i].userinfo.GetName()); -} - -// Implement players who have the ability to change settings in a network game. -void Network::Network_Controller(int playernum, bool add) -{ - if (consoleplayer != Net_Arbitrator) - { - Printf("This command is only accessible to the net arbitrator.\n"); - return; - } - - if (players[playernum].settings_controller && add) - { - Printf("%s is already on the setting controller list.\n", players[playernum].userinfo.GetName()); - return; - } - - if (!players[playernum].settings_controller && !add) - { - Printf("%s is not on the setting controller list.\n", players[playernum].userinfo.GetName()); - return; - } - - if (!playeringame[playernum]) - { - Printf("Player (%d) not found!\n", playernum); - return; - } - - if (players[playernum].Bot != NULL) - { - Printf("Bots cannot be added to the controller list.\n"); - return; - } - - if (playernum == Net_Arbitrator) - { - Printf("The net arbitrator cannot have their status changed on this list.\n"); - return; - } - - if (add) - Net_WriteByte(DEM_ADDCONTROLLER); - else - Net_WriteByte(DEM_DELCONTROLLER); - - Net_WriteByte(playernum); -} - CCMD (pings) { network.ListPingTimes(); diff --git a/src/d_net.h b/src/d_net.h index 11961dc1ee..21820ff7f2 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -78,12 +78,6 @@ public: TicSpecial &operator << (const char *it); }; -struct ArbitrateData -{ - uint32_t playersdetected[MAXNETNODES]; - uint8_t gotsetup[MAXNETNODES]; -}; - struct Network { public: @@ -91,11 +85,6 @@ public: void DispatchEvents(int tic); void SetPlayerCommand(int player, ticcmd_t cmd); -private: - void TryRunTics(); -public: - void NetUpdate() { } - void D_CheckNetGame(); void Net_ClearBuffers(); void D_QuitNetGame(); @@ -133,18 +122,6 @@ public: int ticdup; // 1 = no duplication, 2-5 = dup for slow nets private: - int NetbufferSize(); - int ExpandTics(int low); - void HSendPacket(int node, int len); - bool HGetPacket(); - void PlayerIsGone(int netnode, int netconsole); - void GetPackets(); - bool DoArbitrate(ArbitrateData *data); - void D_ArbitrateNetStart(); - void Net_CheckLastReceived(int counts); - - void SendSetup(uint32_t playersdetected[MAXNETNODES], uint8_t gotsetup[MAXNETNODES], int len); - void ReadTicCmd(uint8_t **stream, int player, int tic); std::unique_ptr doomcom; @@ -228,3 +205,15 @@ void Net_SkipCommand (int type, uint8_t **stream); #define NCMD_2TICS 0x02 // packet contains 2 tics #define NCMD_1TICS 0x01 // packet contains 1 tic #define NCMD_0TICS 0x00 // packet contains 0 tics + +enum +{ + PRE_CONNECT, // Sent from guest to host for initial connection + PRE_KEEPALIVE, + PRE_DISCONNECT, // Sent from guest that aborts the game + PRE_ALLHERE, // Sent from host to guest when everybody has connected + PRE_CONACK, // Sent from host to guest to acknowledge PRE_CONNECT receipt + PRE_ALLFULL, // Sent from host to an unwanted guest + PRE_ALLHEREACK, // Sent from guest to host to acknowledge PRE_ALLHEREACK receipt + PRE_GO // Sent from host to guest to continue game startup +}; diff --git a/src/i_net.cpp b/src/i_net.cpp index 8bef2e1cb5..9791c3f45e 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -69,6 +69,7 @@ #include "doomstat.h" #include "i_net.h" +#include "i_time.h" // As per http://support.microsoft.com/kb/q192599/ the standard // size for network buffers is 8k. @@ -101,127 +102,101 @@ const char *neterror (void); #define neterror() strerror(errno) #endif -enum -{ - PRE_CONNECT, // Sent from guest to host for initial connection - PRE_KEEPALIVE, - PRE_DISCONNECT, // Sent from guest that aborts the game - PRE_ALLHERE, // Sent from host to guest when everybody has connected - PRE_CONACK, // Sent from host to guest to acknowledge PRE_CONNECT receipt - PRE_ALLFULL, // Sent from host to an unwanted guest - PRE_ALLHEREACK, // Sent from guest to host to acknowledge PRE_ALLHEREACK receipt - PRE_GO // Sent from host to guest to continue game startup -}; - -// 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 -{ - uint8_t Fake; - uint8_t Message; - uint8_t NumNodes; - union - { - uint8_t ConsoleNum; - uint8_t NumPresent; - }; - struct - { - uint32_t address; - uint16_t port; - uint8_t player; - uint8_t pad; - } machines[MAXNETNODES]; -}; - class DoomComImpl : public doomcom_t { public: - DoomComImpl(); - ~DoomComImpl() { CloseNetwork(); } + DoomComImpl(int port); + ~DoomComImpl(); void PacketSend(const NetPacket &packet) override; void PacketGet(NetPacket &packet) override; + int Connect(const char *name) override; + void Close(int node) override; + private: - u_short DOOMPORT = (IPPORT_USERRESERVED + 29); - SOCKET mysocket = INVALID_SOCKET; - sockaddr_in sendaddress[MAXNETNODES]; - uint8_t sendplayer[MAXNETNODES]; - - uint8_t TransmitBuffer[TRANSMIT_SIZE]; - - SOCKET UDPsocket(); - void BindToLocalPort(SOCKET s, u_short port); - int FindNode(const sockaddr_in *address); - sockaddr_in *PreGet(void *buffer, int bufferlen, bool noabort); - void PreSend(const void *buffer, int bufferlen, const sockaddr_in *to); void BuildAddress(sockaddr_in *address, const char *name); - void CloseNetwork(); - void StartNetwork(bool autoPort); - void SendAbort(); - void SendConAck(int num_connected, int num_needed); - bool Host_CheckForConnects(); - bool Host_SendAllHere(int *gotack); - void HostGame(int i); - bool Guest_ContactHost(); - bool Guest_WaitForOthers(); - void JoinGame(int i); + int FindNode(const sockaddr_in *address); - static int PrivateNetOf(in_addr in); - bool NodesOnSameNetwork(); + SOCKET mSocket = INVALID_SOCKET; + + sockaddr_in mNodeEndpoints[MAXNETNODES]; + uint64_t mNodeLastUpdate[MAXNETNODES]; + + uint8_t mTransmitBuffer[TRANSMIT_SIZE]; }; -std::unique_ptr I_InitNetwork() +std::unique_ptr I_InitNetwork(int port) { - return std::unique_ptr(new DoomComImpl()); + return std::unique_ptr(new DoomComImpl(port)); } -SOCKET DoomComImpl::UDPsocket() +DoomComImpl::DoomComImpl(int port) { - 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 ()); + memset(mNodeEndpoints, 0, sizeof(mNodeEndpoints)); + memset(mNodeLastUpdate, 0, sizeof(mNodeLastUpdate)); - return s; + mSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (mSocket == INVALID_SOCKET) + I_FatalError("can't create socket: %s", neterror()); + + if (port != 0) + { + 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); + + int v = bind(mSocket, (sockaddr *)&address, sizeof(address)); + if (v == SOCKET_ERROR) + I_FatalError("BindToPort: %s", neterror()); + } } -void DoomComImpl::BindToLocalPort(SOCKET s, u_short port) +DoomComImpl::~DoomComImpl() { - int v; - sockaddr_in address; + if (mSocket != INVALID_SOCKET) + { + closesocket(mSocket); + mSocket = INVALID_SOCKET; + } +} - 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 DoomComImpl::Connect(const char *name) +{ + sockaddr_in addr; + BuildAddress(&addr, name); + return FindNode(&addr); +} + +void DoomComImpl::Close(int node) +{ + mNodeLastUpdate[node] = 0; } int DoomComImpl::FindNode(const 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 == numnodes) + int slot = -1; + for (int i = 0; i < MAXNETNODES; i++) { - // packet is not from one of the players (new game broadcast?) - i = -1; + if (mNodeLastUpdate[i] != 0 && address->sin_addr.s_addr == mNodeEndpoints[i].sin_addr.s_addr && address->sin_port == mNodeEndpoints[i].sin_port) + { + slot = i; + break; + } + else if (mNodeLastUpdate[i] == 0) + { + slot = i; + } } - return i; + + if (slot == -1) + return -1; + + mNodeEndpoints[slot] = *address; + mNodeLastUpdate[slot] = I_nsTime(); + return slot; } void DoomComImpl::PacketSend(const NetPacket &packet) @@ -240,8 +215,8 @@ void DoomComImpl::PacketSend(const NetPacket &packet) uLong size = TRANSMIT_SIZE - 1; if (packet.datalength >= 10) { - TransmitBuffer[0] = packet.data[0] | NCMD_COMPRESSED; - c = compress2(TransmitBuffer + 1, &size, packet.data + 1, packet.datalength - 1, 9); + mTransmitBuffer[0] = packet.data[0] | NCMD_COMPRESSED; + c = compress2(mTransmitBuffer + 1, &size, packet.data + 1, packet.datalength - 1, 9); size += 1; } else @@ -250,8 +225,8 @@ void DoomComImpl::PacketSend(const NetPacket &packet) } if (c == Z_OK && size < (uLong)packet.datalength) { -// Printf("send %lu/%d\n", size, datalength); - c = sendto(mysocket, (char *)TransmitBuffer, size, 0, (sockaddr *)&sendaddress[packet.remotenode], sizeof(sendaddress[packet.remotenode])); + // Printf("send %lu/%d\n", size, datalength); + c = sendto(mSocket, (char *)mTransmitBuffer, size, 0, (sockaddr *)&mNodeEndpoints[packet.remotenode], sizeof(mNodeEndpoints[packet.remotenode])); } else { @@ -261,8 +236,8 @@ void DoomComImpl::PacketSend(const NetPacket &packet) } else { -// Printf("send %d\n", datalength); - c = sendto(mysocket, (char *)packet.data, packet.datalength, 0, (sockaddr *)&sendaddress[packet.remotenode], sizeof(sendaddress[packet.remotenode])); + // Printf("send %d\n", datalength); + c = sendto(mSocket, (char *)packet.data, packet.datalength, 0, (sockaddr *)&mNodeEndpoints[packet.remotenode], sizeof(mNodeEndpoints[packet.remotenode])); } } // if (c == -1) @@ -271,106 +246,78 @@ void DoomComImpl::PacketSend(const NetPacket &packet) void DoomComImpl::PacketGet(NetPacket &packet) { - int c; - socklen_t fromlen; - sockaddr_in fromaddress; - int node; - - fromlen = sizeof(fromaddress); - c = recvfrom (mysocket, (char*)TransmitBuffer, TRANSMIT_SIZE, 0, (sockaddr *)&fromaddress, &fromlen); - node = FindNode (&fromaddress); - - if (node >= 0 && c == SOCKET_ERROR) + // First check if anything timed out. Treat this as a close. + uint64_t nowtime = I_nsTime(); + for (int i = 0; i < MAXNETNODES; i++) { - int err = WSAGetLastError(); - - if (err == WSAECONNRESET) - { // The remote node aborted unexpectedly, so pretend it sent an exit packet - - if (StartScreen != NULL) - { - StartScreen->NetMessage ("The connection from %s was dropped.\n", - players[sendplayer[node]].userinfo.GetName()); - } - else - { - Printf("The connection from %s was dropped.\n", - players[sendplayer[node]].userinfo.GetName()); - } - - packet.data[0] = 0x80; // NCMD_EXIT - c = 1; - } - else if (err != WSAEWOULDBLOCK) + if (mNodeLastUpdate[i] != 0 && nowtime - mNodeLastUpdate[i] > 5'000'000'000) // 5 second timeout { - I_Error ("GetPacket: %s", neterror ()); - } - else - { - packet.remotenode = -1; // no packet + Close(i); + packet.remotenode = i; + packet.datalength = 0; return; } } - else if (node >= 0 && c > 0) + + while (true) { - packet.data[0] = TransmitBuffer[0] & ~NCMD_COMPRESSED; - if (TransmitBuffer[0] & NCMD_COMPRESSED) + sockaddr_in fromaddress; + socklen_t fromlen = sizeof(fromaddress); + int datalength = recvfrom(mSocket, (char*)mTransmitBuffer, TRANSMIT_SIZE, 0, (sockaddr *)&fromaddress, &fromlen); + if (datalength == SOCKET_ERROR) { - uLongf msgsize = MAX_MSGLEN - 1; - int err = uncompress(packet.data + 1, &msgsize, TransmitBuffer + 1, c - 1); -// Printf("recv %d/%lu\n", c, msgsize + 1); - if (err != Z_OK) + int err = WSAGetLastError(); + + if (err == WSAECONNRESET) // The remote node aborted unexpectedly. Treat this as a close. { - Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars()); - // Pretend no packet - packet.remotenode = -1; + int node = FindNode(&fromaddress); + if (node == -1) + continue; + + Close(node); + packet.remotenode = node; + packet.datalength = 0; + return; + } + else if (err != WSAEWOULDBLOCK) + { + I_Error("GetPacket: %s", neterror()); + } + else // no packet + { + packet.remotenode = -1; + packet.datalength = 0; return; } - c = msgsize + 1; } - else + else if (datalength > 0) { -// Printf("recv %d\n", c); - memcpy(packet.data + 1, TransmitBuffer + 1, c - 1); + int node = FindNode(&fromaddress); + if (node == -1) + continue; + + packet.data[0] = mTransmitBuffer[0] & ~NCMD_COMPRESSED; + if (mTransmitBuffer[0] & NCMD_COMPRESSED) + { + uLongf msgsize = MAX_MSGLEN - 1; + int err = uncompress(packet.data + 1, &msgsize, mTransmitBuffer + 1, datalength - 1); + if (err != Z_OK) + { + Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars()); + continue; + } + datalength = msgsize + 1; + } + else + { + memcpy(packet.data + 1, mTransmitBuffer + 1, datalength - 1); + } + + packet.remotenode = node; + packet.datalength = (short)datalength; + return; } } - else if (c > 0) - { //The packet is not from any in-game node, so we might as well discard it. - // Don't show the message for disconnect notifications. - if (c != 2 || TransmitBuffer[0] != PRE_FAKE || TransmitBuffer[1] != PRE_DISCONNECT) - { - DPrintf(DMSG_WARNING, "Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port); - } - packet.remotenode = -1; - return; - } - - packet.remotenode = node; - packet.datalength = (short)c; -} - -sockaddr_in *DoomComImpl::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 DoomComImpl::PreSend(const void *buffer, int bufferlen, const sockaddr_in *to) -{ - sendto (mysocket, (const char *)buffer, bufferlen, 0, (const sockaddr *)to, sizeof(*to)); } void DoomComImpl::BuildAddress(sockaddr_in *address, const char *name) @@ -385,13 +332,13 @@ void DoomComImpl::BuildAddress(sockaddr_in *address, const char *name) address->sin_family = AF_INET; - if ( (portpart = strchr (name, ':')) ) + if ((portpart = strchr(name, ':'))) { target = FString(name, portpart - name); - port = atoi (portpart + 1); + port = atoi(portpart + 1); if (!port) { - Printf ("Weird port: %s (using %d)\n", portpart + 1, DOOMPORT); + Printf("Weird port: %s (using %d)\n", portpart + 1, DOOMPORT); port = DOOMPORT; } } @@ -402,7 +349,7 @@ void DoomComImpl::BuildAddress(sockaddr_in *address, const char *name) } address->sin_port = htons(port); - for (curchar = 0; (c = target[curchar]) ; curchar++) + for (curchar = 0; (c = target[curchar]); curchar++) { if ((c < '0' || c > '9') && c != '.') { @@ -413,554 +360,16 @@ void DoomComImpl::BuildAddress(sockaddr_in *address, const char *name) if (!isnamed) { - address->sin_addr.s_addr = inet_addr (target); - Printf ("Node number %d, address %s\n", numnodes, target.GetChars()); + address->sin_addr.s_addr = inet_addr(target); + // Printf("Node number %d, address %s\n", numnodes, target.GetChars()); } else { - hostentry = gethostbyname (target); + hostentry = gethostbyname(target); if (!hostentry) - I_FatalError ("gethostbyname: couldn't find %s\n%s", target.GetChars(), neterror()); + I_FatalError("gethostbyname: couldn't find %s\n%s", target.GetChars(), neterror()); address->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; - Printf ("Node number %d, hostname %s\n", numnodes, hostentry->h_name); - } -} - -void DoomComImpl::CloseNetwork() -{ - if (mysocket != INVALID_SOCKET) - { - closesocket (mysocket); - mysocket = INVALID_SOCKET; - } -#ifdef __WIN32__ - WSACleanup (); -#endif -} - -void DoomComImpl::StartNetwork(bool autoPort) -{ - u_long trueval = 1; -#ifdef __WIN32__ - WSADATA wsad; - - if (WSAStartup (0x0101, &wsad)) - { - I_FatalError ("Could not initialize Windows Sockets"); - } -#endif - - netgame = true; - multiplayer = true; - - // create communication socket - mysocket = UDPsocket (); - BindToLocalPort (mysocket, autoPort ? 0 : DOOMPORT); -#ifndef __sun - ioctlsocket (mysocket, FIONBIO, &trueval); -#else - fcntl(mysocket, F_SETFL, trueval | O_NONBLOCK); -#endif -} - -void DoomComImpl::SendAbort() -{ - uint8_t dis[2] = { PRE_FAKE, PRE_DISCONNECT }; - int i, j; - - if (numnodes > 1) - { - if (consoleplayer == 0) - { - // The host needs to let everyone know - for (i = 1; i < numnodes; ++i) - { - for (j = 4; j > 0; --j) - { - PreSend (dis, 2, &sendaddress[i]); - } - } - } - else - { - // Guests only need to let the host know. - for (i = 4; i > 0; --i) - { - PreSend (dis, 2, &sendaddress[1]); - } - } - } -} - -void DoomComImpl::SendConAck (int num_connected, int num_needed) -{ - PreGamePacket packet; - - packet.Fake = PRE_FAKE; - packet.Message = PRE_CONACK; - packet.NumNodes = num_needed; - packet.NumPresent = num_connected; - for (int node = 1; node < numnodes; ++node) - { - PreSend (&packet, 4, &sendaddress[node]); - } - StartScreen->NetProgress (numnodes); -} - -bool DoomComImpl::Host_CheckForConnects() -{ - PreGamePacket packet; - sockaddr_in *from; - int node; - - while ( (from = PreGet (&packet, sizeof(packet), false)) ) - { - if (packet.Fake != PRE_FAKE) - { - continue; - } - switch (packet.Message) - { - case PRE_CONNECT: - node = FindNode (from); - if (numnodes == numplayers) - { - if (node == -1) - { - const uint8_t *s_addr_bytes = (const uint8_t *)&from->sin_addr; - StartScreen->NetMessage ("Got extra connect from %d.%d.%d.%d:%d", - s_addr_bytes[0], s_addr_bytes[1], s_addr_bytes[2], s_addr_bytes[3], - from->sin_port); - packet.Message = PRE_ALLFULL; - PreSend (&packet, 2, from); - } - } - else - { - if (node == -1) - { - node = numnodes++; - sendaddress[node] = *from; - StartScreen->NetMessage ("Got connect from node %d.", node); - } - - // Let the new guest (and everyone else) know we got their message. - SendConAck (numnodes, numplayers); - } - break; - - case PRE_DISCONNECT: - node = FindNode (from); - if (node >= 0) - { - StartScreen->NetMessage ("Got disconnect from node %d.", node); - numnodes--; - while (node < numnodes) - { - sendaddress[node] = sendaddress[node+1]; - node++; - } - - // Let remaining guests know that somebody left. - SendConAck (numnodes, numplayers); - } - break; - - case PRE_KEEPALIVE: - break; - } - } - if (numnodes < numplayers) - { - // Send message to everyone as a keepalive - SendConAck(numnodes, numplayers); - return false; - } - - // 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) - { - numnodes--; - while (node < numnodes) - { - sendaddress[node] = sendaddress[node+1]; - node++; - } - // Let remaining guests know that somebody left. - SendConAck (numnodes, numplayers); - } - break; - } - } - return numnodes >= numplayers; -} - -bool DoomComImpl::Host_SendAllHere(int *gotack) -{ - PreGamePacket packet; - int node; - sockaddr_in *from; - - // Send out address information to all guests. Guests that have already - // acknowledged receipt effectively get just a heartbeat packet. - packet.Fake = PRE_FAKE; - packet.Message = PRE_ALLHERE; - for (node = 1; node < numnodes; node++) - { - int machine, spot = 0; - - packet.ConsoleNum = node; - if (!gotack[node]) - { - for (spot = 0, machine = 1; machine < 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. - } - } - packet.NumNodes = numnodes - 2; - } - else - { - packet.NumNodes = 0; - } - PreSend (&packet, 4 + spot*8, &sendaddress[node]); - } - - // Check for replies. - 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; - gotack[MAXNETNODES]++; - } - } - PreSend (&packet, 2, from); - } - } - - // If everybody has replied, then this loop can end. - return gotack[MAXNETNODES] == numnodes - 1; -} - -void DoomComImpl::HostGame(int i) -{ - PreGamePacket packet; - int node; - int gotack[MAXNETNODES+1]; - - if ((i == Args->NumArgs() - 1) || !(numplayers = atoi (Args->GetArg(i+1)))) - { // No player count specified, assume 2 - numplayers = 2; - } - - if (numplayers > MAXNETNODES) - { - I_FatalError("You cannot host a game with %d players. The limit is currently %d.", numplayers, MAXNETNODES); - return; - } - - if (numplayers == 1) - { // Special case: Only 1 player, so don't bother starting the network - netgame = false; - multiplayer = true; - numnodes = 1; - consoleplayer = 0; - return; - } - - StartNetwork (false); - - // [JC] - this computer is starting the game, therefore it should - // be the Net Arbitrator. - consoleplayer = 0; - Printf ("Console player number: %d\n", consoleplayer); - - numnodes = 1; - - StartScreen->NetInit ("Waiting for players", numplayers); - - // Wait for numplayers-1 different connections - if (!StartScreen->NetLoop([&] { return Host_CheckForConnects(); })) - { - SendAbort(); - exit (0); - } - - // Now inform everyone of all machines involved in the game - memset (gotack, 0, sizeof(gotack)); - StartScreen->NetMessage ("Sending all here."); - StartScreen->NetInit ("Done waiting", 1); - - if (!StartScreen->NetLoop([&] { return Host_SendAllHere(gotack); })) - { - SendAbort(); - exit (0); - } - - // Now go - StartScreen->NetMessage ("Go"); - packet.Fake = PRE_FAKE; - packet.Message = PRE_GO; - for (node = 1; node < numnodes; node++) - { - // If we send the packets eight times to each guest, - // hopefully at least one of them will get through. - for (int i = 8; i != 0; --i) - { - PreSend (&packet, 2, &sendaddress[node]); - } - } - - StartScreen->NetMessage ("Total players: %d", numnodes); - - numplayers = numnodes; - - // On the host, each player's number is the same as its node number - for (i = 0; i < numnodes; ++i) - { - sendplayer[i] = i; - } -} - -// 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. - -bool DoomComImpl::Guest_ContactHost() -{ - sockaddr_in *from; - PreGamePacket packet; - - // Let the host know we are here. - packet.Fake = PRE_FAKE; - packet.Message = PRE_CONNECT; - PreSend (&packet, 2, &sendaddress[1]); - - // Listen for a reply. - while ( (from = PreGet (&packet, sizeof(packet), true)) ) - { - if (packet.Fake == PRE_FAKE && FindNode(from) == 1) - { - if (packet.Message == PRE_CONACK) - { - StartScreen->NetMessage ("Total players: %d", packet.NumNodes); - StartScreen->NetInit ("Waiting for other players", packet.NumNodes); - StartScreen->NetProgress (packet.NumPresent); - return true; - } - else if (packet.Message == PRE_DISCONNECT) - { - numnodes = 0; - I_FatalError ("The host cancelled the game."); - } - else if (packet.Message == PRE_ALLFULL) - { - numnodes = 0; - I_FatalError ("The game is full."); - } - } - } - - // In case the progress bar could not be marqueed, bump it. - StartScreen->NetProgress (0); - - return false; -} - -bool DoomComImpl::Guest_WaitForOthers() -{ - sockaddr_in *from; - PreGamePacket packet; - - while ( (from = PreGet (&packet, sizeof(packet), false)) ) - { - if (packet.Fake != PRE_FAKE || FindNode(from) != 1) - { - continue; - } - switch (packet.Message) - { - case PRE_CONACK: - StartScreen->NetProgress (packet.NumPresent); - break; - - case PRE_ALLHERE: - if (numnodes == 2) - { - int node; - - numnodes = packet.NumNodes + 2; - sendplayer[0] = packet.ConsoleNum; // My player number - consoleplayer = packet.ConsoleNum; - StartScreen->NetMessage ("Console player number: %d", consoleplayer); - 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; - } - } - - StartScreen->NetMessage ("Received All Here, sending ACK."); - packet.Fake = PRE_FAKE; - packet.Message = PRE_ALLHEREACK; - PreSend (&packet, 2, &sendaddress[1]); - break; - - case PRE_GO: - StartScreen->NetMessage ("Received \"Go.\""); - return true; - - case PRE_DISCONNECT: - I_FatalError ("The host cancelled the game."); - break; - } - } - - packet.Fake = PRE_FAKE; - packet.Message = PRE_KEEPALIVE; - PreSend(&packet, 2, &sendaddress[1]); - - return false; -} - -void DoomComImpl::JoinGame(int i) -{ - 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; - numnodes = 2; - - // Let host know we are here - StartScreen->NetInit ("Contacting host", 0); - - if (!StartScreen->NetLoop([&] { return Guest_ContactHost(); })) - { - SendAbort(); - exit (0); - } - - // Wait for everyone else to connect - if (!StartScreen->NetLoop([&] { return Guest_WaitForOthers(); })) - { - SendAbort(); - exit (0); - } - - StartScreen->NetMessage ("Total players: %d", numnodes); - - numplayers = numnodes; -} - -int DoomComImpl::PrivateNetOf(in_addr in) -{ - int addr = ntohl(in.s_addr); - if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0 - { - return 0xC0A80000; - } - else if ((addr & 0xFFF00000) == 0xAC100000) // 172.16.0.0 - { - return 0xAC100000; - } - else if ((addr & 0xFF000000) == 0x0A000000) // 10.0.0.0 - { - return 0x0A000000; - } - else if ((addr & 0xFF000000) == 0x7F000000) // 127.0.0.0 (localhost) - { - return 0x7F000000; - } - // Not a private IP - return 0; -} - -// The best I can really do here is check if the others are on the same private network, since that means we (probably) are too. -bool DoomComImpl::NodesOnSameNetwork() -{ - int net1; - - net1 = PrivateNetOf(sendaddress[1].sin_addr); -// Printf("net1 = %08x\n", net1); - if (net1 == 0) - { - return false; - } - for (int i = 2; i < numnodes; ++i) - { - int net = PrivateNetOf(sendaddress[i].sin_addr); -// Printf("Net[%d] = %08x\n", i, net); - if (net != net1) - { - return false; - } - } - return true; -} - -DoomComImpl::DoomComImpl() -{ - int i; - const char *v; - - v = Args->CheckValue ("-port"); - if (v) - { - DOOMPORT = atoi (v); - Printf ("using alternate port %i\n", DOOMPORT); - } - - // parse network game options, - // player 1: -host - // player x: -join - if ( (i = Args->CheckParm ("-host")) ) - { - HostGame (i); - } - else if ( (i = Args->CheckParm ("-join")) ) - { - JoinGame (i); - } - else - { - // single player game - netgame = false; - multiplayer = false; - numplayers = numnodes = 1; - consoleplayer = 0; + // Printf("Node number %d, hostname %s\n", numnodes, hostentry->h_name); } } diff --git a/src/i_net.h b/src/i_net.h index e3402425d1..9a616ce6c0 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -4,6 +4,7 @@ #include #define MAX_MSGLEN 14000 +#define DOOMPORT 5029 struct NetPacket { @@ -30,12 +31,8 @@ struct doomcom_t virtual void PacketSend(const NetPacket &packet) = 0; virtual void PacketGet(NetPacket &packet) = 0; - // info common to all nodes - int16_t numnodes = 0; // console is always node 0. - - // info specific to this node - int16_t consoleplayer = 0; - int16_t numplayers = 0; + virtual int Connect(const char *name) = 0; + virtual void Close(int node) = 0; }; -std::unique_ptr I_InitNetwork(); +std::unique_ptr I_InitNetwork(int port); From e40b93232028847370c2e3f9c161382b0b3646b3 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 28 Mar 2018 03:31:33 +0200 Subject: [PATCH 07/17] - Convert the Network class into an interface and create three implementations of it: single player, client and server --- src/CMakeLists.txt | 3 + src/b_bot.cpp | 6 +- src/b_game.cpp | 14 +- src/b_think.cpp | 10 +- src/c_cmds.cpp | 136 +++++------ src/c_console.cpp | 2 +- src/c_cvars.cpp | 2 +- src/c_dispatch.cpp | 2 +- src/ct_chat.cpp | 8 +- src/d_main.cpp | 33 ++- src/d_net.cpp | 393 ++++++------------------------ src/d_net.h | 177 +++++--------- src/d_netclient.cpp | 207 ++++++++++++++++ src/d_netclient.h | 63 +++++ src/d_netinfo.cpp | 26 +- src/d_netserver.cpp | 226 +++++++++++++++++ src/d_netserver.h | 89 +++++++ src/d_netsingle.cpp | 147 +++++++++++ src/d_netsingle.h | 58 +++++ src/events.cpp | 14 +- src/g_game.cpp | 46 ++-- src/g_inventory/a_weapons.cpp | 32 +-- src/g_level.cpp | 2 +- src/g_shared/a_decals.cpp | 4 +- src/g_shared/shared_hud.cpp | 6 +- src/g_statusbar/shared_sbar.cpp | 2 +- src/hu_scores.cpp | 2 +- src/i_net.cpp | 44 ++-- src/i_net.h | 4 +- src/info.cpp | 12 +- src/intermission/intermission.cpp | 2 +- src/m_cheat.cpp | 4 +- src/p_conversation.cpp | 10 +- src/p_interaction.cpp | 18 +- src/p_lnspec.cpp | 2 +- src/p_user.cpp | 22 +- src/st_stuff.cpp | 4 +- src/statistics.cpp | 2 +- 38 files changed, 1160 insertions(+), 674 deletions(-) create mode 100644 src/d_netclient.cpp create mode 100644 src/d_netclient.h create mode 100644 src/d_netserver.cpp create mode 100644 src/d_netserver.h create mode 100644 src/d_netsingle.cpp create mode 100644 src/d_netsingle.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bbc6c0f22c..87dc9bf6c2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -910,6 +910,9 @@ set (PCH_SOURCES d_main.cpp d_stats.cpp d_net.cpp + d_netsingle.cpp + d_netserver.cpp + d_netclient.cpp d_netinfo.cpp d_protocol.cpp decallib.cpp diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 616c923c2e..cb71f629de 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -213,7 +213,7 @@ CCMD (removebots) return; } - network.Net_WriteByte (DEM_KILLBOTS); + network->WriteByte (DEM_KILLBOTS); } CCMD (freeze) @@ -227,8 +227,8 @@ CCMD (freeze) return; } - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_FREEZE); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_FREEZE); } CCMD (listbots) diff --git a/src/b_game.cpp b/src/b_game.cpp index b44a386cc5..d67c01fb8a 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -319,8 +319,8 @@ bool FCajunMaster::SpawnBot (const char *name, int color) thebot->inuse = BOTINUSE_Waiting; - network.Net_WriteByte (DEM_ADDBOT); - network.Net_WriteByte (botshift); + network->WriteByte (DEM_ADDBOT); + network->WriteByte (botshift); { //Set color. char concat[512]; @@ -334,12 +334,12 @@ bool FCajunMaster::SpawnBot (const char *name, int color) mysnprintf (concat + strlen(concat), countof(concat) - strlen(concat), "\\team\\%d\n", thebot->lastteam); } - network.Net_WriteString (concat); + network->WriteString (concat); } - network.Net_WriteByte(thebot->skill.aiming); - network.Net_WriteByte(thebot->skill.perfection); - network.Net_WriteByte(thebot->skill.reaction); - network.Net_WriteByte(thebot->skill.isp); + network->WriteByte(thebot->skill.aiming); + network->WriteByte(thebot->skill.perfection); + network->WriteByte(thebot->skill.reaction); + network->WriteByte(thebot->skill.isp); return true; } diff --git a/src/b_think.cpp b/src/b_think.cpp index c77a20cb70..e301d42a5e 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -81,13 +81,13 @@ void DBot::Think () ThinkForMove (&cmd); TurnToAng (); - cmd.ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees * (65536 / 360.f)) / network.ticdup; + cmd.ucmd.yaw = (short)((actor->Angles.Yaw - oldyaw).Degrees * (65536 / 360.f)) / network->ticdup; cmd.ucmd.pitch = (short)((oldpitch - actor->Angles.Pitch).Degrees * (65536 / 360.f)); if (cmd.ucmd.pitch == -32768) cmd.ucmd.pitch = -32767; - cmd.ucmd.pitch /= network.ticdup; - actor->Angles.Yaw = oldyaw + DAngle(cmd.ucmd.yaw * network.ticdup * (360 / 65536.f)); - actor->Angles.Pitch = oldpitch - DAngle(cmd.ucmd.pitch * network.ticdup * (360 / 65536.f)); + cmd.ucmd.pitch /= network->ticdup; + actor->Angles.Yaw = oldyaw + DAngle(cmd.ucmd.yaw * network->ticdup * (360 / 65536.f)); + actor->Angles.Pitch = oldpitch - DAngle(cmd.ucmd.pitch * network->ticdup * (360 / 65536.f)); } if (t_active) t_active--; @@ -107,7 +107,7 @@ void DBot::Think () cmd.ucmd.buttons |= BT_USE; } - network.SetBotCommand((int)(player - players), cmd); + network->WriteBotInput((int)(player - players), cmd); } #define THINKDISTSQ (50000.*50000./(65536.*65536.)) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index ba083b3dbb..a1c7691bda 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -122,8 +122,8 @@ CCMD (god) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_GOD); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_GOD); } CCMD(god2) @@ -131,8 +131,8 @@ CCMD(god2) if (CheckCheatmode()) return; - network.Net_WriteByte(DEM_GENERICCHEAT); - network.Net_WriteByte(CHT_GOD2); + network->WriteByte(DEM_GENERICCHEAT); + network->WriteByte(CHT_GOD2); } CCMD (iddqd) @@ -140,8 +140,8 @@ CCMD (iddqd) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_IDDQD); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_IDDQD); } CCMD (buddha) @@ -149,8 +149,8 @@ CCMD (buddha) if (CheckCheatmode()) return; - network.Net_WriteByte(DEM_GENERICCHEAT); - network.Net_WriteByte(CHT_BUDDHA); + network->WriteByte(DEM_GENERICCHEAT); + network->WriteByte(CHT_BUDDHA); } CCMD(buddha2) @@ -158,8 +158,8 @@ CCMD(buddha2) if (CheckCheatmode()) return; - network.Net_WriteByte(DEM_GENERICCHEAT); - network.Net_WriteByte(CHT_BUDDHA2); + network->WriteByte(DEM_GENERICCHEAT); + network->WriteByte(CHT_BUDDHA2); } CCMD (notarget) @@ -167,8 +167,8 @@ CCMD (notarget) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_NOTARGET); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_NOTARGET); } CCMD (fly) @@ -176,8 +176,8 @@ CCMD (fly) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_FLY); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_FLY); } /* @@ -192,8 +192,8 @@ CCMD (noclip) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_NOCLIP); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_NOCLIP); } CCMD (noclip2) @@ -201,8 +201,8 @@ CCMD (noclip2) if (CheckCheatmode()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_NOCLIP2); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_NOCLIP2); } CCMD (powerup) @@ -210,8 +210,8 @@ CCMD (powerup) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_POWER); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_POWER); } CCMD (morphme) @@ -221,13 +221,13 @@ CCMD (morphme) if (argv.argc() == 1) { - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_MORPH); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_MORPH); } else { - network.Net_WriteByte (DEM_MORPHEX); - network.Net_WriteString (argv[1]); + network->WriteByte (DEM_MORPHEX); + network->WriteString (argv[1]); } } @@ -236,8 +236,8 @@ CCMD (anubis) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_ANUBIS); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_ANUBIS); } // [GRB] @@ -246,8 +246,8 @@ CCMD (resurrect) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_RESSURECT); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_RESSURECT); } EXTERN_CVAR (Bool, chasedemo) @@ -278,8 +278,8 @@ CCMD (chase) if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && deathmatch && CheckCheatmode ())) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_CHASECAM); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_CHASECAM); } } @@ -377,14 +377,14 @@ CCMD (changemap) { if (argv.argc() > 2) { - network.Net_WriteByte (DEM_CHANGEMAP2); - network.Net_WriteByte (atoi(argv[2])); + network->WriteByte (DEM_CHANGEMAP2); + network->WriteByte (atoi(argv[2])); } else { - network.Net_WriteByte (DEM_CHANGEMAP); + network->WriteByte (DEM_CHANGEMAP); } - network.Net_WriteString (mapname); + network->WriteString (mapname); } } catch(CRecoverableError &error) @@ -404,12 +404,12 @@ CCMD (give) if (CheckCheatmode () || argv.argc() < 2) return; - network.Net_WriteByte (DEM_GIVECHEAT); - network.Net_WriteString (argv[1]); + network->WriteByte (DEM_GIVECHEAT); + network->WriteString (argv[1]); if (argv.argc() > 2) - network.Net_WriteLong(atoi(argv[2])); + network->WriteLong(atoi(argv[2])); else - network.Net_WriteLong(0); + network->WriteLong(0); } CCMD (take) @@ -417,12 +417,12 @@ CCMD (take) if (CheckCheatmode () || argv.argc() < 2) return; - network.Net_WriteByte (DEM_TAKECHEAT); - network.Net_WriteString (argv[1]); + network->WriteByte (DEM_TAKECHEAT); + network->WriteString (argv[1]); if (argv.argc() > 2) - network.Net_WriteLong(atoi (argv[2])); + network->WriteLong(atoi (argv[2])); else - network.Net_WriteLong (0); + network->WriteLong (0); } CCMD(setinv) @@ -430,17 +430,17 @@ CCMD(setinv) if (CheckCheatmode() || argv.argc() < 2) return; - network.Net_WriteByte(DEM_SETINV); - network.Net_WriteString(argv[1]); + network->WriteByte(DEM_SETINV); + network->WriteString(argv[1]); if (argv.argc() > 2) - network.Net_WriteLong(atoi(argv[2])); + network->WriteLong(atoi(argv[2])); else - network.Net_WriteLong(0); + network->WriteLong(0); if (argv.argc() > 3) - network.Net_WriteByte(!!atoi(argv[3])); + network->WriteByte(!!atoi(argv[3])); else - network.Net_WriteByte(0); + network->WriteByte(0); } @@ -538,18 +538,18 @@ CCMD (puke) if (script > 0) { - network.Net_WriteByte (DEM_RUNSCRIPT); - network.Net_WriteWord (script); + network->WriteByte (DEM_RUNSCRIPT); + network->WriteWord (script); } else { - network.Net_WriteByte (DEM_RUNSCRIPT2); - network.Net_WriteWord (-script); + network->WriteByte (DEM_RUNSCRIPT2); + network->WriteWord (-script); } - network.Net_WriteByte (argn); + network->WriteByte (argn); for (i = 0; i < argn; ++i) { - network.Net_WriteLong (arg[i]); + network->WriteLong (arg[i]); } } } @@ -582,12 +582,12 @@ CCMD (pukename) arg[i] = atoi(argv[argstart + i]); } } - network.Net_WriteByte(DEM_RUNNAMEDSCRIPT); - network.Net_WriteString(argv[1]); - network.Net_WriteByte(argn | (always << 7)); + network->WriteByte(DEM_RUNNAMEDSCRIPT); + network->WriteString(argv[1]); + network->WriteByte(argn | (always << 7)); for (i = 0; i < argn; ++i) { - network.Net_WriteLong(arg[i]); + network->WriteLong(arg[i]); } } } @@ -628,12 +628,12 @@ CCMD (special) return; } } - network.Net_WriteByte(DEM_RUNSPECIAL); - network.Net_WriteWord(specnum); - network.Net_WriteByte(argc - 2); + network->WriteByte(DEM_RUNSPECIAL); + network->WriteWord(specnum); + network->WriteByte(argc - 2); for (int i = 2; i < argc; ++i) { - network.Net_WriteLong(atoi(argv[i])); + network->WriteLong(atoi(argv[i])); } } } @@ -779,10 +779,10 @@ CCMD (warp) } else { - network.Net_WriteByte (DEM_WARPCHEAT); - network.Net_WriteWord (atoi (argv[1])); - network.Net_WriteWord (atoi (argv[2])); - network.Net_WriteWord (argv.argc() == 3 ? ONFLOORZ/65536 : atoi (argv[3])); + network->WriteByte (DEM_WARPCHEAT); + network->WriteWord (atoi (argv[1])); + network->WriteWord (atoi (argv[2])); + network->WriteWord (argv.argc() == 3 ? ONFLOORZ/65536 : atoi (argv[3])); } } @@ -1083,8 +1083,8 @@ CCMD(thaw) if (CheckCheatmode()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_CLEARFROZENPROPS); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_CLEARFROZENPROPS); } //----------------------------------------------------------------------------- diff --git a/src/c_console.cpp b/src/c_console.cpp index 04597112b7..6586c04d3b 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1300,7 +1300,7 @@ void C_FullConsole () { if (demoplayback) G_CheckDemoStatus (); - network.D_QuitNetGame (); + network->D_QuitNetGame (); advancedemo = false; ConsoleState = c_down; HistPos = NULL; diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 5f03029384..7fb210ed06 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1153,7 +1153,7 @@ void FBaseCVar::MarkUnsafe() // This type of cvar is not a "real" cvar. Instead, it gets and sets // the value of a FIntCVar, modifying it bit-by-bit. As such, it has // no default, and is not written to the .cfg or transferred around -// the network. The "host" cvar is responsible for that. +// the network-> The "host" cvar is responsible for that. // FFlagCVar::FFlagCVar (const char *name, FIntCVar &realvar, uint32_t bitval) diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index fad0beb201..1ab00e87ed 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -623,7 +623,7 @@ void C_DoCommand (const char *cmd, int keynum) button->ReleaseKey (keynum); if (button == &Button_Mlook && lookspring) { - network.Net_WriteByte (DEM_CENTERVIEW); + network->WriteByte (DEM_CENTERVIEW); } } return; diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index b54cd3b0cd..7b3aacd821 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -356,16 +356,16 @@ static void ShoveChatStr (const char *str, uint8_t who) who |= 2; } - network.Net_WriteByte (DEM_SAY); - network.Net_WriteByte (who); + network->WriteByte (DEM_SAY); + network->WriteByte (who); if (!chat_substitution || !DoSubstitution (substBuff, str)) { - network.Net_WriteString (str); + network->WriteString (str); } else { - network.Net_WriteString (substBuff); + network->WriteString (substBuff); } } diff --git a/src/d_main.cpp b/src/d_main.cpp index 0994073ade..9db64c24c4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -98,6 +98,7 @@ #include "hardware.h" #include "sbarinfo.h" #include "d_net.h" +#include "d_netsingle.h" #include "g_level.h" #include "d_event.h" #include "d_netinf.h" @@ -411,14 +412,14 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO) if (self & DF_NO_FREELOOK) { - network.Net_WriteByte (DEM_CENTERVIEW); + network->WriteByte (DEM_CENTERVIEW); } // If nofov is set, force everybody to the arbitrator's FOV. if ((self & DF_NO_FOV) && consoleplayer == Net_Arbitrator) { float fov; - network.Net_WriteByte (DEM_FOV); + network->WriteByte (DEM_FOV); // If the game is started with DF_NO_FOV set, the arbitrator's // DesiredFOV will not be set when this callback is run, so @@ -428,7 +429,7 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO) { fov = 90; } - network.Net_WriteFloat (fov); + network->WriteFloat (fov); } } @@ -1003,10 +1004,10 @@ void D_ErrorCleanup () savegamerestore = false; screen->Unlock (); bglobal.RemoveAllBots (true); - network.D_QuitNetGame (); + network->D_QuitNetGame (); if (demorecording || demoplayback) G_CheckDemoStatus (); - network.Net_ClearBuffers (); + network->Net_ClearBuffers (); G_NewInit (); M_ClearMenus (); singletics = false; @@ -1102,19 +1103,17 @@ public: for (int i = 0; i < tics; i++) { - gametic = gametime.BaseGameTic() + i; - network.maketic = gametime.BaseMakeTic() + i; - network.Net_NewMakeTic(); - network.SetPlayerCommand(consoleplayer, G_BuildTiccmd()); + network->SetCurrentTic(gametime.BaseGameTic() + i, gametime.BaseMakeTic() + i); + network->WriteLocalInput(G_BuildTiccmd()); if (advancedemo) D_DoAdvanceDemo(); - network.DispatchEvents(gametic); - C_Ticker(); M_Ticker(); G_Ticker(); + + network->EndCurrentTic(); } P_PredictPlayer(&players[consoleplayer]); @@ -1148,7 +1147,7 @@ void D_DoomLoop() try { gametime.Update(); - network.Update(); + network->Update(); input.Update(); playsim.Update(); input.BeforeDisplayUpdate(); @@ -2440,6 +2439,8 @@ void D_DoomMain (void) D_DoomInit(); + network.reset(new NetSinglePlayer()); + extern void D_ConfirmSendStats(); D_ConfirmSendStats(); @@ -2721,9 +2722,7 @@ void D_DoomMain (void) if (!restart) { - if (!batchrun) Printf ("D_CheckNetGame: Checking network game status.\n"); - StartScreen->LoadingStatus ("Checking network game status.", 0x3f); - network.D_CheckNetGame (); + D_SetupUserInfo(); } // [SP] Force vanilla transparency auto-detection to re-detect our game lumps now @@ -2738,7 +2737,7 @@ void D_DoomMain (void) // [RH] Run any saved commands from the command line or autoexec.cfg now. gamestate = GS_FULLCONSOLE; - network.Net_NewMakeTic (); + network->Startup(); DThinker::RunThinkers (); gamestate = GS_STARTUP; @@ -2821,7 +2820,7 @@ void D_DoomMain (void) G_BeginRecording(NULL); } - atterm([] { network.D_QuitNetGame(); }); // killough + atterm([] { network->D_QuitNetGame(); }); // killough } } } diff --git a/src/d_net.cpp b/src/d_net.cpp index ba895b474a..27c9814414 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -74,7 +74,7 @@ EXTERN_CVAR (Int, disableautosave) EXTERN_CVAR (Int, autosavecount) -Network network; +std::unique_ptr network; //#define SIMULATEERRORS (RAND_MAX/3) #define SIMULATEERRORS 0 @@ -142,220 +142,39 @@ static TArray InBuffer; static TArray OutBuffer; #endif -// [RH] Special "ticcmds" get stored in here -TicSpecial::TicSpecial () - { - int i; - - lastmaketic = -1; - specialsize = 256; - - for (i = 0; i < BACKUPTICS; i++) - streams[i] = NULL; - - for (i = 0; i < BACKUPTICS; i++) - { - streams[i] = (uint8_t *)M_Malloc (256); - used[i] = 0; - } - okay = true; - } - -TicSpecial::~TicSpecial () +void Network::WriteByte(uint8_t it) { - int i; - - for (i = 0; i < BACKUPTICS; i++) - { - if (streams[i]) - { - M_Free (streams[i]); - streams[i] = NULL; - used[i] = 0; - } - } - okay = false; + WriteBytes(&it, 1); } -// Make more room for special commands. -void TicSpecial::GetMoreSpace (size_t needed) +void Network::WriteWord(short it) { - int i; - - specialsize = MAX(specialsize * 2, needed + 30); - - DPrintf (DMSG_NOTIFY, "Expanding special size to %zu\n", specialsize); - - for (i = 0; i < BACKUPTICS; i++) - streams[i] = (uint8_t *)M_Realloc (streams[i], specialsize); - - streamptr = streams[(network.maketic/network.ticdup)%BACKUPTICS] + streamoffs; + uint16_t buf; + uint8_t *streamptr = (uint8_t*)&buf; + ::WriteWord(it, &streamptr); + WriteBytes((const uint8_t*)&buf, sizeof(uint16_t)); } -void TicSpecial::CheckSpace (size_t needed) +void Network::WriteLong(int it) { - if (streamoffs + needed >= specialsize) - GetMoreSpace (streamoffs + needed); - - streamoffs += needed; + uint32_t buf; + uint8_t *streamptr = (uint8_t*)&buf; + ::WriteLong(it, &streamptr); + WriteBytes((const uint8_t*)&buf, sizeof(uint32_t)); } -void TicSpecial::NewMakeTic () +void Network::WriteFloat(float it) { - int mt = network.maketic / network.ticdup; - if (lastmaketic != -1) - { - if (lastmaketic == mt) - return; - used[lastmaketic%BACKUPTICS] = streamoffs; - } - - lastmaketic = mt; - streamptr = streams[mt%BACKUPTICS]; - streamoffs = 0; + float buf; + uint8_t *streamptr = (uint8_t*)&buf; + ::WriteFloat(it, &streamptr); + WriteBytes((const uint8_t*)&buf, sizeof(float)); } -TicSpecial &TicSpecial::operator << (uint8_t it) +void Network::WriteString(const char *it) { - if (streamptr) - { - CheckSpace (1); - WriteByte (it, &streamptr); - } - return *this; -} - -TicSpecial &TicSpecial::operator << (short it) -{ - if (streamptr) - { - CheckSpace (2); - WriteWord (it, &streamptr); - } - return *this; -} - -TicSpecial &TicSpecial::operator << (int it) -{ - if (streamptr) - { - CheckSpace (4); - WriteLong (it, &streamptr); - } - return *this; -} - -TicSpecial &TicSpecial::operator << (float it) -{ - if (streamptr) - { - CheckSpace (4); - WriteFloat (it, &streamptr); - } - return *this; -} - -TicSpecial &TicSpecial::operator << (const char *it) -{ - if (streamptr) - { - CheckSpace (strlen (it) + 1); - WriteString (it, &streamptr); - } - return *this; -} - -///////////////////////////////////////////////////////////////////////////// - -void Network::D_QuitNetGame() -{ -} - -void Network::Net_NewMakeTic() -{ - specials.NewMakeTic(); -} - -void Network::Net_WriteByte(uint8_t it) -{ - specials << it; -} - -void Network::Net_WriteWord(short it) -{ - specials << it; -} - -void Network::Net_WriteLong(int it) -{ - specials << it; -} - -void Network::Net_WriteFloat(float it) -{ - specials << it; -} - -void Network::Net_WriteString(const char *it) -{ - specials << it; -} - -void Network::Net_WriteBytes(const uint8_t *block, int len) -{ - while (len--) - specials << *block++; -} - -bool Network::IsInconsistent(int player, int16_t checkvalue) const -{ - int buf = (gametic / ticdup) % BACKUPTICS; - return gametic > BACKUPTICS*ticdup && consistency[player][buf] != checkvalue; -} - -void Network::SetConsistency(int player, int16_t checkvalue) -{ - int buf = (gametic / ticdup) % BACKUPTICS; - consistency[player][buf] = checkvalue; -} - -int16_t Network::GetConsoleConsistency() const -{ - return consistency[consoleplayer][(maketic / ticdup) % BACKUPTICS]; -} - -size_t Network::CopySpecData(int player, uint8_t *dest, size_t dest_size) -{ - if (gametic % ticdup != 0) - return 0; - - int buf = (gametic / ticdup) % BACKUPTICS; - - int speclen = 0; - uint8_t *specdata = NetSpecs[player][buf].GetData(&speclen); - if (!specdata) - return 0; - - if (dest_size < speclen) - I_FatalError("Demo buffer too small for CopySpecData"); - - memcpy(dest, specdata, speclen); - NetSpecs[player][buf].SetData(nullptr, 0); // Why is this needed? - return speclen; -} - -int Network::GetPing(int player) const -{ - int node = nodeforplayer[player]; - int avgdelay = 0; - for (int i = 0; i < BACKUPTICS; i++) - avgdelay += netdelay[node][i]; - return avgdelay * ticdup * 1000 / TICRATE / BACKUPTICS; -} - -int Network::GetServerPing() const -{ - return GetPing(Net_Arbitrator); + int length = (int)strlen(it); + WriteBytes((const uint8_t*)it, length + 1); } int Network::GetHighPingThreshold() const @@ -363,6 +182,8 @@ int Network::GetHighPingThreshold() const return ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE); } +#if 0 // For reference. Remove when c/s migration is complete + void Network::ReadTicCmd(uint8_t **stream, int player, int tic) { int type; @@ -401,98 +222,6 @@ void Network::ReadTicCmd(uint8_t **stream, int player, int tic) assert(consistency[player][ticmod] == tcmd->consistency); } -void Network::RunNetSpecs(int player) -{ - if (gametic % ticdup == 0) - { - int buf = (gametic / network.ticdup) % BACKUPTICS; - - int len = 0; - uint8_t *stream = NetSpecs[player][buf].GetData(&len); - if (stream) - { - uint8_t *end = stream + len; - while (stream < end) - { - int type = ReadByte(&stream); - Net_DoCommand(type, &stream, player); - } - if (!demorecording) - NetSpecs[player][buf].SetData(nullptr, 0); - } - } -} - -void Network::SetBotCommand(int player, const ticcmd_t &cmd) -{ - netcmds[player][((gametic + 1) / network.ticdup) % BACKUPTICS] = cmd; -} - -ticcmd_t Network::GetLocalCommand(int tic) const -{ - int buf = tic % BACKUPTICS; - return netcmds[consoleplayer][buf]; -} - -ticcmd_t Network::GetPlayerCommand(int player) const -{ - int buf = (gametic / network.ticdup) % BACKUPTICS; - return netcmds[player][buf]; -} - -void Network::SetPlayerCommand(int player, ticcmd_t cmd) -{ - int buf = (gametic / ticdup) % BACKUPTICS; - netcmds[player][buf] = cmd; -} - -void Network::DispatchEvents(int tic) -{ - int player = consoleplayer; - int ticmod = tic % BACKUPTICS; - - if (specials.used[ticmod]) - { - NetSpecs[player][ticmod].SetData(specials.streams[ticmod], (int)specials.used[ticmod]); - specials.used[ticmod] = 0; - } - else - { - NetSpecs[player][ticmod].SetData(nullptr, 0); - } -} - -void Network::Net_ClearBuffers() -{ - memset(localcmds, 0, sizeof(localcmds)); - memset(netcmds, 0, sizeof(netcmds)); - memset(nettics, 0, sizeof(nettics)); - memset(nodeingame, 0, sizeof(nodeingame)); - memset(nodeforplayer, 0, sizeof(nodeforplayer)); - memset(playerfornode, 0, sizeof(playerfornode)); - memset(remoteresend, 0, sizeof(remoteresend)); - memset(resendto, 0, sizeof(resendto)); - memset(resendcount, 0, sizeof(resendcount)); - memset(lastrecvtime, 0, sizeof(lastrecvtime)); - memset(currrecvtime, 0, sizeof(currrecvtime)); - memset(consistency, 0, sizeof(consistency)); - nodeingame[0] = true; - - for (int i = 0; i < MAXPLAYERS; i++) - { - for (int j = 0; j < BACKUPTICS; j++) - { - NetSpecs[i][j].SetData(NULL, 0); - } - } - - oldentertics = entertic; - gametic = 0; - maketic = 0; - - lastglobalrecvtime = 0; -} - // Works out player numbers among the net participants void Network::D_CheckNetGame() { @@ -622,18 +351,7 @@ void Network::D_CheckNetGame() consoleplayer + 1, doomcom->numplayers, doomcom->numnodes); */ } - -void Network::ListPingTimes() -{ - for (int i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - Printf("% 4" PRId64 " %s\n", currrecvtime[i] - lastrecvtime[i], players[i].userinfo.GetName()); -} - -// Implement players who have the ability to change settings in a network game. -void Network::Network_Controller(int playernum, bool add) -{ -} +#endif //========================================================================== // @@ -641,10 +359,13 @@ void Network::Network_Controller(int playernum, bool add) // //========================================================================== -FDynamicBuffer::FDynamicBuffer () +FDynamicBuffer::FDynamicBuffer() { - m_Data = NULL; - m_Len = m_BufferLen = 0; +} + +FDynamicBuffer::FDynamicBuffer(const FDynamicBuffer &src) +{ + SetData(src.GetData(), src.GetSize()); } FDynamicBuffer::~FDynamicBuffer () @@ -652,11 +373,18 @@ FDynamicBuffer::~FDynamicBuffer () if (m_Data) { M_Free (m_Data); - m_Data = NULL; + m_Data = nullptr; } m_Len = m_BufferLen = 0; } +FDynamicBuffer &FDynamicBuffer::operator=(const FDynamicBuffer &src) +{ + if (this != &src) + SetData(src.GetData(), src.GetSize()); + return *this; +} + void FDynamicBuffer::SetData (const uint8_t *data, int len) { if (len > m_BufferLen) @@ -664,7 +392,7 @@ void FDynamicBuffer::SetData (const uint8_t *data, int len) m_BufferLen = (len + 255) & ~255; m_Data = (uint8_t *)M_Realloc (m_Data, m_BufferLen); } - if (data != NULL) + if (data) { m_Len = len; memcpy (m_Data, data, len); @@ -675,13 +403,20 @@ void FDynamicBuffer::SetData (const uint8_t *data, int len) } } -uint8_t *FDynamicBuffer::GetData (int *len) +void FDynamicBuffer::AppendData(const uint8_t *data, int len) { - if (len) - *len = m_Len; - return m_Len ? m_Data : NULL; -} + int pos = m_Len; + int neededlen = m_Len + len; + if (neededlen > m_BufferLen) + { + m_BufferLen = (neededlen + 255) & ~255; + m_Data = (uint8_t *)M_Realloc(m_Data, m_BufferLen); + } + + memcpy(m_Data + pos, data, len); + m_Len += len; +} static int KillAll(PClassActor *cls) { @@ -731,6 +466,24 @@ static int RemoveClass(const PClass *cls) return removecount; } + +void Net_RunCommands(FDynamicBuffer &buffer, int player) +{ + int len = buffer.GetSize(); + uint8_t *stream = buffer.GetData(); + if (stream) + { + uint8_t *end = stream + len; + while (stream < end) + { + int type = ReadByte(&stream); + Net_DoCommand(type, &stream, player); + } + if (!demorecording) + buffer.SetData(nullptr, 0); + } +} + // [RH] Execute a special "ticcmd". The type byte should // have already been read, and the stream is positioned // at the beginning of the command's actual data. @@ -1058,7 +811,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) { break; } - network.Net_WriteByte (DEM_DOAUTOSAVE); + network->WriteByte (DEM_DOAUTOSAVE); break; case DEM_DOAUTOSAVE: @@ -1470,7 +1223,7 @@ void Net_SkipCommand (int type, uint8_t **stream) CCMD (pings) { - network.ListPingTimes(); + network->ListPingTimes(); } CCMD (net_addcontroller) @@ -1487,7 +1240,7 @@ CCMD (net_addcontroller) return; } - network.Network_Controller (atoi (argv[1]), true); + network->Network_Controller (atoi (argv[1]), true); } CCMD (net_removecontroller) @@ -1504,7 +1257,7 @@ CCMD (net_removecontroller) return; } - network.Network_Controller (atoi (argv[1]), false); + network->Network_Controller (atoi (argv[1]), false); } CCMD (net_listcontrollers) diff --git a/src/d_net.h b/src/d_net.h index 21820ff7f2..812a8ce463 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -3,6 +3,7 @@ // Copyright 1993-1996 id Software // Copyright 1999-2016 Randy Heit // Copyright 2002-2016 Christoph Oelckers +// Copyright 2018 Magnus Norddahl // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -26,14 +27,6 @@ #include "i_net.h" #include -// -// Network play related stuff. -// There is a data struct that stores network -// communication related stuff, and another -// one that defines the actual packets to -// be transmitted. -// - #define MAXNETNODES 8 // max computers in a game #define BACKUPTICS 36 // number of tics to remember #define MAXTICDUP 5 @@ -42,139 +35,91 @@ class FDynamicBuffer { public: - FDynamicBuffer (); - ~FDynamicBuffer (); + FDynamicBuffer(); + FDynamicBuffer(const FDynamicBuffer &src); + ~FDynamicBuffer(); - void SetData (const uint8_t *data, int len); - uint8_t *GetData (int *len = NULL); + FDynamicBuffer &operator=(const FDynamicBuffer &src); + + void Clear() { SetData(nullptr, 0); } + void SetData(const uint8_t *data, int len); + void AppendData(const uint8_t *data, int len); + + uint8_t *GetData() { return m_Len ? m_Data : nullptr; } + const uint8_t *GetData() const { return m_Len ? m_Data : nullptr; } + int GetSize() const { return m_Len; } private: - uint8_t *m_Data; - int m_Len, m_BufferLen; + uint8_t *m_Data = nullptr; + int m_Len = 0; + int m_BufferLen = 0; }; -struct TicSpecial -{ - uint8_t *streams[BACKUPTICS]; - size_t used[BACKUPTICS]; - uint8_t *streamptr; - size_t streamoffs; - size_t specialsize; - int lastmaketic; - bool okay; - -public: - TicSpecial(); - ~TicSpecial(); - - void GetMoreSpace(size_t needed); - void CheckSpace(size_t needed); - void NewMakeTic(); - - TicSpecial &operator << (uint8_t it); - TicSpecial &operator << (short it); - TicSpecial &operator << (int it); - TicSpecial &operator << (float it); - TicSpecial &operator << (const char *it); -}; - -struct Network +class Network { public: - void Update() { } - void DispatchEvents(int tic); - void SetPlayerCommand(int player, ticcmd_t cmd); + virtual ~Network() { } - void D_CheckNetGame(); - void Net_ClearBuffers(); - void D_QuitNetGame(); + // Check for incoming packets + virtual void Update() = 0; - void ListPingTimes(); - void Network_Controller(int playernum, bool add); + // Set current tic for reading and writing + virtual void SetCurrentTic(int receivetic, int sendtic) = 0; - void Net_NewMakeTic(); // Only public because DoomMain calls it. Really really shouldn't be public. - void Net_WriteByte(uint8_t it); - void Net_WriteWord(short it); - void Net_WriteLong(int it); - void Net_WriteFloat(float it); - void Net_WriteString(const char *it); - void Net_WriteBytes(const uint8_t *block, int len); + // Send any pending outgoing data + virtual void EndCurrentTic() = 0; - size_t CopySpecData(int player, uint8_t *dest, size_t dest_size); + // Retrieve data about the current tic + virtual int GetSendTick() const = 0; + virtual ticcmd_t GetPlayerInput(int player) const = 0; + virtual ticcmd_t GetLocalInput(int tic) const = 0; - void SetBotCommand(int player, const ticcmd_t &cmd); - ticcmd_t GetPlayerCommand(int player) const; + // Run network commands for current the tic + virtual void RunCommands(int player) = 0; - bool IsInconsistent(int player, int16_t checkvalue) const; - void SetConsistency(int player, int16_t checkvalue); - int16_t GetConsoleConsistency() const; + // Write outgoing data for current the tic + virtual void WriteLocalInput(ticcmd_t cmd) = 0; + virtual void WriteBotInput(int player, const ticcmd_t &cmd) = 0; + virtual void WriteBytes(const uint8_t *block, int len) = 0; + void WriteByte(uint8_t it); + void WriteWord(short it); + void WriteLong(int it); + void WriteFloat(float it); + void WriteString(const char *it); - void RunNetSpecs(int player); - - ticcmd_t GetLocalCommand(int tic) const; - //ticcmd_t GetLocalCommand(int tic) const { return localcmds[tic % LOCALCMDTICS]; } - - int GetPing(int player) const; - int GetServerPing() const; + // Statistics + virtual int GetPing(int player) const = 0; + virtual int GetServerPing() const = 0; int GetHighPingThreshold() const; - int maketic; - int ticdup; // 1 = no duplication, 2-5 = dup for slow nets + // CCMDs + virtual void ListPingTimes() = 0; + virtual void Network_Controller(int playernum, bool add) = 0; -private: - void ReadTicCmd(uint8_t **stream, int player, int tic); + // Old init/deinit stuff + void Startup() { } + void Net_ClearBuffers() { } + void D_QuitNetGame() { } - std::unique_ptr doomcom; - NetPacket netbuffer; + // Demo recording + size_t CopySpecData(int player, uint8_t *dest, size_t dest_size) { return 0; } - int nodeforplayer[MAXPLAYERS]; - int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times. + // Obsolete; only needed for p2p + bool IsInconsistent(int player, int16_t checkvalue) const { return false; } + void SetConsistency(int player, int16_t checkvalue) { } + int16_t GetConsoleConsistency() const { return 0; } - short consistency[MAXPLAYERS][BACKUPTICS]; - ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; - FDynamicBuffer NetSpecs[MAXPLAYERS][BACKUPTICS]; - ticcmd_t localcmds[LOCALCMDTICS]; - - int gametime; - - enum { NET_PeerToPeer, NET_PacketServer }; - uint8_t NetMode = NET_PeerToPeer; - - int nettics[MAXNETNODES]; - bool nodeingame[MAXNETNODES]; // set false as nodes leave game - bool nodejustleft[MAXNETNODES]; // set when a node just left - bool remoteresend[MAXNETNODES]; // set when local needs tics - int resendto[MAXNETNODES]; // set when remote needs tics - int resendcount[MAXNETNODES]; - - uint64_t lastrecvtime[MAXPLAYERS]; // [RH] Used for pings - uint64_t currrecvtime[MAXPLAYERS]; - uint64_t lastglobalrecvtime; // Identify the last time a packet was received. - bool hadlate; - int lastaverage; - - int playerfornode[MAXNETNODES]; - - int skiptics; - - int reboundpacket; - uint8_t reboundstore[MAX_MSGLEN]; - - int frameon; - int frameskip[4]; - int oldnettics; - int mastertics; - - int entertic; - int oldentertics; - - TicSpecial specials; + // Should probably be removed. + int ticdup = 1; }; -extern Network network; +extern std::unique_ptr network; void Net_DoCommand (int type, uint8_t **stream, int player); void Net_SkipCommand (int type, uint8_t **stream); +void Net_RunCommands (FDynamicBuffer &buffer, int player); + +// Old packet format. Kept for reference. Should be removed or updated once the c/s migration is complete. // [RH] // New generic packet structure: diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp new file mode 100644 index 0000000000..ac09e55aa4 --- /dev/null +++ b/src/d_netclient.cpp @@ -0,0 +1,207 @@ +//----------------------------------------------------------------------------- +// +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// Copyright 2018 Magnus Norddahl +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// + +#include +#include + +#include "version.h" +#include "menu/menu.h" +#include "m_random.h" +#include "i_system.h" +#include "i_video.h" +#include "i_net.h" +#include "g_game.h" +#include "doomdef.h" +#include "doomstat.h" +#include "c_console.h" +#include "d_netinf.h" +#include "d_netclient.h" +#include "cmdlib.h" +#include "s_sound.h" +#include "m_cheat.h" +#include "p_local.h" +#include "c_dispatch.h" +#include "sbar.h" +#include "gi.h" +#include "m_misc.h" +#include "gameconfigfile.h" +#include "d_gui.h" +#include "templates.h" +#include "p_acs.h" +#include "p_trace.h" +#include "a_sharedglobal.h" +#include "st_start.h" +#include "teaminfo.h" +#include "p_conversation.h" +#include "g_level.h" +#include "d_event.h" +#include "m_argv.h" +#include "p_lnspec.h" +#include "v_video.h" +#include "p_spec.h" +#include "hardware.h" +#include "r_utility.h" +#include "a_keys.h" +#include "intermission/intermission.h" +#include "g_levellocals.h" +#include "events.h" +#include "i_time.h" + +NetClient::NetClient() +{ +} + +void NetClient::Update() +{ + while (true) + { + NetPacket packet; + mComm->PacketGet(packet); + if (packet.node == -1) + break; + + if (packet.node != mServerNode) + { + mComm->Close(packet.node); + } + else if (packet.size == 0) + { + OnClose(packet); + } + else + { + NetPacketType type = (NetPacketType)packet[0]; + switch (type) + { + default: OnClose(packet); break; + case NetPacketType::ConnectResponse: OnConnectResponse(packet); break; + case NetPacketType::Disconnect: OnDisconnect(packet); break; + case NetPacketType::Tic: OnTic(packet); break; + } + } + } +} + +void NetClient::SetCurrentTic(int receivetic, int sendtic) +{ + gametic = receivetic; + mSendTic = sendtic; +} + +void NetClient::EndCurrentTic() +{ +} + +int NetClient::GetSendTick() const +{ + return mSendTic; +} + +ticcmd_t NetClient::GetPlayerInput(int player) const +{ + return ticcmd_t(); +} + +ticcmd_t NetClient::GetLocalInput(int tic) const +{ + return ticcmd_t(); +} + +void NetClient::RunCommands(int player) +{ +} + +void NetClient::WriteLocalInput(ticcmd_t cmd) +{ +} + +void NetClient::WriteBotInput(int player, const ticcmd_t &cmd) +{ +} + +void NetClient::WriteBytes(const uint8_t *block, int len) +{ +} + +int NetClient::GetPing(int player) const +{ + return 0; +} + +int NetClient::GetServerPing() const +{ + return 0; +} + +void NetClient::ListPingTimes() +{ +} + +void NetClient::Network_Controller(int playernum, bool add) +{ +} + +void NetClient::OnClose(const NetPacket &packet) +{ + mComm->Close(mServerNode); + mServerNode = -1; + mStatus = NodeStatus::Closed; +} + +void NetClient::OnConnectResponse(const NetPacket &packet) +{ + if (packet.size != 3) + return; + + int version = packet[1]; // Protocol version + if (version == 1) + { + if (packet[2] != 255) // Join accepted + { + mPlayer = packet[2]; + mStatus = NodeStatus::InGame; + } + else // Server full + { + mComm->Close(mServerNode); + mServerNode = -1; + mStatus = NodeStatus::Closed; + } + } + else + { + I_Error("Version mismatch. Unable to connect\n"); + mComm->Close(mServerNode); + mServerNode = -1; + mStatus = NodeStatus::Closed; + } +} + +void NetClient::OnDisconnect(const NetPacket &packet) +{ + mComm->Close(packet.node); + mServerNode = -1; + mStatus = NodeStatus::Closed; +} + +void NetClient::OnTic(const NetPacket &packet) +{ +} diff --git a/src/d_netclient.h b/src/d_netclient.h new file mode 100644 index 0000000000..cee73962f5 --- /dev/null +++ b/src/d_netclient.h @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// Copyright 2018 Magnus Norddahl +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// + +#pragma once + +#include "d_netserver.h" + +class NetClient : public Network +{ +public: + NetClient(); + + void Update() override; + + void SetCurrentTic(int receivetic, int sendtic) override; + void EndCurrentTic() override; + + int GetSendTick() const override; + ticcmd_t GetPlayerInput(int player) const override; + ticcmd_t GetLocalInput(int tic) const override; + + void RunCommands(int player) override; + + void WriteLocalInput(ticcmd_t cmd) override; + void WriteBotInput(int player, const ticcmd_t &cmd) override; + void WriteBytes(const uint8_t *block, int len) override; + + int GetPing(int player) const override; + int GetServerPing() const override; + + void ListPingTimes() override; + void Network_Controller(int playernum, bool add) override; + +private: + void OnClose(const NetPacket &packet); + void OnConnectResponse(const NetPacket &packet); + void OnDisconnect(const NetPacket &packet); + void OnTic(const NetPacket &packet); + + std::unique_ptr mComm; + int mServerNode = -1; + int mPlayer = -1; + NodeStatus mStatus = NodeStatus::Closed; + int mSendTic = 0; +}; diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index fa218b616e..9b17b0b4a2 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -549,8 +549,8 @@ void D_UserInfoChanged (FBaseCVar *cvar) mysnprintf (foo, countof(foo), "\\%s\\%s", cvar->GetName(), escaped_val.GetChars()); - network.Net_WriteByte (DEM_UINFCHANGED); - network.Net_WriteString (foo); + network->WriteByte (DEM_UINFCHANGED); + network->WriteString (foo); } static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, bool singlebit) @@ -633,15 +633,15 @@ void D_SendServerInfoChange (const FBaseCVar *cvar, UCVarValue value, ECVarType namelen = strlen (cvar->GetName ()); - network.Net_WriteByte (DEM_SINFCHANGED); - network.Net_WriteByte ((uint8_t)(namelen | (type << 6))); - network.Net_WriteBytes ((uint8_t *)cvar->GetName (), (int)namelen); + network->WriteByte (DEM_SINFCHANGED); + network->WriteByte ((uint8_t)(namelen | (type << 6))); + network->WriteBytes ((uint8_t *)cvar->GetName (), (int)namelen); switch (type) { - case CVAR_Bool: network.Net_WriteByte (value.Bool); break; - case CVAR_Int: network.Net_WriteLong (value.Int); break; - case CVAR_Float: network.Net_WriteFloat (value.Float); break; - case CVAR_String: network.Net_WriteString (value.String); break; + case CVAR_Bool: network->WriteByte (value.Bool); break; + case CVAR_Int: network->WriteLong (value.Int); break; + case CVAR_Float: network->WriteFloat (value.Float); break; + case CVAR_String: network->WriteString (value.String); break; default: break; // Silence GCC } } @@ -652,10 +652,10 @@ void D_SendServerFlagChange (const FBaseCVar *cvar, int bitnum, bool set) namelen = (int)strlen (cvar->GetName ()); - network.Net_WriteByte (DEM_SINFCHANGEDXOR); - network.Net_WriteByte ((uint8_t)namelen); - network.Net_WriteBytes ((uint8_t *)cvar->GetName (), namelen); - network.Net_WriteByte (uint8_t(bitnum | (set << 5))); + network->WriteByte (DEM_SINFCHANGEDXOR); + network->WriteByte ((uint8_t)namelen); + network->WriteBytes ((uint8_t *)cvar->GetName (), namelen); + network->WriteByte (uint8_t(bitnum | (set << 5))); } void D_DoServerInfoChange (uint8_t **stream, bool singlebit) diff --git a/src/d_netserver.cpp b/src/d_netserver.cpp new file mode 100644 index 0000000000..1d4233ac5d --- /dev/null +++ b/src/d_netserver.cpp @@ -0,0 +1,226 @@ +//----------------------------------------------------------------------------- +// +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// Copyright 2018 Magnus Norddahl +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// + +#include +#include + +#include "version.h" +#include "menu/menu.h" +#include "m_random.h" +#include "i_system.h" +#include "i_video.h" +#include "i_net.h" +#include "g_game.h" +#include "doomdef.h" +#include "doomstat.h" +#include "c_console.h" +#include "d_netinf.h" +#include "d_netserver.h" +#include "cmdlib.h" +#include "s_sound.h" +#include "m_cheat.h" +#include "p_local.h" +#include "c_dispatch.h" +#include "sbar.h" +#include "gi.h" +#include "m_misc.h" +#include "gameconfigfile.h" +#include "d_gui.h" +#include "templates.h" +#include "p_acs.h" +#include "p_trace.h" +#include "a_sharedglobal.h" +#include "st_start.h" +#include "teaminfo.h" +#include "p_conversation.h" +#include "g_level.h" +#include "d_event.h" +#include "m_argv.h" +#include "p_lnspec.h" +#include "v_video.h" +#include "p_spec.h" +#include "hardware.h" +#include "r_utility.h" +#include "a_keys.h" +#include "intermission/intermission.h" +#include "g_levellocals.h" +#include "events.h" +#include "i_time.h" + +NetServer::NetServer() +{ +} + +void NetServer::Update() +{ + while (true) + { + NetPacket packet; + mComm->PacketGet(packet); + if (packet.node == -1) + break; + + NetNode &node = mNodes[packet.node]; + + if (packet.size == 0) + { + OnClose(node, packet); + } + else + { + NetPacketType type = (NetPacketType)packet[0]; + switch (type) + { + default: OnClose(node, packet); break; + case NetPacketType::ConnectRequest: OnConnectRequest(node, packet); break; + case NetPacketType::Disconnect: OnDisconnect(node, packet); break; + case NetPacketType::Tic: OnTic(node, packet); break; + } + } + } +} + +void NetServer::SetCurrentTic(int receivetic, int sendtic) +{ + gametic = receivetic; + mSendTic = sendtic; +} + +void NetServer::EndCurrentTic() +{ +} + +int NetServer::GetSendTick() const +{ + return mSendTic; +} + +ticcmd_t NetServer::GetPlayerInput(int player) const +{ + return ticcmd_t(); +} + +ticcmd_t NetServer::GetLocalInput(int tic) const +{ + return ticcmd_t(); +} + +void NetServer::RunCommands(int player) +{ +} + +void NetServer::WriteLocalInput(ticcmd_t cmd) +{ +} + +void NetServer::WriteBotInput(int player, const ticcmd_t &cmd) +{ +} + +void NetServer::WriteBytes(const uint8_t *block, int len) +{ +} + +int NetServer::GetPing(int player) const +{ + return 0; +} + +int NetServer::GetServerPing() const +{ + return 0; +} + +void NetServer::ListPingTimes() +{ +#if 0 + for (int i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + Printf("% 4" PRId64 " %s\n", currrecvtime[i] - lastrecvtime[i], players[i].userinfo.GetName()); +#endif +} + +void NetServer::Network_Controller(int playernum, bool add) +{ +} + +void NetServer::OnClose(NetNode &node, const NetPacket &packet) +{ + node.Status = NodeStatus::Closed; + mComm->Close(packet.node); +} + +void NetServer::OnConnectRequest(NetNode &node, const NetPacket &packet) +{ + if (node.Player == -1) + { + // To do: search for free player spot + node.Player = 1; + } + + if (node.Player != -1) // Join accepted. + { + mNodeForPlayer[node.Player] = packet.node; + + NetPacket response; + response.node = packet.node; + response[0] = (uint8_t)NetPacketType::ConnectResponse; + response[1] = 1; // Protocol version + response[2] = node.Player; + response.size = 3; + mComm->PacketSend(response); + + node.Status = NodeStatus::InGame; + } + else // Server is full. + { + node.Status = NodeStatus::Closed; + + NetPacket response; + response.node = packet.node; + response[0] = (uint8_t)NetPacketType::ConnectResponse; + response[1] = 1; // Protocol version + response[2] = 255; + response.size = 3; + mComm->PacketSend(response); + + node.Status = NodeStatus::Closed; + mComm->Close(packet.node); + } +} + +void NetServer::OnDisconnect(NetNode &node, const NetPacket &packet) +{ + node.Status = NodeStatus::Closed; + mComm->Close(packet.node); +} + +void NetServer::OnTic(NetNode &node, const NetPacket &packet) +{ + if (node.Status == NodeStatus::InGame) + { + } + else + { + node.Status = NodeStatus::Closed; + mComm->Close(packet.node); + } +} diff --git a/src/d_netserver.h b/src/d_netserver.h new file mode 100644 index 0000000000..6a4d6157b2 --- /dev/null +++ b/src/d_netserver.h @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +// +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// Copyright 2018 Magnus Norddahl +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// + +#pragma once + +#include "d_net.h" + +enum class NetPacketType +{ + ConnectRequest, + ConnectResponse, + Disconnect, + Tic +}; + +enum class NodeStatus +{ + Closed, + InPreGame, + InGame +}; + +struct NetNode +{ + NodeStatus Status = NodeStatus::Closed; + + int Ping = 0; + int Gametic = 0; + int Player = -1; + + ticcmd_t PlayerMovement; + FDynamicBuffer Commands; // "NetSpecs" +}; + +class NetServer : public Network +{ +public: + NetServer(); + + void Update() override; + + void SetCurrentTic(int receivetic, int sendtic) override; + void EndCurrentTic() override; + + int GetSendTick() const override; + ticcmd_t GetPlayerInput(int player) const override; + ticcmd_t GetLocalInput(int tic) const override; + + void RunCommands(int player) override; + + void WriteLocalInput(ticcmd_t cmd) override; + void WriteBotInput(int player, const ticcmd_t &cmd) override; + void WriteBytes(const uint8_t *block, int len) override; + + int GetPing(int player) const override; + int GetServerPing() const override; + + void ListPingTimes() override; + void Network_Controller(int playernum, bool add) override; + +private: + void OnClose(NetNode &node, const NetPacket &packet); + void OnConnectRequest(NetNode &node, const NetPacket &packet); + void OnDisconnect(NetNode &node, const NetPacket &packet); + void OnTic(NetNode &node, const NetPacket &packet); + + std::unique_ptr mComm; + NetNode mNodes[MAXNETNODES]; + int mNodeForPlayer[MAXPLAYERS]; + int mSendTic = 0; +}; diff --git a/src/d_netsingle.cpp b/src/d_netsingle.cpp new file mode 100644 index 0000000000..1b9039d56b --- /dev/null +++ b/src/d_netsingle.cpp @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// Copyright 2018 Magnus Norddahl +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// + +#include +#include + +#include "version.h" +#include "menu/menu.h" +#include "m_random.h" +#include "i_system.h" +#include "i_video.h" +#include "i_net.h" +#include "g_game.h" +#include "doomdef.h" +#include "doomstat.h" +#include "c_console.h" +#include "d_netinf.h" +#include "d_netsingle.h" +#include "cmdlib.h" +#include "s_sound.h" +#include "m_cheat.h" +#include "p_local.h" +#include "c_dispatch.h" +#include "sbar.h" +#include "gi.h" +#include "m_misc.h" +#include "gameconfigfile.h" +#include "d_gui.h" +#include "templates.h" +#include "p_acs.h" +#include "p_trace.h" +#include "a_sharedglobal.h" +#include "st_start.h" +#include "teaminfo.h" +#include "p_conversation.h" +#include "g_level.h" +#include "d_event.h" +#include "m_argv.h" +#include "p_lnspec.h" +#include "v_video.h" +#include "p_spec.h" +#include "hardware.h" +#include "r_utility.h" +#include "a_keys.h" +#include "intermission/intermission.h" +#include "g_levellocals.h" +#include "events.h" +#include "i_time.h" + +NetSinglePlayer::NetSinglePlayer() +{ + netgame = false; + multiplayer = false; + consoleplayer = 0; + players[0].settings_controller = true; + playeringame[0] = true; +} + +void NetSinglePlayer::Update() +{ +} + +void NetSinglePlayer::SetCurrentTic(int receivetic, int sendtic) +{ + gametic = receivetic; + mSendTic = sendtic; +} + +void NetSinglePlayer::EndCurrentTic() +{ + mCurrentCommands = mSendCommands; + mSendCommands.Clear(); +} + +int NetSinglePlayer::GetSendTick() const +{ + return mSendTic; +} + +ticcmd_t NetSinglePlayer::GetPlayerInput(int player) const +{ + return mCurrentInput[player]; +} + +ticcmd_t NetSinglePlayer::GetLocalInput(int tic) const +{ + return mCurrentInput[consoleplayer]; +} + +void NetSinglePlayer::RunCommands(int player) +{ + if (player == consoleplayer) + { + Net_RunCommands(mCurrentCommands, consoleplayer); + } +} + +void NetSinglePlayer::WriteLocalInput(ticcmd_t cmd) +{ + mCurrentInput[consoleplayer] = cmd; +} + +void NetSinglePlayer::WriteBotInput(int player, const ticcmd_t &cmd) +{ + mCurrentInput[player] = cmd; +} + +void NetSinglePlayer::WriteBytes(const uint8_t *block, int len) +{ + mSendCommands.AppendData(block, len); +} + +int NetSinglePlayer::GetPing(int player) const +{ + return 0; +} + +int NetSinglePlayer::GetServerPing() const +{ + return 0; +} + +void NetSinglePlayer::ListPingTimes() +{ +} + +void NetSinglePlayer::Network_Controller(int playernum, bool add) +{ +} diff --git a/src/d_netsingle.h b/src/d_netsingle.h new file mode 100644 index 0000000000..d00a690f36 --- /dev/null +++ b/src/d_netsingle.h @@ -0,0 +1,58 @@ +//----------------------------------------------------------------------------- +// +// Copyright 1993-1996 id Software +// Copyright 1999-2016 Randy Heit +// Copyright 2002-2016 Christoph Oelckers +// Copyright 2018 Magnus Norddahl +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// + +#pragma once + +#include "d_net.h" + +class NetSinglePlayer : public Network +{ +public: + NetSinglePlayer(); + + void Update() override; + + void SetCurrentTic(int receivetic, int sendtic) override; + void EndCurrentTic() override; + + int GetSendTick() const override; + ticcmd_t GetPlayerInput(int player) const override; + ticcmd_t GetLocalInput(int tic) const override; + + void RunCommands(int player) override; + + void WriteLocalInput(ticcmd_t cmd) override; + void WriteBotInput(int player, const ticcmd_t &cmd) override; + void WriteBytes(const uint8_t *block, int len) override; + + int GetPing(int player) const override; + int GetServerPing() const override; + + void ListPingTimes() override; + void Network_Controller(int playernum, bool add) override; + +private: + ticcmd_t mCurrentInput[MAXPLAYERS]; + FDynamicBuffer mCurrentCommands; + + int mSendTic = 0; + FDynamicBuffer mSendCommands; +}; diff --git a/src/events.cpp b/src/events.cpp index 38bb6c19a0..f206057d54 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -154,13 +154,13 @@ bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual) if (gamestate != GS_LEVEL) return false; - network.Net_WriteByte(DEM_NETEVENT); - network.Net_WriteString(name); - network.Net_WriteByte(3); - network.Net_WriteLong(arg1); - network.Net_WriteLong(arg2); - network.Net_WriteLong(arg3); - network.Net_WriteByte(manual); + network->WriteByte(DEM_NETEVENT); + network->WriteString(name); + network->WriteByte(3); + network->WriteLong(arg1); + network->WriteLong(arg2); + network->WriteLong(arg3); + network->WriteByte(manual); return true; } diff --git a/src/g_game.cpp b/src/g_game.cpp index 01e02958e1..2002105cf7 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -313,12 +313,12 @@ CCMD (slot) CCMD (centerview) { - network.Net_WriteByte (DEM_CENTERVIEW); + network->WriteByte (DEM_CENTERVIEW); } CCMD(crouch) { - network.Net_WriteByte(DEM_CROUCH); + network->WriteByte(DEM_CROUCH); } CCMD (land) @@ -571,7 +571,7 @@ ticcmd_t G_BuildTiccmd () ticcmd_t cmd; - cmd.consistency = network.GetConsoleConsistency(); + cmd.consistency = network->GetConsoleConsistency(); strafe = Button_Strafe.bDown; speed = Button_Speed.bDown ^ (int)cl_run; @@ -582,7 +582,7 @@ ticcmd_t G_BuildTiccmd () // and not the joystick, since we treat the joystick as // the analog device it is. if (Button_Left.bDown || Button_Right.bDown) - turnheld += network.ticdup; + turnheld += network->ticdup; else turnheld = 0; @@ -748,32 +748,32 @@ ticcmd_t G_BuildTiccmd () if (sendpause) { sendpause = false; - network.Net_WriteByte (DEM_PAUSE); + network->WriteByte (DEM_PAUSE); } if (sendsave) { sendsave = false; - network.Net_WriteByte (DEM_SAVEGAME); - network.Net_WriteString (savegamefile); - network.Net_WriteString (savedescription); + network->WriteByte (DEM_SAVEGAME); + network->WriteString (savegamefile); + network->WriteString (savedescription); savegamefile = ""; } if (SendItemUse == (const AInventory *)1) { - network.Net_WriteByte (DEM_INVUSEALL); + network->WriteByte (DEM_INVUSEALL); SendItemUse = NULL; } else if (SendItemUse != NULL) { - network.Net_WriteByte (DEM_INVUSE); - network.Net_WriteLong (SendItemUse->InventoryID); + network->WriteByte (DEM_INVUSE); + network->WriteLong (SendItemUse->InventoryID); SendItemUse = NULL; } if (SendItemDrop != NULL) { - network.Net_WriteByte (DEM_INVDROP); - network.Net_WriteLong (SendItemDrop->InventoryID); - network.Net_WriteLong(SendItemDropAmount); + network->WriteByte (DEM_INVDROP); + network->WriteLong (SendItemDrop->InventoryID); + network->WriteLong(SendItemDropAmount); SendItemDrop = NULL; } @@ -879,7 +879,7 @@ static void ChangeSpy (int changespy) // has done this for you, since it could desync otherwise. if (!demoplayback) { - network.Net_WriteByte(DEM_REVERTCAMERA); + network->WriteByte(DEM_REVERTCAMERA); } return; } @@ -1160,9 +1160,9 @@ void G_Ticker () if (playeringame[i]) { ticcmd_t *cmd = &players[i].cmd; - ticcmd_t newcmd = network.GetPlayerCommand(i); + ticcmd_t newcmd = network->GetPlayerInput(i); - network.RunNetSpecs(i); + network->RunCommands(i); if (demorecording) { @@ -1188,21 +1188,21 @@ void G_Ticker () Printf ("%s is turbo!\n", players[i].userinfo.GetName()); } - if (netgame && players[i].Bot == NULL && !demoplayback && (gametic%network.ticdup) == 0) + if (netgame && players[i].Bot == NULL && !demoplayback && (gametic%network->ticdup) == 0) { - if (network.IsInconsistent(i, cmd->consistency)) + if (network->IsInconsistent(i, cmd->consistency)) { - players[i].inconsistant = gametic - BACKUPTICS*network.ticdup; + players[i].inconsistant = gametic - BACKUPTICS*network->ticdup; } if (players[i].mo) { uint32_t sum = rngsum + int((players[i].mo->X() + players[i].mo->Y() + players[i].mo->Z())*257) + players[i].mo->Angles.Yaw.BAMs() + players[i].mo->Angles.Pitch.BAMs(); sum ^= players[i].health; - network.SetConsistency(i, sum); + network->SetConsistency(i, sum); } else { - network.SetConsistency(i, rngsum); + network->SetConsistency(i, rngsum); } } } @@ -2462,7 +2462,7 @@ void G_WriteDemoTiccmd (ticcmd_t *cmd, int player) } // [RH] Write any special "ticcmds" for this player to the demo - demo_p += network.CopySpecData(player, demo_p, maxdemosize - (demo_p - demobuffer)); + demo_p += network->CopySpecData(player, demo_p, maxdemosize - (demo_p - demobuffer)); // [RH] Now write out a "normal" ticcmd. WriteUserCmdMessage (&cmd->ucmd, &players[player].cmd.ucmd, &demo_p); diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index b7e82182e7..893e9740b9 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1110,15 +1110,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other) // The slots differ. Send mine. if (playernum == consoleplayer) { - network.Net_WriteByte(DEM_SETSLOT); + network->WriteByte(DEM_SETSLOT); } else { - network.Net_WriteByte(DEM_SETSLOTPNUM); - network.Net_WriteByte(playernum); + network->WriteByte(DEM_SETSLOTPNUM); + network->WriteByte(playernum); } - network.Net_WriteByte(i); - network.Net_WriteByte(Slots[i].Size()); + network->WriteByte(i); + network->WriteByte(Slots[i].Size()); for (j = 0; j < Slots[i].Size(); ++j) { Net_WriteWeapon(Slots[i].GetWeapon(j)); @@ -1248,9 +1248,9 @@ CCMD (setslot) Printf ("Slot %d cleared\n", slot); } - network.Net_WriteByte(DEM_SETSLOT); - network.Net_WriteByte(slot); - network.Net_WriteByte(argv.argc()-2); + network->WriteByte(DEM_SETSLOT); + network->WriteByte(slot); + network->WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { Net_WriteWeapon(PClass::FindActor(argv[i])); @@ -1299,8 +1299,8 @@ CCMD (addslot) } else { - network.Net_WriteByte(DEM_ADDSLOT); - network.Net_WriteByte(slot); + network->WriteByte(DEM_ADDSLOT); + network->WriteByte(slot); Net_WriteWeapon(type); } } @@ -1375,8 +1375,8 @@ CCMD (addslotdefault) } else { - network.Net_WriteByte(DEM_ADDSLOTDEFAULT); - network.Net_WriteByte(slot); + network->WriteByte(DEM_ADDSLOTDEFAULT); + network->WriteByte(slot); Net_WriteWeapon(type); } } @@ -1447,7 +1447,7 @@ void P_SetupWeapons_ntohton() // for any game appear second, and weapons that filter for some other game // appear last. The idea here is to try to keep all the weapons that are // most likely to be used at the start of the list so that they only need -// one byte to transmit across the network. +// one byte to transmit across the network-> // //=========================================================================== @@ -1541,12 +1541,12 @@ void Net_WriteWeapon(PClassActor *type) assert(index >= 0 && index <= 32767); if (index < 128) { - network.Net_WriteByte(index); + network->WriteByte(index); } else { - network.Net_WriteByte(0x80 | index); - network.Net_WriteByte(index >> 7); + network->WriteByte(0x80 | index); + network->WriteByte(index >> 7); } } diff --git a/src/g_level.cpp b/src/g_level.cpp index 75ceba6ca6..e0b2039baa 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -892,7 +892,7 @@ IMPLEMENT_CLASS(DAutosaver, false, false) void DAutosaver::Tick () { - network.Net_WriteByte (DEM_CHECKAUTOSAVE); + network->WriteByte (DEM_CHECKAUTOSAVE); Destroy (); } diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index be72f9f502..0f1e89c86b 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -700,8 +700,8 @@ CCMD (spray) return; } - network.Net_WriteByte (DEM_SPRAY); - network.Net_WriteString (argv[1]); + network->WriteByte (DEM_SPRAY); + network->WriteString (argv[1]); } void SprayDecal(AActor *shooter, const char *name, double distance) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 0525549880..e616e6d945 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -1053,8 +1053,8 @@ static void DrawLatency() { return; } - int localdelay = network.GetPing(0); - int arbitratordelay = network.GetServerPing(); + int localdelay = network->GetPing(0); + int arbitratordelay = network->GetServerPing(); int color = CR_GREEN; if (MAX(localdelay, arbitratordelay) > 200) { @@ -1064,7 +1064,7 @@ static void DrawLatency() { color = CR_ORANGE; } - if (MAX(localdelay, arbitratordelay) >= network.GetHighPingThreshold()) + if (MAX(localdelay, arbitratordelay) >= network->GetHighPingThreshold()) { color = CR_RED; } diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index a9f11795d7..2d02aa704a 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1255,7 +1255,7 @@ void DBaseStatusBar::DrawConsistancy () const { fprintf (debugfile, "%s as of tic %d (%d)\n", conbuff, players[1-consoleplayer].inconsistant, - players[1-consoleplayer].inconsistant/network.ticdup); + players[1-consoleplayer].inconsistant/network->ticdup); } } screen->DrawText (SmallFont, CR_GREEN, diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index 7a351a5c7f..7f29d47fdd 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -434,7 +434,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); - mysnprintf(str, countof(str), "%d", network.GetPing((int)(player - players))); + mysnprintf(str, countof(str), "%d", network->GetPing((int)(player - players))); screen->DrawText(SmallFont, color, col5, y + ypadding, str, DTA_CleanNoMove, true, TAG_DONE); diff --git a/src/i_net.cpp b/src/i_net.cpp index 9791c3f45e..0675e5017c 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -206,38 +206,36 @@ void DoomComImpl::PacketSend(const NetPacket &packet) // FIXME: Catch this before we've overflown the buffer. With long chat // text and lots of backup tics, it could conceivably happen. (Though // apparently it hasn't yet, which is good.) - if (packet.datalength > MAX_MSGLEN) + if (packet.size > MAX_MSGLEN) { I_FatalError("Netbuffer overflow!"); } assert(!(packet.data[0] & NCMD_COMPRESSED)); uLong size = TRANSMIT_SIZE - 1; - if (packet.datalength >= 10) + if (packet.size >= 10) { mTransmitBuffer[0] = packet.data[0] | NCMD_COMPRESSED; - c = compress2(mTransmitBuffer + 1, &size, packet.data + 1, packet.datalength - 1, 9); + c = compress2(mTransmitBuffer + 1, &size, packet.data + 1, packet.size - 1, 9); size += 1; } else { c = -1; // Just some random error code to avoid sending the compressed buffer. } - if (c == Z_OK && size < (uLong)packet.datalength) + if (c == Z_OK && size < (uLong)packet.size) { - // Printf("send %lu/%d\n", size, datalength); - c = sendto(mSocket, (char *)mTransmitBuffer, size, 0, (sockaddr *)&mNodeEndpoints[packet.remotenode], sizeof(mNodeEndpoints[packet.remotenode])); + c = sendto(mSocket, (char *)mTransmitBuffer, size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); } else { - if (packet.datalength > TRANSMIT_SIZE) + if (packet.size > TRANSMIT_SIZE) { I_Error("Net compression failed (zlib error %d)", c); } else { - // Printf("send %d\n", datalength); - c = sendto(mSocket, (char *)packet.data, packet.datalength, 0, (sockaddr *)&mNodeEndpoints[packet.remotenode], sizeof(mNodeEndpoints[packet.remotenode])); + c = sendto(mSocket, (char *)packet.data, packet.size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); } } // if (c == -1) @@ -253,8 +251,8 @@ void DoomComImpl::PacketGet(NetPacket &packet) if (mNodeLastUpdate[i] != 0 && nowtime - mNodeLastUpdate[i] > 5'000'000'000) // 5 second timeout { Close(i); - packet.remotenode = i; - packet.datalength = 0; + packet.node = i; + packet.size = 0; return; } } @@ -263,8 +261,8 @@ void DoomComImpl::PacketGet(NetPacket &packet) { sockaddr_in fromaddress; socklen_t fromlen = sizeof(fromaddress); - int datalength = recvfrom(mSocket, (char*)mTransmitBuffer, TRANSMIT_SIZE, 0, (sockaddr *)&fromaddress, &fromlen); - if (datalength == SOCKET_ERROR) + int size = recvfrom(mSocket, (char*)mTransmitBuffer, TRANSMIT_SIZE, 0, (sockaddr *)&fromaddress, &fromlen); + if (size == SOCKET_ERROR) { int err = WSAGetLastError(); @@ -275,8 +273,8 @@ void DoomComImpl::PacketGet(NetPacket &packet) continue; Close(node); - packet.remotenode = node; - packet.datalength = 0; + packet.node = node; + packet.size = 0; return; } else if (err != WSAEWOULDBLOCK) @@ -285,12 +283,12 @@ void DoomComImpl::PacketGet(NetPacket &packet) } else // no packet { - packet.remotenode = -1; - packet.datalength = 0; + packet.node = -1; + packet.size = 0; return; } } - else if (datalength > 0) + else if (size > 0) { int node = FindNode(&fromaddress); if (node == -1) @@ -300,21 +298,21 @@ void DoomComImpl::PacketGet(NetPacket &packet) if (mTransmitBuffer[0] & NCMD_COMPRESSED) { uLongf msgsize = MAX_MSGLEN - 1; - int err = uncompress(packet.data + 1, &msgsize, mTransmitBuffer + 1, datalength - 1); + int err = uncompress(packet.data + 1, &msgsize, mTransmitBuffer + 1, size - 1); if (err != Z_OK) { Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars()); continue; } - datalength = msgsize + 1; + size = msgsize + 1; } else { - memcpy(packet.data + 1, mTransmitBuffer + 1, datalength - 1); + memcpy(packet.data + 1, mTransmitBuffer + 1, size - 1); } - packet.remotenode = node; - packet.datalength = (short)datalength; + packet.node = node; + packet.size = (short)size; return; } } diff --git a/src/i_net.h b/src/i_net.h index 9a616ce6c0..ccea62bacb 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -14,10 +14,10 @@ struct NetPacket uint8_t data[MAX_MSGLEN]; // bytes in data to be sent - int16_t datalength = 0; + int16_t size = 0; // dest for send, set by get (-1 = no packet). - int16_t remotenode = 0; + int16_t node = 0; uint8_t &operator[](int i) { return data[i]; } const uint8_t &operator[](int i) const { return data[i]; } diff --git a/src/info.cpp b/src/info.cpp index 73c9713bd1..382441a465 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -594,17 +594,17 @@ static void SummonActor (int command, int command2, FCommandLine argv) Printf ("Unknown actor '%s'\n", argv[1]); return; } - network.Net_WriteByte (argv.argc() > 2 ? command2 : command); - network.Net_WriteString (type->TypeName.GetChars()); + network->WriteByte (argv.argc() > 2 ? command2 : command); + network->WriteString (type->TypeName.GetChars()); if (argv.argc () > 2) { - network.Net_WriteWord (atoi (argv[2])); // angle - network.Net_WriteWord ((argv.argc() > 3) ? atoi(argv[3]) : 0); // TID - network.Net_WriteByte ((argv.argc() > 4) ? atoi(argv[4]) : 0); // special + network->WriteWord (atoi (argv[2])); // angle + network->WriteWord ((argv.argc() > 3) ? atoi(argv[3]) : 0); // TID + network->WriteByte ((argv.argc() > 4) ? atoi(argv[4]) : 0); // special for (int i = 5; i < 10; i++) { // args[5] - network.Net_WriteLong((i < argv.argc()) ? atoi(argv[i]) : 0); + network->WriteLong((i < argv.argc()) ? atoi(argv[i]) : 0); } } } diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 1d96bcddf2..eb3744c273 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -809,7 +809,7 @@ bool DIntermissionController::Responder (event_t *ev) int res = mScreen->Responder(ev); if (res == -1 && !mSentAdvance) { - network.Net_WriteByte(DEM_ADVANCEINTER); + network->WriteByte(DEM_ADVANCEINTER); mSentAdvance = true; } return !!res; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index dd08f492a1..ce5767305f 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -701,6 +701,6 @@ CCMD (mdk) return; const char *name = argv.argc() > 1 ? argv[1] : ""; - network.Net_WriteByte (DEM_MDK); - network.Net_WriteString(name); + network->WriteByte (DEM_MDK); + network->WriteString(name); } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 41b7eb4177..537958e20b 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -695,17 +695,17 @@ DEFINE_ACTION_FUNCTION(DConversationMenu, SendConversationReply) switch (node) { case -1: - network.Net_WriteByte(DEM_CONVNULL); + network->WriteByte(DEM_CONVNULL); break; case -2: - network.Net_WriteByte(DEM_CONVCLOSE); + network->WriteByte(DEM_CONVCLOSE); break; default: - network.Net_WriteByte(DEM_CONVREPLY); - network.Net_WriteWord(node); - network.Net_WriteByte(reply); + network->WriteByte(DEM_CONVREPLY); + network->WriteWord(node); + network->WriteByte(reply); break; } StaticLastReply = reply; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 760dbd4676..8d1178fd68 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1981,8 +1981,8 @@ CCMD (kill) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_MASSACRE); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_MASSACRE); } else if (!stricmp (argv[1], "baddies")) { @@ -1990,13 +1990,13 @@ CCMD (kill) if (CheckCheatmode ()) return; - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (CHT_MASSACRE2); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (CHT_MASSACRE2); } else { - network.Net_WriteByte (DEM_KILLCLASSCHEAT); - network.Net_WriteString (argv[1]); + network->WriteByte (DEM_KILLCLASSCHEAT); + network->WriteString (argv[1]); } } else @@ -2006,7 +2006,7 @@ CCMD (kill) return; // Kill the player - network.Net_WriteByte (DEM_SUICIDE); + network->WriteByte (DEM_SUICIDE); } C_HideConsole (); } @@ -2018,8 +2018,8 @@ CCMD(remove) if (CheckCheatmode()) return; - network.Net_WriteByte(DEM_REMOVE); - network.Net_WriteString(argv[1]); + network->WriteByte(DEM_REMOVE); + network->WriteString(argv[1]); C_HideConsole(); } else diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index a6e6b56c3c..e10463c69e 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3088,7 +3088,7 @@ FUNC(LS_Autosave) if (gameaction != ga_savegame) { level.flags2 &= ~LEVEL2_NOAUTOSAVEHINT; - network.Net_WriteByte (DEM_CHECKAUTOSAVE); + network->WriteByte (DEM_CHECKAUTOSAVE); } return true; } diff --git a/src/p_user.cpp b/src/p_user.cpp index 6c42807e3e..8d034522d5 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -602,7 +602,7 @@ void player_t::SetFOV(float fov) { if (consoleplayer == Net_Arbitrator) { - network.Net_WriteByte(DEM_MYFOV); + network->WriteByte(DEM_MYFOV); } else { @@ -612,9 +612,9 @@ void player_t::SetFOV(float fov) } else { - network.Net_WriteByte(DEM_MYFOV); + network->WriteByte(DEM_MYFOV); } - network.Net_WriteFloat(clamp(fov, 5.f, 179.f)); + network->WriteFloat(clamp(fov, 5.f, 179.f)); } } @@ -734,9 +734,9 @@ void player_t::SendPitchLimits() const { if (this - players == consoleplayer) { - network.Net_WriteByte(DEM_SETPITCHLIMIT); - network.Net_WriteByte(Renderer->GetMaxViewPitch(false)); // up - network.Net_WriteByte(Renderer->GetMaxViewPitch(true)); // down + network->WriteByte(DEM_SETPITCHLIMIT); + network->WriteByte(Renderer->GetMaxViewPitch(false)); // up + network->WriteByte(Renderer->GetMaxViewPitch(true)); // down } } @@ -1025,7 +1025,7 @@ void APlayerPawn::PostBeginPlay() // // Sets up the default weapon slots for this player. If this is also the // local player, determines local modifications and sends those across the -// network. Ignores voodoo dolls. +// network-> Ignores voodoo dolls. // //=========================================================================== @@ -2438,8 +2438,6 @@ nodetype *RestoreNodeList(AActor *act, nodetype *head, nodetype *linktype::*othe void P_PredictPlayer (player_t *player) { - int maxtic; - if (cl_noprediction || singletics || demoplayback || @@ -2453,7 +2451,7 @@ void P_PredictPlayer (player_t *player) return; } - maxtic = network.maketic; + int maxtic = network->GetSendTick(); if (gametic == maxtic) { @@ -2504,13 +2502,13 @@ void P_PredictPlayer (player_t *player) act->BlockNode = NULL; // Values too small to be usable for lerping can be considered "off". - bool CanLerp = (!(cl_predict_lerpscale < 0.01f) && (network.ticdup == 1)), DoLerp = false, NoInterpolateOld = R_GetViewInterpolationStatus(); + bool CanLerp = (!(cl_predict_lerpscale < 0.01f) && (network->ticdup == 1)), DoLerp = false, NoInterpolateOld = R_GetViewInterpolationStatus(); for (int i = gametic; i < maxtic; ++i) { if (!NoInterpolateOld) R_RebuildViewInterpolation(player); - player->cmd = network.GetLocalCommand(i); + player->cmd = network->GetLocalInput(i); P_PlayerThink (player); player->mo->Tick (); diff --git a/src/st_stuff.cpp b/src/st_stuff.cpp index aed2681c20..366453ade8 100644 --- a/src/st_stuff.cpp +++ b/src/st_stuff.cpp @@ -433,8 +433,8 @@ static bool CheatAddKey (cheatseq_t *cheat, uint8_t key, bool *eat) static bool Cht_Generic (cheatseq_t *cheat) { - network.Net_WriteByte (DEM_GENERICCHEAT); - network.Net_WriteByte (cheat->Args[0]); + network->WriteByte (DEM_GENERICCHEAT); + network->WriteByte (cheat->Args[0]); return true; } diff --git a/src/statistics.cpp b/src/statistics.cpp index e701f33ca0..2df5d3322d 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -599,7 +599,7 @@ CCMD(finishgame) return; } // This CCMD simulates an end-of-game action and exists to end mods that never exit their last level. - network.Net_WriteByte(DEM_FINISHGAME); + network->WriteByte(DEM_FINISHGAME); } ADD_STAT(statistics) From b212cca1fba7469d91cfbba2e2bddcb7e0f5d2bb Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 28 Mar 2018 03:59:10 +0200 Subject: [PATCH 08/17] - Rename GetLocalInput to GetSentInput --- src/d_net.h | 6 +++--- src/d_netclient.cpp | 2 +- src/d_netclient.h | 2 +- src/d_netserver.cpp | 2 +- src/d_netserver.h | 2 +- src/d_netsingle.cpp | 2 +- src/d_netsingle.h | 2 +- src/p_user.cpp | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/d_net.h b/src/d_net.h index 812a8ce463..3a827350b9 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -72,12 +72,12 @@ public: // Retrieve data about the current tic virtual int GetSendTick() const = 0; virtual ticcmd_t GetPlayerInput(int player) const = 0; - virtual ticcmd_t GetLocalInput(int tic) const = 0; + virtual ticcmd_t GetSentInput(int tic) const = 0; - // Run network commands for current the tic + // Run network commands for the current tic virtual void RunCommands(int player) = 0; - // Write outgoing data for current the tic + // Write outgoing data for the current tic virtual void WriteLocalInput(ticcmd_t cmd) = 0; virtual void WriteBotInput(int player, const ticcmd_t &cmd) = 0; virtual void WriteBytes(const uint8_t *block, int len) = 0; diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp index ac09e55aa4..066451cc55 100644 --- a/src/d_netclient.cpp +++ b/src/d_netclient.cpp @@ -120,7 +120,7 @@ ticcmd_t NetClient::GetPlayerInput(int player) const return ticcmd_t(); } -ticcmd_t NetClient::GetLocalInput(int tic) const +ticcmd_t NetClient::GetSentInput(int tic) const { return ticcmd_t(); } diff --git a/src/d_netclient.h b/src/d_netclient.h index cee73962f5..afa7eca790 100644 --- a/src/d_netclient.h +++ b/src/d_netclient.h @@ -35,7 +35,7 @@ public: int GetSendTick() const override; ticcmd_t GetPlayerInput(int player) const override; - ticcmd_t GetLocalInput(int tic) const override; + ticcmd_t GetSentInput(int tic) const override; void RunCommands(int player) override; diff --git a/src/d_netserver.cpp b/src/d_netserver.cpp index 1d4233ac5d..329f1c1487 100644 --- a/src/d_netserver.cpp +++ b/src/d_netserver.cpp @@ -118,7 +118,7 @@ ticcmd_t NetServer::GetPlayerInput(int player) const return ticcmd_t(); } -ticcmd_t NetServer::GetLocalInput(int tic) const +ticcmd_t NetServer::GetSentInput(int tic) const { return ticcmd_t(); } diff --git a/src/d_netserver.h b/src/d_netserver.h index 6a4d6157b2..846da657e9 100644 --- a/src/d_netserver.h +++ b/src/d_netserver.h @@ -62,7 +62,7 @@ public: int GetSendTick() const override; ticcmd_t GetPlayerInput(int player) const override; - ticcmd_t GetLocalInput(int tic) const override; + ticcmd_t GetSentInput(int tic) const override; void RunCommands(int player) override; diff --git a/src/d_netsingle.cpp b/src/d_netsingle.cpp index 1b9039d56b..8922fd9779 100644 --- a/src/d_netsingle.cpp +++ b/src/d_netsingle.cpp @@ -100,7 +100,7 @@ ticcmd_t NetSinglePlayer::GetPlayerInput(int player) const return mCurrentInput[player]; } -ticcmd_t NetSinglePlayer::GetLocalInput(int tic) const +ticcmd_t NetSinglePlayer::GetSentInput(int tic) const { return mCurrentInput[consoleplayer]; } diff --git a/src/d_netsingle.h b/src/d_netsingle.h index d00a690f36..3434240b0d 100644 --- a/src/d_netsingle.h +++ b/src/d_netsingle.h @@ -35,7 +35,7 @@ public: int GetSendTick() const override; ticcmd_t GetPlayerInput(int player) const override; - ticcmd_t GetLocalInput(int tic) const override; + ticcmd_t GetSentInput(int tic) const override; void RunCommands(int player) override; diff --git a/src/p_user.cpp b/src/p_user.cpp index 8d034522d5..8551ead2b2 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2508,7 +2508,7 @@ void P_PredictPlayer (player_t *player) if (!NoInterpolateOld) R_RebuildViewInterpolation(player); - player->cmd = network->GetLocalInput(i); + player->cmd = network->GetSentInput(i); P_PlayerThink (player); player->mo->Tick (); From 57fac769c56204e5b5c0a4b0e64ccb5fbdd1664d Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 28 Mar 2018 23:20:48 +0200 Subject: [PATCH 09/17] - Client connect code and socket init fixes --- src/d_main.cpp | 2 ++ src/d_net.cpp | 14 ++++++++++++ src/d_net.h | 1 + src/d_netclient.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++-- src/d_netclient.h | 2 +- src/g_game.cpp | 21 ++++++++++++++++++ src/g_game.h | 2 ++ src/i_net.cpp | 35 ++++++++++++++++++++++++++++- 8 files changed, 127 insertions(+), 4 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 9db64c24c4..2e330224eb 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1147,6 +1147,8 @@ void D_DoomLoop() try { gametime.Update(); + if (netconnect) + netconnect->Update(); network->Update(); input.Update(); playsim.Update(); diff --git a/src/d_net.cpp b/src/d_net.cpp index 27c9814414..3b65109e27 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -40,6 +40,8 @@ #include "c_console.h" #include "d_netinf.h" #include "d_net.h" +#include "d_netclient.h" +#include "d_netserver.h" #include "cmdlib.h" #include "s_sound.h" #include "m_cheat.h" @@ -75,6 +77,7 @@ EXTERN_CVAR (Int, disableautosave) EXTERN_CVAR (Int, autosavecount) std::unique_ptr network; +std::unique_ptr netconnect; //#define SIMULATEERRORS (RAND_MAX/3) #define SIMULATEERRORS 0 @@ -1281,3 +1284,14 @@ CCMD (net_listcontrollers) } } } + +CCMD(connect) +{ + if (argv.argc() < 2) + { + Printf("Usage: connect \n"); + return; + } + + netconnect.reset(new NetClient(argv[1])); +} diff --git a/src/d_net.h b/src/d_net.h index 3a827350b9..dff885d506 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -114,6 +114,7 @@ public: }; extern std::unique_ptr network; +extern std::unique_ptr netconnect; void Net_DoCommand (int type, uint8_t **stream, int player); void Net_SkipCommand (int type, uint8_t **stream); diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp index 066451cc55..5c0afee2a8 100644 --- a/src/d_netclient.cpp +++ b/src/d_netclient.cpp @@ -34,6 +34,7 @@ #include "c_console.h" #include "d_netinf.h" #include "d_netclient.h" +#include "d_netsingle.h" #include "cmdlib.h" #include "s_sound.h" #include "m_cheat.h" @@ -65,8 +66,19 @@ #include "events.h" #include "i_time.h" -NetClient::NetClient() +NetClient::NetClient(FString server) { + Printf("Connecting to %s..\n", server.GetChars()); + + mComm = I_InitNetwork(0); + mServerNode = mComm->Connect(server); + mStatus = NodeStatus::InPreGame; + + NetPacket packet; + packet.node = mServerNode; + packet.size = 1; + packet[0] = (uint8_t)NetPacketType::ConnectRequest; + mComm->PacketSend(packet); } void NetClient::Update() @@ -85,6 +97,7 @@ void NetClient::Update() else if (packet.size == 0) { OnClose(packet); + break; } else { @@ -97,6 +110,20 @@ void NetClient::Update() case NetPacketType::Tic: OnTic(packet); break; } } + + if (mStatus == NodeStatus::Closed) + { + if (network.get() == this) + { + G_EndNetGame(); + network.reset(new NetSinglePlayer()); + } + else + { + netconnect.reset(); + } + return; + } } } @@ -164,6 +191,15 @@ void NetClient::OnClose(const NetPacket &packet) mComm->Close(mServerNode); mServerNode = -1; mStatus = NodeStatus::Closed; + + if (network.get() == this) + { + Printf("Disconnected\n"); + } + else + { + Printf("Could not connect\n"); + } } void NetClient::OnConnectResponse(const NetPacket &packet) @@ -178,17 +214,31 @@ void NetClient::OnConnectResponse(const NetPacket &packet) { mPlayer = packet[2]; mStatus = NodeStatus::InGame; + + netgame = true; + multiplayer = true; + consoleplayer = mPlayer; + players[consoleplayer].settings_controller = true; + playeringame[consoleplayer] = true; + + GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars + D_SetupUserInfo(); + + //network->WriteByte(DEM_CHANGEMAP); + //network->WriteString("e1m1"); } else // Server full { mComm->Close(mServerNode); mServerNode = -1; mStatus = NodeStatus::Closed; + + Printf("Could not connect: server is full!\n"); } } else { - I_Error("Version mismatch. Unable to connect\n"); + Printf("Could not connect: version mismatch.\n"); mComm->Close(mServerNode); mServerNode = -1; mStatus = NodeStatus::Closed; diff --git a/src/d_netclient.h b/src/d_netclient.h index afa7eca790..8e2480f2c9 100644 --- a/src/d_netclient.h +++ b/src/d_netclient.h @@ -26,7 +26,7 @@ class NetClient : public Network { public: - NetClient(); + NetClient(FString server); void Update() override; diff --git a/src/g_game.cpp b/src/g_game.cpp index 2002105cf7..3c26d5bc77 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2864,6 +2864,27 @@ void G_TimeDemo (const char* name) } +void G_EndNetGame() +{ + gameaction = ga_fullconsole; + + // Should we do this? + //C_RestoreCVars(); // Is this a good idea? + + P_SetupWeapons_ntohton(); + demoplayback = false; + netgame = false; + multiplayer = false; + for (int i = 1; i < MAXPLAYERS; i++) + playeringame[i] = 0; + consoleplayer = 0; + players[0].camera = NULL; + if (StatusBar != NULL) + { + StatusBar->AttachToPlayer(&players[0]); + } +} + /* =================== = diff --git a/src/g_game.h b/src/g_game.h index 2ac019059c..bddb696209 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -63,6 +63,8 @@ void G_PlayDemo (char* name); void G_TimeDemo (const char* name); bool G_CheckDemoStatus (void); +void G_EndNetGame(); + void G_WorldDone (void); void G_Ticker (void); diff --git a/src/i_net.cpp b/src/i_net.cpp index 0675e5017c..2a5d6a67f6 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -126,8 +126,32 @@ private: uint8_t mTransmitBuffer[TRANSMIT_SIZE]; }; +class InitSockets +{ +public: + InitSockets() + { +#ifdef __WIN32__ + WSADATA wsad; + + if (WSAStartup(0x0101, &wsad)) + { + I_FatalError("Could not initialize Windows Sockets"); + } +#endif + } + + ~InitSockets() + { +#ifdef __WIN32__ + WSACleanup(); +#endif + } +}; + std::unique_ptr I_InitNetwork(int port) { + static InitSockets initsockets; return std::unique_ptr(new DoomComImpl(port)); } @@ -152,6 +176,14 @@ DoomComImpl::DoomComImpl(int port) if (v == SOCKET_ERROR) I_FatalError("BindToPort: %s", neterror()); } + +#ifndef __sun + u_long trueval = 1; + ioctlsocket(mSocket, FIONBIO, &trueval); +#else + u_long trueval = 1; + fcntl(mysocket, F_SETFL, trueval | O_NONBLOCK); +#endif } DoomComImpl::~DoomComImpl() @@ -187,7 +219,8 @@ int DoomComImpl::FindNode(const sockaddr_in *address) } else if (mNodeLastUpdate[i] == 0) { - slot = i; + if (slot == -1) + slot = i; } } From 2ee2dc9d9dd956b08db10fe8c174cf9fb3666958 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 29 Mar 2018 13:02:15 +0200 Subject: [PATCH 10/17] - Implement enough of client/server communication to allow them to connect and let client steer the player on the server --- src/d_net.cpp | 6 ++++ src/d_netclient.cpp | 28 +++++++++++++--- src/d_netclient.h | 4 +++ src/d_netserver.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++--- src/d_netserver.h | 4 +++ 5 files changed, 111 insertions(+), 10 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 3b65109e27..b65e7cafaa 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1295,3 +1295,9 @@ CCMD(connect) netconnect.reset(new NetClient(argv[1])); } + +CCMD(hostgame) +{ + netconnect.reset(); + network.reset(new NetServer()); +} diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp index 5c0afee2a8..a1e11db99d 100644 --- a/src/d_netclient.cpp +++ b/src/d_netclient.cpp @@ -115,8 +115,8 @@ void NetClient::Update() { if (network.get() == this) { - G_EndNetGame(); network.reset(new NetSinglePlayer()); + G_EndNetGame(); } else { @@ -135,6 +135,16 @@ void NetClient::SetCurrentTic(int receivetic, int sendtic) void NetClient::EndCurrentTic() { + NetPacket packet; + packet.node = mServerNode; + packet.size = 2 + sizeof(usercmd_t); + packet[0] = (uint8_t)NetPacketType::Tic; + packet[1] = 0; // target gametic + memcpy(&packet[2], &mCurrentInput[consoleplayer].ucmd, sizeof(usercmd_t)); + mComm->PacketSend(packet); + + mCurrentCommands = mSendCommands; + mSendCommands.Clear(); } int NetClient::GetSendTick() const @@ -144,28 +154,35 @@ int NetClient::GetSendTick() const ticcmd_t NetClient::GetPlayerInput(int player) const { - return ticcmd_t(); + return mCurrentInput[player]; } ticcmd_t NetClient::GetSentInput(int tic) const { - return ticcmd_t(); + return mCurrentInput[consoleplayer]; } void NetClient::RunCommands(int player) { + if (player == consoleplayer) + { + Net_RunCommands(mCurrentCommands, consoleplayer); + } } void NetClient::WriteLocalInput(ticcmd_t cmd) { + mCurrentInput[consoleplayer] = cmd; } void NetClient::WriteBotInput(int player, const ticcmd_t &cmd) { + mCurrentInput[player] = cmd; } void NetClient::WriteBytes(const uint8_t *block, int len) { + mSendCommands.AppendData(block, len); } int NetClient::GetPing(int player) const @@ -224,8 +241,9 @@ void NetClient::OnConnectResponse(const NetPacket &packet) GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars D_SetupUserInfo(); - //network->WriteByte(DEM_CHANGEMAP); - //network->WriteString("e1m1"); + G_DeferedInitNew("e1m1"); + + network = std::move(netconnect); } else // Server full { diff --git a/src/d_netclient.h b/src/d_netclient.h index 8e2480f2c9..cdf629c4e2 100644 --- a/src/d_netclient.h +++ b/src/d_netclient.h @@ -60,4 +60,8 @@ private: int mPlayer = -1; NodeStatus mStatus = NodeStatus::Closed; int mSendTic = 0; + + ticcmd_t mCurrentInput[MAXPLAYERS]; + FDynamicBuffer mCurrentCommands; + FDynamicBuffer mSendCommands; }; diff --git a/src/d_netserver.cpp b/src/d_netserver.cpp index 329f1c1487..a369ac62bf 100644 --- a/src/d_netserver.cpp +++ b/src/d_netserver.cpp @@ -67,6 +67,20 @@ NetServer::NetServer() { + Printf("Started hosting multiplayer game..\n"); + + mComm = I_InitNetwork(DOOMPORT); + + netgame = true; + multiplayer = true; + consoleplayer = 0; + players[consoleplayer].settings_controller = true; + playeringame[consoleplayer] = true; + + GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars + D_SetupUserInfo(); + + G_DeferedInitNew("e1m1"); } void NetServer::Update() @@ -106,6 +120,21 @@ void NetServer::SetCurrentTic(int receivetic, int sendtic) void NetServer::EndCurrentTic() { + for (int i = 0; i < MAXNETNODES; i++) + { + if (mNodes[i].Status == NodeStatus::InGame) + { + NetPacket packet; + packet.node = i; + packet.size = 2; + packet[0] = (uint8_t)NetPacketType::Tic; + packet[1] = gametic; + mComm->PacketSend(packet); + } + } + + mCurrentCommands = mSendCommands; + mSendCommands.Clear(); } int NetServer::GetSendTick() const @@ -115,28 +144,35 @@ int NetServer::GetSendTick() const ticcmd_t NetServer::GetPlayerInput(int player) const { - return ticcmd_t(); + return mCurrentInput[player]; } ticcmd_t NetServer::GetSentInput(int tic) const { - return ticcmd_t(); + return mCurrentInput[consoleplayer]; } void NetServer::RunCommands(int player) { + if (player == consoleplayer) + { + Net_RunCommands(mCurrentCommands, consoleplayer); + } } void NetServer::WriteLocalInput(ticcmd_t cmd) { + mCurrentInput[consoleplayer] = cmd; } void NetServer::WriteBotInput(int player, const ticcmd_t &cmd) { + mCurrentInput[player] = cmd; } void NetServer::WriteBytes(const uint8_t *block, int len) { + mSendCommands.AppendData(block, len); } int NetServer::GetPing(int player) const @@ -164,20 +200,40 @@ void NetServer::Network_Controller(int playernum, bool add) void NetServer::OnClose(NetNode &node, const NetPacket &packet) { + if (node.Status == NodeStatus::InGame) + { + Printf("Player %d left the server", node.Player); + + playeringame[node.Player] = false; + players[node.Player].settings_controller = false; + node.Player = -1; + } + node.Status = NodeStatus::Closed; mComm->Close(packet.node); } void NetServer::OnConnectRequest(NetNode &node, const NetPacket &packet) { - if (node.Player == -1) + // Search for a spot in the player list + if (node.Status != NodeStatus::InGame) { - // To do: search for free player spot - node.Player = 1; + for (int i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + { + node.Player = i; + playeringame[i] = true; + players[i].settings_controller = false; + break; + } + } } if (node.Player != -1) // Join accepted. { + Printf("Player %d joined the server", node.Player); + mNodeForPlayer[node.Player] = packet.node; NetPacket response; @@ -209,6 +265,15 @@ void NetServer::OnConnectRequest(NetNode &node, const NetPacket &packet) void NetServer::OnDisconnect(NetNode &node, const NetPacket &packet) { + if (node.Status == NodeStatus::InGame) + { + Printf("Player %d left the server", node.Player); + + playeringame[node.Player] = false; + players[node.Player].settings_controller = false; + node.Player = -1; + } + node.Status = NodeStatus::Closed; mComm->Close(packet.node); } @@ -217,6 +282,10 @@ void NetServer::OnTic(NetNode &node, const NetPacket &packet) { if (node.Status == NodeStatus::InGame) { + if (packet.size != 2 + sizeof(usercmd_t)) + return; + + memcpy(&mCurrentInput[node.Player].ucmd, &packet[2], sizeof(usercmd_t)); } else { diff --git a/src/d_netserver.h b/src/d_netserver.h index 846da657e9..29acca84b1 100644 --- a/src/d_netserver.h +++ b/src/d_netserver.h @@ -86,4 +86,8 @@ private: NetNode mNodes[MAXNETNODES]; int mNodeForPlayer[MAXPLAYERS]; int mSendTic = 0; + + ticcmd_t mCurrentInput[MAXPLAYERS]; + FDynamicBuffer mCurrentCommands; + FDynamicBuffer mSendCommands; }; From 8eff789f4cddd730d6e29824ddbbee5548877886 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 30 Mar 2018 23:09:11 +0200 Subject: [PATCH 11/17] - Tell the client where its player is --- src/d_netclient.cpp | 27 +++++++++++++++++---------- src/d_netserver.cpp | 32 +++++++++++++++++++++----------- src/g_game.cpp | 30 ++++++++++++++++++++++++++++++ src/g_game.h | 2 ++ 4 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp index a1e11db99d..6845d1a72f 100644 --- a/src/d_netclient.cpp +++ b/src/d_netclient.cpp @@ -232,16 +232,7 @@ void NetClient::OnConnectResponse(const NetPacket &packet) mPlayer = packet[2]; mStatus = NodeStatus::InGame; - netgame = true; - multiplayer = true; - consoleplayer = mPlayer; - players[consoleplayer].settings_controller = true; - playeringame[consoleplayer] = true; - - GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars - D_SetupUserInfo(); - - G_DeferedInitNew("e1m1"); + G_InitClientNetGame(mPlayer, "e1m1"); network = std::move(netconnect); } @@ -272,4 +263,20 @@ void NetClient::OnDisconnect(const NetPacket &packet) void NetClient::OnTic(const NetPacket &packet) { + if (packet.size != 2 + sizeof(float) * 5) + return; + + int tic = packet[1]; + float x = *(float*)&packet[2]; + float y = *(float*)&packet[6]; + float z = *(float*)&packet[10]; + float yaw = *(float*)&packet[14]; + float pitch = *(float*)&packet[18]; + + if (playeringame[consoleplayer] && players[consoleplayer].mo) + { + players[consoleplayer].mo->SetXYZ(x, y, z); + players[consoleplayer].mo->Angles.Yaw = yaw; + players[consoleplayer].mo->Angles.Pitch = pitch; + } } diff --git a/src/d_netserver.cpp b/src/d_netserver.cpp index a369ac62bf..96e02ad437 100644 --- a/src/d_netserver.cpp +++ b/src/d_netserver.cpp @@ -71,16 +71,7 @@ NetServer::NetServer() mComm = I_InitNetwork(DOOMPORT); - netgame = true; - multiplayer = true; - consoleplayer = 0; - players[consoleplayer].settings_controller = true; - playeringame[consoleplayer] = true; - - GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars - D_SetupUserInfo(); - - G_DeferedInitNew("e1m1"); + G_InitServerNetGame("e1m1"); } void NetServer::Update() @@ -126,9 +117,28 @@ void NetServer::EndCurrentTic() { NetPacket packet; packet.node = i; - packet.size = 2; + packet.size = 2 + sizeof(float) * 5; packet[0] = (uint8_t)NetPacketType::Tic; packet[1] = gametic; + + int player = mNodes[i].Player; + if (playeringame[player] && players[player].mo) + { + *(float*)&packet[2] = (float)players[player].mo->X(); + *(float*)&packet[6] = (float)players[player].mo->Y(); + *(float*)&packet[10] = (float)players[player].mo->Z(); + *(float*)&packet[14] = (float)players[player].mo->Angles.Yaw.Degrees; + *(float*)&packet[18] = (float)players[player].mo->Angles.Pitch.Degrees; + } + else + { + *(float*)&packet[2] = 0.0f; + *(float*)&packet[6] = 0.0f; + *(float*)&packet[10] = 0.0f; + *(float*)&packet[14] = 0.0f; + *(float*)&packet[18] = 0.0f; + } + mComm->PacketSend(packet); } } diff --git a/src/g_game.cpp b/src/g_game.cpp index 3c26d5bc77..324da4c247 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -94,6 +94,7 @@ #include "g_levellocals.h" #include "events.h" #include "d_main.h" +#include "gameconfigfile.h" static FRandom pr_dmspawn ("DMSpawn"); @@ -2863,6 +2864,35 @@ void G_TimeDemo (const char* name) gameaction = (gameaction == ga_loadgame) ? ga_loadgameplaydemo : ga_playdemo; } +void G_InitServerNetGame(const char *mapname) +{ + netgame = true; + multiplayer = true; + multiplayernext = true; + consoleplayer = 0; + players[consoleplayer].settings_controller = true; + playeringame[consoleplayer] = true; + + GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars + D_SetupUserInfo(); + + G_DeferedInitNew(mapname); +} + +void G_InitClientNetGame(int player, const char* mapname) +{ + netgame = true; + multiplayer = true; + multiplayernext = true; + consoleplayer = player; + players[consoleplayer].settings_controller = true; + playeringame[consoleplayer] = true; + + GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars + D_SetupUserInfo(); + + G_DeferedInitNew(mapname); +} void G_EndNetGame() { diff --git a/src/g_game.h b/src/g_game.h index bddb696209..808dc3a5d6 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -63,6 +63,8 @@ void G_PlayDemo (char* name); void G_TimeDemo (const char* name); bool G_CheckDemoStatus (void); +void G_InitServerNetGame(const char *mapname); +void G_InitClientNetGame(int player, const char* mapname); void G_EndNetGame(); void G_WorldDone (void); From 260096ba2ae164a260ca79c7fdf8cd2b498afb78 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 31 Mar 2018 16:41:30 +0200 Subject: [PATCH 12/17] - Don't spawn things on the client side --- src/doomstat.h | 3 +++ src/g_game.cpp | 5 +++++ src/p_setup.cpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/doomstat.h b/src/doomstat.h index 3e76d7f2f7..3ed3642b66 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -79,6 +79,9 @@ extern bool multiplayer; // [SP] Map dm/coop implementation - invokes fake multiplayer without bots extern bool multiplayernext; +// clientside playsim +extern bool netclient; + // Flag: true only if started as net deathmatch. EXTERN_CVAR (Int, deathmatch) diff --git a/src/g_game.cpp b/src/g_game.cpp index 324da4c247..8b467a8577 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -170,6 +170,7 @@ bool viewactive; bool netgame; // only true if packets are broadcast bool multiplayer; bool multiplayernext = false; // [SP] Map coop/dm implementation +bool netclient; // clientside playsim player_t players[MAXPLAYERS]; bool playeringame[MAXPLAYERS]; @@ -2867,6 +2868,7 @@ void G_TimeDemo (const char* name) void G_InitServerNetGame(const char *mapname) { netgame = true; + netclient = false; multiplayer = true; multiplayernext = true; consoleplayer = 0; @@ -2882,6 +2884,7 @@ void G_InitServerNetGame(const char *mapname) void G_InitClientNetGame(int player, const char* mapname) { netgame = true; + netclient = true; multiplayer = true; multiplayernext = true; consoleplayer = player; @@ -2904,7 +2907,9 @@ void G_EndNetGame() P_SetupWeapons_ntohton(); demoplayback = false; netgame = false; + netclient = false; multiplayer = false; + multiplayernext = false; for (int i = 1; i < MAXPLAYERS; i++) playeringame[i] = 0; consoleplayer = 0; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 648502542a..b5b18d6386 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1842,6 +1842,10 @@ void P_SpawnThings (int position) for (int i=0; i < numthings; i++) { + // Only spawn the player mobj for the client in a client/server game + if (netclient && (MapThingsConverted[i].info->Type || MapThingsConverted[i].info->Special != SMT_Player1Start + position)) + continue; + AActor *actor = SpawnMapThing (i, &MapThingsConverted[i], position); unsigned *udi = MapThingsUserDataIndex.CheckKey((unsigned)i); if (udi != NULL) From b7c711b85ed51ed090c8841c221fba3744aad63b Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Thu, 19 Apr 2018 13:46:13 -0400 Subject: [PATCH 13/17] - start creating basic structures for actor sync --- src/actor.h | 5 +++++ src/d_netsync.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/d_netsync.h diff --git a/src/actor.h b/src/actor.h index 863e4fb46a..675d406a63 100644 --- a/src/actor.h +++ b/src/actor.h @@ -48,6 +48,8 @@ #include "tflags.h" #include "portal.h" +#include "d_netsync.h" + struct subsector_t; struct FBlockNode; struct FPortalGroupArray; @@ -635,6 +637,9 @@ public: AActor &operator= (const AActor &other); ~AActor (); + NetSyncData syncdata; + NetSyncData synccompare; + virtual void Finalize(FStateDefinitions &statedef); virtual void OnDestroy() override; virtual void Serialize(FSerializer &arc) override; diff --git a/src/d_netsync.h b/src/d_netsync.h new file mode 100644 index 0000000000..8bb6883cd9 --- /dev/null +++ b/src/d_netsync.h @@ -0,0 +1,33 @@ +#ifndef __D_NETSYNC_H__ +#define __D_NETSYNC_H__ + +struct NetSyncData { + DVector3 Pos; + DVector3 Vel; + DAngle SpriteAngle; + DAngle SpriteRotation; + DRotator Angles; + DVector2 Scale; // Scaling values; 1 is normal size + double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double. + int sprite; // used to find patch_t and flip value + uint8_t frame; // sprite frame to draw + uint8_t effects; // [RH] see p_effect.h + FRenderStyle RenderStyle; // Style to draw this actor with + uint32_t Translation; + uint32_t RenderRequired; // current renderer must have this feature set + uint32_t RenderHidden; // current renderer must *not* have any of these features + ActorRenderFlags renderflags; // Different rendering flags + double Floorclip; // value to use for floor clipping + DAngle VisibleStartAngle; + DAngle VisibleStartPitch; + DAngle VisibleEndAngle; + DAngle VisibleEndPitch; + double Speed; + double FloatSpeed; + double CameraHeight; // Height of camera when used as such + double CameraFOV; + double StealthAlpha; // Minmum alpha for MF_STEALTH. + +}; + +#endif //__D_NETSYNC_H__ \ No newline at end of file From 42463b7547fa7b19b948786c9806296ec6f330c8 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Thu, 19 Apr 2018 14:16:50 -0400 Subject: [PATCH 14/17] - fix compile --- src/d_netsync.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/d_netsync.h b/src/d_netsync.h index 8bb6883cd9..3c764077c0 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -13,10 +13,10 @@ struct NetSyncData { uint8_t frame; // sprite frame to draw uint8_t effects; // [RH] see p_effect.h FRenderStyle RenderStyle; // Style to draw this actor with - uint32_t Translation; - uint32_t RenderRequired; // current renderer must have this feature set - uint32_t RenderHidden; // current renderer must *not* have any of these features - ActorRenderFlags renderflags; // Different rendering flags + uint32_t Translation; + uint32_t RenderRequired; // current renderer must have this feature set + uint32_t RenderHidden; // current renderer must *not* have any of these features + uint32_t renderflags; // Different rendering flags double Floorclip; // value to use for floor clipping DAngle VisibleStartAngle; DAngle VisibleStartPitch; From bb235ab5720340d67f3206ab72db1e405007d6a3 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sat, 28 Apr 2018 10:04:22 -0400 Subject: [PATCH 15/17] - properly set 'netgame' in C/S situations to disable cheats and make the game continue running when the menu/console are active --- src/d_net.cpp | 30 +++--------------------------- src/d_netsingle.cpp | 4 ++++ src/g_game.cpp | 3 +++ src/g_level.cpp | 4 +++- 4 files changed, 13 insertions(+), 28 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 444a27ad65..3be096d703 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -246,33 +246,9 @@ void Network::D_CheckNetGame() Printf("using alternate port %i\n", port); } - // parse network game options, - // player 1: -host - // player x: -join - if ((i = Args->CheckParm("-host"))) - { - doomcom = I_InitNetwork(port); - //HostGame(i); - } - else if ((i = Args->CheckParm("-join"))) - { - 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"); - - doomcom = I_InitNetwork(0); - doomcom->Connect(Args->GetArg(i + 1)); - //JoinGame(i); - } - else - { - // single player game - netgame = false; - multiplayer = false; - //numplayers = numnodes = 1; - consoleplayer = 0; - } + netgame = false; + multiplayer = false; + consoleplayer = 0; v = Args->CheckValue("-dup"); if (v) diff --git a/src/d_netsingle.cpp b/src/d_netsingle.cpp index 8922fd9779..9f8357108f 100644 --- a/src/d_netsingle.cpp +++ b/src/d_netsingle.cpp @@ -65,9 +65,13 @@ #include "events.h" #include "i_time.h" +extern bool netserver, netclient; + NetSinglePlayer::NetSinglePlayer() { netgame = false; + netclient = false; + netserver = false; multiplayer = false; consoleplayer = 0; players[0].settings_controller = true; diff --git a/src/g_game.cpp b/src/g_game.cpp index 683e1edd95..e3ad8b033b 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -154,6 +154,7 @@ bool netgame; // only true if packets are broadcast bool multiplayer; bool multiplayernext = false; // [SP] Map coop/dm implementation bool netclient; // clientside playsim +bool netserver = false; // used to enforce 'netplay = true' player_t players[MAXPLAYERS]; bool playeringame[MAXPLAYERS]; @@ -2851,6 +2852,7 @@ void G_TimeDemo (const char* name) void G_InitServerNetGame(const char *mapname) { netgame = true; + netserver = true; netclient = false; multiplayer = true; multiplayernext = true; @@ -2867,6 +2869,7 @@ void G_InitServerNetGame(const char *mapname) void G_InitClientNetGame(int player, const char* mapname) { netgame = true; + netserver = false; netclient = true; multiplayer = true; multiplayernext = true; diff --git a/src/g_level.cpp b/src/g_level.cpp index 47f27bf9d3..0badab9184 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -150,6 +150,8 @@ extern bool sendpause, sendsave, sendturn180, SendLand; void *statcopy; // for statistics driver FLevelLocals level; // info about current level +extern bool netserver; // serverside playsim +extern bool netclient; // clientside playsim //========================================================================== @@ -350,7 +352,7 @@ void G_NewInit () } G_ClearSnapshots (); - netgame = false; + netgame = (netclient || netserver); multiplayer = multiplayernext; multiplayernext = false; if (demoplayback) From c89c63d9dac9c60fdca34493534a1440fdb1d98a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 28 Apr 2018 16:21:05 +0200 Subject: [PATCH 16/17] - Improve player prediction --- src/d_netclient.cpp | 3 ++- src/d_netclient.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp index 6845d1a72f..dc1817143e 100644 --- a/src/d_netclient.cpp +++ b/src/d_netclient.cpp @@ -159,7 +159,7 @@ ticcmd_t NetClient::GetPlayerInput(int player) const ticcmd_t NetClient::GetSentInput(int tic) const { - return mCurrentInput[consoleplayer]; + return mSentInput[tic % BACKUPTICS]; } void NetClient::RunCommands(int player) @@ -173,6 +173,7 @@ void NetClient::RunCommands(int player) void NetClient::WriteLocalInput(ticcmd_t cmd) { mCurrentInput[consoleplayer] = cmd; + mSentInput[gametic % BACKUPTICS] = cmd; } void NetClient::WriteBotInput(int player, const ticcmd_t &cmd) diff --git a/src/d_netclient.h b/src/d_netclient.h index cdf629c4e2..e7ef5668ac 100644 --- a/src/d_netclient.h +++ b/src/d_netclient.h @@ -62,6 +62,7 @@ private: int mSendTic = 0; ticcmd_t mCurrentInput[MAXPLAYERS]; + ticcmd_t mSentInput[BACKUPTICS]; FDynamicBuffer mCurrentCommands; FDynamicBuffer mSendCommands; }; From 9122c6439830e1f7415c5eae396e3d86733e5df0 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 28 Apr 2018 16:45:23 +0200 Subject: [PATCH 17/17] - fix exit crash in netgames --- src/p_user.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_user.cpp b/src/p_user.cpp index ebd54d66bd..8ae754ceba 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2588,6 +2588,7 @@ void P_UnPredictPlayer () int inventorytics = player->inventorytics; *player = PredictionPlayerBackup; + PredictionPlayerBackup = {}; // Clear the copy so its destructor doesn't try delete the psprites list // Restore the camera instead of using the backup's copy, because spynext/prev // could cause it to change during prediction.