From 0df692bfec1ff90195f98eac3f4be384cf8d4905 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 24 Mar 2018 00:31:08 +0100 Subject: [PATCH 01/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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/46] - 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. From 8d8d03d13906f8b1cafa56cdf4344f4a88df1a51 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sat, 21 Jul 2018 17:41:35 +0200 Subject: [PATCH 18/46] added and adapted Zandronum's netID system for actors --- src/CMakeLists.txt | 1 + src/d_netsync.cpp | 165 +++++++++++++++++++++++++++++++++++++++++++++ src/d_netsync.h | 79 ++++++++++++++++++++++ src/p_mobj.cpp | 7 ++ 4 files changed, 252 insertions(+) create mode 100644 src/d_netsync.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a79e547fee..82e5fd3ee9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -878,6 +878,7 @@ set (PCH_SOURCES d_net.cpp d_netsingle.cpp d_netserver.cpp + d_netsync.cpp d_netclient.cpp d_netinfo.cpp d_protocol.cpp diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp new file mode 100644 index 0000000000..aed0100c37 --- /dev/null +++ b/src/d_netsync.cpp @@ -0,0 +1,165 @@ +//----------------------------------------------------------------------------- +// +// Copyright 2018 Benjamin Berkels +// +// 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 "d_player.h" +#include "d_netsync.h" +#include "c_dispatch.h" +#include "actor.h" +#include "doomstat.h" + +extern bool netserver, netclient; + +IDList g_NetIDList; + +//***************************************************************************** +// +void NetSyncData::AssignNetID ( AActor *pActor ) +{ + if ( netserver ) + { + NetID = g_NetIDList.getNewID( ); + g_NetIDList.useID ( NetID, pActor ); + } + else + NetID = -1; +} + +//***************************************************************************** +// +void NetSyncData::FreeNetID ( ) +{ + g_NetIDList.freeID ( NetID ); +} + +//***************************************************************************** +// +template +void IDList::clear( void ) +{ + for ( unsigned int ulIdx = 0; ulIdx < MAX_NETID; ulIdx++ ) + freeID ( ulIdx ); + + _firstFreeID = 1; +} + +//***************************************************************************** +// +template +void IDList::rebuild( void ) +{ + clear(); + + T *pActor; + + TThinkerIterator it; + + while ( (pActor = it.Next()) ) + { + if (( pActor->syncdata.NetID > 0 ) && ( pActor->syncdata.NetID < MAX_NETID )) + useID ( pActor->syncdata.NetID, pActor ); + } +} + +//***************************************************************************** +// +template +void IDList::useID ( const int lNetID, T *pActor ) +{ + if ( isIndexValid ( lNetID ) ) + { + if ( ( _entries[lNetID].bFree == false ) && ( _entries[lNetID].pActor != pActor ) ) + Printf ( "IDList::useID is using an already used ID.\n" ); + + _entries[lNetID].bFree = false; + _entries[lNetID].pActor = pActor; + } +} + +//***************************************************************************** +// +void CountActors ( ) +{ + TMap actorCountMap; + AActor * mo; + int numActors = 0; + int numActorsWithNetID = 0; + + TThinkerIterator it; + + while ( (mo = it.Next()) ) + { + numActors++; + if ( mo->syncdata.NetID > 0 ) + numActorsWithNetID++; + const FName curName = mo->GetClass()->TypeName.GetChars(); + if ( actorCountMap.CheckKey( curName ) == NULL ) + actorCountMap.Insert( curName, 1 ); + else + actorCountMap [ curName ] ++; + } + + const TMap::Pair *pair; + + Printf ( "%d actors in total found, %d have a NetID. Detailed listing:\n", numActors, numActorsWithNetID ); + + TMap::ConstIterator mapit(actorCountMap); + while (mapit.NextPair (pair)) + { + Printf ( "%s %d\n", pair->Key.GetChars(), pair->Value ); + } +} + +CCMD(countactors) +{ + CountActors (); +} + +//***************************************************************************** +// +template +unsigned int IDList::getNewID( void ) +{ + // Actor's network ID is the first availible net ID. + unsigned int ulID = _firstFreeID; + + do + { + _firstFreeID++; + if ( _firstFreeID >= MAX_NETID ) + _firstFreeID = 1; + + if ( _firstFreeID == ulID ) + { + // [BB] In case there is no free netID, the server has to abort the current game. + if ( netserver ) + { + // [BB] We can only spawn (MAX_NETID-2) actors with netID, because ID zero is reserved and + // we already check that a new ID for the next actor is available when assign a net ID. + Printf( "ACTOR_GetNewNetID: Network ID limit reached (>=%d actors)\n", MAX_NETID - 1 ); + CountActors ( ); + I_Error ("Network ID limit reached (>=%d actors)!\n", MAX_NETID - 1 ); + } + + return ( 0 ); + } + } while ( _entries[_firstFreeID].bFree == false ); + + return ( ulID ); +} + +template class IDList; diff --git a/src/d_netsync.h b/src/d_netsync.h index 3c764077c0..1ff6b09f9c 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -1,6 +1,9 @@ #ifndef __D_NETSYNC_H__ #define __D_NETSYNC_H__ +#include "vectors.h" +#include "r_data/renderstyle.h" + struct NetSyncData { DVector3 Pos; DVector3 Vel; @@ -27,7 +30,83 @@ struct NetSyncData { double CameraHeight; // Height of camera when used as such double CameraFOV; double StealthAlpha; // Minmum alpha for MF_STEALTH. + int NetID; + void AssignNetID ( AActor *pActor ); + void FreeNetID (); +}; + +//========================================================================== +// +// IDList +// +// Manages IDs to reference a certain type of objects over the network. +// Since it still mimics the old Actor ID mechanism, 0 is never assigned as +// ID. +// +// @author Benjamin Berkels +// +//========================================================================== + +template +class IDList +{ +public: + const static int MAX_NETID = 32768; + +private: + // List of all possible network ID's for an actor. Slot is true if it available for use. + typedef struct + { + // Is this node occupied, or free to be used by a new actor? + bool bFree; + + // If this node is occupied, this is the actor occupying it. + T *pActor; + + } IDNODE_t; + + IDNODE_t _entries[MAX_NETID]; + unsigned int _firstFreeID; + + inline bool isIndexValid ( const int lNetID ) const + { + return ( lNetID >= 0 ) && ( lNetID < MAX_NETID ); + } +public: + void clear ( ); + + // [BB] Rebuild the global list of used / free NetIDs from scratch. + void rebuild ( ); + + IDList ( ) + { + clear ( ); + } + + void useID ( const int lNetID, T *pActor ); + + void freeID ( const int lNetID ) + { + if ( isIndexValid ( lNetID ) ) + { + _entries[lNetID].bFree = true; + _entries[lNetID].pActor = NULL; + } + } + + unsigned int getNewID ( ); + + T* findPointerByID ( const int lNetID ) const + { + if ( isIndexValid ( lNetID ) == false ) + return ( NULL ); + + if (( _entries[lNetID].bFree == false ) && ( _entries[lNetID].pActor )) + return ( _entries[lNetID].pActor ); + + return ( NULL ); + } }; #endif //__D_NETSYNC_H__ \ No newline at end of file diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2f8b89a843..f98e5b6660 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5099,6 +5099,10 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a } // force scroller check in the first tic. actor->flags8 |= MF8_INSCROLLSEC; + + // [BB] Give this actor a NetID so that we can sync it to the clients. + actor->syncdata.AssignNetID( actor ); + return actor; } @@ -5368,6 +5372,9 @@ void AActor::CallDeactivate(AActor *activator) void AActor::OnDestroy () { + // [BB] Free it's network ID. + syncdata.FreeNetID (); + // [ZZ] call destroy event hook. // note that this differs from ThingSpawned in that you can actually override OnDestroy to avoid calling the hook. // but you can't really do that without utterly breaking the game, so it's ok. From b3361bb83321da66575a4e7123b2d92c8d81a574 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sun, 22 Jul 2018 15:53:37 +0200 Subject: [PATCH 19/46] added Zandronum's BYTESTREAM_s --- src/d_netsync.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++++ src/d_netsync.h | 17 +++++++++ 2 files changed, 105 insertions(+) diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp index aed0100c37..ee87850262 100644 --- a/src/d_netsync.cpp +++ b/src/d_netsync.cpp @@ -24,8 +24,58 @@ extern bool netserver, netclient; +//***************************************************************************** +// VARIABLES + +// [BB] Are we measuring outbound traffic? +static bool g_MeasuringOutboundTraffic = false; +// [BB] Number of bytes sent by NETWORK_Write* since NETWORK_StartTrafficMeasurement() was called. +static int g_OutboundBytesMeasured = 0; + IDList g_NetIDList; +//***************************************************************************** +// +void NETWORK_AdvanceByteStreamPointer( BYTESTREAM_s *pByteStream, const int NumBytes, const bool OutboundTraffic ) +{ + pByteStream->pbStream += NumBytes; + + // [BB] + if ( g_MeasuringOutboundTraffic && OutboundTraffic ) + g_OutboundBytesMeasured += NumBytes; +} + +//***************************************************************************** +// +int NETWORK_ReadByte( BYTESTREAM_s *pByteStream ) +{ + int Byte = -1; + + if (( pByteStream->pbStream + 1 ) <= pByteStream->pbStreamEnd ) + Byte = *pByteStream->pbStream; + + // Advance the pointer. + pByteStream->pbStream += 1; + + return ( Byte ); +} + +//***************************************************************************** +// +void NETWORK_WriteByte( BYTESTREAM_s *pByteStream, int Byte ) +{ + if (( pByteStream->pbStream + 1 ) > pByteStream->pbStreamEnd ) + { + Printf( "NETWORK_WriteByte: Overflow!\n" ); + return; + } + + *pByteStream->pbStream = Byte; + + // Advance the pointer. + NETWORK_AdvanceByteStreamPointer ( pByteStream, 1, true ); +} + //***************************************************************************** // void NetSyncData::AssignNetID ( AActor *pActor ) @@ -46,6 +96,44 @@ void NetSyncData::FreeNetID ( ) g_NetIDList.freeID ( NetID ); } +//***************************************************************************** +// +BYTESTREAM_s::BYTESTREAM_s() : + bitBuffer( NULL ), + bitShift( -1 ) {} + +//***************************************************************************** +// +void BYTESTREAM_s::EnsureBitSpace( int bits, bool writing ) +{ + if ( ( bitBuffer == NULL ) || ( bitShift < 0 ) || ( bitShift + bits > 8 ) ) + { + if ( writing ) + { + // Not enough bits left in our current byte, we need a new one. + NETWORK_WriteByte( this, 0 ); + bitBuffer = pbStream - 1; + } + else + { + // No room for the value in this byte, so we need a new one. + if ( NETWORK_ReadByte( this ) != -1 ) + { + bitBuffer = pbStream - 1; + } + else + { + // Argh! No bytes left! + Printf("BYTESTREAM_s::EnsureBitSpace: out of bytes to use\n"); + static uint8_t fallback = 0; + bitBuffer = &fallback; + } + } + + bitShift = 0; + } +} + //***************************************************************************** // template diff --git a/src/d_netsync.h b/src/d_netsync.h index 1ff6b09f9c..7af9def747 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -36,6 +36,23 @@ struct NetSyncData { void FreeNetID (); }; +//***************************************************************************** +struct BYTESTREAM_s +{ + BYTESTREAM_s(); + void EnsureBitSpace( int bits, bool writing ); + + // Pointer to our stream of data. + uint8_t *pbStream; + + // Pointer to the end of the stream. When pbStream > pbStreamEnd, the + // entire stream has been read. + uint8_t *pbStreamEnd; + + uint8_t *bitBuffer; + int bitShift; +}; + //========================================================================== // // IDList From 7117af6b6601745108fcc296fb78a08622490868 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sun, 22 Jul 2018 16:01:13 +0200 Subject: [PATCH 20/46] added Zandronum's NETBUFFER_s --- src/d_netsync.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++++++ src/d_netsync.h | 37 +++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp index ee87850262..be1525ab31 100644 --- a/src/d_netsync.cpp +++ b/src/d_netsync.cpp @@ -76,6 +76,22 @@ void NETWORK_WriteByte( BYTESTREAM_s *pByteStream, int Byte ) NETWORK_AdvanceByteStreamPointer ( pByteStream, 1, true ); } +//***************************************************************************** +// +void NETWORK_WriteBuffer( BYTESTREAM_s *pByteStream, const void *pvBuffer, int nLength ) +{ + if (( pByteStream->pbStream + nLength ) > pByteStream->pbStreamEnd ) + { + Printf( "NETWORK_WriteLBuffer: Overflow!\n" ); + return; + } + + memcpy( pByteStream->pbStream, pvBuffer, nLength ); + + // Advance the pointer. + NETWORK_AdvanceByteStreamPointer ( pByteStream, nLength, true ); +} + //***************************************************************************** // void NetSyncData::AssignNetID ( AActor *pActor ) @@ -134,6 +150,91 @@ void BYTESTREAM_s::EnsureBitSpace( int bits, bool writing ) } } +//***************************************************************************** +// +NETBUFFER_s::NETBUFFER_s ( ) +{ + this->pbData = NULL; + this->ulMaxSize = 0; + this->BufferType = (BUFFERTYPE_e)0; + Clear(); +} + +//***************************************************************************** +// +NETBUFFER_s::NETBUFFER_s ( const NETBUFFER_s &Buffer ) +{ + Init ( Buffer.ulMaxSize, Buffer.BufferType ); + Clear(); + + memcpy( this->pbData, Buffer.pbData, Buffer.ulMaxSize ); + this->ByteStream.pbStream = this->pbData + ( Buffer.ByteStream.pbStream - Buffer.pbData ); + this->ByteStream.pbStreamEnd = this->pbData + ( Buffer.ByteStream.pbStreamEnd - Buffer.pbData ); + this->ByteStream.bitShift = Buffer.ByteStream.bitShift; + if ( Buffer.ByteStream.bitBuffer != NULL ) + this->ByteStream.bitBuffer = this->ByteStream.pbStream + ( Buffer.ByteStream.bitBuffer - Buffer.ByteStream.pbStream ); + + this->ulCurrentSize = Buffer.ulCurrentSize; +} + +//***************************************************************************** +// +void NETBUFFER_s::Init( unsigned int ulLength, BUFFERTYPE_e BufferType ) +{ + memset( this, 0, sizeof( *this )); + this->ulMaxSize = ulLength; + this->pbData = new uint8_t[ulLength]; + this->BufferType = BufferType; +} + +//***************************************************************************** +// +void NETBUFFER_s::Free() +{ + if ( this->pbData ) + { + delete[] ( this->pbData ); + this->pbData = NULL; + } + + this->ulMaxSize = 0; + this->BufferType = (BUFFERTYPE_e)0; +} + +//***************************************************************************** +// +void NETBUFFER_s::Clear() +{ + this->ulCurrentSize = 0; + this->ByteStream.pbStream = this->pbData; + this->ByteStream.bitBuffer = NULL; + this->ByteStream.bitShift = -1; + if ( this->BufferType == BUFFERTYPE_READ ) + this->ByteStream.pbStreamEnd = this->ByteStream.pbStream; + else + this->ByteStream.pbStreamEnd = this->ByteStream.pbStream + this->ulMaxSize; +} + +//***************************************************************************** +// +int NETBUFFER_s::CalcSize() const +{ + if ( this->BufferType == BUFFERTYPE_READ ) + return ( int( this->ByteStream.pbStreamEnd - this->ByteStream.pbStream )); + else + return ( int( this->ByteStream.pbStream - this->pbData )); +} + +//***************************************************************************** +// +int NETBUFFER_s::WriteTo( BYTESTREAM_s &ByteStream ) const +{ + int bufferSize = CalcSize(); + if ( bufferSize > 0 ) + NETWORK_WriteBuffer( &ByteStream, this->pbData, bufferSize ); + return bufferSize; +} + //***************************************************************************** // template diff --git a/src/d_netsync.h b/src/d_netsync.h index 7af9def747..172d14ab03 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -53,6 +53,43 @@ struct BYTESTREAM_s int bitShift; }; +//***************************************************************************** +enum BUFFERTYPE_e +{ + BUFFERTYPE_READ, + BUFFERTYPE_WRITE, + +}; + +//***************************************************************************** +struct NETBUFFER_s +{ + // This is the data in our packet. + uint8_t *pbData; + + // The maximum amount of data this packet can hold. + unsigned int ulMaxSize; + + // How much data is currently in this packet? + unsigned int ulCurrentSize; + + // Byte stream for this buffer for managing our current position and where + // the end of the stream is. + BYTESTREAM_s ByteStream; + + // Is this a buffer that we write to, or read from? + BUFFERTYPE_e BufferType; + + NETBUFFER_s ( ); + NETBUFFER_s ( const NETBUFFER_s &Buffer ); + + void Init( unsigned int ulLength, BUFFERTYPE_e BufferType ); + void Free(); + void Clear(); + int CalcSize() const; + int WriteTo( BYTESTREAM_s &ByteStream ) const; +}; + //========================================================================== // // IDList From 540d074e549bf3bfca9d45e23927fe0fa64bf4d4 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sun, 22 Jul 2018 16:21:50 +0200 Subject: [PATCH 21/46] added Zandronum's FName::IsPredefined() --- src/name.cpp | 11 +++++++++++ src/name.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/name.cpp b/src/name.cpp index ecedcf0f31..537eebccf1 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -286,3 +286,14 @@ FName::NameManager::~NameManager() NumNames = MaxNames = 0; memset (Buckets, -1, sizeof(Buckets)); } + +//========================================================================== +// +// [TP] FName :: IsPredefined +// +//========================================================================== + +bool FName::IsPredefined() const +{ + return static_cast( Index ) < countof( PredefinedNames ); +} diff --git a/src/name.h b/src/name.h index 521a8e697d..301cbce78f 100644 --- a/src/name.h +++ b/src/name.h @@ -86,6 +86,9 @@ public: bool operator > (ENamedName index) const { return Index > index; } bool operator >= (ENamedName index) const { return Index >= index; } + // [TP] + bool IsPredefined() const; + protected: int Index; From 953ae5aa76025f9ce07db63a118da8a117522571 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sun, 22 Jul 2018 16:23:03 +0200 Subject: [PATCH 22/46] added part of Zandronum's NetCommand and a bunch of functions necessary for this --- src/d_netsync.cpp | 250 ++++++++++++++++++++++++++++++++++++++++++++++ src/d_netsync.h | 34 +++++++ 2 files changed, 284 insertions(+) diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp index be1525ab31..fc9cdcaf97 100644 --- a/src/d_netsync.cpp +++ b/src/d_netsync.cpp @@ -76,6 +76,42 @@ void NETWORK_WriteByte( BYTESTREAM_s *pByteStream, int Byte ) NETWORK_AdvanceByteStreamPointer ( pByteStream, 1, true ); } +//***************************************************************************** +// +void NETWORK_WriteShort( BYTESTREAM_s *pByteStream, int Short ) +{ + if (( pByteStream->pbStream + 2 ) > pByteStream->pbStreamEnd ) + { + Printf( "NETWORK_WriteShort: Overflow!\n" ); + return; + } + + pByteStream->pbStream[0] = Short & 0xff; + pByteStream->pbStream[1] = Short >> 8; + + // Advance the pointer. + NETWORK_AdvanceByteStreamPointer ( pByteStream, 2, true ); +} + +//***************************************************************************** +// +void NETWORK_WriteLong( BYTESTREAM_s *pByteStream, int Long ) +{ + if (( pByteStream->pbStream + 4 ) > pByteStream->pbStreamEnd ) + { + Printf( "NETWORK_WriteLong: Overflow!\n" ); + return; + } + + pByteStream->pbStream[0] = Long & 0xff; + pByteStream->pbStream[1] = ( Long >> 8 ) & 0xff; + pByteStream->pbStream[2] = ( Long >> 16 ) & 0xff; + pByteStream->pbStream[3] = ( Long >> 24 ); + + // Advance the pointer. + NETWORK_AdvanceByteStreamPointer ( pByteStream, 4, true ); +} + //***************************************************************************** // void NETWORK_WriteBuffer( BYTESTREAM_s *pByteStream, const void *pvBuffer, int nLength ) @@ -92,6 +128,63 @@ void NETWORK_WriteBuffer( BYTESTREAM_s *pByteStream, const void *pvBuffer, int n NETWORK_AdvanceByteStreamPointer ( pByteStream, nLength, true ); } +//***************************************************************************** +// +void NETWORK_WriteBit( BYTESTREAM_s *byteStream, bool bit ) +{ + // Add a bit to this byte + byteStream->EnsureBitSpace( 1, true ); + if ( bit ) + *byteStream->bitBuffer |= 1 << byteStream->bitShift; + ++byteStream->bitShift; +} + +//***************************************************************************** +// +void NETWORK_WriteVariable( BYTESTREAM_s *byteStream, int value ) +{ + int length; + + // Determine how long we need to send this value + if ( value == 0 ) + length = 0; // 0 - don't bother sending it at all + else if (( value <= 0xFF ) && ( value >= 0 )) + length = 1; // Can be sent as a byte + else if (( value <= 0x7FFF ) && ( value >= -0x8000 )) + length = 2; // Can be sent as a short + else + length = 3; // Must be sent as a long + + // Write this length as two bits + NETWORK_WriteBit( byteStream, !!( length & 1 ) ); + NETWORK_WriteBit( byteStream, !!( length & 2 ) ); + + // Depending on the required length, write the value. + switch ( length ) + { + case 1: NETWORK_WriteByte( byteStream, value ); break; + case 2: NETWORK_WriteShort( byteStream, value ); break; + case 3: NETWORK_WriteLong( byteStream, value ); break; + } +} + +//***************************************************************************** +// +void NETWORK_WriteShortByte( BYTESTREAM_s *byteStream, int value, int bits ) +{ + if (( bits < 1 ) || ( bits > 8 )) + { + Printf( "NETWORK_WriteShortByte: bits must be within range [1..8], got %d.\n", bits ); + return; + } + + byteStream->EnsureBitSpace( bits, true ); + value &= (( 1 << bits ) - 1 ); // Form a mask from the bits and trim our value using it. + value <<= byteStream->bitShift; // Shift the value to its proper position. + *byteStream->bitBuffer |= value; // Add it to the byte. + byteStream->bitShift += bits; // Bump the shift value accordingly. +} + //***************************************************************************** // void NetSyncData::AssignNetID ( AActor *pActor ) @@ -235,6 +328,163 @@ int NETBUFFER_s::WriteTo( BYTESTREAM_s &ByteStream ) const return bufferSize; } +//***************************************************************************** +// +NetCommand::NetCommand ( const NetPacketType Header ) : + _unreliable( false ) +{ + _buffer.Init( MAX_UDP_PACKET, BUFFERTYPE_WRITE ); + _buffer.Clear(); + addByte( static_cast(Header) ); +} + +//***************************************************************************** +// +NetCommand::~NetCommand ( ) +{ + _buffer.Free(); +} + +//***************************************************************************** +// +void NetCommand::addInteger( const int IntValue, const int Size ) +{ + if ( ( _buffer.ByteStream.pbStream + Size ) > _buffer.ByteStream.pbStreamEnd ) + { + Printf( "NetCommand::AddInteger: Overflow! Header: %d\n", _buffer.pbData[0] ); + return; + } + + for ( int i = 0; i < Size; ++i ) + _buffer.ByteStream.pbStream[i] = ( IntValue >> ( 8*i ) ) & 0xff; + + _buffer.ByteStream.pbStream += Size; + _buffer.ulCurrentSize = _buffer.CalcSize(); +} + +//***************************************************************************** +// +void NetCommand::addByte ( const int ByteValue ) +{ + addInteger( static_cast ( ByteValue ), sizeof( uint8_t ) ); +} + +//***************************************************************************** +// +void NetCommand::addShort ( const int ShortValue ) +{ + addInteger( static_cast ( ShortValue ), sizeof( int16_t ) ); +} + +//***************************************************************************** +// +void NetCommand::addLong ( const int32_t LongValue ) +{ + addInteger( LongValue, sizeof( int32_t ) ); +} + +//***************************************************************************** +// +void NetCommand::addFloat ( const float FloatValue ) +{ + union + { + float f; + int32_t l; + } dat; + dat.f = FloatValue; + addInteger ( dat.l, sizeof( int32_t ) ); +} + +//***************************************************************************** +// +void NetCommand::addBit( const bool value ) +{ + NETWORK_WriteBit( &_buffer.ByteStream, value ); + _buffer.ulCurrentSize = _buffer.CalcSize(); +} + +//***************************************************************************** +// +void NetCommand::addVariable( const int value ) +{ + NETWORK_WriteVariable( &_buffer.ByteStream, value ); + _buffer.ulCurrentSize = _buffer.CalcSize(); +} + +//***************************************************************************** +// [TP] +// +void NetCommand::addShortByte ( int value, int bits ) +{ + NETWORK_WriteShortByte( &_buffer.ByteStream, value, bits ); + _buffer.ulCurrentSize = _buffer.CalcSize(); +} + +//***************************************************************************** +// +void NetCommand::addString ( const char *pszString ) +{ + const int len = ( pszString != NULL ) ? strlen( pszString ) : 0; + + if ( len > MAX_NETWORK_STRING ) + { + Printf( "NETWORK_WriteString: String exceeds %d characters! Header: %d\n", MAX_NETWORK_STRING, _buffer.pbData[0] ); + return; + } + + for ( int i = 0; i < len; ++i ) + addByte( pszString[i] ); + addByte( 0 ); +} + +//***************************************************************************** +// +void NetCommand::addName ( FName name ) +{ + if ( name.IsPredefined() ) + { + addShort( name ); + } + else + { + addShort( -1 ); + addString( name ); + } +} + +//***************************************************************************** +// +void NetCommand::writeCommandToStream ( BYTESTREAM_s &ByteStream ) const +{ + // [BB] This also handles the traffic counting (NETWORK_StartTrafficMeasurement/NETWORK_StopTrafficMeasurement). + _buffer.WriteTo ( ByteStream ); +} + +//***************************************************************************** +// [TP] +// +bool NetCommand::isUnreliable() const +{ + return _unreliable; +} + +//***************************************************************************** +// [TP] +// +void NetCommand::setUnreliable ( bool a ) +{ + _unreliable = a; +} + +//***************************************************************************** +// [TP] Returns the size of this net command. +// +int NetCommand::calcSize() const +{ + return _buffer.CalcSize(); +} + //***************************************************************************** // template diff --git a/src/d_netsync.h b/src/d_netsync.h index 172d14ab03..8609dcbdeb 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -3,6 +3,13 @@ #include "vectors.h" #include "r_data/renderstyle.h" +#include "d_netserver.h" + +// Maximum size of the packets sent out by the server. +#define MAX_UDP_PACKET 8192 + +// This is the longest possible string we can pass over the network. +#define MAX_NETWORK_STRING 2048 struct NetSyncData { DVector3 Pos; @@ -90,6 +97,33 @@ struct NETBUFFER_s int WriteTo( BYTESTREAM_s &ByteStream ) const; }; +/** + * \author Benjamin Berkels + */ +class NetCommand { + NETBUFFER_s _buffer; + bool _unreliable; + +public: + NetCommand ( const NetPacketType Header ); + ~NetCommand ( ); + + void addInteger( const int IntValue, const int Size ); + void addByte ( const int ByteValue ); + void addShort ( const int ShortValue ); + void addLong ( const int32_t LongValue ); + void addFloat ( const float FloatValue ); + void addString ( const char *pszString ); + void addName ( FName name ); + void addBit ( const bool value ); + void addVariable ( const int value ); + void addShortByte ( int value, int bits ); + void writeCommandToStream ( BYTESTREAM_s &ByteStream ) const; + bool isUnreliable() const; + void setUnreliable ( bool a ); + int calcSize() const; +}; + //========================================================================== // // IDList From 70141f7591fbb8b5eda3fcea93b5a5c6ab36c3ed Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sun, 22 Jul 2018 21:53:32 +0200 Subject: [PATCH 23/46] the server's NetPacketType::ConnectResponse command is now implemented using NetCommand --- src/d_netserver.cpp | 10 ++++++---- src/d_netsync.cpp | 9 +++++++++ src/d_netsync.h | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/d_netserver.cpp b/src/d_netserver.cpp index 96e02ad437..a3f3962a2c 100644 --- a/src/d_netserver.cpp +++ b/src/d_netserver.cpp @@ -248,10 +248,12 @@ void NetServer::OnConnectRequest(NetNode &node, const NetPacket &packet) NetPacket response; response.node = packet.node; - response[0] = (uint8_t)NetPacketType::ConnectResponse; - response[1] = 1; // Protocol version - response[2] = node.Player; - response.size = 3; + + NetCommand cmd ( NetPacketType::ConnectResponse ); + cmd.addByte ( 1 ); // Protocol version + cmd.addByte ( node.Player ); + cmd.writeCommandToPacket ( response ); + mComm->PacketSend(response); node.Status = NodeStatus::InGame; diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp index fc9cdcaf97..755d20f111 100644 --- a/src/d_netsync.cpp +++ b/src/d_netsync.cpp @@ -461,6 +461,15 @@ void NetCommand::writeCommandToStream ( BYTESTREAM_s &ByteStream ) const _buffer.WriteTo ( ByteStream ); } +//***************************************************************************** +// +void NetCommand::writeCommandToPacket ( NetPacket &response ) const +{ + const int size = _buffer.CalcSize(); + memcpy( response.data + response.size, _buffer.pbData, _buffer.CalcSize() ); + response.size += _buffer.CalcSize(); +} + //***************************************************************************** // [TP] // diff --git a/src/d_netsync.h b/src/d_netsync.h index 8609dcbdeb..e6432db0a8 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -119,6 +119,7 @@ public: void addVariable ( const int value ); void addShortByte ( int value, int bits ); void writeCommandToStream ( BYTESTREAM_s &ByteStream ) const; + void writeCommandToPacket ( NetPacket &response ) const; bool isUnreliable() const; void setUnreliable ( bool a ); int calcSize() const; From c439f2586b2dd63d1d11319fa9e3158510860cc4 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sat, 28 Jul 2018 16:55:00 +0200 Subject: [PATCH 24/46] updated BYTESTREAM_s with the recent changes from Zandronum --- src/d_netsync.cpp | 299 ++++++++++++++++++++++++++++++++++++++-------- src/d_netsync.h | 24 ++++ 2 files changed, 271 insertions(+), 52 deletions(-) diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp index 755d20f111..793c23f5f7 100644 --- a/src/d_netsync.cpp +++ b/src/d_netsync.cpp @@ -36,112 +36,307 @@ IDList g_NetIDList; //***************************************************************************** // -void NETWORK_AdvanceByteStreamPointer( BYTESTREAM_s *pByteStream, const int NumBytes, const bool OutboundTraffic ) +void BYTESTREAM_s::AdvancePointer( const int NumBytes, const bool OutboundTraffic ) { - pByteStream->pbStream += NumBytes; + this->pbStream += NumBytes; - // [BB] if ( g_MeasuringOutboundTraffic && OutboundTraffic ) g_OutboundBytesMeasured += NumBytes; } //***************************************************************************** // -int NETWORK_ReadByte( BYTESTREAM_s *pByteStream ) +int BYTESTREAM_s::ReadByte() { int Byte = -1; - if (( pByteStream->pbStream + 1 ) <= pByteStream->pbStreamEnd ) - Byte = *pByteStream->pbStream; + if (( this->pbStream + 1 ) <= this->pbStreamEnd ) + Byte = *this->pbStream; // Advance the pointer. - pByteStream->pbStream += 1; + this->pbStream += 1; return ( Byte ); } //***************************************************************************** // -void NETWORK_WriteByte( BYTESTREAM_s *pByteStream, int Byte ) +int BYTESTREAM_s::ReadShort() { - if (( pByteStream->pbStream + 1 ) > pByteStream->pbStreamEnd ) - { - Printf( "NETWORK_WriteByte: Overflow!\n" ); - return; - } + int Short = -1; - *pByteStream->pbStream = Byte; + if (( this->pbStream + 2 ) <= this->pbStreamEnd ) + Short = (short)(( this->pbStream[0] ) + ( this->pbStream[1] << 8 )); // Advance the pointer. - NETWORK_AdvanceByteStreamPointer ( pByteStream, 1, true ); + this->pbStream += 2; + + return ( Short ); } //***************************************************************************** // -void NETWORK_WriteShort( BYTESTREAM_s *pByteStream, int Short ) +int BYTESTREAM_s::ReadLong() { - if (( pByteStream->pbStream + 2 ) > pByteStream->pbStreamEnd ) + int Long = -1; + + if (( this->pbStream + 4 ) <= this->pbStreamEnd ) + { + Long = (( this->pbStream[0] ) + + ( this->pbStream[1] << 8 ) + + ( this->pbStream[2] << 16 ) + + ( this->pbStream[3] << 24 )); + } + + // Advance the pointer. + this->pbStream += 4; + + return ( Long ); +} + +//***************************************************************************** +// +float BYTESTREAM_s::ReadFloat() +{ + union + { + float f; + int i; + } dat; + + dat.i = this->ReadLong(); + return ( dat.f ); +} + +//***************************************************************************** +// +const char *BYTESTREAM_s::ReadString() +{ + int c; + static char s_szString[MAX_NETWORK_STRING]; + + // Read in characters until we've reached the end of the string. + unsigned int ulIdx = 0; + do + { + c = this->ReadByte(); + if ( c <= 0 ) + break; + + // Place this character into our string. + // [BB] Even if we don't have enough space in s_szString, we have to fully + // parse the received string. Otherwise we can't continue parsing the packet. + if ( ulIdx < MAX_NETWORK_STRING - 1 ) + s_szString[ulIdx] = static_cast ( c ); + + ++ulIdx; + + } while ( true ); + + // [BB] We may have read more chars than we can store. + const int endIndex = ( ulIdx < MAX_NETWORK_STRING ) ? ulIdx : MAX_NETWORK_STRING - 1; + s_szString[endIndex] = '\0'; + return ( s_szString ); +} + +//***************************************************************************** +// +bool BYTESTREAM_s::ReadBit() +{ + this->EnsureBitSpace( 1, false ); + + // Use a bit shift to extract a bit from our current byte + bool result = !!( *this->bitBuffer & ( 1 << this->bitShift )); + this->bitShift++; + return result; +} + +//***************************************************************************** +// +int BYTESTREAM_s::ReadVariable() +{ + // Read two bits to form an integer 0...3 + int length = this->ReadBit(); + length |= this->ReadBit() << 1; + + // Use this length to read in an integer of variable length. + switch ( length ) + { + default: + case 0: return 0; + case 1: return this->ReadByte(); + case 2: return this->ReadShort(); + case 3: return this->ReadLong(); + } +} + +//***************************************************************************** +// +int BYTESTREAM_s::ReadShortByte ( int bits ) +{ + if ( bits >= 0 && bits <= 8 ) + { + this->EnsureBitSpace( bits, false ); + int mask = ( 1 << bits ) - 1; // Create a mask to cover the bits we want. + mask <<= this->bitShift; // Shift the mask so that it covers the correct bits. + int result = *this->bitBuffer & mask; // Apply the shifted mask on our byte to remove unwanted bits. + result >>= this->bitShift; // Shift the result back to start from 0. + this->bitShift += bits; // Increase shift to mark these bits as used. + return result; + } + else + { + return 0; + } +} + +//***************************************************************************** +// +void BYTESTREAM_s::ReadBuffer( void *buffer, size_t length ) +{ + if (( this->pbStream + length ) > this->pbStreamEnd ) + { + Printf( "BYTESTREAM_s::ReadBuffer: Overflow!\n" ); + } + else + { + memcpy( buffer, this->pbStream, length ); + this->pbStream += length; + } +} + +//***************************************************************************** +// +void BYTESTREAM_s::WriteByte( int Byte ) +{ + if (( this->pbStream + 1 ) > this->pbStreamEnd ) + { + Printf( "BYTESTREAM_s::WriteByte: Overflow!\n" ); + return; + } + + *this->pbStream = Byte; + + // Advance the pointer. + this->AdvancePointer ( 1, true ); +} + +//***************************************************************************** +// +void BYTESTREAM_s::WriteShort( int Short ) +{ + if (( this->pbStream + 2 ) > this->pbStreamEnd ) { Printf( "NETWORK_WriteShort: Overflow!\n" ); return; } - pByteStream->pbStream[0] = Short & 0xff; - pByteStream->pbStream[1] = Short >> 8; + this->pbStream[0] = Short & 0xff; + this->pbStream[1] = Short >> 8; // Advance the pointer. - NETWORK_AdvanceByteStreamPointer ( pByteStream, 2, true ); + this->AdvancePointer ( 2, true ); } //***************************************************************************** // -void NETWORK_WriteLong( BYTESTREAM_s *pByteStream, int Long ) +void BYTESTREAM_s::WriteLong( int Long ) { - if (( pByteStream->pbStream + 4 ) > pByteStream->pbStreamEnd ) + if (( this->pbStream + 4 ) > this->pbStreamEnd ) { Printf( "NETWORK_WriteLong: Overflow!\n" ); return; } - pByteStream->pbStream[0] = Long & 0xff; - pByteStream->pbStream[1] = ( Long >> 8 ) & 0xff; - pByteStream->pbStream[2] = ( Long >> 16 ) & 0xff; - pByteStream->pbStream[3] = ( Long >> 24 ); + this->pbStream[0] = Long & 0xff; + this->pbStream[1] = ( Long >> 8 ) & 0xff; + this->pbStream[2] = ( Long >> 16 ) & 0xff; + this->pbStream[3] = ( Long >> 24 ); // Advance the pointer. - NETWORK_AdvanceByteStreamPointer ( pByteStream, 4, true ); + this->AdvancePointer ( 4, true ); } //***************************************************************************** // -void NETWORK_WriteBuffer( BYTESTREAM_s *pByteStream, const void *pvBuffer, int nLength ) +void BYTESTREAM_s::WriteFloat( float Float ) { - if (( pByteStream->pbStream + nLength ) > pByteStream->pbStreamEnd ) + union + { + float f; + int l; + } dat; + + dat.f = Float; + + this->WriteLong( dat.l ); +} + +//***************************************************************************** +// +void BYTESTREAM_s::WriteString( const char *pszString ) +{ + if (( pszString ) && ( strlen( pszString ) > MAX_NETWORK_STRING )) + { + Printf( "BYTESTREAM_s::WriteString: String exceeds %d characters!\n", MAX_NETWORK_STRING ); + return; + } + +#ifdef WIN32 + if ( pszString == NULL ) + this->WriteBuffer( "", 1 ); + else + this->WriteBuffer( pszString, (int)( strlen( pszString )) + 1 ); +#else + if ( pszString == NULL ) + this->WriteByte( 0 ); + else + { + this->WriteBuffer( pszString, strlen( pszString )); + this->WriteByte( 0 ); + } +#endif +} + +//***************************************************************************** +// +void BYTESTREAM_s::WriteBuffer( const void *pvBuffer, int nLength ) +{ + if (( this->pbStream + nLength ) > this->pbStreamEnd ) { Printf( "NETWORK_WriteLBuffer: Overflow!\n" ); return; } - memcpy( pByteStream->pbStream, pvBuffer, nLength ); + memcpy( this->pbStream, pvBuffer, nLength ); // Advance the pointer. - NETWORK_AdvanceByteStreamPointer ( pByteStream, nLength, true ); + this->AdvancePointer ( nLength, true ); } //***************************************************************************** // -void NETWORK_WriteBit( BYTESTREAM_s *byteStream, bool bit ) +void BYTESTREAM_s::WriteHeader( int Byte ) +{ + this->WriteByte( Byte ); + this->bitBuffer = NULL; + this->bitShift = -1; +} + +//***************************************************************************** +// +void BYTESTREAM_s::WriteBit( bool bit ) { // Add a bit to this byte - byteStream->EnsureBitSpace( 1, true ); + this->EnsureBitSpace( 1, true ); if ( bit ) - *byteStream->bitBuffer |= 1 << byteStream->bitShift; - ++byteStream->bitShift; + *this->bitBuffer |= 1 << this->bitShift; + ++this->bitShift; } //***************************************************************************** // -void NETWORK_WriteVariable( BYTESTREAM_s *byteStream, int value ) +void BYTESTREAM_s::WriteVariable( int value ) { int length; @@ -156,21 +351,21 @@ void NETWORK_WriteVariable( BYTESTREAM_s *byteStream, int value ) length = 3; // Must be sent as a long // Write this length as two bits - NETWORK_WriteBit( byteStream, !!( length & 1 ) ); - NETWORK_WriteBit( byteStream, !!( length & 2 ) ); + this->WriteBit( !!( length & 1 ) ); + this->WriteBit( !!( length & 2 ) ); // Depending on the required length, write the value. switch ( length ) { - case 1: NETWORK_WriteByte( byteStream, value ); break; - case 2: NETWORK_WriteShort( byteStream, value ); break; - case 3: NETWORK_WriteLong( byteStream, value ); break; + case 1: this->WriteByte( value ); break; + case 2: this->WriteShort( value ); break; + case 3: this->WriteLong( value ); break; } } //***************************************************************************** // -void NETWORK_WriteShortByte( BYTESTREAM_s *byteStream, int value, int bits ) +void BYTESTREAM_s::WriteShortByte( int value, int bits ) { if (( bits < 1 ) || ( bits > 8 )) { @@ -178,11 +373,11 @@ void NETWORK_WriteShortByte( BYTESTREAM_s *byteStream, int value, int bits ) return; } - byteStream->EnsureBitSpace( bits, true ); + this->EnsureBitSpace( bits, true ); value &= (( 1 << bits ) - 1 ); // Form a mask from the bits and trim our value using it. - value <<= byteStream->bitShift; // Shift the value to its proper position. - *byteStream->bitBuffer |= value; // Add it to the byte. - byteStream->bitShift += bits; // Bump the shift value accordingly. + value <<= this->bitShift; // Shift the value to its proper position. + *this->bitBuffer |= value; // Add it to the byte. + this->bitShift += bits; // Bump the shift value accordingly. } //***************************************************************************** @@ -220,13 +415,13 @@ void BYTESTREAM_s::EnsureBitSpace( int bits, bool writing ) if ( writing ) { // Not enough bits left in our current byte, we need a new one. - NETWORK_WriteByte( this, 0 ); + WriteByte( 0 ); bitBuffer = pbStream - 1; } else { // No room for the value in this byte, so we need a new one. - if ( NETWORK_ReadByte( this ) != -1 ) + if ( this->ReadByte() != -1 ) { bitBuffer = pbStream - 1; } @@ -324,7 +519,7 @@ int NETBUFFER_s::WriteTo( BYTESTREAM_s &ByteStream ) const { int bufferSize = CalcSize(); if ( bufferSize > 0 ) - NETWORK_WriteBuffer( &ByteStream, this->pbData, bufferSize ); + ByteStream.WriteBuffer( this->pbData, bufferSize ); return bufferSize; } @@ -400,7 +595,7 @@ void NetCommand::addFloat ( const float FloatValue ) // void NetCommand::addBit( const bool value ) { - NETWORK_WriteBit( &_buffer.ByteStream, value ); + _buffer.ByteStream.WriteBit( value ); _buffer.ulCurrentSize = _buffer.CalcSize(); } @@ -408,7 +603,7 @@ void NetCommand::addBit( const bool value ) // void NetCommand::addVariable( const int value ) { - NETWORK_WriteVariable( &_buffer.ByteStream, value ); + _buffer.ByteStream.WriteVariable( value ); _buffer.ulCurrentSize = _buffer.CalcSize(); } @@ -417,7 +612,7 @@ void NetCommand::addVariable( const int value ) // void NetCommand::addShortByte ( int value, int bits ) { - NETWORK_WriteShortByte( &_buffer.ByteStream, value, bits ); + _buffer.ByteStream.WriteShortByte( value, bits ); _buffer.ulCurrentSize = _buffer.CalcSize(); } diff --git a/src/d_netsync.h b/src/d_netsync.h index e6432db0a8..7dd531a1f9 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -49,6 +49,28 @@ struct BYTESTREAM_s BYTESTREAM_s(); void EnsureBitSpace( int bits, bool writing ); + int ReadByte(); + int ReadShort(); + int ReadLong(); + float ReadFloat(); + const char* ReadString(); + bool ReadBit(); + int ReadVariable(); + int ReadShortByte( int bits ); + void ReadBuffer( void* buffer, size_t length ); + + void WriteByte( int Byte ); + void WriteShort( int Short ); + void WriteLong( int Long ); + void WriteFloat( float Float ); + void WriteString( const char *pszString ); + void WriteBit( bool bit ); + void WriteVariable( int value ); + void WriteShortByte( int value, int bits ); + void WriteBuffer( const void *pvBuffer, int nLength ); + + void WriteHeader( int Byte ); + // Pointer to our stream of data. uint8_t *pbStream; @@ -58,6 +80,8 @@ struct BYTESTREAM_s uint8_t *bitBuffer; int bitShift; + + void AdvancePointer( const int NumBytes, const bool OutboundTraffic ); }; //***************************************************************************** From 37fec050f15186fc32acdb3eec70a8aa24a6517d Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sat, 28 Jul 2018 17:15:44 +0200 Subject: [PATCH 25/46] NetPacket now exposes its data as BYTESTREAM_s --- src/d_netserver.h | 8 -------- src/d_netsync.cpp | 1 + src/d_netsync.h | 13 ++++++++++++- src/i_net.h | 12 +++++++++++- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/d_netserver.h b/src/d_netserver.h index 29acca84b1..c7e191390a 100644 --- a/src/d_netserver.h +++ b/src/d_netserver.h @@ -23,14 +23,6 @@ #include "d_net.h" -enum class NetPacketType -{ - ConnectRequest, - ConnectResponse, - Disconnect, - Tic -}; - enum class NodeStatus { Closed, diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp index 793c23f5f7..23369d3f50 100644 --- a/src/d_netsync.cpp +++ b/src/d_netsync.cpp @@ -21,6 +21,7 @@ #include "c_dispatch.h" #include "actor.h" #include "doomstat.h" +#include "i_net.h" extern bool netserver, netclient; diff --git a/src/d_netsync.h b/src/d_netsync.h index 7dd531a1f9..9c7a486a49 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -3,7 +3,6 @@ #include "vectors.h" #include "r_data/renderstyle.h" -#include "d_netserver.h" // Maximum size of the packets sent out by the server. #define MAX_UDP_PACKET 8192 @@ -11,6 +10,16 @@ // This is the longest possible string we can pass over the network. #define MAX_NETWORK_STRING 2048 +enum class NetPacketType +{ + ConnectRequest, + ConnectResponse, + Disconnect, + Tic +}; + +class AActor; + struct NetSyncData { DVector3 Pos; DVector3 Vel; @@ -121,6 +130,8 @@ struct NETBUFFER_s int WriteTo( BYTESTREAM_s &ByteStream ) const; }; +struct NetPacket; + /** * \author Benjamin Berkels */ diff --git a/src/i_net.h b/src/i_net.h index ccea62bacb..090a250f44 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -2,13 +2,21 @@ #pragma once #include +#include "d_netsync.h" #define MAX_MSGLEN 14000 #define DOOMPORT 5029 struct NetPacket { - NetPacket() { memset(data, 0, sizeof(data)); } + NetPacket() + { + memset(data, 0, sizeof(data)); + stream.pbStream = data; + stream.bitBuffer = NULL; + stream.bitShift = -1; + stream.pbStreamEnd = stream.pbStream + sizeof(data); + } // packet data to be sent uint8_t data[MAX_MSGLEN]; @@ -21,6 +29,8 @@ struct NetPacket uint8_t &operator[](int i) { return data[i]; } const uint8_t &operator[](int i) const { return data[i]; } + + BYTESTREAM_s stream; }; // Network packet data. From 43891c31036992d880b7d926de7a9f24e58579e7 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sat, 28 Jul 2018 17:37:46 +0200 Subject: [PATCH 26/46] added new member function addBuffer to NetCommand --- src/d_netsync.cpp | 8 ++++++++ src/d_netsync.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp index 23369d3f50..765b795631 100644 --- a/src/d_netsync.cpp +++ b/src/d_netsync.cpp @@ -649,6 +649,14 @@ void NetCommand::addName ( FName name ) } } +//***************************************************************************** +// +void NetCommand::addBuffer ( const void *pvBuffer, int nLength ) +{ + _buffer.ByteStream.WriteBuffer( pvBuffer, nLength ); + _buffer.ulCurrentSize = _buffer.CalcSize(); +} + //***************************************************************************** // void NetCommand::writeCommandToStream ( BYTESTREAM_s &ByteStream ) const diff --git a/src/d_netsync.h b/src/d_netsync.h index 9c7a486a49..5121d52fcf 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -153,6 +153,7 @@ public: void addBit ( const bool value ); void addVariable ( const int value ); void addShortByte ( int value, int bits ); + void addBuffer ( const void *pvBuffer, int nLength ); void writeCommandToStream ( BYTESTREAM_s &ByteStream ) const; void writeCommandToPacket ( NetPacket &response ) const; bool isUnreliable() const; From a07f8feb75bb3b36f494d08b1fa213db91cefe50 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sat, 28 Jul 2018 18:05:41 +0200 Subject: [PATCH 27/46] Client and server now use NetCommand to fill outgoing NetPackets and use the byte stream to parse the received NetPackets. This is a preparation to put multiple commands into one packet. --- src/d_netclient.cpp | 41 +++++++++++++++++++++++------------------ src/d_netclient.h | 4 ++-- src/d_netserver.cpp | 44 ++++++++++++++++++++++++-------------------- src/d_netserver.h | 2 +- 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp index dc1817143e..76ce527f80 100644 --- a/src/d_netclient.cpp +++ b/src/d_netclient.cpp @@ -76,8 +76,10 @@ NetClient::NetClient(FString server) NetPacket packet; packet.node = mServerNode; - packet.size = 1; - packet[0] = (uint8_t)NetPacketType::ConnectRequest; + + NetCommand cmd ( NetPacketType::ConnectRequest ); + cmd.writeCommandToPacket ( packet ); + mComm->PacketSend(packet); } @@ -101,7 +103,7 @@ void NetClient::Update() } else { - NetPacketType type = (NetPacketType)packet[0]; + NetPacketType type = (NetPacketType)packet.stream.ReadByte(); switch (type) { default: OnClose(packet); break; @@ -137,10 +139,12 @@ 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)); + + NetCommand cmd ( NetPacketType::Tic ); + cmd.addByte ( 0 ); // target gametic + cmd.addBuffer ( &mCurrentInput[consoleplayer].ucmd, sizeof(usercmd_t) ); + cmd.writeCommandToPacket ( packet ); + mComm->PacketSend(packet); mCurrentCommands = mSendCommands; @@ -220,17 +224,18 @@ void NetClient::OnClose(const NetPacket &packet) } } -void NetClient::OnConnectResponse(const NetPacket &packet) +void NetClient::OnConnectResponse(NetPacket &packet) { if (packet.size != 3) return; - int version = packet[1]; // Protocol version + int version = packet.stream.ReadByte(); // Protocol version if (version == 1) { - if (packet[2] != 255) // Join accepted + int playernum = packet.stream.ReadByte(); + if (playernum != 255) // Join accepted { - mPlayer = packet[2]; + mPlayer = playernum; mStatus = NodeStatus::InGame; G_InitClientNetGame(mPlayer, "e1m1"); @@ -262,17 +267,17 @@ void NetClient::OnDisconnect(const NetPacket &packet) mStatus = NodeStatus::Closed; } -void NetClient::OnTic(const NetPacket &packet) +void NetClient::OnTic(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]; + int tic = packet.stream.ReadByte(); + float x = packet.stream.ReadFloat(); + float y = packet.stream.ReadFloat(); + float z = packet.stream.ReadFloat(); + float yaw = packet.stream.ReadFloat(); + float pitch = packet.stream.ReadFloat(); if (playeringame[consoleplayer] && players[consoleplayer].mo) { diff --git a/src/d_netclient.h b/src/d_netclient.h index e7ef5668ac..7b5163f636 100644 --- a/src/d_netclient.h +++ b/src/d_netclient.h @@ -51,9 +51,9 @@ public: private: void OnClose(const NetPacket &packet); - void OnConnectResponse(const NetPacket &packet); + void OnConnectResponse(NetPacket &packet); void OnDisconnect(const NetPacket &packet); - void OnTic(const NetPacket &packet); + void OnTic(NetPacket &packet); std::unique_ptr mComm; int mServerNode = -1; diff --git a/src/d_netserver.cpp b/src/d_netserver.cpp index a3f3962a2c..5a012cd18b 100644 --- a/src/d_netserver.cpp +++ b/src/d_netserver.cpp @@ -91,7 +91,7 @@ void NetServer::Update() } else { - NetPacketType type = (NetPacketType)packet[0]; + NetPacketType type = (NetPacketType)packet.stream.ReadByte(); switch (type) { default: OnClose(node, packet); break; @@ -117,27 +117,28 @@ void NetServer::EndCurrentTic() { NetPacket packet; packet.node = i; - packet.size = 2 + sizeof(float) * 5; - packet[0] = (uint8_t)NetPacketType::Tic; - packet[1] = gametic; + + NetCommand cmd ( NetPacketType::Tic); + cmd.addByte ( 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; + cmd.addFloat ( static_cast ( players[player].mo->X() ) ); + cmd.addFloat ( static_cast ( players[player].mo->Y() ) ); + cmd.addFloat ( static_cast ( players[player].mo->Z() ) ); + cmd.addFloat ( static_cast ( players[player].mo->Angles.Yaw.Degrees ) ); + cmd.addFloat ( static_cast ( 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; + cmd.addFloat ( 0.0f ); + cmd.addFloat ( 0.0f ); + cmd.addFloat ( 0.0f ); + cmd.addFloat ( 0.0f ); + cmd.addFloat ( 0.0f ); } + cmd.writeCommandToPacket ( packet ); mComm->PacketSend(packet); } @@ -264,10 +265,12 @@ void NetServer::OnConnectRequest(NetNode &node, const NetPacket &packet) NetPacket response; response.node = packet.node; - response[0] = (uint8_t)NetPacketType::ConnectResponse; - response[1] = 1; // Protocol version - response[2] = 255; - response.size = 3; + + NetCommand cmd ( NetPacketType::ConnectResponse ); + cmd.addByte ( 1 ); // Protocol version + cmd.addByte ( 255 ); + cmd.writeCommandToPacket ( response ); + mComm->PacketSend(response); node.Status = NodeStatus::Closed; @@ -290,14 +293,15 @@ void NetServer::OnDisconnect(NetNode &node, const NetPacket &packet) mComm->Close(packet.node); } -void NetServer::OnTic(NetNode &node, const NetPacket &packet) +void NetServer::OnTic(NetNode &node, 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)); + /* gametic */ packet.stream.ReadByte(); + packet.stream.ReadBuffer ( &mCurrentInput[node.Player].ucmd, sizeof(usercmd_t)); } else { diff --git a/src/d_netserver.h b/src/d_netserver.h index c7e191390a..aa51cc6650 100644 --- a/src/d_netserver.h +++ b/src/d_netserver.h @@ -72,7 +72,7 @@ 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); + void OnTic(NetNode &node, NetPacket &packet); std::unique_ptr mComm; NetNode mNodes[MAXNETNODES]; From f3a509ac2d22a0366a7a442dc4a43c5a31aff5e4 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sun, 19 Aug 2018 17:01:55 +0200 Subject: [PATCH 28/46] changed the packet parsing so that one packet can contain more than one command --- src/d_netclient.cpp | 28 ++++++++++++++++------------ src/d_netserver.cpp | 25 ++++++++++++++++--------- src/d_netsync.cpp | 14 ++++++++++++++ src/d_netsync.h | 2 ++ src/i_net.cpp | 4 ++++ 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp index 76ce527f80..70f2f21b15 100644 --- a/src/d_netclient.cpp +++ b/src/d_netclient.cpp @@ -103,14 +103,24 @@ void NetClient::Update() } else { - NetPacketType type = (NetPacketType)packet.stream.ReadByte(); - switch (type) + if (packet.stream.ReadByte () != 0) { - default: OnClose(packet); break; - case NetPacketType::ConnectResponse: OnConnectResponse(packet); break; - case NetPacketType::Disconnect: OnDisconnect(packet); break; - case NetPacketType::Tic: OnTic(packet); break; + Printf ("Error parsing packet. Unexpected header.\n"); + break; } + + while ( packet.stream.IsAtEnd() == false ) + { + NetPacketType type = (NetPacketType)packet.stream.ReadByte(); + switch (type) + { + default: OnClose(packet); break; + case NetPacketType::ConnectResponse: OnConnectResponse(packet); break; + case NetPacketType::Disconnect: OnDisconnect(packet); break; + case NetPacketType::Tic: OnTic(packet); break; + } + } + break; } if (mStatus == NodeStatus::Closed) @@ -226,9 +236,6 @@ void NetClient::OnClose(const NetPacket &packet) void NetClient::OnConnectResponse(NetPacket &packet) { - if (packet.size != 3) - return; - int version = packet.stream.ReadByte(); // Protocol version if (version == 1) { @@ -269,9 +276,6 @@ void NetClient::OnDisconnect(const NetPacket &packet) void NetClient::OnTic(NetPacket &packet) { - if (packet.size != 2 + sizeof(float) * 5) - return; - int tic = packet.stream.ReadByte(); float x = packet.stream.ReadFloat(); float y = packet.stream.ReadFloat(); diff --git a/src/d_netserver.cpp b/src/d_netserver.cpp index 5a012cd18b..73873a9101 100644 --- a/src/d_netserver.cpp +++ b/src/d_netserver.cpp @@ -91,14 +91,24 @@ void NetServer::Update() } else { - NetPacketType type = (NetPacketType)packet.stream.ReadByte(); - switch (type) + if (packet.stream.ReadByte () != 0) { - 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; + Printf ("Error parsing packet. Unexpected header.\n"); + break; } + + while ( packet.stream.IsAtEnd() == false ) + { + NetPacketType type = (NetPacketType)packet.stream.ReadByte(); + 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; + } + } + break; } } } @@ -297,9 +307,6 @@ void NetServer::OnTic(NetNode &node, NetPacket &packet) { if (node.Status == NodeStatus::InGame) { - if (packet.size != 2 + sizeof(usercmd_t)) - return; - /* gametic */ packet.stream.ReadByte(); packet.stream.ReadBuffer ( &mCurrentInput[node.Player].ucmd, sizeof(usercmd_t)); } diff --git a/src/d_netsync.cpp b/src/d_netsync.cpp index 765b795631..15679f67a5 100644 --- a/src/d_netsync.cpp +++ b/src/d_netsync.cpp @@ -324,6 +324,13 @@ void BYTESTREAM_s::WriteHeader( int Byte ) this->bitShift = -1; } +//***************************************************************************** +// +bool BYTESTREAM_s::IsAtEnd() const +{ + return ( this->pbStream >= this->pbStreamEnd ); +} + //***************************************************************************** // void BYTESTREAM_s::WriteBit( bool bit ) @@ -669,6 +676,13 @@ void NetCommand::writeCommandToStream ( BYTESTREAM_s &ByteStream ) const // void NetCommand::writeCommandToPacket ( NetPacket &response ) const { + // The packet is empty, let it start with a header. + if ( response.size == 0 ) + { + response.stream.WriteByte ( 0 ); // Header + response.size = 1; + } + const int size = _buffer.CalcSize(); memcpy( response.data + response.size, _buffer.pbData, _buffer.CalcSize() ); response.size += _buffer.CalcSize(); diff --git a/src/d_netsync.h b/src/d_netsync.h index 5121d52fcf..88fe065dc6 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -80,6 +80,8 @@ struct BYTESTREAM_s void WriteHeader( int Byte ); + bool IsAtEnd() const; + // Pointer to our stream of data. uint8_t *pbStream; diff --git a/src/i_net.cpp b/src/i_net.cpp index c53bd740f2..9f182cf4d9 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -280,6 +280,7 @@ void DoomComImpl::PacketGet(NetPacket &packet) Close(i); packet.node = i; packet.size = 0; + packet.stream.pbStreamEnd = packet.stream.pbStream; return; } } @@ -302,6 +303,7 @@ void DoomComImpl::PacketGet(NetPacket &packet) Close(node); packet.node = node; packet.size = 0; + packet.stream.pbStreamEnd = packet.stream.pbStream; return; } else if (err != WSAEWOULDBLOCK) @@ -312,6 +314,7 @@ void DoomComImpl::PacketGet(NetPacket &packet) { packet.node = -1; packet.size = 0; + packet.stream.pbStreamEnd = packet.stream.pbStream; return; } } @@ -340,6 +343,7 @@ void DoomComImpl::PacketGet(NetPacket &packet) packet.node = node; packet.size = (short)size; + packet.stream.pbStreamEnd = packet.stream.pbStream + packet.size; return; } } From 9c2ff032d90c171be9ebbf9a235a2495352694c8 Mon Sep 17 00:00:00 2001 From: Benjamin Berkels Date: Sun, 19 Aug 2018 20:09:20 +0200 Subject: [PATCH 29/46] a first step towards spawning players on the other clients --- src/d_netclient.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++ src/d_netclient.h | 1 + src/d_netserver.cpp | 31 ++++++++++++++++++++++++++++++ src/d_netserver.h | 3 +++ src/d_netsync.h | 3 ++- 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/d_netclient.cpp b/src/d_netclient.cpp index 70f2f21b15..fd6387f0ab 100644 --- a/src/d_netclient.cpp +++ b/src/d_netclient.cpp @@ -66,6 +66,10 @@ #include "events.h" #include "i_time.h" +extern IDList g_NetIDList; + +CVAR( Int, cl_showspawnnames, 0, CVAR_ARCHIVE ) + NetClient::NetClient(FString server) { Printf("Connecting to %s..\n", server.GetChars()); @@ -87,6 +91,11 @@ void NetClient::Update() { while (true) { + // [BB] Don't check net packets while we are supposed to load a map. + // This way the commands from the full update will not be parsed before we loaded the map. + if ( ( gameaction == ga_newgame ) || ( gameaction == ga_newgame2 ) ) + return; + NetPacket packet; mComm->PacketGet(packet); if (packet.node == -1) @@ -118,6 +127,7 @@ void NetClient::Update() case NetPacketType::ConnectResponse: OnConnectResponse(packet); break; case NetPacketType::Disconnect: OnDisconnect(packet); break; case NetPacketType::Tic: OnTic(packet); break; + case NetPacketType::SpawnPlayer: OnSpawnPlayer(packet); break; } } break; @@ -290,3 +300,39 @@ void NetClient::OnTic(NetPacket &packet) players[consoleplayer].mo->Angles.Pitch = pitch; } } + +void NetClient::OnSpawnPlayer(NetPacket &packet) +{ + int player = packet.stream.ReadByte(); + const float x = packet.stream.ReadFloat(); + const float y = packet.stream.ReadFloat(); + const float z = packet.stream.ReadFloat(); + const int16_t netID = packet.stream.ReadShort(); + + AActor *oldNetActor = g_NetIDList.findPointerByID ( netID ); + + // If there's already an actor with this net ID, destroy it. + if ( oldNetActor != NULL ) + { + oldNetActor->Destroy( ); + g_NetIDList.freeID ( netID ); + } + + // This player is now in the game. + playeringame[player] = true; + player_t p = players[player]; + + if ( cl_showspawnnames ) + Printf ( "Spawning player %d at %f,%f,%f (id %d)\n", player, x, y, z, netID ); + + DVector3 spawn ( x, y, z ); + + p.mo = static_cast(Spawn (p.cls, spawn, NO_REPLACE)); + + if ( p.mo ) + { + // Set the network ID. + p.mo->syncdata.NetID = netID; + g_NetIDList.useID ( netID, p.mo ); + } +} diff --git a/src/d_netclient.h b/src/d_netclient.h index 7b5163f636..7d64a0ef7a 100644 --- a/src/d_netclient.h +++ b/src/d_netclient.h @@ -54,6 +54,7 @@ private: void OnConnectResponse(NetPacket &packet); void OnDisconnect(const NetPacket &packet); void OnTic(NetPacket &packet); + void OnSpawnPlayer(NetPacket &packet); std::unique_ptr mComm; int mServerNode = -1; diff --git a/src/d_netserver.cpp b/src/d_netserver.cpp index 73873a9101..d3417c4d96 100644 --- a/src/d_netserver.cpp +++ b/src/d_netserver.cpp @@ -268,6 +268,8 @@ void NetServer::OnConnectRequest(NetNode &node, const NetPacket &packet) mComm->PacketSend(response); node.Status = NodeStatus::InGame; + + FullUpdate ( node ); } else // Server is full. { @@ -316,3 +318,32 @@ void NetServer::OnTic(NetNode &node, NetPacket &packet) mComm->Close(packet.node); } } + +void NetServer::CmdSpawnPlayer(NetNode &node, int player) +{ + // TODO: This shouldn't be one packet per command. + NetPacket packet; + packet.node = &node-mNodes; + NetCommand cmd ( NetPacketType::SpawnPlayer ); + cmd.addByte ( player ); + cmd.addFloat ( static_cast ( players[player].mo->X() ) ); + cmd.addFloat ( static_cast ( players[player].mo->Y() ) ); + cmd.addFloat ( static_cast ( players[player].mo->Z() ) ); + cmd.addShort ( players[player].mo->syncdata.NetID ); + cmd.writeCommandToPacket ( packet ); + + mComm->PacketSend(packet); +} + +void NetServer::FullUpdate(NetNode &node) +{ + // Inform the client about all players already in the game. + for ( int i = 0; i < MAXPLAYERNAME; ++i ) + { + if ( i == node.Player ) + continue; + + if ( playeringame[i] == true ) + CmdSpawnPlayer(node, i); + } +} diff --git a/src/d_netserver.h b/src/d_netserver.h index aa51cc6650..d474cc2a2b 100644 --- a/src/d_netserver.h +++ b/src/d_netserver.h @@ -74,6 +74,9 @@ private: void OnDisconnect(NetNode &node, const NetPacket &packet); void OnTic(NetNode &node, NetPacket &packet); + void CmdSpawnPlayer(NetNode &node, int player); + void FullUpdate(NetNode &node); + std::unique_ptr mComm; NetNode mNodes[MAXNETNODES]; int mNodeForPlayer[MAXPLAYERS]; diff --git a/src/d_netsync.h b/src/d_netsync.h index 88fe065dc6..bb3326ecf0 100644 --- a/src/d_netsync.h +++ b/src/d_netsync.h @@ -15,7 +15,8 @@ enum class NetPacketType ConnectRequest, ConnectResponse, Disconnect, - Tic + Tic, + SpawnPlayer }; class AActor; From 7e359b1977aa59dc39c508144c7dacbef9b0c69b Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sat, 6 Oct 2018 05:55:10 -0400 Subject: [PATCH 30/46] - fix compile error --- src/d_main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 9ebea5e855..7af7399b0f 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -883,7 +883,6 @@ void D_Display () if (!wipe || NoWipe < 0 || wipe_type == wipe_None) { - NetUpdate (); // normal update // draw ZScript UI stuff C_DrawConsole (); // draw console From beed2817f24b882ef08705b6e77104e35f43aedf Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 11 Nov 2018 01:17:54 +0100 Subject: [PATCH 31/46] - move network code into its own folder - remove obsolete network includes in the software renderers --- src/CMakeLists.txt | 14 ++++++++------ src/actor.h | 2 +- src/b_bot.cpp | 2 +- src/b_game.cpp | 2 +- src/b_think.cpp | 2 +- src/c_cmds.cpp | 2 +- src/c_console.cpp | 2 +- src/c_dispatch.cpp | 2 +- src/ct_chat.cpp | 2 +- src/d_main.cpp | 4 ++-- src/d_netinfo.cpp | 2 +- src/d_protocol.cpp | 2 +- src/events.cpp | 2 +- src/g_game.cpp | 2 +- src/g_inventory/a_weapons.cpp | 2 +- src/g_level.cpp | 2 +- src/g_shared/a_decals.cpp | 2 +- src/g_shared/shared_hud.cpp | 2 +- src/g_statusbar/shared_sbar.cpp | 2 +- src/hu_scores.cpp | 2 +- src/info.cpp | 2 +- src/intermission/intermission.cpp | 2 +- src/m_cheat.cpp | 2 +- src/{ => network}/i_net.cpp | 2 +- src/{ => network}/i_net.h | 2 +- src/{d_net.cpp => network/net.cpp} | 6 +++--- src/{d_net.h => network/net.h} | 0 src/{d_netclient.cpp => network/netclient.cpp} | 4 ++-- src/{d_netclient.h => network/netclient.h} | 2 +- src/{d_netserver.cpp => network/netserver.cpp} | 4 ++-- src/{d_netserver.h => network/netserver.h} | 2 +- src/{d_netsingle.cpp => network/netsingle.cpp} | 2 +- src/{d_netsingle.h => network/netsingle.h} | 2 +- src/{d_netsync.cpp => network/netsync.cpp} | 4 ++-- src/{d_netsync.h => network/netsync.h} | 0 src/p_conversation.cpp | 2 +- src/p_interaction.cpp | 2 +- src/p_lnspec.cpp | 2 +- src/p_user.cpp | 2 +- src/polyrenderer/poly_renderer.cpp | 1 - src/r_utility.cpp | 2 +- src/st_stuff.cpp | 2 +- src/statistics.cpp | 2 +- src/swrenderer/line/r_farclip_line.cpp | 1 - src/swrenderer/line/r_fogboundary.cpp | 1 - src/swrenderer/line/r_line.cpp | 1 - src/swrenderer/line/r_renderdrawsegment.cpp | 1 - src/swrenderer/line/r_walldraw.cpp | 1 - src/swrenderer/line/r_wallsetup.cpp | 1 - src/swrenderer/plane/r_flatplane.cpp | 1 - src/swrenderer/plane/r_planerenderer.cpp | 1 - src/swrenderer/plane/r_skyplane.cpp | 1 - src/swrenderer/plane/r_slopeplane.cpp | 1 - src/swrenderer/plane/r_visibleplane.cpp | 1 - src/swrenderer/plane/r_visibleplanelist.cpp | 1 - src/swrenderer/scene/r_light.cpp | 1 - src/swrenderer/scene/r_portal.cpp | 1 - src/swrenderer/scene/r_scene.cpp | 1 - src/swrenderer/segments/r_drawsegment.cpp | 1 - src/swrenderer/things/r_decal.cpp | 1 - src/swrenderer/things/r_particle.cpp | 1 - src/swrenderer/things/r_playersprite.cpp | 1 - src/swrenderer/things/r_sprite.cpp | 1 - src/swrenderer/things/r_voxel.cpp | 1 - src/swrenderer/things/r_wallsprite.cpp | 1 - src/swrenderer/viewport/r_viewport.cpp | 1 - src/win32/i_system.cpp | 1 - 67 files changed, 53 insertions(+), 76 deletions(-) rename src/{ => network}/i_net.cpp (99%) rename src/{ => network}/i_net.h (97%) rename src/{d_net.cpp => network/net.cpp} (99%) rename src/{d_net.h => network/net.h} (100%) rename src/{d_netclient.cpp => network/netclient.cpp} (99%) rename src/{d_netclient.h => network/netclient.h} (98%) rename src/{d_netserver.cpp => network/netserver.cpp} (99%) rename src/{d_netserver.h => network/netserver.h} (99%) rename src/{d_netsingle.cpp => network/netsingle.cpp} (99%) rename src/{d_netsingle.h => network/netsingle.h} (98%) rename src/{d_netsync.cpp => network/netsync.cpp} (99%) rename src/{d_netsync.h => network/netsync.h} (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 66007a9562..8e85b7cc98 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -672,6 +672,7 @@ file( GLOB HEADER_FILES scripting/decorate/*.h scripting/zscript/*.h scripting/vm/*.h + network/*.h sound/midisources/*.h sound/oplsynth/*.h sound/oplsynth/dosbox/*.h @@ -896,11 +897,12 @@ set (PCH_SOURCES d_iwad.cpp d_main.cpp d_anonstats.cpp - d_net.cpp - d_netsingle.cpp - d_netserver.cpp - d_netsync.cpp - d_netclient.cpp + network/net.cpp + network/netsingle.cpp + network/netserver.cpp + network/netsync.cpp + network/netclient.cpp + network/i_net.cpp d_netinfo.cpp d_protocol.cpp decallib.cpp @@ -925,7 +927,6 @@ set (PCH_SOURCES gitinfo.cpp hu_scores.cpp i_module.cpp - i_net.cpp i_time.cpp info.cpp keysections.cpp @@ -1461,6 +1462,7 @@ source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_ source_group("Scripting\\Compiler backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/backend/.+") source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+") source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+") +source_group("Network" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/network/.+") source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+") source_group("Statusbar" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_statusbar/.+") source_group("Versioning" FILES version.h win32/zdoom.rc) diff --git a/src/actor.h b/src/actor.h index f4c0639863..4b4f0a15ee 100644 --- a/src/actor.h +++ b/src/actor.h @@ -48,7 +48,7 @@ #include "tflags.h" #include "portal.h" -#include "d_netsync.h" +#include "network/netsync.h" struct subsector_t; struct FBlockNode; diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 3c2998d1f8..12ccd634e9 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -44,7 +44,7 @@ #include "p_local.h" #include "cmdlib.h" #include "teaminfo.h" -#include "d_net.h" +#include "network/net.h" #include "serializer.h" #include "d_player.h" #include "vm.h" diff --git a/src/b_game.cpp b/src/b_game.cpp index c79958cb8b..8f2b8c426b 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -87,7 +87,7 @@ Everything that is changed is marked (maybe commented) with "Added by MC" #include "sbar.h" #include "p_acs.h" #include "teaminfo.h" -#include "d_net.h" +#include "network/net.h" #include "d_netinf.h" #include "d_player.h" #include "events.h" diff --git a/src/b_think.cpp b/src/b_think.cpp index 33111d2277..64baebb243 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -47,7 +47,7 @@ #include "p_local.h" #include "b_bot.h" #include "g_game.h" -#include "d_net.h" +#include "network/net.h" #include "d_event.h" #include "d_player.h" #include "actorinlines.h" diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 6c31ca98ea..eb16f333bc 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -62,7 +62,7 @@ #include "r_sky.h" #include "p_setup.h" #include "cmdlib.h" -#include "d_net.h" +#include "network/net.h" #include "v_text.h" #include "p_lnspec.h" #include "r_utility.h" diff --git a/src/c_console.cpp b/src/c_console.cpp index 22deb8676d..4d3b96d78d 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -54,7 +54,7 @@ #include "doomstat.h" #include "d_gui.h" #include "cmdlib.h" -#include "d_net.h" +#include "network/net.h" #include "d_event.h" #include "d_player.h" #include "gstrings.h" diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index d464d67335..ed4847ef14 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -49,7 +49,7 @@ #include "d_player.h" #include "configfile.h" #include "v_text.h" -#include "d_net.h" +#include "network/net.h" #include "d_main.h" #include "serializer.h" #include "menu/menu.h" diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index 941e2274b4..7a1d5ca8a0 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -35,7 +35,7 @@ #include "v_text.h" #include "d_gui.h" #include "g_input.h" -#include "d_net.h" +#include "network/net.h" #include "d_event.h" #include "sbar.h" diff --git a/src/d_main.cpp b/src/d_main.cpp index 246b161f4b..cd7e710d16 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -85,7 +85,7 @@ #include "teaminfo.h" #include "hardware.h" #include "sbarinfo.h" -#include "d_net.h" +#include "network/net.h" #include "d_event.h" #include "d_netinf.h" #include "m_cheat.h" @@ -101,7 +101,7 @@ #include "vm.h" #include "types.h" #include "r_data/r_vanillatrans.h" -#include "d_netsingle.h" +#include "network/netsingle.h" EXTERN_CVAR(Bool, hud_althud) EXTERN_CVAR(Int, vr_mode) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index d6a8b1d725..48e04e9745 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -40,7 +40,7 @@ #include "doomdef.h" #include "doomstat.h" #include "d_netinf.h" -#include "d_net.h" +#include "network/net.h" #include "d_player.h" #include "c_dispatch.h" #include "r_state.h" diff --git a/src/d_protocol.cpp b/src/d_protocol.cpp index cb7efb44df..1dfd346032 100644 --- a/src/d_protocol.cpp +++ b/src/d_protocol.cpp @@ -34,7 +34,7 @@ #include "i_system.h" #include "d_protocol.h" -#include "d_net.h" +#include "network/net.h" #include "doomstat.h" #include "cmdlib.h" #include "serializer.h" diff --git a/src/events.cpp b/src/events.cpp index a4731c3870..1ccd76875f 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -37,7 +37,7 @@ #include "gi.h" #include "actor.h" #include "c_dispatch.h" -#include "d_net.h" +#include "network/net.h" #include "info.h" DStaticEventHandler* E_FirstEventHandler = nullptr; diff --git a/src/g_game.cpp b/src/g_game.cpp index ac52c5e939..7409929f66 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -59,7 +59,7 @@ #include "m_png.h" #include "a_keys.h" #include "cmdlib.h" -#include "d_net.h" +#include "network/net.h" #include "d_event.h" #include "p_acs.h" #include "p_effect.h" diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 76af80bd26..230ec302a3 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -43,7 +43,7 @@ #include "gameconfigfile.h" #include "cmdlib.h" #include "sbar.h" -#include "d_net.h" +#include "network/net.h" #include "serializer.h" #include "vm.h" diff --git a/src/g_level.cpp b/src/g_level.cpp index d63c24acd1..b21115ead6 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -67,7 +67,7 @@ #include "sbarinfo.h" #include "p_lnspec.h" #include "cmdlib.h" -#include "d_net.h" +#include "network/net.h" #include "d_netinf.h" #include "menu/menu.h" #include "a_sharedglobal.h" diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 471ac267b0..33c596bf84 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -39,7 +39,7 @@ #include "p_trace.h" #include "decallib.h" #include "c_dispatch.h" -#include "d_net.h" +#include "network/net.h" #include "serializer.h" #include "doomdata.h" #include "g_levellocals.h" diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 50f574a964..a952d5b912 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -47,7 +47,7 @@ #include "p_local.h" #include "doomstat.h" #include "g_level.h" -#include "d_net.h" +#include "network/net.h" #include "d_player.h" #include "r_utility.h" #include "cmdlib.h" diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 59438f8135..cf3e45cf56 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -46,7 +46,7 @@ #include "gi.h" #include "doomstat.h" #include "g_level.h" -#include "d_net.h" +#include "network/net.h" #include "d_player.h" #include "serializer.h" #include "r_utility.h" diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index 40296ff4f4..7f5d65f95d 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -46,7 +46,7 @@ #include "d_player.h" #include "hu_stuff.h" #include "gstrings.h" -#include "d_net.h" +#include "network/net.h" #include "c_dispatch.h" #include "g_levellocals.h" #include "sbar.h" diff --git a/src/info.cpp b/src/info.cpp index 6d0dc0e0bc..031c4520b4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -38,7 +38,7 @@ #include "doomstat.h" #include "info.h" #include "c_dispatch.h" -#include "d_net.h" +#include "network/net.h" #include "v_text.h" #include "gi.h" diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 66c2b975fc..7d9122503d 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -47,7 +47,7 @@ #include "c_bind.h" #include "p_conversation.h" #include "menu/menu.h" -#include "d_net.h" +#include "network/net.h" #include "g_levellocals.h" FIntermissionDescriptorList IntermissionDescriptors; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 697f20be1e..582d86af29 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -47,7 +47,7 @@ #include "sbar.h" #include "c_dispatch.h" #include "a_keys.h" -#include "d_net.h" +#include "network/net.h" #include "serializer.h" #include "r_utility.h" #include "a_morph.h" diff --git a/src/i_net.cpp b/src/network/i_net.cpp similarity index 99% rename from src/i_net.cpp rename to src/network/i_net.cpp index 9f182cf4d9..997aa006fb 100644 --- a/src/i_net.cpp +++ b/src/network/i_net.cpp @@ -55,7 +55,7 @@ #include "doomtype.h" #include "i_system.h" -#include "d_net.h" +#include "net.h" #include "m_argv.h" #include "m_crc32.h" #include "d_player.h" diff --git a/src/i_net.h b/src/network/i_net.h similarity index 97% rename from src/i_net.h rename to src/network/i_net.h index 090a250f44..b68b42aec6 100644 --- a/src/i_net.h +++ b/src/network/i_net.h @@ -2,7 +2,7 @@ #pragma once #include -#include "d_netsync.h" +#include "netsync.h" #define MAX_MSGLEN 14000 #define DOOMPORT 5029 diff --git a/src/d_net.cpp b/src/network/net.cpp similarity index 99% rename from src/d_net.cpp rename to src/network/net.cpp index 909230d4cc..46ae18d54b 100644 --- a/src/d_net.cpp +++ b/src/network/net.cpp @@ -36,9 +36,9 @@ #include "g_game.h" #include "c_console.h" #include "d_netinf.h" -#include "d_net.h" -#include "d_netclient.h" -#include "d_netserver.h" +#include "net.h" +#include "netclient.h" +#include "netserver.h" #include "cmdlib.h" #include "m_cheat.h" #include "p_local.h" diff --git a/src/d_net.h b/src/network/net.h similarity index 100% rename from src/d_net.h rename to src/network/net.h diff --git a/src/d_netclient.cpp b/src/network/netclient.cpp similarity index 99% rename from src/d_netclient.cpp rename to src/network/netclient.cpp index fd6387f0ab..875a5e26c1 100644 --- a/src/d_netclient.cpp +++ b/src/network/netclient.cpp @@ -33,8 +33,8 @@ #include "doomstat.h" #include "c_console.h" #include "d_netinf.h" -#include "d_netclient.h" -#include "d_netsingle.h" +#include "netclient.h" +#include "netsingle.h" #include "cmdlib.h" #include "s_sound.h" #include "m_cheat.h" diff --git a/src/d_netclient.h b/src/network/netclient.h similarity index 98% rename from src/d_netclient.h rename to src/network/netclient.h index 7d64a0ef7a..96387102dc 100644 --- a/src/d_netclient.h +++ b/src/network/netclient.h @@ -21,7 +21,7 @@ #pragma once -#include "d_netserver.h" +#include "netserver.h" class NetClient : public Network { diff --git a/src/d_netserver.cpp b/src/network/netserver.cpp similarity index 99% rename from src/d_netserver.cpp rename to src/network/netserver.cpp index d3417c4d96..5aba8df2ac 100644 --- a/src/d_netserver.cpp +++ b/src/network/netserver.cpp @@ -33,7 +33,7 @@ #include "doomstat.h" #include "c_console.h" #include "d_netinf.h" -#include "d_netserver.h" +#include "netserver.h" #include "cmdlib.h" #include "s_sound.h" #include "m_cheat.h" @@ -323,7 +323,7 @@ void NetServer::CmdSpawnPlayer(NetNode &node, int player) { // TODO: This shouldn't be one packet per command. NetPacket packet; - packet.node = &node-mNodes; + packet.node = (int)(ptrdiff_t)(&node-mNodes); NetCommand cmd ( NetPacketType::SpawnPlayer ); cmd.addByte ( player ); cmd.addFloat ( static_cast ( players[player].mo->X() ) ); diff --git a/src/d_netserver.h b/src/network/netserver.h similarity index 99% rename from src/d_netserver.h rename to src/network/netserver.h index d474cc2a2b..f37070621a 100644 --- a/src/d_netserver.h +++ b/src/network/netserver.h @@ -21,7 +21,7 @@ #pragma once -#include "d_net.h" +#include "net.h" enum class NodeStatus { diff --git a/src/d_netsingle.cpp b/src/network/netsingle.cpp similarity index 99% rename from src/d_netsingle.cpp rename to src/network/netsingle.cpp index 9f8357108f..c7ce67947f 100644 --- a/src/d_netsingle.cpp +++ b/src/network/netsingle.cpp @@ -33,7 +33,7 @@ #include "doomstat.h" #include "c_console.h" #include "d_netinf.h" -#include "d_netsingle.h" +#include "netsingle.h" #include "cmdlib.h" #include "s_sound.h" #include "m_cheat.h" diff --git a/src/d_netsingle.h b/src/network/netsingle.h similarity index 98% rename from src/d_netsingle.h rename to src/network/netsingle.h index 3434240b0d..c08dd6b1f8 100644 --- a/src/d_netsingle.h +++ b/src/network/netsingle.h @@ -21,7 +21,7 @@ #pragma once -#include "d_net.h" +#include "network/net.h" class NetSinglePlayer : public Network { diff --git a/src/d_netsync.cpp b/src/network/netsync.cpp similarity index 99% rename from src/d_netsync.cpp rename to src/network/netsync.cpp index 15679f67a5..873ec37b5f 100644 --- a/src/d_netsync.cpp +++ b/src/network/netsync.cpp @@ -17,7 +17,7 @@ // #include "d_player.h" -#include "d_netsync.h" +#include "netsync.h" #include "c_dispatch.h" #include "actor.h" #include "doomstat.h" @@ -628,7 +628,7 @@ void NetCommand::addShortByte ( int value, int bits ) // void NetCommand::addString ( const char *pszString ) { - const int len = ( pszString != NULL ) ? strlen( pszString ) : 0; + const int len = ( pszString != NULL ) ? (int)strlen( pszString ) : 0; if ( len > MAX_NETWORK_STRING ) { diff --git a/src/d_netsync.h b/src/network/netsync.h similarity index 100% rename from src/d_netsync.h rename to src/network/netsync.h diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 40d3a090de..dbebeef213 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -45,7 +45,7 @@ #include "gstrings.h" #include "sound/i_music.h" #include "p_setup.h" -#include "d_net.h" +#include "network/net.h" #include "d_event.h" #include "doomstat.h" #include "c_console.h" diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 34e30b904a..687d4ac2ba 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -54,7 +54,7 @@ #include "d_player.h" #include "gi.h" #include "sbar.h" -#include "d_net.h" +#include "network/net.h" #include "d_netinf.h" #include "a_morph.h" #include "vm.h" diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index d92aa66d8e..f4ca05db51 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -46,7 +46,7 @@ #include "gi.h" #include "p_conversation.h" #include "p_3dmidtex.h" -#include "d_net.h" +#include "network/net.h" #include "d_event.h" #include "gstrings.h" #include "po_man.h" diff --git a/src/p_user.cpp b/src/p_user.cpp index b5ed0fcc9d..e7128b5138 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -76,7 +76,7 @@ #include "intermission/intermission.h" #include "c_console.h" #include "c_dispatch.h" -#include "d_net.h" +#include "network/net.h" #include "serializer.h" #include "r_renderer.h" #include "d_player.h" diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp index 46667d1803..e9ae82c03f 100644 --- a/src/polyrenderer/poly_renderer.cpp +++ b/src/polyrenderer/poly_renderer.cpp @@ -29,7 +29,6 @@ #include "r_data/r_interpolate.h" #include "r_data/models/models.h" #include "poly_renderer.h" -#include "d_net.h" #include "po_man.h" #include "st_stuff.h" #include "g_levellocals.h" diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 77c6856264..066ca88ea3 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -34,7 +34,7 @@ #include "templates.h" #include "doomdef.h" -#include "d_net.h" +#include "network/net.h" #include "doomstat.h" #include "m_random.h" #include "m_bbox.h" diff --git a/src/st_stuff.cpp b/src/st_stuff.cpp index 366453ade8..f6edefed9d 100644 --- a/src/st_stuff.cpp +++ b/src/st_stuff.cpp @@ -31,7 +31,7 @@ #include "c_dispatch.h" #include "d_event.h" #include "gi.h" -#include "d_net.h" +#include "network/net.h" #include "doomstat.h" #include "g_level.h" #include "g_levellocals.h" diff --git a/src/statistics.cpp b/src/statistics.cpp index 2d88f828a4..066de51a0e 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -42,7 +42,7 @@ #include "gstrings.h" #include "doomstat.h" #include "c_dispatch.h" -#include "d_net.h" +#include "network/net.h" #include "g_game.h" #include "m_png.h" #include "doomerrors.h" diff --git a/src/swrenderer/line/r_farclip_line.cpp b/src/swrenderer/line/r_farclip_line.cpp index 5b55e654f4..b3b7cb3f42 100644 --- a/src/swrenderer/line/r_farclip_line.cpp +++ b/src/swrenderer/line/r_farclip_line.cpp @@ -33,7 +33,6 @@ #include "w_wad.h" #include "stats.h" #include "a_sharedglobal.h" -#include "d_net.h" #include "g_level.h" #include "g_levellocals.h" #include "r_wallsetup.h" diff --git a/src/swrenderer/line/r_fogboundary.cpp b/src/swrenderer/line/r_fogboundary.cpp index 1b8f1c99d0..64c9599d4d 100644 --- a/src/swrenderer/line/r_fogboundary.cpp +++ b/src/swrenderer/line/r_fogboundary.cpp @@ -33,7 +33,6 @@ #include "a_sharedglobal.h" #include "c_console.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "v_palette.h" #include "r_data/colormaps.h" diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp index 77ac90f5bd..76a70d0696 100644 --- a/src/swrenderer/line/r_line.cpp +++ b/src/swrenderer/line/r_line.cpp @@ -35,7 +35,6 @@ #include "w_wad.h" #include "stats.h" #include "a_sharedglobal.h" -#include "d_net.h" #include "g_level.h" #include "g_levellocals.h" #include "r_wallsetup.h" diff --git a/src/swrenderer/line/r_renderdrawsegment.cpp b/src/swrenderer/line/r_renderdrawsegment.cpp index f7d35d1e2f..f1e937b4c2 100644 --- a/src/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/swrenderer/line/r_renderdrawsegment.cpp @@ -37,7 +37,6 @@ #include "r_sky.h" #include "po_man.h" #include "r_data/colormaps.h" -#include "d_net.h" #include "swrenderer/r_memory.h" #include "swrenderer/r_renderthread.h" #include "swrenderer/drawers/r_draw.h" diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index 5fac3dfc91..0c7d2d5344 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -33,7 +33,6 @@ #include "m_swap.h" #include "a_sharedglobal.h" -#include "d_net.h" #include "g_level.h" #include "r_walldraw.h" #include "v_palette.h" diff --git a/src/swrenderer/line/r_wallsetup.cpp b/src/swrenderer/line/r_wallsetup.cpp index b910bfec86..20f0137746 100644 --- a/src/swrenderer/line/r_wallsetup.cpp +++ b/src/swrenderer/line/r_wallsetup.cpp @@ -34,7 +34,6 @@ #include "w_wad.h" #include "stats.h" #include "a_sharedglobal.h" -#include "d_net.h" #include "g_level.h" #include "r_wallsetup.h" #include "v_palette.h" diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 51d376bd4c..d6375585ea 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -33,7 +33,6 @@ #include "a_sharedglobal.h" #include "c_console.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "g_levellocals.h" #include "swrenderer/scene/r_opaque_pass.h" diff --git a/src/swrenderer/plane/r_planerenderer.cpp b/src/swrenderer/plane/r_planerenderer.cpp index bc1eb22f91..e4695aa165 100644 --- a/src/swrenderer/plane/r_planerenderer.cpp +++ b/src/swrenderer/plane/r_planerenderer.cpp @@ -34,7 +34,6 @@ #include "a_sharedglobal.h" #include "c_console.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "a_dynlight.h" #include "swrenderer/plane/r_visibleplane.h" diff --git a/src/swrenderer/plane/r_skyplane.cpp b/src/swrenderer/plane/r_skyplane.cpp index afa9496c03..954eda7de9 100644 --- a/src/swrenderer/plane/r_skyplane.cpp +++ b/src/swrenderer/plane/r_skyplane.cpp @@ -33,7 +33,6 @@ #include "a_sharedglobal.h" #include "c_console.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "swrenderer/scene/r_opaque_pass.h" #include "r_skyplane.h" diff --git a/src/swrenderer/plane/r_slopeplane.cpp b/src/swrenderer/plane/r_slopeplane.cpp index 20eb3dbf4e..bc93635cb7 100644 --- a/src/swrenderer/plane/r_slopeplane.cpp +++ b/src/swrenderer/plane/r_slopeplane.cpp @@ -33,7 +33,6 @@ #include "a_sharedglobal.h" #include "c_console.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "g_levellocals.h" #include "swrenderer/scene/r_opaque_pass.h" diff --git a/src/swrenderer/plane/r_visibleplane.cpp b/src/swrenderer/plane/r_visibleplane.cpp index 19cb0fb42d..33064b88e6 100644 --- a/src/swrenderer/plane/r_visibleplane.cpp +++ b/src/swrenderer/plane/r_visibleplane.cpp @@ -34,7 +34,6 @@ #include "a_sharedglobal.h" #include "c_console.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "a_dynlight.h" #include "swrenderer/r_memory.h" diff --git a/src/swrenderer/plane/r_visibleplanelist.cpp b/src/swrenderer/plane/r_visibleplanelist.cpp index 561930cc27..1326d22c23 100644 --- a/src/swrenderer/plane/r_visibleplanelist.cpp +++ b/src/swrenderer/plane/r_visibleplanelist.cpp @@ -34,7 +34,6 @@ #include "a_sharedglobal.h" #include "c_console.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "a_dynlight.h" #include "swrenderer/r_memory.h" diff --git a/src/swrenderer/scene/r_light.cpp b/src/swrenderer/scene/r_light.cpp index c120c22ebe..0fa0d5b350 100644 --- a/src/swrenderer/scene/r_light.cpp +++ b/src/swrenderer/scene/r_light.cpp @@ -35,7 +35,6 @@ #include "c_console.h" #include "c_dispatch.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "r_utility.h" #include "d_player.h" diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index d6fa849b56..236efeff50 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -26,7 +26,6 @@ #include "templates.h" #include "doomdef.h" -#include "d_net.h" #include "doomstat.h" #include "m_random.h" #include "m_bbox.h" diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index d10139896e..6a2034851b 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -34,7 +34,6 @@ #include "c_console.h" #include "c_dispatch.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "p_effect.h" #include "po_man.h" diff --git a/src/swrenderer/segments/r_drawsegment.cpp b/src/swrenderer/segments/r_drawsegment.cpp index 76b13df97b..8c33c44b49 100644 --- a/src/swrenderer/segments/r_drawsegment.cpp +++ b/src/swrenderer/segments/r_drawsegment.cpp @@ -35,7 +35,6 @@ #include "r_sky.h" #include "po_man.h" #include "r_data/colormaps.h" -#include "d_net.h" #include "swrenderer/r_memory.h" #include "swrenderer/drawers/r_draw.h" #include "swrenderer/scene/r_3dfloors.h" diff --git a/src/swrenderer/things/r_decal.cpp b/src/swrenderer/things/r_decal.cpp index 1f9dbf6a74..7bd972d09c 100644 --- a/src/swrenderer/things/r_decal.cpp +++ b/src/swrenderer/things/r_decal.cpp @@ -33,7 +33,6 @@ #include "w_wad.h" #include "stats.h" #include "a_sharedglobal.h" -#include "d_net.h" #include "g_level.h" #include "swrenderer/scene/r_opaque_pass.h" #include "r_decal.h" diff --git a/src/swrenderer/things/r_particle.cpp b/src/swrenderer/things/r_particle.cpp index 0e167f7c4c..e5bb9f1f89 100644 --- a/src/swrenderer/things/r_particle.cpp +++ b/src/swrenderer/things/r_particle.cpp @@ -40,7 +40,6 @@ #include "r_sky.h" #include "cmdlib.h" #include "g_level.h" -#include "d_net.h" #include "colormatcher.h" #include "d_netinf.h" #include "p_effect.h" diff --git a/src/swrenderer/things/r_playersprite.cpp b/src/swrenderer/things/r_playersprite.cpp index b29e496879..77415bd01d 100644 --- a/src/swrenderer/things/r_playersprite.cpp +++ b/src/swrenderer/things/r_playersprite.cpp @@ -41,7 +41,6 @@ #include "r_sky.h" #include "cmdlib.h" #include "g_level.h" -#include "d_net.h" #include "colormatcher.h" #include "d_netinf.h" #include "p_effect.h" diff --git a/src/swrenderer/things/r_sprite.cpp b/src/swrenderer/things/r_sprite.cpp index b980555dd0..5fcffab90f 100644 --- a/src/swrenderer/things/r_sprite.cpp +++ b/src/swrenderer/things/r_sprite.cpp @@ -41,7 +41,6 @@ #include "r_sky.h" #include "cmdlib.h" #include "g_level.h" -#include "d_net.h" #include "colormatcher.h" #include "d_netinf.h" #include "p_effect.h" diff --git a/src/swrenderer/things/r_voxel.cpp b/src/swrenderer/things/r_voxel.cpp index faab6e785c..633870dd87 100644 --- a/src/swrenderer/things/r_voxel.cpp +++ b/src/swrenderer/things/r_voxel.cpp @@ -39,7 +39,6 @@ #include "r_data/colormaps.h" #include "r_data/voxels.h" #include "r_data/sprites.h" -#include "d_net.h" #include "po_man.h" #include "r_utility.h" #include "i_time.h" diff --git a/src/swrenderer/things/r_wallsprite.cpp b/src/swrenderer/things/r_wallsprite.cpp index a9f8154251..cb03561cdd 100644 --- a/src/swrenderer/things/r_wallsprite.cpp +++ b/src/swrenderer/things/r_wallsprite.cpp @@ -41,7 +41,6 @@ #include "r_sky.h" #include "cmdlib.h" #include "g_level.h" -#include "d_net.h" #include "colormatcher.h" #include "d_netinf.h" #include "p_effect.h" diff --git a/src/swrenderer/viewport/r_viewport.cpp b/src/swrenderer/viewport/r_viewport.cpp index e3cfc15483..7583920c99 100644 --- a/src/swrenderer/viewport/r_viewport.cpp +++ b/src/swrenderer/viewport/r_viewport.cpp @@ -33,7 +33,6 @@ #include "a_sharedglobal.h" #include "c_console.h" #include "cmdlib.h" -#include "d_net.h" #include "g_level.h" #include "r_utility.h" #include "swrenderer/viewport/r_viewport.h" diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 13b36dc1f2..8c296429b7 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -70,7 +70,6 @@ #include "stats.h" #include "d_main.h" -#include "d_net.h" #include "g_game.h" #include "i_input.h" #include "c_dispatch.h" From 6827e56a4e4b39b0b1601122de768f355b97855a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 11 Nov 2018 10:13:57 +0100 Subject: [PATCH 32/46] - misc fixes to client server handshaking and playsim ticking --- src/d_main.cpp | 9 ++-- src/network/i_net.cpp | 55 ++++++++------------ src/network/i_net.h | 3 ++ src/network/net.h | 4 +- src/network/netclient.cpp | 97 ++++++++++++++++++++++++++-------- src/network/netclient.h | 19 ++++++- src/network/netserver.cpp | 106 +++++++++++++++++++++++++++----------- src/network/netserver.h | 13 +++-- src/network/netsingle.cpp | 7 ++- src/network/netsingle.h | 3 +- 10 files changed, 211 insertions(+), 105 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index cd7e710d16..dc38d11bd5 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -986,11 +986,6 @@ public: return LastTic; } - int BaseMakeTic() const - { - return LastTic + 1; - } - private: int LastTic = 0; int CurrentTic = 0; @@ -1038,7 +1033,7 @@ public: for (int i = 0; i < tics; i++) { - network->SetCurrentTic(gametime.BaseGameTic() + i, gametime.BaseMakeTic() + i); + network->SetCurrentTic(gametime.BaseGameTic() + i); network->WriteLocalInput(G_BuildTiccmd()); if (advancedemo) @@ -1095,6 +1090,8 @@ void D_DoomLoop() if (wantToRestart) { + P_UnPredictPlayer(); + wantToRestart = false; return; } diff --git a/src/network/i_net.cpp b/src/network/i_net.cpp index 997aa006fb..5d2a5abfe4 100644 --- a/src/network/i_net.cpp +++ b/src/network/i_net.cpp @@ -228,45 +228,31 @@ int DoomComImpl::FindNode(const sockaddr_in *address) 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 (packet.size > MAX_MSGLEN) - { - I_FatalError("Netbuffer overflow!"); - } assert(!(packet.data[0] & NCMD_COMPRESSED)); - uLong size = TRANSMIT_SIZE - 1; if (packet.size >= 10) { mTransmitBuffer[0] = packet.data[0] | NCMD_COMPRESSED; - c = compress2(mTransmitBuffer + 1, &size, packet.data + 1, packet.size - 1, 9); + + uLong size = TRANSMIT_SIZE - 1; + int c = compress2(mTransmitBuffer + 1, &size, packet.data + 1, packet.size - 1, 9); size += 1; + + if (c == Z_OK && size < (uLong)packet.size) + { + sendto(mSocket, (char *)mTransmitBuffer, size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); + return; + } + } + + if (packet.size <= TRANSMIT_SIZE) + { + sendto(mSocket, (char *)packet.data, packet.size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); } else { - c = -1; // Just some random error code to avoid sending the compressed buffer. + I_Error("NetPacket is too large to be transmitted"); } - if (c == Z_OK && size < (uLong)packet.size) - { - c = sendto(mSocket, (char *)mTransmitBuffer, size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); - } - else - { - if (packet.size > TRANSMIT_SIZE) - { - I_Error("Net compression failed (zlib error %d)", c); - } - else - { - c = sendto(mSocket, (char *)packet.data, packet.size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); - } - } - // if (c == -1) - // I_Error ("SendPacket error: %s",strerror(errno)); } void DoomComImpl::PacketGet(NetPacket &packet) @@ -303,7 +289,8 @@ void DoomComImpl::PacketGet(NetPacket &packet) Close(node); packet.node = node; packet.size = 0; - packet.stream.pbStreamEnd = packet.stream.pbStream; + packet.stream.pbStream = packet.data; + packet.stream.pbStreamEnd = packet.data + packet.size; return; } else if (err != WSAEWOULDBLOCK) @@ -314,7 +301,8 @@ void DoomComImpl::PacketGet(NetPacket &packet) { packet.node = -1; packet.size = 0; - packet.stream.pbStreamEnd = packet.stream.pbStream; + packet.stream.pbStream = packet.data; + packet.stream.pbStreamEnd = packet.data + packet.size; return; } } @@ -325,7 +313,7 @@ void DoomComImpl::PacketGet(NetPacket &packet) continue; packet.data[0] = mTransmitBuffer[0] & ~NCMD_COMPRESSED; - if (mTransmitBuffer[0] & NCMD_COMPRESSED) + if ((mTransmitBuffer[0] & NCMD_COMPRESSED) && size > 1) { uLongf msgsize = MAX_MSGLEN - 1; int err = uncompress(packet.data + 1, &msgsize, mTransmitBuffer + 1, size - 1); @@ -343,7 +331,8 @@ void DoomComImpl::PacketGet(NetPacket &packet) packet.node = node; packet.size = (short)size; - packet.stream.pbStreamEnd = packet.stream.pbStream + packet.size; + packet.stream.pbStream = packet.data; + packet.stream.pbStreamEnd = packet.data + packet.size; return; } } diff --git a/src/network/i_net.h b/src/network/i_net.h index b68b42aec6..72b4670119 100644 --- a/src/network/i_net.h +++ b/src/network/i_net.h @@ -31,6 +31,9 @@ struct NetPacket const uint8_t &operator[](int i) const { return data[i]; } BYTESTREAM_s stream; + + NetPacket(const NetPacket &) = delete; + NetPacket &operator=(const NetPacket &) = delete; }; // Network packet data. diff --git a/src/network/net.h b/src/network/net.h index dff885d506..594a5bdf5d 100644 --- a/src/network/net.h +++ b/src/network/net.h @@ -63,8 +63,8 @@ public: // Check for incoming packets virtual void Update() = 0; - // Set current tic for reading and writing - virtual void SetCurrentTic(int receivetic, int sendtic) = 0; + // Set current tic time + virtual void SetCurrentTic(int localtic) = 0; // Send any pending outgoing data virtual void EndCurrentTic() = 0; diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index 875a5e26c1..b043f322fb 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -82,6 +82,7 @@ NetClient::NetClient(FString server) packet.node = mServerNode; NetCommand cmd ( NetPacketType::ConnectRequest ); + cmd.addString("ZDoom Connect Request"); cmd.writeCommandToPacket ( packet ); mComm->PacketSend(packet); @@ -149,26 +150,62 @@ void NetClient::Update() } } -void NetClient::SetCurrentTic(int receivetic, int sendtic) +void NetClient::SetCurrentTic(int tictime) { - gametic = receivetic; - mSendTic = sendtic; + gametic = tictime; + mSendTic = gametic + 10; + + int jitter = 2; + if (mLastReceivedTic == -1) + { + mServerTic = 0; + } + else + { + if (mServerTicDelta == -1 || std::abs(gametic + mServerTicDelta - mLastReceivedTic) > jitter) + { + //Printf("netcable icon! ;)\n"); + mServerTicDelta = mLastReceivedTic - gametic - jitter; + } + + mServerTic = MAX(gametic + mServerTicDelta, 0); + } + + mCurrentInput[consoleplayer] = mSentInput[gametic % BACKUPTICS]; } void NetClient::EndCurrentTic() { + mCurrentCommands = mSendCommands; + mSendCommands.Clear(); + + if (mStatus != NodeStatus::InGame) + return; + + int targettic = (mSendTic + mServerTicDelta); + NetPacket packet; packet.node = mServerNode; NetCommand cmd ( NetPacketType::Tic ); - cmd.addByte ( 0 ); // target gametic - cmd.addBuffer ( &mCurrentInput[consoleplayer].ucmd, sizeof(usercmd_t) ); + cmd.addByte (targettic); // target gametic + cmd.addBuffer ( &mSentInput[(mSendTic - 1) % BACKUPTICS].ucmd, sizeof(usercmd_t) ); cmd.writeCommandToPacket ( packet ); mComm->PacketSend(packet); - mCurrentCommands = mSendCommands; - mSendCommands.Clear(); + TicUpdate &update = mTicUpdates[mServerTic % BACKUPTICS]; + if (update.received) + { + if (playeringame[consoleplayer] && players[consoleplayer].mo) + { + players[consoleplayer].mo->SetXYZ(update.x, update.y, update.z); + players[consoleplayer].mo->Angles.Yaw = update.yaw; + players[consoleplayer].mo->Angles.Pitch = update.pitch; + } + + update.received = false; + } } int NetClient::GetSendTick() const @@ -196,8 +233,7 @@ void NetClient::RunCommands(int player) void NetClient::WriteLocalInput(ticcmd_t cmd) { - mCurrentInput[consoleplayer] = cmd; - mSentInput[gametic % BACKUPTICS] = cmd; + mSentInput[(mSendTic - 1) % BACKUPTICS] = cmd; } void NetClient::WriteBotInput(int player, const ticcmd_t &cmd) @@ -284,25 +320,42 @@ void NetClient::OnDisconnect(const NetPacket &packet) mStatus = NodeStatus::Closed; } +void NetClient::UpdateLastReceivedTic(int tic) +{ + if (mLastReceivedTic != -1) + { + int delta = tic - (mLastReceivedTic & 0xff); + if (delta > 128) delta -= 256; + else if (delta < -128) delta += 256; + mLastReceivedTic += delta; + } + else + { + mLastReceivedTic = tic; + } + mLastReceivedTic = MAX(mLastReceivedTic, 0); +} + void NetClient::OnTic(NetPacket &packet) { - int tic = packet.stream.ReadByte(); - float x = packet.stream.ReadFloat(); - float y = packet.stream.ReadFloat(); - float z = packet.stream.ReadFloat(); - float yaw = packet.stream.ReadFloat(); - float pitch = packet.stream.ReadFloat(); + UpdateLastReceivedTic(packet.stream.ReadByte()); - 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; - } + TicUpdate update; + update.received = true; + update.x = packet.stream.ReadFloat(); + update.y = packet.stream.ReadFloat(); + update.z = packet.stream.ReadFloat(); + update.yaw = packet.stream.ReadFloat(); + update.pitch = packet.stream.ReadFloat(); + + mTicUpdates[mLastReceivedTic % BACKUPTICS] = update; } void NetClient::OnSpawnPlayer(NetPacket &packet) { + // To do: this needs a tic and should be inserted in mTicUpdates. + // Otherwise it might not arrive at the intended moment in time. + int player = packet.stream.ReadByte(); const float x = packet.stream.ReadFloat(); const float y = packet.stream.ReadFloat(); @@ -320,7 +373,7 @@ void NetClient::OnSpawnPlayer(NetPacket &packet) // This player is now in the game. playeringame[player] = true; - player_t p = players[player]; + player_t &p = players[player]; if ( cl_showspawnnames ) Printf ( "Spawning player %d at %f,%f,%f (id %d)\n", player, x, y, z, netID ); diff --git a/src/network/netclient.h b/src/network/netclient.h index 96387102dc..6295280bb5 100644 --- a/src/network/netclient.h +++ b/src/network/netclient.h @@ -30,7 +30,7 @@ public: void Update() override; - void SetCurrentTic(int receivetic, int sendtic) override; + void SetCurrentTic(int tictime) override; void EndCurrentTic() override; int GetSendTick() const override; @@ -56,11 +56,28 @@ private: void OnTic(NetPacket &packet); void OnSpawnPlayer(NetPacket &packet); + void UpdateLastReceivedTic(int tic); + std::unique_ptr mComm; int mServerNode = -1; int mPlayer = -1; NodeStatus mStatus = NodeStatus::Closed; + int mSendTic = 0; + int mServerTic = 0; + int mServerTicDelta = -1; + int mLastReceivedTic = -1; + + struct TicUpdate + { + bool received = false; + float x; + float y; + float z; + float yaw; + float pitch; + }; + TicUpdate mTicUpdates[BACKUPTICS]; ticcmd_t mCurrentInput[MAXPLAYERS]; ticcmd_t mSentInput[BACKUPTICS]; diff --git a/src/network/netserver.cpp b/src/network/netserver.cpp index 5aba8df2ac..f490cf1f44 100644 --- a/src/network/netserver.cpp +++ b/src/network/netserver.cpp @@ -76,16 +76,17 @@ NetServer::NetServer() void NetServer::Update() { + // Read all packets currently available from clients while (true) { NetPacket packet; mComm->PacketGet(packet); if (packet.node == -1) - break; + break; // No more packets. We are done. NetNode &node = mNodes[packet.node]; - if (packet.size == 0) + if (packet.size == 0) // Connection to node closed (timed out) { OnClose(node, packet); } @@ -108,15 +109,27 @@ void NetServer::Update() case NetPacketType::Tic: OnTic(node, packet); break; } } - break; } } } -void NetServer::SetCurrentTic(int receivetic, int sendtic) +void NetServer::SetCurrentTic(int tictime) { - gametic = receivetic; - mSendTic = sendtic; + gametic = tictime; + + for (int i = 0; i < MAXNETNODES; i++) + { + NetNode &node = mNodes[i]; + if (node.Status == NodeStatus::InGame && node.Player != -1) + { + NetNode::TicUpdate &update = node.TicUpdates[gametic % BACKUPTICS]; + if (update.received) + { + mCurrentInput[node.Player].ucmd = update.input; + update.received = false; + } + } + } } void NetServer::EndCurrentTic() @@ -160,7 +173,7 @@ void NetServer::EndCurrentTic() int NetServer::GetSendTick() const { - return mSendTic; + return gametic; } ticcmd_t NetServer::GetPlayerInput(int player) const @@ -223,7 +236,7 @@ void NetServer::OnClose(NetNode &node, const NetPacket &packet) { if (node.Status == NodeStatus::InGame) { - Printf("Player %d left the server", node.Player); + Printf("Player %d left the server\n", node.Player); playeringame[node.Player] = false; players[node.Player].settings_controller = false; @@ -234,29 +247,49 @@ void NetServer::OnClose(NetNode &node, const NetPacket &packet) mComm->Close(packet.node); } -void NetServer::OnConnectRequest(NetNode &node, const NetPacket &packet) +void NetServer::OnConnectRequest(NetNode &node, NetPacket &packet) { - // Search for a spot in the player list - if (node.Status != NodeStatus::InGame) + // Make the initial connect packet a bit more complex than a bunch of zeros.. + if (strcmp(packet.stream.ReadString(), "ZDoom Connect Request") != 0) { - for (int i = 0; i < MAXPLAYERS; i++) + if (node.Status == NodeStatus::InGame) { - if (!playeringame[i]) - { - node.Player = i; - playeringame[i] = true; - players[i].settings_controller = false; - break; - } + Printf("Junk data received from a joined player\n"); + } + else + { + node.Status = NodeStatus::Closed; + mComm->Close(packet.node); + return; + } + } + + if (node.Status == NodeStatus::InGame) + return; + + // Search for a spot in the player list + for (int i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + { + node.Player = i; + break; } } if (node.Player != -1) // Join accepted. { - Printf("Player %d joined the server", node.Player); + Printf("Player %d joined the server\n", node.Player); + for (int i = 0; i < BACKUPTICS; i++) + node.TicUpdates[i].received = false; + + node.Status = NodeStatus::InGame; mNodeForPlayer[node.Player] = packet.node; + playeringame[node.Player] = true; + players[node.Player].settings_controller = false; + NetPacket response; response.node = packet.node; @@ -267,8 +300,6 @@ void NetServer::OnConnectRequest(NetNode &node, const NetPacket &packet) mComm->PacketSend(response); - node.Status = NodeStatus::InGame; - FullUpdate ( node ); } else // Server is full. @@ -294,7 +325,7 @@ void NetServer::OnDisconnect(NetNode &node, const NetPacket &packet) { if (node.Status == NodeStatus::InGame) { - Printf("Player %d left the server", node.Player); + Printf("Player %d left the server\n", node.Player); playeringame[node.Player] = false; players[node.Player].settings_controller = false; @@ -307,16 +338,29 @@ void NetServer::OnDisconnect(NetNode &node, const NetPacket &packet) void NetServer::OnTic(NetNode &node, NetPacket &packet) { - if (node.Status == NodeStatus::InGame) + if (node.Status != NodeStatus::InGame) + return; + + int tic = packet.stream.ReadByte(); + + int delta = tic - (gametic & 0xff); + if (delta > 128) delta -= 256; + else if (delta < -128) delta += 256; + tic = gametic + delta; + + if (tic <= gametic) { - /* gametic */ packet.stream.ReadByte(); - packet.stream.ReadBuffer ( &mCurrentInput[node.Player].ucmd, sizeof(usercmd_t)); - } - else - { - node.Status = NodeStatus::Closed; - mComm->Close(packet.node); + // Packet arrived too late. + tic = gametic + 1; + + if (tic < 0 || node.TicUpdates[tic % BACKUPTICS].received) + return; // We already received the proper packet. } + + NetNode::TicUpdate update; + update.received = true; + packet.stream.ReadBuffer(&update.input, sizeof(usercmd_t)); + node.TicUpdates[tic % BACKUPTICS] = update; } void NetServer::CmdSpawnPlayer(NetNode &node, int player) diff --git a/src/network/netserver.h b/src/network/netserver.h index f37070621a..f2584c2f59 100644 --- a/src/network/netserver.h +++ b/src/network/netserver.h @@ -38,7 +38,13 @@ struct NetNode int Gametic = 0; int Player = -1; - ticcmd_t PlayerMovement; + struct TicUpdate + { + bool received = false; + usercmd_t input; + }; + TicUpdate TicUpdates[BACKUPTICS]; + FDynamicBuffer Commands; // "NetSpecs" }; @@ -49,7 +55,7 @@ public: void Update() override; - void SetCurrentTic(int receivetic, int sendtic) override; + void SetCurrentTic(int tictime) override; void EndCurrentTic() override; int GetSendTick() const override; @@ -70,7 +76,7 @@ public: private: void OnClose(NetNode &node, const NetPacket &packet); - void OnConnectRequest(NetNode &node, const NetPacket &packet); + void OnConnectRequest(NetNode &node, NetPacket &packet); void OnDisconnect(NetNode &node, const NetPacket &packet); void OnTic(NetNode &node, NetPacket &packet); @@ -80,7 +86,6 @@ private: std::unique_ptr mComm; NetNode mNodes[MAXNETNODES]; int mNodeForPlayer[MAXPLAYERS]; - int mSendTic = 0; ticcmd_t mCurrentInput[MAXPLAYERS]; FDynamicBuffer mCurrentCommands; diff --git a/src/network/netsingle.cpp b/src/network/netsingle.cpp index c7ce67947f..9bc337c9fc 100644 --- a/src/network/netsingle.cpp +++ b/src/network/netsingle.cpp @@ -82,10 +82,9 @@ void NetSinglePlayer::Update() { } -void NetSinglePlayer::SetCurrentTic(int receivetic, int sendtic) +void NetSinglePlayer::SetCurrentTic(int tictime) { - gametic = receivetic; - mSendTic = sendtic; + gametic = tictime; } void NetSinglePlayer::EndCurrentTic() @@ -96,7 +95,7 @@ void NetSinglePlayer::EndCurrentTic() int NetSinglePlayer::GetSendTick() const { - return mSendTic; + return gametic; } ticcmd_t NetSinglePlayer::GetPlayerInput(int player) const diff --git a/src/network/netsingle.h b/src/network/netsingle.h index c08dd6b1f8..884abf9794 100644 --- a/src/network/netsingle.h +++ b/src/network/netsingle.h @@ -30,7 +30,7 @@ public: void Update() override; - void SetCurrentTic(int receivetic, int sendtic) override; + void SetCurrentTic(int tictime) override; void EndCurrentTic() override; int GetSendTick() const override; @@ -53,6 +53,5 @@ private: ticcmd_t mCurrentInput[MAXPLAYERS]; FDynamicBuffer mCurrentCommands; - int mSendTic = 0; FDynamicBuffer mSendCommands; }; From b203dddf6ce6f3b28f4fb3d103adb666c303ea13 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Nov 2018 02:01:41 +0100 Subject: [PATCH 33/46] - move the netcommand and bytestream code out of netsync - split byte stream writing from reading - fix duplicate tic commands not getting fully read - force net packet reading and writing to go through streams --- src/CMakeLists.txt | 1 + src/network/i_net.cpp | 44 +- src/network/i_net.h | 49 +-- src/network/net.cpp | 2 +- src/network/netclient.cpp | 70 ++-- src/network/netclient.h | 11 +- src/network/netcommand.cpp | 485 ++++++++++++++++++++++ src/network/netcommand.h | 121 ++++++ src/network/netserver.cpp | 87 ++-- src/network/netserver.h | 12 +- src/network/netsync.cpp | 799 +++---------------------------------- src/network/netsync.h | 177 ++------ 12 files changed, 826 insertions(+), 1032 deletions(-) create mode 100644 src/network/netcommand.cpp create mode 100644 src/network/netcommand.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e85b7cc98..6e2f36fb5b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -902,6 +902,7 @@ set (PCH_SOURCES network/netserver.cpp network/netsync.cpp network/netclient.cpp + network/netcommand.cpp network/i_net.cpp d_netinfo.cpp d_protocol.cpp diff --git a/src/network/i_net.cpp b/src/network/i_net.cpp index 5d2a5abfe4..64bf79f5f2 100644 --- a/src/network/i_net.cpp +++ b/src/network/i_net.cpp @@ -102,8 +102,8 @@ public: DoomComImpl(int port); ~DoomComImpl(); - void PacketSend(const NetPacket &packet) override; - void PacketGet(NetPacket &packet) override; + void PacketSend(const NetOutputPacket &packet) override; + void PacketGet(NetInputPacket &packet) override; int Connect(const char *name) override; void Close(int node) override; @@ -226,28 +226,29 @@ int DoomComImpl::FindNode(const sockaddr_in *address) return slot; } -void DoomComImpl::PacketSend(const NetPacket &packet) +void DoomComImpl::PacketSend(const NetOutputPacket &packet) { - assert(!(packet.data[0] & NCMD_COMPRESSED)); + assert(!(packet.buffer[0] & NCMD_COMPRESSED)); - if (packet.size >= 10) + int packetSize = packet.stream.GetSize() + 1; + if (packetSize >= 10) { - mTransmitBuffer[0] = packet.data[0] | NCMD_COMPRESSED; + mTransmitBuffer[0] = packet.buffer[0] | NCMD_COMPRESSED; uLong size = TRANSMIT_SIZE - 1; - int c = compress2(mTransmitBuffer + 1, &size, packet.data + 1, packet.size - 1, 9); + int c = compress2(mTransmitBuffer + 1, &size, packet.buffer + 1, packetSize - 1, 9); size += 1; - if (c == Z_OK && size < (uLong)packet.size) + if (c == Z_OK && size < (uLong)packetSize) { sendto(mSocket, (char *)mTransmitBuffer, size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); return; } } - if (packet.size <= TRANSMIT_SIZE) + if (packetSize <= TRANSMIT_SIZE) { - sendto(mSocket, (char *)packet.data, packet.size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); + sendto(mSocket, (char *)packet.buffer, packetSize, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node])); } else { @@ -255,7 +256,7 @@ void DoomComImpl::PacketSend(const NetPacket &packet) } } -void DoomComImpl::PacketGet(NetPacket &packet) +void DoomComImpl::PacketGet(NetInputPacket &packet) { // First check if anything timed out. Treat this as a close. uint64_t nowtime = I_nsTime(); @@ -265,8 +266,7 @@ void DoomComImpl::PacketGet(NetPacket &packet) { Close(i); packet.node = i; - packet.size = 0; - packet.stream.pbStreamEnd = packet.stream.pbStream; + packet.stream.SetBuffer(nullptr, 0); return; } } @@ -288,9 +288,7 @@ void DoomComImpl::PacketGet(NetPacket &packet) Close(node); packet.node = node; - packet.size = 0; - packet.stream.pbStream = packet.data; - packet.stream.pbStreamEnd = packet.data + packet.size; + packet.stream.SetBuffer(nullptr, 0); return; } else if (err != WSAEWOULDBLOCK) @@ -300,9 +298,7 @@ void DoomComImpl::PacketGet(NetPacket &packet) else // no packet { packet.node = -1; - packet.size = 0; - packet.stream.pbStream = packet.data; - packet.stream.pbStreamEnd = packet.data + packet.size; + packet.stream.SetBuffer(nullptr, 0); return; } } @@ -312,11 +308,11 @@ void DoomComImpl::PacketGet(NetPacket &packet) if (node == -1) continue; - packet.data[0] = mTransmitBuffer[0] & ~NCMD_COMPRESSED; + packet.buffer[0] = mTransmitBuffer[0] & ~NCMD_COMPRESSED; if ((mTransmitBuffer[0] & NCMD_COMPRESSED) && size > 1) { uLongf msgsize = MAX_MSGLEN - 1; - int err = uncompress(packet.data + 1, &msgsize, mTransmitBuffer + 1, size - 1); + int err = uncompress(packet.buffer + 1, &msgsize, mTransmitBuffer + 1, size - 1); if (err != Z_OK) { Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars()); @@ -326,13 +322,11 @@ void DoomComImpl::PacketGet(NetPacket &packet) } else { - memcpy(packet.data + 1, mTransmitBuffer + 1, size - 1); + memcpy(packet.buffer + 1, mTransmitBuffer + 1, size - 1); } packet.node = node; - packet.size = (short)size; - packet.stream.pbStream = packet.data; - packet.stream.pbStreamEnd = packet.data + packet.size; + packet.stream.SetBuffer(packet.buffer + 1, size - 1); return; } } diff --git a/src/network/i_net.h b/src/network/i_net.h index 72b4670119..88295fe08c 100644 --- a/src/network/i_net.h +++ b/src/network/i_net.h @@ -2,38 +2,41 @@ #pragma once #include -#include "netsync.h" +#include "netcommand.h" #define MAX_MSGLEN 14000 #define DOOMPORT 5029 -struct NetPacket +class NetOutputPacket { - NetPacket() - { - memset(data, 0, sizeof(data)); - stream.pbStream = data; - stream.bitBuffer = NULL; - stream.bitShift = -1; - stream.pbStreamEnd = stream.pbStream + sizeof(data); - } +public: + NetOutputPacket() : stream(buffer + 1, MAX_MSGLEN - 1) { buffer[0] = 0; } - // packet data to be sent - uint8_t data[MAX_MSGLEN]; + int node = 0; + ByteOutputStream stream; - // bytes in data to be sent - int16_t size = 0; +private: + uint8_t buffer[MAX_MSGLEN]; - // dest for send, set by get (-1 = no packet). - int16_t node = 0; + NetOutputPacket(const NetOutputPacket &) = delete; + NetOutputPacket &operator=(const NetOutputPacket &) = delete; + friend class DoomComImpl; +}; - uint8_t &operator[](int i) { return data[i]; } - const uint8_t &operator[](int i) const { return data[i]; } +class NetInputPacket +{ +public: + NetInputPacket() = default; - BYTESTREAM_s stream; + int node = -1; // -1 = no packet available + ByteInputStream stream; - NetPacket(const NetPacket &) = delete; - NetPacket &operator=(const NetPacket &) = delete; +private: + uint8_t buffer[MAX_MSGLEN]; + + NetInputPacket(const NetInputPacket &) = delete; + NetInputPacket &operator=(const NetInputPacket &) = delete; + friend class DoomComImpl; }; // Network packet data. @@ -41,8 +44,8 @@ struct doomcom_t { virtual ~doomcom_t() { } - virtual void PacketSend(const NetPacket &packet) = 0; - virtual void PacketGet(NetPacket &packet) = 0; + virtual void PacketSend(const NetOutputPacket &packet) = 0; + virtual void PacketGet(NetInputPacket &packet) = 0; virtual int Connect(const char *name) = 0; virtual void Close(int node) = 0; diff --git a/src/network/net.cpp b/src/network/net.cpp index 46ae18d54b..21fecb0dbd 100644 --- a/src/network/net.cpp +++ b/src/network/net.cpp @@ -124,7 +124,7 @@ CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO | CVAR_NOSAVE) } } -#ifdef _DEBUG +#if 0 CVAR(Int, net_fakelatency, 0, 0); struct PacketStore diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index b043f322fb..b66cd01cf9 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -78,12 +78,12 @@ NetClient::NetClient(FString server) mServerNode = mComm->Connect(server); mStatus = NodeStatus::InPreGame; - NetPacket packet; + NetOutputPacket packet; packet.node = mServerNode; NetCommand cmd ( NetPacketType::ConnectRequest ); cmd.addString("ZDoom Connect Request"); - cmd.writeCommandToPacket ( packet ); + cmd.writeCommandToStream (packet.stream); mComm->PacketSend(packet); } @@ -97,7 +97,7 @@ void NetClient::Update() if ( ( gameaction == ga_newgame ) || ( gameaction == ga_newgame2 ) ) return; - NetPacket packet; + NetInputPacket packet; mComm->PacketGet(packet); if (packet.node == -1) break; @@ -106,29 +106,23 @@ void NetClient::Update() { mComm->Close(packet.node); } - else if (packet.size == 0) + else if (packet.stream.IsAtEnd()) { - OnClose(packet); + OnClose(); break; } else { - if (packet.stream.ReadByte () != 0) - { - Printf ("Error parsing packet. Unexpected header.\n"); - break; - } - while ( packet.stream.IsAtEnd() == false ) { NetPacketType type = (NetPacketType)packet.stream.ReadByte(); switch (type) { - default: OnClose(packet); break; - case NetPacketType::ConnectResponse: OnConnectResponse(packet); break; - case NetPacketType::Disconnect: OnDisconnect(packet); break; - case NetPacketType::Tic: OnTic(packet); break; - case NetPacketType::SpawnPlayer: OnSpawnPlayer(packet); break; + default: OnClose(); break; + case NetPacketType::ConnectResponse: OnConnectResponse(packet.stream); break; + case NetPacketType::Disconnect: OnDisconnect(); break; + case NetPacketType::Tic: OnTic(packet.stream); break; + case NetPacketType::SpawnPlayer: OnSpawnPlayer(packet.stream); break; } } break; @@ -184,13 +178,13 @@ void NetClient::EndCurrentTic() int targettic = (mSendTic + mServerTicDelta); - NetPacket packet; + NetOutputPacket packet; packet.node = mServerNode; NetCommand cmd ( NetPacketType::Tic ); cmd.addByte (targettic); // target gametic cmd.addBuffer ( &mSentInput[(mSendTic - 1) % BACKUPTICS].ucmd, sizeof(usercmd_t) ); - cmd.writeCommandToPacket ( packet ); + cmd.writeCommandToStream ( packet.stream ); mComm->PacketSend(packet); @@ -264,7 +258,7 @@ void NetClient::Network_Controller(int playernum, bool add) { } -void NetClient::OnClose(const NetPacket &packet) +void NetClient::OnClose() { mComm->Close(mServerNode); mServerNode = -1; @@ -280,13 +274,13 @@ void NetClient::OnClose(const NetPacket &packet) } } -void NetClient::OnConnectResponse(NetPacket &packet) +void NetClient::OnConnectResponse(ByteInputStream &stream) { - int version = packet.stream.ReadByte(); // Protocol version + int version = stream.ReadByte(); // Protocol version if (version == 1) { - int playernum = packet.stream.ReadByte(); - if (playernum != 255) // Join accepted + int playernum = stream.ReadByte(); + if (playernum > 0 && playernum < MAXPLAYERS) // Join accepted { mPlayer = playernum; mStatus = NodeStatus::InGame; @@ -313,9 +307,9 @@ void NetClient::OnConnectResponse(NetPacket &packet) } } -void NetClient::OnDisconnect(const NetPacket &packet) +void NetClient::OnDisconnect() { - mComm->Close(packet.node); + mComm->Close(mServerNode); mServerNode = -1; mStatus = NodeStatus::Closed; } @@ -336,31 +330,31 @@ void NetClient::UpdateLastReceivedTic(int tic) mLastReceivedTic = MAX(mLastReceivedTic, 0); } -void NetClient::OnTic(NetPacket &packet) +void NetClient::OnTic(ByteInputStream &stream) { - UpdateLastReceivedTic(packet.stream.ReadByte()); + UpdateLastReceivedTic(stream.ReadByte()); TicUpdate update; update.received = true; - update.x = packet.stream.ReadFloat(); - update.y = packet.stream.ReadFloat(); - update.z = packet.stream.ReadFloat(); - update.yaw = packet.stream.ReadFloat(); - update.pitch = packet.stream.ReadFloat(); + update.x = stream.ReadFloat(); + update.y = stream.ReadFloat(); + update.z = stream.ReadFloat(); + update.yaw = stream.ReadFloat(); + update.pitch = stream.ReadFloat(); mTicUpdates[mLastReceivedTic % BACKUPTICS] = update; } -void NetClient::OnSpawnPlayer(NetPacket &packet) +void NetClient::OnSpawnPlayer(ByteInputStream &stream) { // To do: this needs a tic and should be inserted in mTicUpdates. // Otherwise it might not arrive at the intended moment in time. - int player = packet.stream.ReadByte(); - const float x = packet.stream.ReadFloat(); - const float y = packet.stream.ReadFloat(); - const float z = packet.stream.ReadFloat(); - const int16_t netID = packet.stream.ReadShort(); + int player = stream.ReadByte(); + const float x = stream.ReadFloat(); + const float y = stream.ReadFloat(); + const float z = stream.ReadFloat(); + const int16_t netID = stream.ReadShort(); AActor *oldNetActor = g_NetIDList.findPointerByID ( netID ); diff --git a/src/network/netclient.h b/src/network/netclient.h index 6295280bb5..932f94a704 100644 --- a/src/network/netclient.h +++ b/src/network/netclient.h @@ -22,6 +22,7 @@ #pragma once #include "netserver.h" +#include "netcommand.h" class NetClient : public Network { @@ -50,11 +51,11 @@ public: void Network_Controller(int playernum, bool add) override; private: - void OnClose(const NetPacket &packet); - void OnConnectResponse(NetPacket &packet); - void OnDisconnect(const NetPacket &packet); - void OnTic(NetPacket &packet); - void OnSpawnPlayer(NetPacket &packet); + void OnClose(); + void OnConnectResponse(ByteInputStream &stream); + void OnDisconnect(); + void OnTic(ByteInputStream &stream); + void OnSpawnPlayer(ByteInputStream &stream); void UpdateLastReceivedTic(int tic); diff --git a/src/network/netcommand.cpp b/src/network/netcommand.cpp new file mode 100644 index 0000000000..b74f07ff92 --- /dev/null +++ b/src/network/netcommand.cpp @@ -0,0 +1,485 @@ +//----------------------------------------------------------------------------- +// +// Copyright 2018 Benjamin Berkels +// +// 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 "d_player.h" +#include "netcommand.h" +#include "i_net.h" + +extern bool netserver, netclient; + +// [BB] Are we measuring outbound traffic? +static bool g_MeasuringOutboundTraffic = false; +// [BB] Number of bytes sent by NETWORK_Write* since NETWORK_StartTrafficMeasurement() was called. +static int g_OutboundBytesMeasured = 0; + +//***************************************************************************** + +ByteOutputStream::ByteOutputStream(void *buffer, int size) +{ + SetBuffer(buffer, size); +} + +void ByteOutputStream::SetBuffer(void *buffer, int size) +{ + mData = (uint8_t*)buffer; + pbStream = mData; + pbStreamEnd = pbStream + size; + bitBuffer = nullptr; + bitShift = -1; +} + +void ByteOutputStream::AdvancePointer(const int NumBytes, const bool OutboundTraffic) +{ + pbStream += NumBytes; + + if (g_MeasuringOutboundTraffic && OutboundTraffic) + g_OutboundBytesMeasured += NumBytes; +} + +void ByteOutputStream::WriteByte(int Byte) +{ + if ((pbStream + 1) > pbStreamEnd) + { + Printf("ByteOutputStream::WriteByte: Overflow!\n"); + return; + } + + *pbStream = Byte; + + // Advance the pointer. + AdvancePointer(1, true); +} + +void ByteOutputStream::WriteShort(int Short) +{ + if ((pbStream + 2) > pbStreamEnd) + { + Printf("NETWORK_WriteShort: Overflow!\n"); + return; + } + + pbStream[0] = Short & 0xff; + pbStream[1] = Short >> 8; + + // Advance the pointer. + AdvancePointer(2, true); +} + +void ByteOutputStream::WriteLong(int Long) +{ + if ((pbStream + 4) > pbStreamEnd) + { + Printf("NETWORK_WriteLong: Overflow!\n"); + return; + } + + pbStream[0] = Long & 0xff; + pbStream[1] = (Long >> 8) & 0xff; + pbStream[2] = (Long >> 16) & 0xff; + pbStream[3] = (Long >> 24); + + // Advance the pointer. + AdvancePointer(4, true); +} + +void ByteOutputStream::WriteFloat(float Float) +{ + union + { + float f; + int l; + } dat; + + dat.f = Float; + + WriteLong(dat.l); +} + +void ByteOutputStream::WriteString(const char *pszString) +{ + if ((pszString) && (strlen(pszString) > MAX_NETWORK_STRING)) + { + Printf("ByteOutputStream::WriteString: String exceeds %d characters!\n", MAX_NETWORK_STRING); + return; + } + + if (pszString) + WriteBuffer("", 1); + else + WriteBuffer(pszString, (int)(strlen(pszString)) + 1); +} + +void ByteOutputStream::WriteBuffer(const void *pvBuffer, int nLength) +{ + if ((pbStream + nLength) > pbStreamEnd) + { + Printf("NETWORK_WriteLBuffer: Overflow!\n"); + return; + } + + memcpy(pbStream, pvBuffer, nLength); + + // Advance the pointer. + AdvancePointer(nLength, true); +} + +void ByteOutputStream::WriteBit(bool bit) +{ + // Add a bit to this byte + EnsureBitSpace(1, true); + if (bit) + *bitBuffer |= 1 << bitShift; + ++bitShift; +} + +void ByteOutputStream::WriteVariable(int value) +{ + int length; + + // Determine how long we need to send this value + if (value == 0) + length = 0; // 0 - don't bother sending it at all + else if ((value <= 0xFF) && (value >= 0)) + length = 1; // Can be sent as a byte + else if ((value <= 0x7FFF) && (value >= -0x8000)) + length = 2; // Can be sent as a short + else + length = 3; // Must be sent as a long + + // Write this length as two bits + WriteBit(!!(length & 1)); + WriteBit(!!(length & 2)); + + // Depending on the required length, write the value. + switch (length) + { + case 1: WriteByte(value); break; + case 2: WriteShort(value); break; + case 3: WriteLong(value); break; + } +} + +void ByteOutputStream::WriteShortByte(int value, int bits) +{ + if ((bits < 1) || (bits > 8)) + { + Printf("NETWORK_WriteShortByte: bits must be within range [1..8], got %d.\n", bits); + return; + } + + EnsureBitSpace(bits, true); + value &= ((1 << bits) - 1); // Form a mask from the bits and trim our value using it. + value <<= bitShift; // Shift the value to its proper position. + *bitBuffer |= value; // Add it to the byte. + bitShift += bits; // Bump the shift value accordingly. +} + +void ByteOutputStream::EnsureBitSpace(int bits, bool writing) +{ + if ((bitBuffer == nullptr) || (bitShift < 0) || (bitShift + bits > 8)) + { + // Not enough bits left in our current byte, we need a new one. + WriteByte(0); + bitBuffer = pbStream - 1; + + bitShift = 0; + } +} + +//***************************************************************************** + +ByteInputStream::ByteInputStream(const void *buffer, int size) +{ + SetBuffer(buffer, size); +} + +void ByteInputStream::SetBuffer(const void *buffer, int size) +{ + mData = (uint8_t*)buffer; + pbStream = mData; + pbStreamEnd = pbStream + size; + bitBuffer = nullptr; + bitShift = -1; +} + +int ByteInputStream::ReadByte() +{ + int Byte = -1; + + if ((pbStream + 1) <= pbStreamEnd) + Byte = *pbStream; + + // Advance the pointer. + pbStream += 1; + + return (Byte); +} + +int ByteInputStream::ReadShort() +{ + int Short = -1; + + if ((pbStream + 2) <= pbStreamEnd) + Short = (short)((pbStream[0]) + (pbStream[1] << 8)); + + // Advance the pointer. + pbStream += 2; + + return (Short); +} + +int ByteInputStream::ReadLong() +{ + int Long = -1; + + if ((pbStream + 4) <= pbStreamEnd) + { + Long = ((pbStream[0]) + (pbStream[1] << 8) + (pbStream[2] << 16) + (pbStream[3] << 24)); + } + + // Advance the pointer. + pbStream += 4; + + return (Long); +} + +float ByteInputStream::ReadFloat() +{ + union + { + float f; + int i; + } dat; + + dat.i = ReadLong(); + return (dat.f); +} + +const char *ByteInputStream::ReadString() +{ + int c; + static char s_szString[MAX_NETWORK_STRING]; + + // Read in characters until we've reached the end of the string. + unsigned int ulIdx = 0; + do + { + c = ReadByte(); + if (c <= 0) + break; + + // Place this character into our string. + // [BB] Even if we don't have enough space in s_szString, we have to fully + // parse the received string. Otherwise we can't continue parsing the packet. + if (ulIdx < MAX_NETWORK_STRING - 1) + s_szString[ulIdx] = static_cast (c); + + ++ulIdx; + + } while (true); + + // [BB] We may have read more chars than we can store. + const int endIndex = (ulIdx < MAX_NETWORK_STRING) ? ulIdx : MAX_NETWORK_STRING - 1; + s_szString[endIndex] = '\0'; + return (s_szString); +} + +bool ByteInputStream::ReadBit() +{ + EnsureBitSpace(1, false); + + // Use a bit shift to extract a bit from our current byte + bool result = !!(*bitBuffer & (1 << bitShift)); + bitShift++; + return result; +} + +int ByteInputStream::ReadVariable() +{ + // Read two bits to form an integer 0...3 + int length = ReadBit(); + length |= ReadBit() << 1; + + // Use this length to read in an integer of variable length. + switch (length) + { + default: + case 0: return 0; + case 1: return ReadByte(); + case 2: return ReadShort(); + case 3: return ReadLong(); + } +} + +int ByteInputStream::ReadShortByte(int bits) +{ + if (bits >= 0 && bits <= 8) + { + EnsureBitSpace(bits, false); + int mask = (1 << bits) - 1; // Create a mask to cover the bits we want. + mask <<= bitShift; // Shift the mask so that it covers the correct bits. + int result = *bitBuffer & mask; // Apply the shifted mask on our byte to remove unwanted bits. + result >>= bitShift; // Shift the result back to start from 0. + bitShift += bits; // Increase shift to mark these bits as used. + return result; + } + else + { + return 0; + } +} + +void ByteInputStream::ReadBuffer(void *buffer, size_t length) +{ + if ((pbStream + length) > pbStreamEnd) + { + Printf("ByteInputStream::ReadBuffer: Overflow!\n"); + } + else + { + memcpy(buffer, pbStream, length); + pbStream += length; + } +} + +bool ByteInputStream::IsAtEnd() const +{ + return (pbStream >= pbStreamEnd); +} + +void ByteInputStream::EnsureBitSpace(int bits, bool writing) +{ + if ((bitBuffer == nullptr) || (bitShift < 0) || (bitShift + bits > 8)) + { + // No room for the value in this byte, so we need a new one. + if (ReadByte() != -1) + { + bitBuffer = pbStream - 1; + } + else + { + // Argh! No bytes left! + Printf("ByteInputStream::EnsureBitSpace: out of bytes to use\n"); + static uint8_t fallback = 0; + bitBuffer = &fallback; + } + + bitShift = 0; + } +} + +//***************************************************************************** + +NetCommand::NetCommand(const NetPacketType Header) +{ + // To do: improve memory handling here. 8 kb per command is very wasteful + mBuffer = std::make_shared(MAX_UDP_PACKET); + mStream.SetBuffer(mBuffer->data, mBuffer->size); + + addByte(static_cast(Header)); +} + +void NetCommand::addInteger(const int IntValue, const int Size) +{ + for (int i = 0; i < Size; ++i) + mStream.WriteByte((IntValue >> (8 * i)) & 0xff); +} + +void NetCommand::addByte(const int ByteValue) +{ + addInteger(static_cast (ByteValue), sizeof(uint8_t)); +} + +void NetCommand::addShort(const int ShortValue) +{ + addInteger(static_cast (ShortValue), sizeof(int16_t)); +} + +void NetCommand::addLong(const int32_t LongValue) +{ + addInteger(LongValue, sizeof(int32_t)); +} + +void NetCommand::addFloat(const float FloatValue) +{ + union + { + float f; + int32_t l; + } dat; + dat.f = FloatValue; + addInteger(dat.l, sizeof(int32_t)); +} + +void NetCommand::addBit(const bool value) +{ + mStream.WriteBit(value); +} + +void NetCommand::addVariable(const int value) +{ + mStream.WriteVariable(value); +} + +void NetCommand::addShortByte(int value, int bits) +{ + mStream.WriteShortByte(value, bits); +} + +void NetCommand::addString(const char *pszString) +{ + const int len = (pszString != nullptr) ? (int)strlen(pszString) : 0; + + if (len > MAX_NETWORK_STRING) + { + Printf("NETWORK_WriteString: String exceeds %d characters! Header: %d\n", MAX_NETWORK_STRING, static_cast(mStream.GetData())[0]); + return; + } + + for (int i = 0; i < len; ++i) + addByte(pszString[i]); + addByte(0); +} + +void NetCommand::addName(FName name) +{ + if (name.IsPredefined()) + { + addShort(name); + } + else + { + addShort(-1); + addString(name); + } +} + +void NetCommand::addBuffer(const void *pvBuffer, int nLength) +{ + mStream.WriteBuffer(pvBuffer, nLength); +} + +void NetCommand::writeCommandToStream(ByteOutputStream &stream) const +{ + stream.WriteBuffer(mStream.GetData(), mStream.GetSize()); +} + +int NetCommand::getSize() const +{ + return mStream.GetSize(); +} diff --git a/src/network/netcommand.h b/src/network/netcommand.h new file mode 100644 index 0000000000..32c8226eda --- /dev/null +++ b/src/network/netcommand.h @@ -0,0 +1,121 @@ + +#pragma once + +#include "vectors.h" +#include "r_data/renderstyle.h" + +// Maximum size of the packets sent out by the server. +#define MAX_UDP_PACKET 8192 + +// This is the longest possible string we can pass over the network. +#define MAX_NETWORK_STRING 2048 + +enum class NetPacketType +{ + ConnectRequest, + ConnectResponse, + Disconnect, + Tic, + SpawnPlayer +}; + +class ByteInputStream +{ +public: + ByteInputStream() = default; + ByteInputStream(const void *buffer, int size); + + void SetBuffer(const void *buffer, int size); + + int ReadByte(); + int ReadShort(); + int ReadLong(); + float ReadFloat(); + const char* ReadString(); + bool ReadBit(); + int ReadVariable(); + int ReadShortByte(int bits); + void ReadBuffer(void* buffer, size_t length); + + bool IsAtEnd() const; + +private: + void EnsureBitSpace(int bits, bool writing); + + uint8_t *mData = nullptr; // Pointer to our stream of data + uint8_t *pbStream; // Cursor position for next read. + uint8_t *pbStreamEnd; // Pointer to the end of the stream. When pbStream >= pbStreamEnd, the entire stream has been read. + + uint8_t *bitBuffer = nullptr; + int bitShift = -1; +}; + +class ByteOutputStream +{ +public: + ByteOutputStream() = default; + ByteOutputStream(void *buffer, int size); + + void SetBuffer(void *buffer, int size); + + void WriteByte(int Byte); + void WriteShort(int Short); + void WriteLong(int Long); + void WriteFloat(float Float); + void WriteString(const char *pszString); + void WriteBit(bool bit); + void WriteVariable(int value); + void WriteShortByte(int value, int bits); + void WriteBuffer(const void *pvBuffer, int nLength); + + const void *GetData() const { return mData; } + int GetSize() const { return (int)(ptrdiff_t)(pbStream - mData); } + +private: + void AdvancePointer(const int NumBytes, const bool OutboundTraffic); + void EnsureBitSpace(int bits, bool writing); + + uint8_t *mData = nullptr; // Pointer to our stream of data + uint8_t *pbStream; // Cursor position for next write + uint8_t *pbStreamEnd; // Pointer to the end of the data buffer + + uint8_t *bitBuffer = nullptr; + int bitShift = -1; +}; + +/** + * \author Benjamin Berkels + */ +class NetCommand +{ + struct DataBuffer + { + DataBuffer(int size) : data(new uint8_t[size]), size(size) { } + ~DataBuffer() { delete[] data; } + + uint8_t *data; + int size; + }; + std::shared_ptr mBuffer; + ByteOutputStream mStream; + bool mUnreliable = false; + +public: + NetCommand ( const NetPacketType Header ); + + void addInteger( const int IntValue, const int Size ); + void addByte ( const int ByteValue ); + void addShort ( const int ShortValue ); + void addLong ( const int32_t LongValue ); + void addFloat ( const float FloatValue ); + void addString ( const char *pszString ); + void addName ( FName name ); + void addBit ( const bool value ); + void addVariable ( const int value ); + void addShortByte ( int value, int bits ); + void addBuffer ( const void *pvBuffer, int nLength ); + void writeCommandToStream ( ByteOutputStream &stream ) const; + bool isUnreliable() const { return mUnreliable; } + void setUnreliable(bool a) { mUnreliable = a; } + int getSize() const; +}; diff --git a/src/network/netserver.cpp b/src/network/netserver.cpp index f490cf1f44..149829adda 100644 --- a/src/network/netserver.cpp +++ b/src/network/netserver.cpp @@ -69,6 +69,9 @@ NetServer::NetServer() { Printf("Started hosting multiplayer game..\n"); + for (int i = 0; i < MAXNETNODES; i++) + mNodes[i].NodeIndex = i; + mComm = I_InitNetwork(DOOMPORT); G_InitServerNetGame("e1m1"); @@ -79,34 +82,28 @@ void NetServer::Update() // Read all packets currently available from clients while (true) { - NetPacket packet; + NetInputPacket packet; mComm->PacketGet(packet); if (packet.node == -1) break; // No more packets. We are done. NetNode &node = mNodes[packet.node]; - if (packet.size == 0) // Connection to node closed (timed out) + if (packet.stream.IsAtEnd()) // Connection to node closed (timed out) { - OnClose(node, packet); + OnClose(node, packet.stream); } else { - if (packet.stream.ReadByte () != 0) - { - Printf ("Error parsing packet. Unexpected header.\n"); - break; - } - - while ( packet.stream.IsAtEnd() == false ) + while (packet.stream.IsAtEnd() == false) { NetPacketType type = (NetPacketType)packet.stream.ReadByte(); 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; + default: OnClose(node, packet.stream); break; + case NetPacketType::ConnectRequest: OnConnectRequest(node, packet.stream); break; + case NetPacketType::Disconnect: OnDisconnect(node, packet.stream); break; + case NetPacketType::Tic: OnTic(node, packet.stream); break; } } } @@ -138,7 +135,7 @@ void NetServer::EndCurrentTic() { if (mNodes[i].Status == NodeStatus::InGame) { - NetPacket packet; + NetOutputPacket packet; packet.node = i; NetCommand cmd ( NetPacketType::Tic); @@ -161,8 +158,8 @@ void NetServer::EndCurrentTic() cmd.addFloat ( 0.0f ); cmd.addFloat ( 0.0f ); } - cmd.writeCommandToPacket ( packet ); + cmd.writeCommandToStream(packet.stream); mComm->PacketSend(packet); } } @@ -232,7 +229,7 @@ void NetServer::Network_Controller(int playernum, bool add) { } -void NetServer::OnClose(NetNode &node, const NetPacket &packet) +void NetServer::OnClose(NetNode &node, ByteInputStream &stream) { if (node.Status == NodeStatus::InGame) { @@ -244,13 +241,13 @@ void NetServer::OnClose(NetNode &node, const NetPacket &packet) } node.Status = NodeStatus::Closed; - mComm->Close(packet.node); + mComm->Close(node.NodeIndex); } -void NetServer::OnConnectRequest(NetNode &node, NetPacket &packet) +void NetServer::OnConnectRequest(NetNode &node, ByteInputStream &stream) { // Make the initial connect packet a bit more complex than a bunch of zeros.. - if (strcmp(packet.stream.ReadString(), "ZDoom Connect Request") != 0) + if (strcmp(stream.ReadString(), "ZDoom Connect Request") != 0) { if (node.Status == NodeStatus::InGame) { @@ -259,7 +256,7 @@ void NetServer::OnConnectRequest(NetNode &node, NetPacket &packet) else { node.Status = NodeStatus::Closed; - mComm->Close(packet.node); + mComm->Close(node.NodeIndex); return; } } @@ -285,18 +282,18 @@ void NetServer::OnConnectRequest(NetNode &node, NetPacket &packet) node.TicUpdates[i].received = false; node.Status = NodeStatus::InGame; - mNodeForPlayer[node.Player] = packet.node; + mNodeForPlayer[node.Player] = node.NodeIndex; playeringame[node.Player] = true; players[node.Player].settings_controller = false; - NetPacket response; - response.node = packet.node; + NetOutputPacket response; + response.node = node.NodeIndex; NetCommand cmd ( NetPacketType::ConnectResponse ); cmd.addByte ( 1 ); // Protocol version cmd.addByte ( node.Player ); - cmd.writeCommandToPacket ( response ); + cmd.writeCommandToStream ( response.stream ); mComm->PacketSend(response); @@ -306,22 +303,22 @@ void NetServer::OnConnectRequest(NetNode &node, NetPacket &packet) { node.Status = NodeStatus::Closed; - NetPacket response; - response.node = packet.node; + NetOutputPacket response; + response.node = node.NodeIndex; NetCommand cmd ( NetPacketType::ConnectResponse ); cmd.addByte ( 1 ); // Protocol version cmd.addByte ( 255 ); - cmd.writeCommandToPacket ( response ); + cmd.writeCommandToStream (response.stream); mComm->PacketSend(response); node.Status = NodeStatus::Closed; - mComm->Close(packet.node); + mComm->Close(node.NodeIndex); } } -void NetServer::OnDisconnect(NetNode &node, const NetPacket &packet) +void NetServer::OnDisconnect(NetNode &node, ByteInputStream &stream) { if (node.Status == NodeStatus::InGame) { @@ -333,21 +330,24 @@ void NetServer::OnDisconnect(NetNode &node, const NetPacket &packet) } node.Status = NodeStatus::Closed; - mComm->Close(packet.node); + mComm->Close(node.NodeIndex); } -void NetServer::OnTic(NetNode &node, NetPacket &packet) +void NetServer::OnTic(NetNode &node, ByteInputStream &stream) { if (node.Status != NodeStatus::InGame) return; - int tic = packet.stream.ReadByte(); - + int tic = stream.ReadByte(); int delta = tic - (gametic & 0xff); if (delta > 128) delta -= 256; else if (delta < -128) delta += 256; tic = gametic + delta; + NetNode::TicUpdate update; + update.received = true; + stream.ReadBuffer(&update.input, sizeof(usercmd_t)); + if (tic <= gametic) { // Packet arrived too late. @@ -357,30 +357,25 @@ void NetServer::OnTic(NetNode &node, NetPacket &packet) return; // We already received the proper packet. } - NetNode::TicUpdate update; - update.received = true; - packet.stream.ReadBuffer(&update.input, sizeof(usercmd_t)); node.TicUpdates[tic % BACKUPTICS] = update; } -void NetServer::CmdSpawnPlayer(NetNode &node, int player) +void NetServer::CmdSpawnPlayer(ByteOutputStream &stream, int player) { - // TODO: This shouldn't be one packet per command. - NetPacket packet; - packet.node = (int)(ptrdiff_t)(&node-mNodes); NetCommand cmd ( NetPacketType::SpawnPlayer ); cmd.addByte ( player ); cmd.addFloat ( static_cast ( players[player].mo->X() ) ); cmd.addFloat ( static_cast ( players[player].mo->Y() ) ); cmd.addFloat ( static_cast ( players[player].mo->Z() ) ); cmd.addShort ( players[player].mo->syncdata.NetID ); - cmd.writeCommandToPacket ( packet ); - - mComm->PacketSend(packet); + cmd.writeCommandToStream ( stream ); } void NetServer::FullUpdate(NetNode &node) { + NetOutputPacket packet; + packet.node = node.NodeIndex; + // Inform the client about all players already in the game. for ( int i = 0; i < MAXPLAYERNAME; ++i ) { @@ -388,6 +383,8 @@ void NetServer::FullUpdate(NetNode &node) continue; if ( playeringame[i] == true ) - CmdSpawnPlayer(node, i); + CmdSpawnPlayer(packet.stream, i); } + + mComm->PacketSend(packet); } diff --git a/src/network/netserver.h b/src/network/netserver.h index f2584c2f59..3d3ac200f1 100644 --- a/src/network/netserver.h +++ b/src/network/netserver.h @@ -22,6 +22,7 @@ #pragma once #include "net.h" +#include "netcommand.h" enum class NodeStatus { @@ -37,6 +38,7 @@ struct NetNode int Ping = 0; int Gametic = 0; int Player = -1; + int NodeIndex = -1; struct TicUpdate { @@ -75,12 +77,12 @@ public: void Network_Controller(int playernum, bool add) override; private: - void OnClose(NetNode &node, const NetPacket &packet); - void OnConnectRequest(NetNode &node, NetPacket &packet); - void OnDisconnect(NetNode &node, const NetPacket &packet); - void OnTic(NetNode &node, NetPacket &packet); + void OnClose(NetNode &node, ByteInputStream &stream); + void OnConnectRequest(NetNode &node, ByteInputStream &stream); + void OnDisconnect(NetNode &node, ByteInputStream &stream); + void OnTic(NetNode &node, ByteInputStream &packet); - void CmdSpawnPlayer(NetNode &node, int player); + void CmdSpawnPlayer(ByteOutputStream &stream, int player); void FullUpdate(NetNode &node); std::unique_ptr mComm; diff --git a/src/network/netsync.cpp b/src/network/netsync.cpp index 873ec37b5f..e13dbb2b47 100644 --- a/src/network/netsync.cpp +++ b/src/network/netsync.cpp @@ -25,708 +25,35 @@ extern bool netserver, netclient; -//***************************************************************************** -// VARIABLES - -// [BB] Are we measuring outbound traffic? -static bool g_MeasuringOutboundTraffic = false; -// [BB] Number of bytes sent by NETWORK_Write* since NETWORK_StartTrafficMeasurement() was called. -static int g_OutboundBytesMeasured = 0; - IDList g_NetIDList; -//***************************************************************************** -// -void BYTESTREAM_s::AdvancePointer( const int NumBytes, const bool OutboundTraffic ) +void NetSyncData::AssignNetID(AActor *pActor) { - this->pbStream += NumBytes; - - if ( g_MeasuringOutboundTraffic && OutboundTraffic ) - g_OutboundBytesMeasured += NumBytes; -} - -//***************************************************************************** -// -int BYTESTREAM_s::ReadByte() -{ - int Byte = -1; - - if (( this->pbStream + 1 ) <= this->pbStreamEnd ) - Byte = *this->pbStream; - - // Advance the pointer. - this->pbStream += 1; - - return ( Byte ); -} - -//***************************************************************************** -// -int BYTESTREAM_s::ReadShort() -{ - int Short = -1; - - if (( this->pbStream + 2 ) <= this->pbStreamEnd ) - Short = (short)(( this->pbStream[0] ) + ( this->pbStream[1] << 8 )); - - // Advance the pointer. - this->pbStream += 2; - - return ( Short ); -} - -//***************************************************************************** -// -int BYTESTREAM_s::ReadLong() -{ - int Long = -1; - - if (( this->pbStream + 4 ) <= this->pbStreamEnd ) + if (netserver) { - Long = (( this->pbStream[0] ) - + ( this->pbStream[1] << 8 ) - + ( this->pbStream[2] << 16 ) - + ( this->pbStream[3] << 24 )); - } - - // Advance the pointer. - this->pbStream += 4; - - return ( Long ); -} - -//***************************************************************************** -// -float BYTESTREAM_s::ReadFloat() -{ - union - { - float f; - int i; - } dat; - - dat.i = this->ReadLong(); - return ( dat.f ); -} - -//***************************************************************************** -// -const char *BYTESTREAM_s::ReadString() -{ - int c; - static char s_szString[MAX_NETWORK_STRING]; - - // Read in characters until we've reached the end of the string. - unsigned int ulIdx = 0; - do - { - c = this->ReadByte(); - if ( c <= 0 ) - break; - - // Place this character into our string. - // [BB] Even if we don't have enough space in s_szString, we have to fully - // parse the received string. Otherwise we can't continue parsing the packet. - if ( ulIdx < MAX_NETWORK_STRING - 1 ) - s_szString[ulIdx] = static_cast ( c ); - - ++ulIdx; - - } while ( true ); - - // [BB] We may have read more chars than we can store. - const int endIndex = ( ulIdx < MAX_NETWORK_STRING ) ? ulIdx : MAX_NETWORK_STRING - 1; - s_szString[endIndex] = '\0'; - return ( s_szString ); -} - -//***************************************************************************** -// -bool BYTESTREAM_s::ReadBit() -{ - this->EnsureBitSpace( 1, false ); - - // Use a bit shift to extract a bit from our current byte - bool result = !!( *this->bitBuffer & ( 1 << this->bitShift )); - this->bitShift++; - return result; -} - -//***************************************************************************** -// -int BYTESTREAM_s::ReadVariable() -{ - // Read two bits to form an integer 0...3 - int length = this->ReadBit(); - length |= this->ReadBit() << 1; - - // Use this length to read in an integer of variable length. - switch ( length ) - { - default: - case 0: return 0; - case 1: return this->ReadByte(); - case 2: return this->ReadShort(); - case 3: return this->ReadLong(); - } -} - -//***************************************************************************** -// -int BYTESTREAM_s::ReadShortByte ( int bits ) -{ - if ( bits >= 0 && bits <= 8 ) - { - this->EnsureBitSpace( bits, false ); - int mask = ( 1 << bits ) - 1; // Create a mask to cover the bits we want. - mask <<= this->bitShift; // Shift the mask so that it covers the correct bits. - int result = *this->bitBuffer & mask; // Apply the shifted mask on our byte to remove unwanted bits. - result >>= this->bitShift; // Shift the result back to start from 0. - this->bitShift += bits; // Increase shift to mark these bits as used. - return result; - } - else - { - return 0; - } -} - -//***************************************************************************** -// -void BYTESTREAM_s::ReadBuffer( void *buffer, size_t length ) -{ - if (( this->pbStream + length ) > this->pbStreamEnd ) - { - Printf( "BYTESTREAM_s::ReadBuffer: Overflow!\n" ); - } - else - { - memcpy( buffer, this->pbStream, length ); - this->pbStream += length; - } -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteByte( int Byte ) -{ - if (( this->pbStream + 1 ) > this->pbStreamEnd ) - { - Printf( "BYTESTREAM_s::WriteByte: Overflow!\n" ); - return; - } - - *this->pbStream = Byte; - - // Advance the pointer. - this->AdvancePointer ( 1, true ); -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteShort( int Short ) -{ - if (( this->pbStream + 2 ) > this->pbStreamEnd ) - { - Printf( "NETWORK_WriteShort: Overflow!\n" ); - return; - } - - this->pbStream[0] = Short & 0xff; - this->pbStream[1] = Short >> 8; - - // Advance the pointer. - this->AdvancePointer ( 2, true ); -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteLong( int Long ) -{ - if (( this->pbStream + 4 ) > this->pbStreamEnd ) - { - Printf( "NETWORK_WriteLong: Overflow!\n" ); - return; - } - - this->pbStream[0] = Long & 0xff; - this->pbStream[1] = ( Long >> 8 ) & 0xff; - this->pbStream[2] = ( Long >> 16 ) & 0xff; - this->pbStream[3] = ( Long >> 24 ); - - // Advance the pointer. - this->AdvancePointer ( 4, true ); -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteFloat( float Float ) -{ - union - { - float f; - int l; - } dat; - - dat.f = Float; - - this->WriteLong( dat.l ); -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteString( const char *pszString ) -{ - if (( pszString ) && ( strlen( pszString ) > MAX_NETWORK_STRING )) - { - Printf( "BYTESTREAM_s::WriteString: String exceeds %d characters!\n", MAX_NETWORK_STRING ); - return; - } - -#ifdef WIN32 - if ( pszString == NULL ) - this->WriteBuffer( "", 1 ); - else - this->WriteBuffer( pszString, (int)( strlen( pszString )) + 1 ); -#else - if ( pszString == NULL ) - this->WriteByte( 0 ); - else - { - this->WriteBuffer( pszString, strlen( pszString )); - this->WriteByte( 0 ); - } -#endif -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteBuffer( const void *pvBuffer, int nLength ) -{ - if (( this->pbStream + nLength ) > this->pbStreamEnd ) - { - Printf( "NETWORK_WriteLBuffer: Overflow!\n" ); - return; - } - - memcpy( this->pbStream, pvBuffer, nLength ); - - // Advance the pointer. - this->AdvancePointer ( nLength, true ); -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteHeader( int Byte ) -{ - this->WriteByte( Byte ); - this->bitBuffer = NULL; - this->bitShift = -1; -} - -//***************************************************************************** -// -bool BYTESTREAM_s::IsAtEnd() const -{ - return ( this->pbStream >= this->pbStreamEnd ); -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteBit( bool bit ) -{ - // Add a bit to this byte - this->EnsureBitSpace( 1, true ); - if ( bit ) - *this->bitBuffer |= 1 << this->bitShift; - ++this->bitShift; -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteVariable( int value ) -{ - int length; - - // Determine how long we need to send this value - if ( value == 0 ) - length = 0; // 0 - don't bother sending it at all - else if (( value <= 0xFF ) && ( value >= 0 )) - length = 1; // Can be sent as a byte - else if (( value <= 0x7FFF ) && ( value >= -0x8000 )) - length = 2; // Can be sent as a short - else - length = 3; // Must be sent as a long - - // Write this length as two bits - this->WriteBit( !!( length & 1 ) ); - this->WriteBit( !!( length & 2 ) ); - - // Depending on the required length, write the value. - switch ( length ) - { - case 1: this->WriteByte( value ); break; - case 2: this->WriteShort( value ); break; - case 3: this->WriteLong( value ); break; - } -} - -//***************************************************************************** -// -void BYTESTREAM_s::WriteShortByte( int value, int bits ) -{ - if (( bits < 1 ) || ( bits > 8 )) - { - Printf( "NETWORK_WriteShortByte: bits must be within range [1..8], got %d.\n", bits ); - return; - } - - this->EnsureBitSpace( bits, true ); - value &= (( 1 << bits ) - 1 ); // Form a mask from the bits and trim our value using it. - value <<= this->bitShift; // Shift the value to its proper position. - *this->bitBuffer |= value; // Add it to the byte. - this->bitShift += bits; // Bump the shift value accordingly. -} - -//***************************************************************************** -// -void NetSyncData::AssignNetID ( AActor *pActor ) -{ - if ( netserver ) - { - NetID = g_NetIDList.getNewID( ); - g_NetIDList.useID ( NetID, pActor ); + NetID = g_NetIDList.getNewID(); + g_NetIDList.useID(NetID, pActor); } else NetID = -1; } -//***************************************************************************** -// -void NetSyncData::FreeNetID ( ) +void NetSyncData::FreeNetID() { - g_NetIDList.freeID ( NetID ); + g_NetIDList.freeID(NetID); } -//***************************************************************************** -// -BYTESTREAM_s::BYTESTREAM_s() : - bitBuffer( NULL ), - bitShift( -1 ) {} - -//***************************************************************************** -// -void BYTESTREAM_s::EnsureBitSpace( int bits, bool writing ) -{ - if ( ( bitBuffer == NULL ) || ( bitShift < 0 ) || ( bitShift + bits > 8 ) ) - { - if ( writing ) - { - // Not enough bits left in our current byte, we need a new one. - WriteByte( 0 ); - bitBuffer = pbStream - 1; - } - else - { - // No room for the value in this byte, so we need a new one. - if ( this->ReadByte() != -1 ) - { - bitBuffer = pbStream - 1; - } - else - { - // Argh! No bytes left! - Printf("BYTESTREAM_s::EnsureBitSpace: out of bytes to use\n"); - static uint8_t fallback = 0; - bitBuffer = &fallback; - } - } - - bitShift = 0; - } -} - -//***************************************************************************** -// -NETBUFFER_s::NETBUFFER_s ( ) -{ - this->pbData = NULL; - this->ulMaxSize = 0; - this->BufferType = (BUFFERTYPE_e)0; - Clear(); -} - -//***************************************************************************** -// -NETBUFFER_s::NETBUFFER_s ( const NETBUFFER_s &Buffer ) -{ - Init ( Buffer.ulMaxSize, Buffer.BufferType ); - Clear(); - - memcpy( this->pbData, Buffer.pbData, Buffer.ulMaxSize ); - this->ByteStream.pbStream = this->pbData + ( Buffer.ByteStream.pbStream - Buffer.pbData ); - this->ByteStream.pbStreamEnd = this->pbData + ( Buffer.ByteStream.pbStreamEnd - Buffer.pbData ); - this->ByteStream.bitShift = Buffer.ByteStream.bitShift; - if ( Buffer.ByteStream.bitBuffer != NULL ) - this->ByteStream.bitBuffer = this->ByteStream.pbStream + ( Buffer.ByteStream.bitBuffer - Buffer.ByteStream.pbStream ); - - this->ulCurrentSize = Buffer.ulCurrentSize; -} - -//***************************************************************************** -// -void NETBUFFER_s::Init( unsigned int ulLength, BUFFERTYPE_e BufferType ) -{ - memset( this, 0, sizeof( *this )); - this->ulMaxSize = ulLength; - this->pbData = new uint8_t[ulLength]; - this->BufferType = BufferType; -} - -//***************************************************************************** -// -void NETBUFFER_s::Free() -{ - if ( this->pbData ) - { - delete[] ( this->pbData ); - this->pbData = NULL; - } - - this->ulMaxSize = 0; - this->BufferType = (BUFFERTYPE_e)0; -} - -//***************************************************************************** -// -void NETBUFFER_s::Clear() -{ - this->ulCurrentSize = 0; - this->ByteStream.pbStream = this->pbData; - this->ByteStream.bitBuffer = NULL; - this->ByteStream.bitShift = -1; - if ( this->BufferType == BUFFERTYPE_READ ) - this->ByteStream.pbStreamEnd = this->ByteStream.pbStream; - else - this->ByteStream.pbStreamEnd = this->ByteStream.pbStream + this->ulMaxSize; -} - -//***************************************************************************** -// -int NETBUFFER_s::CalcSize() const -{ - if ( this->BufferType == BUFFERTYPE_READ ) - return ( int( this->ByteStream.pbStreamEnd - this->ByteStream.pbStream )); - else - return ( int( this->ByteStream.pbStream - this->pbData )); -} - -//***************************************************************************** -// -int NETBUFFER_s::WriteTo( BYTESTREAM_s &ByteStream ) const -{ - int bufferSize = CalcSize(); - if ( bufferSize > 0 ) - ByteStream.WriteBuffer( this->pbData, bufferSize ); - return bufferSize; -} - -//***************************************************************************** -// -NetCommand::NetCommand ( const NetPacketType Header ) : - _unreliable( false ) -{ - _buffer.Init( MAX_UDP_PACKET, BUFFERTYPE_WRITE ); - _buffer.Clear(); - addByte( static_cast(Header) ); -} - -//***************************************************************************** -// -NetCommand::~NetCommand ( ) -{ - _buffer.Free(); -} - -//***************************************************************************** -// -void NetCommand::addInteger( const int IntValue, const int Size ) -{ - if ( ( _buffer.ByteStream.pbStream + Size ) > _buffer.ByteStream.pbStreamEnd ) - { - Printf( "NetCommand::AddInteger: Overflow! Header: %d\n", _buffer.pbData[0] ); - return; - } - - for ( int i = 0; i < Size; ++i ) - _buffer.ByteStream.pbStream[i] = ( IntValue >> ( 8*i ) ) & 0xff; - - _buffer.ByteStream.pbStream += Size; - _buffer.ulCurrentSize = _buffer.CalcSize(); -} - -//***************************************************************************** -// -void NetCommand::addByte ( const int ByteValue ) -{ - addInteger( static_cast ( ByteValue ), sizeof( uint8_t ) ); -} - -//***************************************************************************** -// -void NetCommand::addShort ( const int ShortValue ) -{ - addInteger( static_cast ( ShortValue ), sizeof( int16_t ) ); -} - -//***************************************************************************** -// -void NetCommand::addLong ( const int32_t LongValue ) -{ - addInteger( LongValue, sizeof( int32_t ) ); -} - -//***************************************************************************** -// -void NetCommand::addFloat ( const float FloatValue ) -{ - union - { - float f; - int32_t l; - } dat; - dat.f = FloatValue; - addInteger ( dat.l, sizeof( int32_t ) ); -} - -//***************************************************************************** -// -void NetCommand::addBit( const bool value ) -{ - _buffer.ByteStream.WriteBit( value ); - _buffer.ulCurrentSize = _buffer.CalcSize(); -} - -//***************************************************************************** -// -void NetCommand::addVariable( const int value ) -{ - _buffer.ByteStream.WriteVariable( value ); - _buffer.ulCurrentSize = _buffer.CalcSize(); -} - -//***************************************************************************** -// [TP] -// -void NetCommand::addShortByte ( int value, int bits ) -{ - _buffer.ByteStream.WriteShortByte( value, bits ); - _buffer.ulCurrentSize = _buffer.CalcSize(); -} - -//***************************************************************************** -// -void NetCommand::addString ( const char *pszString ) -{ - const int len = ( pszString != NULL ) ? (int)strlen( pszString ) : 0; - - if ( len > MAX_NETWORK_STRING ) - { - Printf( "NETWORK_WriteString: String exceeds %d characters! Header: %d\n", MAX_NETWORK_STRING, _buffer.pbData[0] ); - return; - } - - for ( int i = 0; i < len; ++i ) - addByte( pszString[i] ); - addByte( 0 ); -} - -//***************************************************************************** -// -void NetCommand::addName ( FName name ) -{ - if ( name.IsPredefined() ) - { - addShort( name ); - } - else - { - addShort( -1 ); - addString( name ); - } -} - -//***************************************************************************** -// -void NetCommand::addBuffer ( const void *pvBuffer, int nLength ) -{ - _buffer.ByteStream.WriteBuffer( pvBuffer, nLength ); - _buffer.ulCurrentSize = _buffer.CalcSize(); -} - -//***************************************************************************** -// -void NetCommand::writeCommandToStream ( BYTESTREAM_s &ByteStream ) const -{ - // [BB] This also handles the traffic counting (NETWORK_StartTrafficMeasurement/NETWORK_StopTrafficMeasurement). - _buffer.WriteTo ( ByteStream ); -} - -//***************************************************************************** -// -void NetCommand::writeCommandToPacket ( NetPacket &response ) const -{ - // The packet is empty, let it start with a header. - if ( response.size == 0 ) - { - response.stream.WriteByte ( 0 ); // Header - response.size = 1; - } - - const int size = _buffer.CalcSize(); - memcpy( response.data + response.size, _buffer.pbData, _buffer.CalcSize() ); - response.size += _buffer.CalcSize(); -} - -//***************************************************************************** -// [TP] -// -bool NetCommand::isUnreliable() const -{ - return _unreliable; -} - -//***************************************************************************** -// [TP] -// -void NetCommand::setUnreliable ( bool a ) -{ - _unreliable = a; -} - -//***************************************************************************** -// [TP] Returns the size of this net command. -// -int NetCommand::calcSize() const -{ - return _buffer.CalcSize(); -} - -//***************************************************************************** -// template -void IDList::clear( void ) +void IDList::clear() { - for ( unsigned int ulIdx = 0; ulIdx < MAX_NETID; ulIdx++ ) - freeID ( ulIdx ); + for (unsigned int ulIdx = 0; ulIdx < MAX_NETID; ulIdx++) + freeID(ulIdx); _firstFreeID = 1; } -//***************************************************************************** -// template -void IDList::rebuild( void ) +void IDList::rebuild() { clear(); @@ -734,31 +61,62 @@ void IDList::rebuild( void ) TThinkerIterator it; - while ( (pActor = it.Next()) ) + while ((pActor = it.Next())) { - if (( pActor->syncdata.NetID > 0 ) && ( pActor->syncdata.NetID < MAX_NETID )) - useID ( pActor->syncdata.NetID, pActor ); + if ((pActor->syncdata.NetID > 0) && (pActor->syncdata.NetID < MAX_NETID)) + useID(pActor->syncdata.NetID, pActor); } } -//***************************************************************************** -// template -void IDList::useID ( const int lNetID, T *pActor ) +void IDList::useID(const int lNetID, T *pActor) { - if ( isIndexValid ( lNetID ) ) + if (isIndexValid(lNetID)) { - if ( ( _entries[lNetID].bFree == false ) && ( _entries[lNetID].pActor != pActor ) ) - Printf ( "IDList::useID is using an already used ID.\n" ); + if ((_entries[lNetID].bFree == false) && (_entries[lNetID].pActor != pActor)) + Printf("IDList::useID is using an already used ID.\n"); _entries[lNetID].bFree = false; _entries[lNetID].pActor = pActor; } } +template +unsigned int IDList::getNewID() +{ + // Actor's network ID is the first availible net ID. + unsigned int ulID = _firstFreeID; + + do + { + _firstFreeID++; + if (_firstFreeID >= MAX_NETID) + _firstFreeID = 1; + + if (_firstFreeID == ulID) + { + // [BB] In case there is no free netID, the server has to abort the current game. + if (netserver) + { + // [BB] We can only spawn (MAX_NETID-2) actors with netID, because ID zero is reserved and + // we already check that a new ID for the next actor is available when assign a net ID. + Printf("ACTOR_GetNewNetID: Network ID limit reached (>=%d actors)\n", MAX_NETID - 1); + CountActors(); + I_Error("Network ID limit reached (>=%d actors)!\n", MAX_NETID - 1); + } + + return (0); + } + } while (_entries[_firstFreeID].bFree == false); + + return (ulID); +} + +template class IDList; + //***************************************************************************** -// -void CountActors ( ) + +void CountActors() { TMap actorCountMap; AActor * mo; @@ -767,65 +125,30 @@ void CountActors ( ) TThinkerIterator it; - while ( (mo = it.Next()) ) + while ((mo = it.Next())) { numActors++; - if ( mo->syncdata.NetID > 0 ) + if (mo->syncdata.NetID > 0) numActorsWithNetID++; const FName curName = mo->GetClass()->TypeName.GetChars(); - if ( actorCountMap.CheckKey( curName ) == NULL ) - actorCountMap.Insert( curName, 1 ); + if (actorCountMap.CheckKey(curName) == NULL) + actorCountMap.Insert(curName, 1); else - actorCountMap [ curName ] ++; + actorCountMap[curName] ++; } const TMap::Pair *pair; - Printf ( "%d actors in total found, %d have a NetID. Detailed listing:\n", numActors, numActorsWithNetID ); + Printf("%d actors in total found, %d have a NetID. Detailed listing:\n", numActors, numActorsWithNetID); TMap::ConstIterator mapit(actorCountMap); - while (mapit.NextPair (pair)) + while (mapit.NextPair(pair)) { - Printf ( "%s %d\n", pair->Key.GetChars(), pair->Value ); + Printf("%s %d\n", pair->Key.GetChars(), pair->Value); } } CCMD(countactors) { - CountActors (); + CountActors(); } - -//***************************************************************************** -// -template -unsigned int IDList::getNewID( void ) -{ - // Actor's network ID is the first availible net ID. - unsigned int ulID = _firstFreeID; - - do - { - _firstFreeID++; - if ( _firstFreeID >= MAX_NETID ) - _firstFreeID = 1; - - if ( _firstFreeID == ulID ) - { - // [BB] In case there is no free netID, the server has to abort the current game. - if ( netserver ) - { - // [BB] We can only spawn (MAX_NETID-2) actors with netID, because ID zero is reserved and - // we already check that a new ID for the next actor is available when assign a net ID. - Printf( "ACTOR_GetNewNetID: Network ID limit reached (>=%d actors)\n", MAX_NETID - 1 ); - CountActors ( ); - I_Error ("Network ID limit reached (>=%d actors)!\n", MAX_NETID - 1 ); - } - - return ( 0 ); - } - } while ( _entries[_firstFreeID].bFree == false ); - - return ( ulID ); -} - -template class IDList; diff --git a/src/network/netsync.h b/src/network/netsync.h index bb3326ecf0..7a8c4e9cce 100644 --- a/src/network/netsync.h +++ b/src/network/netsync.h @@ -1,27 +1,13 @@ -#ifndef __D_NETSYNC_H__ -#define __D_NETSYNC_H__ + +#pragma once #include "vectors.h" #include "r_data/renderstyle.h" -// Maximum size of the packets sent out by the server. -#define MAX_UDP_PACKET 8192 - -// This is the longest possible string we can pass over the network. -#define MAX_NETWORK_STRING 2048 - -enum class NetPacketType -{ - ConnectRequest, - ConnectResponse, - Disconnect, - Tic, - SpawnPlayer -}; - class AActor; -struct NetSyncData { +struct NetSyncData +{ DVector3 Pos; DVector3 Vel; DAngle SpriteAngle; @@ -49,119 +35,8 @@ struct NetSyncData { double StealthAlpha; // Minmum alpha for MF_STEALTH. int NetID; - void AssignNetID ( AActor *pActor ); - void FreeNetID (); -}; - -//***************************************************************************** -struct BYTESTREAM_s -{ - BYTESTREAM_s(); - void EnsureBitSpace( int bits, bool writing ); - - int ReadByte(); - int ReadShort(); - int ReadLong(); - float ReadFloat(); - const char* ReadString(); - bool ReadBit(); - int ReadVariable(); - int ReadShortByte( int bits ); - void ReadBuffer( void* buffer, size_t length ); - - void WriteByte( int Byte ); - void WriteShort( int Short ); - void WriteLong( int Long ); - void WriteFloat( float Float ); - void WriteString( const char *pszString ); - void WriteBit( bool bit ); - void WriteVariable( int value ); - void WriteShortByte( int value, int bits ); - void WriteBuffer( const void *pvBuffer, int nLength ); - - void WriteHeader( int Byte ); - - bool IsAtEnd() const; - - // Pointer to our stream of data. - uint8_t *pbStream; - - // Pointer to the end of the stream. When pbStream > pbStreamEnd, the - // entire stream has been read. - uint8_t *pbStreamEnd; - - uint8_t *bitBuffer; - int bitShift; - - void AdvancePointer( const int NumBytes, const bool OutboundTraffic ); -}; - -//***************************************************************************** -enum BUFFERTYPE_e -{ - BUFFERTYPE_READ, - BUFFERTYPE_WRITE, - -}; - -//***************************************************************************** -struct NETBUFFER_s -{ - // This is the data in our packet. - uint8_t *pbData; - - // The maximum amount of data this packet can hold. - unsigned int ulMaxSize; - - // How much data is currently in this packet? - unsigned int ulCurrentSize; - - // Byte stream for this buffer for managing our current position and where - // the end of the stream is. - BYTESTREAM_s ByteStream; - - // Is this a buffer that we write to, or read from? - BUFFERTYPE_e BufferType; - - NETBUFFER_s ( ); - NETBUFFER_s ( const NETBUFFER_s &Buffer ); - - void Init( unsigned int ulLength, BUFFERTYPE_e BufferType ); - void Free(); - void Clear(); - int CalcSize() const; - int WriteTo( BYTESTREAM_s &ByteStream ) const; -}; - -struct NetPacket; - -/** - * \author Benjamin Berkels - */ -class NetCommand { - NETBUFFER_s _buffer; - bool _unreliable; - -public: - NetCommand ( const NetPacketType Header ); - ~NetCommand ( ); - - void addInteger( const int IntValue, const int Size ); - void addByte ( const int ByteValue ); - void addShort ( const int ShortValue ); - void addLong ( const int32_t LongValue ); - void addFloat ( const float FloatValue ); - void addString ( const char *pszString ); - void addName ( FName name ); - void addBit ( const bool value ); - void addVariable ( const int value ); - void addShortByte ( int value, int bits ); - void addBuffer ( const void *pvBuffer, int nLength ); - void writeCommandToStream ( BYTESTREAM_s &ByteStream ) const; - void writeCommandToPacket ( NetPacket &response ) const; - bool isUnreliable() const; - void setUnreliable ( bool a ); - int calcSize() const; + void AssignNetID(AActor *pActor); + void FreeNetID(); }; //========================================================================== @@ -187,54 +62,52 @@ private: typedef struct { // Is this node occupied, or free to be used by a new actor? - bool bFree; + bool bFree; // If this node is occupied, this is the actor occupying it. - T *pActor; + T *pActor; } IDNODE_t; IDNODE_t _entries[MAX_NETID]; unsigned int _firstFreeID; - inline bool isIndexValid ( const int lNetID ) const + inline bool isIndexValid(const int lNetID) const { - return ( lNetID >= 0 ) && ( lNetID < MAX_NETID ); + return (lNetID >= 0) && (lNetID < MAX_NETID); } public: - void clear ( ); + void clear(); // [BB] Rebuild the global list of used / free NetIDs from scratch. - void rebuild ( ); + void rebuild(); - IDList ( ) + IDList() { - clear ( ); + clear(); } - void useID ( const int lNetID, T *pActor ); + void useID(const int lNetID, T *pActor); - void freeID ( const int lNetID ) + void freeID(const int lNetID) { - if ( isIndexValid ( lNetID ) ) + if (isIndexValid(lNetID)) { _entries[lNetID].bFree = true; - _entries[lNetID].pActor = NULL; + _entries[lNetID].pActor = nullptr; } } - unsigned int getNewID ( ); + unsigned int getNewID(); - T* findPointerByID ( const int lNetID ) const + T* findPointerByID(const int lNetID) const { - if ( isIndexValid ( lNetID ) == false ) - return ( NULL ); + if (isIndexValid(lNetID) == false) + return nullptr; - if (( _entries[lNetID].bFree == false ) && ( _entries[lNetID].pActor )) - return ( _entries[lNetID].pActor ); + if ((_entries[lNetID].bFree == false) && (_entries[lNetID].pActor)) + return _entries[lNetID].pActor; - return ( NULL ); + return nullptr; } }; - -#endif //__D_NETSYNC_H__ \ No newline at end of file From 3538ef8a153c3c5dc4ff1a4dd8dd0664afb08d5c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Nov 2018 02:04:32 +0100 Subject: [PATCH 34/46] - add destination node to NetOutputPacket constructor --- src/network/i_net.h | 2 +- src/network/netclient.cpp | 6 ++---- src/network/netserver.cpp | 12 ++++-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/network/i_net.h b/src/network/i_net.h index 88295fe08c..b0753f28b3 100644 --- a/src/network/i_net.h +++ b/src/network/i_net.h @@ -10,7 +10,7 @@ class NetOutputPacket { public: - NetOutputPacket() : stream(buffer + 1, MAX_MSGLEN - 1) { buffer[0] = 0; } + NetOutputPacket(int node) : node(node), stream(buffer + 1, MAX_MSGLEN - 1) { buffer[0] = 0; } int node = 0; ByteOutputStream stream; diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index b66cd01cf9..657ac7c2d6 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -78,8 +78,7 @@ NetClient::NetClient(FString server) mServerNode = mComm->Connect(server); mStatus = NodeStatus::InPreGame; - NetOutputPacket packet; - packet.node = mServerNode; + NetOutputPacket packet(mServerNode); NetCommand cmd ( NetPacketType::ConnectRequest ); cmd.addString("ZDoom Connect Request"); @@ -178,8 +177,7 @@ void NetClient::EndCurrentTic() int targettic = (mSendTic + mServerTicDelta); - NetOutputPacket packet; - packet.node = mServerNode; + NetOutputPacket packet(mServerNode); NetCommand cmd ( NetPacketType::Tic ); cmd.addByte (targettic); // target gametic diff --git a/src/network/netserver.cpp b/src/network/netserver.cpp index 149829adda..3225255084 100644 --- a/src/network/netserver.cpp +++ b/src/network/netserver.cpp @@ -135,8 +135,7 @@ void NetServer::EndCurrentTic() { if (mNodes[i].Status == NodeStatus::InGame) { - NetOutputPacket packet; - packet.node = i; + NetOutputPacket packet(i); NetCommand cmd ( NetPacketType::Tic); cmd.addByte ( gametic ); @@ -287,8 +286,7 @@ void NetServer::OnConnectRequest(NetNode &node, ByteInputStream &stream) playeringame[node.Player] = true; players[node.Player].settings_controller = false; - NetOutputPacket response; - response.node = node.NodeIndex; + NetOutputPacket response(node.NodeIndex); NetCommand cmd ( NetPacketType::ConnectResponse ); cmd.addByte ( 1 ); // Protocol version @@ -303,8 +301,7 @@ void NetServer::OnConnectRequest(NetNode &node, ByteInputStream &stream) { node.Status = NodeStatus::Closed; - NetOutputPacket response; - response.node = node.NodeIndex; + NetOutputPacket response(node.NodeIndex); NetCommand cmd ( NetPacketType::ConnectResponse ); cmd.addByte ( 1 ); // Protocol version @@ -373,8 +370,7 @@ void NetServer::CmdSpawnPlayer(ByteOutputStream &stream, int player) void NetServer::FullUpdate(NetNode &node) { - NetOutputPacket packet; - packet.node = node.NodeIndex; + NetOutputPacket packet(node.NodeIndex); // Inform the client about all players already in the game. for ( int i = 0; i < MAXPLAYERNAME; ++i ) From a92663b710d6c5ab06cfe6ba0e9ddef5ffbba68f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Nov 2018 02:42:59 +0100 Subject: [PATCH 35/46] - fix compile error --- src/network/netsync.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/netsync.cpp b/src/network/netsync.cpp index e13dbb2b47..1da06a46c8 100644 --- a/src/network/netsync.cpp +++ b/src/network/netsync.cpp @@ -27,6 +27,8 @@ extern bool netserver, netclient; IDList g_NetIDList; +void CountActors(); + void NetSyncData::AssignNetID(AActor *pActor) { if (netserver) From efa8f3447d40950f5734cc5e0782e504b483a41e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Nov 2018 03:07:08 +0100 Subject: [PATCH 36/46] - another compile error fix --- src/network/netclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index 657ac7c2d6..823ced202f 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -65,6 +65,7 @@ #include "g_levellocals.h" #include "events.h" #include "i_time.h" +#include extern IDList g_NetIDList; From 6f38ecad9b1068305ced62589915f17cd64b1d36 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Nov 2018 03:48:46 +0100 Subject: [PATCH 37/46] - compile error fix for linux --- src/network/netclient.cpp | 2 +- src/posix/sdl/i_system.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index 823ced202f..166830cbba 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -156,7 +156,7 @@ void NetClient::SetCurrentTic(int tictime) } else { - if (mServerTicDelta == -1 || std::abs(gametic + mServerTicDelta - mLastReceivedTic) > jitter) + if (mServerTicDelta == -1 || abs(gametic + mServerTicDelta - mLastReceivedTic) > jitter) { //Printf("netcable icon! ;)\n"); mServerTicDelta = mLastReceivedTic - gametic - jitter; diff --git a/src/posix/sdl/i_system.cpp b/src/posix/sdl/i_system.cpp index e1dfdbee0a..d16ede03ca 100644 --- a/src/posix/sdl/i_system.cpp +++ b/src/posix/sdl/i_system.cpp @@ -46,7 +46,7 @@ #include "x86.h" #include "d_main.h" -#include "d_net.h" +#include "network/net.h" #include "g_game.h" #include "c_dispatch.h" From 567e8e2c55703c4f5863b3609615292d8c70fca6 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 12 Nov 2018 09:26:21 +0100 Subject: [PATCH 38/46] - implement sending some player syncdata each tic - create ANetSyncActor so the client can spawn objects entirely operated by the server --- src/network/netclient.cpp | 35 ++++++++++++++++++++++++++++- src/network/netclient.h | 17 ++++++++++++++ src/network/netserver.cpp | 37 ++++++++++++++++++++++--------- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/network.txt | 4 ++++ 5 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 wadsrc/static/zscript/network.txt diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index 166830cbba..c2039be4de 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -197,7 +197,19 @@ void NetClient::EndCurrentTic() players[consoleplayer].mo->Angles.Pitch = update.pitch; } - update.received = false; + for (unsigned int i = 0; i < update.syncUpdates.Size(); i++) + { + const TicSyncData &syncdata = update.syncUpdates[i]; + AActor *netactor = g_NetIDList.findPointerByID(syncdata.netID); + if (netactor) + { + netactor->SetXYZ(syncdata.x, syncdata.y, syncdata.z); + netactor->Angles.Yaw = syncdata.yaw; + netactor->Angles.Pitch = syncdata.pitch; + } + } + + update = TicUpdate(); } } @@ -341,6 +353,21 @@ void NetClient::OnTic(ByteInputStream &stream) update.yaw = stream.ReadFloat(); update.pitch = stream.ReadFloat(); + while (true) + { + TicSyncData syncdata; + syncdata.netID = stream.ReadShort(); + if (syncdata.netID == -1) + break; + + syncdata.x = stream.ReadFloat(); + syncdata.y = stream.ReadFloat(); + syncdata.z = stream.ReadFloat(); + syncdata.yaw = stream.ReadFloat(); + syncdata.pitch = stream.ReadFloat(); + update.syncUpdates.Push(syncdata); + } + mTicUpdates[mLastReceivedTic % BACKUPTICS] = update; } @@ -381,4 +408,10 @@ void NetClient::OnSpawnPlayer(ByteInputStream &stream) p.mo->syncdata.NetID = netID; g_NetIDList.useID ( netID, p.mo ); } + + //ANetSyncActor *syncactor = Spawn(DVector3(x, y, z), NO_REPLACE); + //syncactor->sprite = GetSpriteIndex("POSSA1"); } + +IMPLEMENT_CLASS(ANetSyncActor, false, false) + diff --git a/src/network/netclient.h b/src/network/netclient.h index 932f94a704..006c409be6 100644 --- a/src/network/netclient.h +++ b/src/network/netclient.h @@ -69,6 +69,16 @@ private: int mServerTicDelta = -1; int mLastReceivedTic = -1; + struct TicSyncData + { + int16_t netID; + float x; + float y; + float z; + float yaw; + float pitch; + }; + struct TicUpdate { bool received = false; @@ -77,6 +87,7 @@ private: float z; float yaw; float pitch; + TArray syncUpdates; }; TicUpdate mTicUpdates[BACKUPTICS]; @@ -85,3 +96,9 @@ private: FDynamicBuffer mCurrentCommands; FDynamicBuffer mSendCommands; }; + +class ANetSyncActor : public AActor +{ + DECLARE_CLASS(ANetSyncActor, AActor) +public: +}; diff --git a/src/network/netserver.cpp b/src/network/netserver.cpp index 3225255084..c7d33d0897 100644 --- a/src/network/netserver.cpp +++ b/src/network/netserver.cpp @@ -143,21 +143,36 @@ void NetServer::EndCurrentTic() int player = mNodes[i].Player; if (playeringame[player] && players[player].mo) { - cmd.addFloat ( static_cast ( players[player].mo->X() ) ); - cmd.addFloat ( static_cast ( players[player].mo->Y() ) ); - cmd.addFloat ( static_cast ( players[player].mo->Z() ) ); - cmd.addFloat ( static_cast ( players[player].mo->Angles.Yaw.Degrees ) ); - cmd.addFloat ( static_cast ( players[player].mo->Angles.Pitch.Degrees ) ); + cmd.addFloat(static_cast (players[player].mo->X())); + cmd.addFloat(static_cast (players[player].mo->Y())); + cmd.addFloat(static_cast (players[player].mo->Z())); + cmd.addFloat(static_cast (players[player].mo->Angles.Yaw.Degrees)); + cmd.addFloat(static_cast (players[player].mo->Angles.Pitch.Degrees)); } else { - cmd.addFloat ( 0.0f ); - cmd.addFloat ( 0.0f ); - cmd.addFloat ( 0.0f ); - cmd.addFloat ( 0.0f ); - cmd.addFloat ( 0.0f ); + cmd.addFloat(0.0f); + cmd.addFloat(0.0f); + cmd.addFloat(0.0f); + cmd.addFloat(0.0f); + cmd.addFloat(0.0f); } + // To do: needs to be done for all syncdata objects that changed and not just players + for (player = 0; player < MAXPLAYERS; player++) + { + if (player != mNodes[i].Player && playeringame[player] && players[player].mo) + { + cmd.addShort(players[player].mo->syncdata.NetID); + cmd.addFloat(static_cast (players[player].mo->X())); + cmd.addFloat(static_cast (players[player].mo->Y())); + cmd.addFloat(static_cast (players[player].mo->Z())); + cmd.addFloat(static_cast (players[player].mo->Angles.Yaw.Degrees)); + cmd.addFloat(static_cast (players[player].mo->Angles.Pitch.Degrees)); + } + } + cmd.addShort(-1); + cmd.writeCommandToStream(packet.stream); mComm->PacketSend(packet); } @@ -373,7 +388,7 @@ void NetServer::FullUpdate(NetNode &node) NetOutputPacket packet(node.NodeIndex); // Inform the client about all players already in the game. - for ( int i = 0; i < MAXPLAYERNAME; ++i ) + for ( int i = 0; i < MAXPLAYERS; ++i ) { if ( i == node.Player ) continue; diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 41b3851412..f10a9d7435 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -9,6 +9,7 @@ version "3.7" #include "zscript/events.txt" #include "zscript/destructible.txt" #include "zscript/level_compatibility.txt" +#include "zscript/network.txt" #include "zscript/menu/menuitembase.txt" #include "zscript/menu/menu.txt" diff --git a/wadsrc/static/zscript/network.txt b/wadsrc/static/zscript/network.txt new file mode 100644 index 0000000000..5d5da291bd --- /dev/null +++ b/wadsrc/static/zscript/network.txt @@ -0,0 +1,4 @@ + +class NetSyncActor : Actor native +{ +} From 18f0a00198659ef5bda93e891dc67e519be734b4 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 13 Nov 2018 01:12:54 +0100 Subject: [PATCH 39/46] - fix crash when using three or more players --- src/g_game.cpp | 8 +++++++- src/network/netclient.cpp | 13 ++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 7409929f66..6dd21184f5 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2853,7 +2853,13 @@ void G_InitClientNetGame(int player, const char* mapname) multiplayer = true; multiplayernext = true; consoleplayer = player; - players[consoleplayer].settings_controller = true; + + for (int i = 0; i < MAXPLAYERS; i++) + { + playeringame[i] = false; + players[i].settings_controller = false; + } + playeringame[consoleplayer] = true; GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index c2039be4de..de4b6a7d69 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -192,7 +192,7 @@ void NetClient::EndCurrentTic() { if (playeringame[consoleplayer] && players[consoleplayer].mo) { - players[consoleplayer].mo->SetXYZ(update.x, update.y, update.z); + players[consoleplayer].mo->SetOrigin(update.x, update.y, update.z, false); players[consoleplayer].mo->Angles.Yaw = update.yaw; players[consoleplayer].mo->Angles.Pitch = update.pitch; } @@ -203,7 +203,7 @@ void NetClient::EndCurrentTic() AActor *netactor = g_NetIDList.findPointerByID(syncdata.netID); if (netactor) { - netactor->SetXYZ(syncdata.x, syncdata.y, syncdata.z); + netactor->SetOrigin(syncdata.x, syncdata.y, syncdata.z, true); netactor->Angles.Yaw = syncdata.yaw; netactor->Angles.Pitch = syncdata.pitch; } @@ -391,6 +391,7 @@ void NetClient::OnSpawnPlayer(ByteInputStream &stream) g_NetIDList.freeID ( netID ); } +#if 0 // Use playerpawn, problematic as client pawn behavior may have to deviate from server side // This player is now in the game. playeringame[player] = true; player_t &p = players[player]; @@ -408,9 +409,11 @@ void NetClient::OnSpawnPlayer(ByteInputStream &stream) p.mo->syncdata.NetID = netID; g_NetIDList.useID ( netID, p.mo ); } - - //ANetSyncActor *syncactor = Spawn(DVector3(x, y, z), NO_REPLACE); - //syncactor->sprite = GetSpriteIndex("POSSA1"); +#else + ANetSyncActor *pawn = Spawn(DVector3(x, y, z), NO_REPLACE); + pawn->sprite = GetSpriteIndex("PLAYA"); + g_NetIDList.useID(netID, pawn); +#endif } IMPLEMENT_CLASS(ANetSyncActor, false, false) From 4ff81c0b8d4ee00ffcf5eb5ad858d7a848d139a8 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 13 Nov 2018 03:58:23 +0100 Subject: [PATCH 40/46] - replicate all the actors --- src/network/netclient.cpp | 30 +++++++++++------------- src/network/netclient.h | 3 ++- src/network/netcommand.h | 2 +- src/network/netserver.cpp | 49 ++++++++++++++++++++------------------- src/network/netserver.h | 2 +- 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index de4b6a7d69..b6ab31e50e 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -122,7 +122,7 @@ void NetClient::Update() case NetPacketType::ConnectResponse: OnConnectResponse(packet.stream); break; case NetPacketType::Disconnect: OnDisconnect(); break; case NetPacketType::Tic: OnTic(packet.stream); break; - case NetPacketType::SpawnPlayer: OnSpawnPlayer(packet.stream); break; + case NetPacketType::SpawnActor: OnSpawnActor(packet.stream); break; } } break; @@ -206,6 +206,7 @@ void NetClient::EndCurrentTic() netactor->SetOrigin(syncdata.x, syncdata.y, syncdata.z, true); netactor->Angles.Yaw = syncdata.yaw; netactor->Angles.Pitch = syncdata.pitch; + netactor->sprite = syncdata.sprite; } } @@ -365,32 +366,34 @@ void NetClient::OnTic(ByteInputStream &stream) syncdata.z = stream.ReadFloat(); syncdata.yaw = stream.ReadFloat(); syncdata.pitch = stream.ReadFloat(); + syncdata.sprite = stream.ReadShort(); update.syncUpdates.Push(syncdata); } mTicUpdates[mLastReceivedTic % BACKUPTICS] = update; } -void NetClient::OnSpawnPlayer(ByteInputStream &stream) +void NetClient::OnSpawnActor(ByteInputStream &stream) { - // To do: this needs a tic and should be inserted in mTicUpdates. - // Otherwise it might not arrive at the intended moment in time. - - int player = stream.ReadByte(); + const int16_t netID = stream.ReadShort(); const float x = stream.ReadFloat(); const float y = stream.ReadFloat(); const float z = stream.ReadFloat(); - const int16_t netID = stream.ReadShort(); - AActor *oldNetActor = g_NetIDList.findPointerByID ( netID ); + AActor *oldNetActor = g_NetIDList.findPointerByID(netID); // If there's already an actor with this net ID, destroy it. - if ( oldNetActor != NULL ) + if (oldNetActor) { - oldNetActor->Destroy( ); - g_NetIDList.freeID ( netID ); + oldNetActor->Destroy(); + g_NetIDList.freeID(netID); } + ANetSyncActor *actor = Spawn(DVector3(x, y, z), NO_REPLACE); + //actor->sprite = GetSpriteIndex("PLAYA"); + g_NetIDList.useID(netID, actor); +} + #if 0 // Use playerpawn, problematic as client pawn behavior may have to deviate from server side // This player is now in the game. playeringame[player] = true; @@ -409,12 +412,7 @@ void NetClient::OnSpawnPlayer(ByteInputStream &stream) p.mo->syncdata.NetID = netID; g_NetIDList.useID ( netID, p.mo ); } -#else - ANetSyncActor *pawn = Spawn(DVector3(x, y, z), NO_REPLACE); - pawn->sprite = GetSpriteIndex("PLAYA"); - g_NetIDList.useID(netID, pawn); #endif -} IMPLEMENT_CLASS(ANetSyncActor, false, false) diff --git a/src/network/netclient.h b/src/network/netclient.h index 006c409be6..6dc0a131c9 100644 --- a/src/network/netclient.h +++ b/src/network/netclient.h @@ -55,7 +55,7 @@ private: void OnConnectResponse(ByteInputStream &stream); void OnDisconnect(); void OnTic(ByteInputStream &stream); - void OnSpawnPlayer(ByteInputStream &stream); + void OnSpawnActor(ByteInputStream &stream); void UpdateLastReceivedTic(int tic); @@ -77,6 +77,7 @@ private: float z; float yaw; float pitch; + int16_t sprite; }; struct TicUpdate diff --git a/src/network/netcommand.h b/src/network/netcommand.h index 32c8226eda..1ecc0a6785 100644 --- a/src/network/netcommand.h +++ b/src/network/netcommand.h @@ -16,7 +16,7 @@ enum class NetPacketType ConnectResponse, Disconnect, Tic, - SpawnPlayer + SpawnActor }; class ByteInputStream diff --git a/src/network/netserver.cpp b/src/network/netserver.cpp index c7d33d0897..9bdb2ccd8b 100644 --- a/src/network/netserver.cpp +++ b/src/network/netserver.cpp @@ -158,17 +158,19 @@ void NetServer::EndCurrentTic() cmd.addFloat(0.0f); } - // To do: needs to be done for all syncdata objects that changed and not just players - for (player = 0; player < MAXPLAYERS; player++) + TThinkerIterator it; + AActor *mo; + while (mo = it.Next()) { - if (player != mNodes[i].Player && playeringame[player] && players[player].mo) + if (mo != players[player].mo) { - cmd.addShort(players[player].mo->syncdata.NetID); - cmd.addFloat(static_cast (players[player].mo->X())); - cmd.addFloat(static_cast (players[player].mo->Y())); - cmd.addFloat(static_cast (players[player].mo->Z())); - cmd.addFloat(static_cast (players[player].mo->Angles.Yaw.Degrees)); - cmd.addFloat(static_cast (players[player].mo->Angles.Pitch.Degrees)); + cmd.addShort(mo->syncdata.NetID); + cmd.addFloat(static_cast (mo->X())); + cmd.addFloat(static_cast (mo->Y())); + cmd.addFloat(static_cast (mo->Z())); + cmd.addFloat(static_cast (mo->Angles.Yaw.Degrees)); + cmd.addFloat(static_cast (mo->Angles.Pitch.Degrees)); + cmd.addShort(mo->sprite); } } cmd.addShort(-1); @@ -372,29 +374,28 @@ void NetServer::OnTic(NetNode &node, ByteInputStream &stream) node.TicUpdates[tic % BACKUPTICS] = update; } -void NetServer::CmdSpawnPlayer(ByteOutputStream &stream, int player) +void NetServer::CmdSpawnActor(ByteOutputStream &stream, AActor *actor) { - NetCommand cmd ( NetPacketType::SpawnPlayer ); - cmd.addByte ( player ); - cmd.addFloat ( static_cast ( players[player].mo->X() ) ); - cmd.addFloat ( static_cast ( players[player].mo->Y() ) ); - cmd.addFloat ( static_cast ( players[player].mo->Z() ) ); - cmd.addShort ( players[player].mo->syncdata.NetID ); - cmd.writeCommandToStream ( stream ); + NetCommand cmd(NetPacketType::SpawnActor); + cmd.addShort(actor->syncdata.NetID); + cmd.addFloat(static_cast(actor->X())); + cmd.addFloat(static_cast(actor->Y())); + cmd.addFloat(static_cast(actor->Z())); + cmd.writeCommandToStream(stream); } void NetServer::FullUpdate(NetNode &node) { NetOutputPacket packet(node.NodeIndex); - // Inform the client about all players already in the game. - for ( int i = 0; i < MAXPLAYERS; ++i ) + TThinkerIterator it; + AActor *mo; + while (mo = it.Next()) { - if ( i == node.Player ) - continue; - - if ( playeringame[i] == true ) - CmdSpawnPlayer(packet.stream, i); + if (mo != players[node.Player].mo) + { + CmdSpawnActor(packet.stream, mo); + } } mComm->PacketSend(packet); diff --git a/src/network/netserver.h b/src/network/netserver.h index 3d3ac200f1..3d0da02a02 100644 --- a/src/network/netserver.h +++ b/src/network/netserver.h @@ -82,7 +82,7 @@ private: void OnDisconnect(NetNode &node, ByteInputStream &stream); void OnTic(NetNode &node, ByteInputStream &packet); - void CmdSpawnPlayer(ByteOutputStream &stream, int player); + void CmdSpawnActor(ByteOutputStream &stream, AActor *actor); void FullUpdate(NetNode &node); std::unique_ptr mComm; From 96e55b1bd06886a44954b47b71a152d98aea8a39 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 13 Nov 2018 19:04:15 +0100 Subject: [PATCH 41/46] - implement actor destroy --- src/network/net.h | 6 ++++++ src/network/netclient.cpp | 32 ++++++++++++++++++++++++-------- src/network/netclient.h | 7 +++++++ src/network/netcommand.cpp | 21 ++++++++++++++++++--- src/network/netcommand.h | 19 ++++++++++++------- src/network/netserver.cpp | 30 +++++++++++++++++++++++++++++- src/network/netserver.h | 8 ++++++++ src/network/netsync.cpp | 20 +------------------- src/network/netsync.h | 3 --- src/p_mobj.cpp | 9 +++++---- 10 files changed, 110 insertions(+), 45 deletions(-) diff --git a/src/network/net.h b/src/network/net.h index 594a5bdf5d..a5a058e9dc 100644 --- a/src/network/net.h +++ b/src/network/net.h @@ -32,6 +32,8 @@ #define MAXTICDUP 5 #define LOCALCMDTICS (BACKUPTICS*MAXTICDUP) +class AActor; + class FDynamicBuffer { public: @@ -96,6 +98,10 @@ public: virtual void ListPingTimes() = 0; virtual void Network_Controller(int playernum, bool add) = 0; + // Playsim events + virtual void ActorSpawned(AActor *actor) { } + virtual void ActorDestroyed(AActor *actor) { } + // Old init/deinit stuff void Startup() { } void Net_ClearBuffers() { } diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index b6ab31e50e..105570d074 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -67,8 +67,6 @@ #include "i_time.h" #include -extern IDList g_NetIDList; - CVAR( Int, cl_showspawnnames, 0, CVAR_ARCHIVE ) NetClient::NetClient(FString server) @@ -123,6 +121,7 @@ void NetClient::Update() case NetPacketType::Disconnect: OnDisconnect(); break; case NetPacketType::Tic: OnTic(packet.stream); break; case NetPacketType::SpawnActor: OnSpawnActor(packet.stream); break; + case NetPacketType::DestroyActor: OnDestroyActor(packet.stream); break; } } break; @@ -200,13 +199,14 @@ void NetClient::EndCurrentTic() for (unsigned int i = 0; i < update.syncUpdates.Size(); i++) { const TicSyncData &syncdata = update.syncUpdates[i]; - AActor *netactor = g_NetIDList.findPointerByID(syncdata.netID); + AActor *netactor = mNetIDList.findPointerByID(syncdata.netID); if (netactor) { netactor->SetOrigin(syncdata.x, syncdata.y, syncdata.z, true); netactor->Angles.Yaw = syncdata.yaw; netactor->Angles.Pitch = syncdata.pitch; netactor->sprite = syncdata.sprite; + netactor->frame = syncdata.frame; } } @@ -270,6 +270,15 @@ void NetClient::Network_Controller(int playernum, bool add) { } +void NetClient::ActorSpawned(AActor *actor) +{ + actor->syncdata.NetID = -1; +} + +void NetClient::ActorDestroyed(AActor *actor) +{ +} + void NetClient::OnClose() { mComm->Close(mServerNode); @@ -367,6 +376,7 @@ void NetClient::OnTic(ByteInputStream &stream) syncdata.yaw = stream.ReadFloat(); syncdata.pitch = stream.ReadFloat(); syncdata.sprite = stream.ReadShort(); + syncdata.frame = stream.ReadByte(); update.syncUpdates.Push(syncdata); } @@ -380,18 +390,24 @@ void NetClient::OnSpawnActor(ByteInputStream &stream) const float y = stream.ReadFloat(); const float z = stream.ReadFloat(); - AActor *oldNetActor = g_NetIDList.findPointerByID(netID); + AActor *oldNetActor = mNetIDList.findPointerByID(netID); // If there's already an actor with this net ID, destroy it. if (oldNetActor) { oldNetActor->Destroy(); - g_NetIDList.freeID(netID); + mNetIDList.freeID(netID); } ANetSyncActor *actor = Spawn(DVector3(x, y, z), NO_REPLACE); - //actor->sprite = GetSpriteIndex("PLAYA"); - g_NetIDList.useID(netID, actor); + mNetIDList.useID(netID, actor); +} + +void NetClient::OnDestroyActor(ByteInputStream &stream) +{ + const int16_t netID = stream.ReadShort(); + AActor *actor = mNetIDList.findPointerByID(netID); + actor->Destroy(); } #if 0 // Use playerpawn, problematic as client pawn behavior may have to deviate from server side @@ -410,7 +426,7 @@ void NetClient::OnSpawnActor(ByteInputStream &stream) { // Set the network ID. p.mo->syncdata.NetID = netID; - g_NetIDList.useID ( netID, p.mo ); + mNetIDList.useID ( netID, p.mo ); } #endif diff --git a/src/network/netclient.h b/src/network/netclient.h index 6dc0a131c9..1cea32da5b 100644 --- a/src/network/netclient.h +++ b/src/network/netclient.h @@ -50,12 +50,16 @@ public: void ListPingTimes() override; void Network_Controller(int playernum, bool add) override; + void ActorSpawned(AActor *actor) override; + void ActorDestroyed(AActor *actor) override; + private: void OnClose(); void OnConnectResponse(ByteInputStream &stream); void OnDisconnect(); void OnTic(ByteInputStream &stream); void OnSpawnActor(ByteInputStream &stream); + void OnDestroyActor(ByteInputStream &stream); void UpdateLastReceivedTic(int tic); @@ -78,6 +82,7 @@ private: float yaw; float pitch; int16_t sprite; + uint8_t frame; }; struct TicUpdate @@ -96,6 +101,8 @@ private: ticcmd_t mSentInput[BACKUPTICS]; FDynamicBuffer mCurrentCommands; FDynamicBuffer mSendCommands; + + IDList mNetIDList; }; class ANetSyncActor : public AActor diff --git a/src/network/netcommand.cpp b/src/network/netcommand.cpp index b74f07ff92..17e8970211 100644 --- a/src/network/netcommand.cpp +++ b/src/network/netcommand.cpp @@ -29,16 +29,32 @@ static int g_OutboundBytesMeasured = 0; //***************************************************************************** +ByteOutputStream::ByteOutputStream(int size) +{ + SetBuffer(size); +} + ByteOutputStream::ByteOutputStream(void *buffer, int size) { SetBuffer(buffer, size); } +void ByteOutputStream::SetBuffer(int size) +{ + mBuffer = std::make_shared(size); + SetBuffer(mBuffer->data, mBuffer->size); +} + void ByteOutputStream::SetBuffer(void *buffer, int size) { mData = (uint8_t*)buffer; + pbStreamEnd = mData + size; + ResetPos(); +} + +void ByteOutputStream::ResetPos() +{ pbStream = mData; - pbStreamEnd = pbStream + size; bitBuffer = nullptr; bitShift = -1; } @@ -388,8 +404,7 @@ void ByteInputStream::EnsureBitSpace(int bits, bool writing) NetCommand::NetCommand(const NetPacketType Header) { // To do: improve memory handling here. 8 kb per command is very wasteful - mBuffer = std::make_shared(MAX_UDP_PACKET); - mStream.SetBuffer(mBuffer->data, mBuffer->size); + mStream.SetBuffer(MAX_UDP_PACKET); addByte(static_cast(Header)); } diff --git a/src/network/netcommand.h b/src/network/netcommand.h index 1ecc0a6785..73fb9c0c28 100644 --- a/src/network/netcommand.h +++ b/src/network/netcommand.h @@ -16,7 +16,8 @@ enum class NetPacketType ConnectResponse, Disconnect, Tic, - SpawnActor + SpawnActor, + DestroyActor }; class ByteInputStream @@ -54,9 +55,12 @@ class ByteOutputStream { public: ByteOutputStream() = default; + ByteOutputStream(int size); ByteOutputStream(void *buffer, int size); + void SetBuffer(int size); void SetBuffer(void *buffer, int size); + void ResetPos(); void WriteByte(int Byte); void WriteShort(int Short); @@ -81,13 +85,7 @@ private: uint8_t *bitBuffer = nullptr; int bitShift = -1; -}; -/** - * \author Benjamin Berkels - */ -class NetCommand -{ struct DataBuffer { DataBuffer(int size) : data(new uint8_t[size]), size(size) { } @@ -97,6 +95,13 @@ class NetCommand int size; }; std::shared_ptr mBuffer; +}; + +/** + * \author Benjamin Berkels + */ +class NetCommand +{ ByteOutputStream mStream; bool mUnreliable = false; diff --git a/src/network/netserver.cpp b/src/network/netserver.cpp index 9bdb2ccd8b..ecb2dc3dbd 100644 --- a/src/network/netserver.cpp +++ b/src/network/netserver.cpp @@ -69,6 +69,8 @@ NetServer::NetServer() { Printf("Started hosting multiplayer game..\n"); + mBroadcastCommands.SetBuffer(MAX_MSGLEN); + for (int i = 0; i < MAXNETNODES; i++) mNodes[i].NodeIndex = i; @@ -137,6 +139,8 @@ void NetServer::EndCurrentTic() { NetOutputPacket packet(i); + packet.stream.WriteBuffer(mBroadcastCommands.GetData(), mBroadcastCommands.GetSize()); + NetCommand cmd ( NetPacketType::Tic); cmd.addByte ( gametic ); @@ -162,7 +166,7 @@ void NetServer::EndCurrentTic() AActor *mo; while (mo = it.Next()) { - if (mo != players[player].mo) + if (mo != players[player].mo && mo->syncdata.NetID) { cmd.addShort(mo->syncdata.NetID); cmd.addFloat(static_cast (mo->X())); @@ -171,6 +175,7 @@ void NetServer::EndCurrentTic() cmd.addFloat(static_cast (mo->Angles.Yaw.Degrees)); cmd.addFloat(static_cast (mo->Angles.Pitch.Degrees)); cmd.addShort(mo->sprite); + cmd.addByte(mo->frame); } } cmd.addShort(-1); @@ -180,6 +185,8 @@ void NetServer::EndCurrentTic() } } + mBroadcastCommands.ResetPos(); + mCurrentCommands = mSendCommands; mSendCommands.Clear(); } @@ -384,6 +391,13 @@ void NetServer::CmdSpawnActor(ByteOutputStream &stream, AActor *actor) cmd.writeCommandToStream(stream); } +void NetServer::CmdDestroyActor(ByteOutputStream &stream, AActor *actor) +{ + NetCommand cmd(NetPacketType::DestroyActor); + cmd.addShort(actor->syncdata.NetID); + cmd.writeCommandToStream(stream); +} + void NetServer::FullUpdate(NetNode &node) { NetOutputPacket packet(node.NodeIndex); @@ -400,3 +414,17 @@ void NetServer::FullUpdate(NetNode &node) mComm->PacketSend(packet); } + +void NetServer::ActorSpawned(AActor *actor) +{ + actor->syncdata.NetID = mNetIDList.getNewID(); + mNetIDList.useID(actor->syncdata.NetID, actor); + + CmdSpawnActor(mBroadcastCommands, actor); +} + +void NetServer::ActorDestroyed(AActor *actor) +{ + CmdDestroyActor(mBroadcastCommands, actor); + mNetIDList.freeID(actor->syncdata.NetID); +} diff --git a/src/network/netserver.h b/src/network/netserver.h index 3d0da02a02..0be346536d 100644 --- a/src/network/netserver.h +++ b/src/network/netserver.h @@ -76,6 +76,9 @@ public: void ListPingTimes() override; void Network_Controller(int playernum, bool add) override; + void ActorSpawned(AActor *actor) override; + void ActorDestroyed(AActor *actor) override; + private: void OnClose(NetNode &node, ByteInputStream &stream); void OnConnectRequest(NetNode &node, ByteInputStream &stream); @@ -83,6 +86,7 @@ private: void OnTic(NetNode &node, ByteInputStream &packet); void CmdSpawnActor(ByteOutputStream &stream, AActor *actor); + void CmdDestroyActor(ByteOutputStream &stream, AActor *actor); void FullUpdate(NetNode &node); std::unique_ptr mComm; @@ -92,4 +96,8 @@ private: ticcmd_t mCurrentInput[MAXPLAYERS]; FDynamicBuffer mCurrentCommands; FDynamicBuffer mSendCommands; + + IDList mNetIDList; + + ByteOutputStream mBroadcastCommands; // Playsim events everyone should hear about }; diff --git a/src/network/netsync.cpp b/src/network/netsync.cpp index 1da06a46c8..0bed8b8d1e 100644 --- a/src/network/netsync.cpp +++ b/src/network/netsync.cpp @@ -23,28 +23,10 @@ #include "doomstat.h" #include "i_net.h" -extern bool netserver, netclient; - -IDList g_NetIDList; +extern bool netserver; void CountActors(); -void NetSyncData::AssignNetID(AActor *pActor) -{ - if (netserver) - { - NetID = g_NetIDList.getNewID(); - g_NetIDList.useID(NetID, pActor); - } - else - NetID = -1; -} - -void NetSyncData::FreeNetID() -{ - g_NetIDList.freeID(NetID); -} - template void IDList::clear() { diff --git a/src/network/netsync.h b/src/network/netsync.h index 7a8c4e9cce..668bad55ec 100644 --- a/src/network/netsync.h +++ b/src/network/netsync.h @@ -34,9 +34,6 @@ struct NetSyncData double CameraFOV; double StealthAlpha; // Minmum alpha for MF_STEALTH. int NetID; - - void AssignNetID(AActor *pActor); - void FreeNetID(); }; //========================================================================== diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index bdf5c85be7..6f61904296 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -98,6 +98,7 @@ #include "events.h" #include "actorinlines.h" #include "a_dynlight.h" +#include "network/net.h" // MACROS ------------------------------------------------------------------ @@ -5169,8 +5170,8 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a // force scroller check in the first tic. actor->flags8 |= MF8_INSCROLLSEC; - // [BB] Give this actor a NetID so that we can sync it to the clients. - actor->syncdata.AssignNetID( actor ); + // notify network that we got a new actor + network->ActorSpawned(actor); return actor; } @@ -5441,8 +5442,8 @@ void AActor::CallDeactivate(AActor *activator) void AActor::OnDestroy () { - // [BB] Free it's network ID. - syncdata.FreeNetID (); + // Notify network + network->ActorDestroyed(this); // [ZZ] call destroy event hook. // note that this differs from ThingSpawned in that you can actually override OnDestroy to avoid calling the hook. From a1b7c66150c13f6f86c2adeefa0e65bb9bc8f7af Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 14 Nov 2018 03:59:53 +0100 Subject: [PATCH 42/46] - fix player prediction when moving across lines --- src/network/netclient.cpp | 20 ++++++++++++++------ src/network/netclient.h | 5 ++--- src/network/netserver.cpp | 6 ++++++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index 105570d074..ddf1027725 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -191,9 +191,14 @@ void NetClient::EndCurrentTic() { if (playeringame[consoleplayer] && players[consoleplayer].mo) { - players[consoleplayer].mo->SetOrigin(update.x, update.y, update.z, false); - players[consoleplayer].mo->Angles.Yaw = update.yaw; - players[consoleplayer].mo->Angles.Pitch = update.pitch; + APlayerPawn *pawn = players[consoleplayer].mo; + if ((update.Pos - pawn->Pos()).LengthSquared() > 10.0) + pawn->SetOrigin(update.Pos, false); + else + P_TryMove(pawn, update.Pos.XY(), true); + pawn->Vel = update.Vel; + pawn->Angles.Yaw = update.yaw; + pawn->Angles.Pitch = update.pitch; } for (unsigned int i = 0; i < update.syncUpdates.Size(); i++) @@ -357,9 +362,12 @@ void NetClient::OnTic(ByteInputStream &stream) TicUpdate update; update.received = true; - update.x = stream.ReadFloat(); - update.y = stream.ReadFloat(); - update.z = stream.ReadFloat(); + update.Pos.X = stream.ReadFloat(); + update.Pos.Y = stream.ReadFloat(); + update.Pos.Z = stream.ReadFloat(); + update.Vel.X = stream.ReadFloat(); + update.Vel.Y = stream.ReadFloat(); + update.Vel.Z = stream.ReadFloat(); update.yaw = stream.ReadFloat(); update.pitch = stream.ReadFloat(); diff --git a/src/network/netclient.h b/src/network/netclient.h index 1cea32da5b..9a1e42a336 100644 --- a/src/network/netclient.h +++ b/src/network/netclient.h @@ -88,9 +88,8 @@ private: struct TicUpdate { bool received = false; - float x; - float y; - float z; + DVector3 Pos; + DVector3 Vel; float yaw; float pitch; TArray syncUpdates; diff --git a/src/network/netserver.cpp b/src/network/netserver.cpp index ecb2dc3dbd..738014454f 100644 --- a/src/network/netserver.cpp +++ b/src/network/netserver.cpp @@ -150,6 +150,9 @@ void NetServer::EndCurrentTic() cmd.addFloat(static_cast (players[player].mo->X())); cmd.addFloat(static_cast (players[player].mo->Y())); cmd.addFloat(static_cast (players[player].mo->Z())); + cmd.addFloat(static_cast (players[player].mo->Vel.X)); + cmd.addFloat(static_cast (players[player].mo->Vel.Y)); + cmd.addFloat(static_cast (players[player].mo->Vel.Z)); cmd.addFloat(static_cast (players[player].mo->Angles.Yaw.Degrees)); cmd.addFloat(static_cast (players[player].mo->Angles.Pitch.Degrees)); } @@ -160,6 +163,9 @@ void NetServer::EndCurrentTic() cmd.addFloat(0.0f); cmd.addFloat(0.0f); cmd.addFloat(0.0f); + cmd.addFloat(0.0f); + cmd.addFloat(0.0f); + cmd.addFloat(0.0f); } TThinkerIterator it; From b03babbd05c39b4a2700cee34e4637cdab3006b4 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 14 Nov 2018 04:08:11 +0100 Subject: [PATCH 43/46] - fix crash --- src/network/netclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index ddf1027725..92beaf653a 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -416,6 +416,7 @@ void NetClient::OnDestroyActor(ByteInputStream &stream) const int16_t netID = stream.ReadShort(); AActor *actor = mNetIDList.findPointerByID(netID); actor->Destroy(); + mNetIDList.freeID(netID); } #if 0 // Use playerpawn, problematic as client pawn behavior may have to deviate from server side From 9608c2c2593c4109d10a3f69e347b471dd107422 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 7 Dec 2018 07:01:44 +0100 Subject: [PATCH 44/46] - improve NetSyncData to handle any simple data type in Actor --- src/actor.h | 1 - src/network/netsync.cpp | 129 ++++++++++++++++++++++++++++++++++++++++ src/network/netsync.h | 58 +++++++++--------- 3 files changed, 160 insertions(+), 28 deletions(-) diff --git a/src/actor.h b/src/actor.h index b55c88f682..95a0b466ad 100644 --- a/src/actor.h +++ b/src/actor.h @@ -643,7 +643,6 @@ public: ~AActor (); NetSyncData syncdata; - NetSyncData synccompare; virtual void OnDestroy() override; virtual void Serialize(FSerializer &arc) override; diff --git a/src/network/netsync.cpp b/src/network/netsync.cpp index 0bed8b8d1e..ca81b7a317 100644 --- a/src/network/netsync.cpp +++ b/src/network/netsync.cpp @@ -22,11 +22,140 @@ #include "actor.h" #include "doomstat.h" #include "i_net.h" +#include "cmdlib.h" extern bool netserver; void CountActors(); +class NetSyncWriter +{ +public: + NetSyncWriter(NetCommand &cmd, int netid) : cmd(cmd), NetID(netid) { } + + void Write(void *compval, void *actorval, size_t size) + { + if (memcmp(compval, actorval, size) != 0) + { + if (firstwrite) + { + firstwrite = false; + cmd.addShort(NetID); + } + cmd.addByte(fieldindex); + cmd.addBuffer(actorval, (int)size); + memcpy(compval, actorval, size); + } + fieldindex++; + } + + void WriteEnd() + { + if (!firstwrite) + { + cmd.addByte(255); + } + } + +private: + NetCommand &cmd; + int NetID; + bool firstwrite = true; + int fieldindex = 0; +}; + +NetSyncClass::NetSyncClass() +{ + mSyncVars.Push({ myoffsetof(AActor, Vel.X), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Vel.Y), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Vel.Z), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, SpriteAngle.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, SpriteRotation.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Angles.Yaw.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Angles.Pitch.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Angles.Roll.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Scale.X), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Scale.Y), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Alpha), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, sprite), sizeof(uint32_t) }); + mSyncVars.Push({ myoffsetof(AActor, frame), sizeof(uint8_t) }); + mSyncVars.Push({ myoffsetof(AActor, effects), sizeof(uint8_t) }); + mSyncVars.Push({ myoffsetof(AActor, RenderStyle.AsDWORD), sizeof(uint32_t) }); + mSyncVars.Push({ myoffsetof(AActor, Translation), sizeof(uint32_t) }); + mSyncVars.Push({ myoffsetof(AActor, RenderRequired), sizeof(uint32_t) }); + mSyncVars.Push({ myoffsetof(AActor, RenderHidden), sizeof(uint32_t) }); + mSyncVars.Push({ myoffsetof(AActor, renderflags.Value), sizeof(uint32_t) }); + mSyncVars.Push({ myoffsetof(AActor, Floorclip), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, VisibleStartAngle.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, VisibleStartPitch.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, VisibleEndAngle.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, VisibleEndPitch.Degrees), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, Speed), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, FloatSpeed), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, CameraHeight), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, CameraFOV), sizeof(double) }); + mSyncVars.Push({ myoffsetof(AActor, StealthAlpha), sizeof(double) }); + + // To do: create NetSyncVariable entries for all the script variables we want sent to the client +} + +void NetSyncClass::InitSyncData(AActor *actor) +{ + auto &syncdata = actor->syncdata; + + size_t scriptvarsize = 0; + for (unsigned int i = 0; i < mSyncVars.Size(); i++) + scriptvarsize += mSyncVars[i].size; + syncdata.CompareData.Resize((unsigned int)scriptvarsize); + + syncdata.Pos = actor->Pos(); + + size_t pos = 0; + for (unsigned int i = 0; i < mSyncVars.Size(); i++) + { + memcpy(syncdata.CompareData.Data() + pos, ((uint8_t*)actor) + mSyncVars[i].offset, scriptvarsize); + pos += mSyncVars[i].size; + } +} + +void NetSyncClass::WriteSyncUpdate(NetCommand &cmd, AActor *actor) +{ + NetSyncWriter writer(cmd, actor->syncdata.NetID); + + DVector3 pos = actor->Pos(); + writer.Write(&actor->syncdata.Pos, &pos, sizeof(DVector3)); + + size_t compareoffset = 0; + for (unsigned int i = 0; i < mSyncVars.Size(); i++) + { + writer.Write(actor->syncdata.CompareData.Data() + compareoffset, ((uint8_t*)actor) + mSyncVars[i].offset, mSyncVars[i].size); + compareoffset += mSyncVars[i].size; + } +} + +void NetSyncClass::ReadSyncUpdate(ByteInputStream &stream, AActor *actor) +{ + while (true) + { + int fieldindex = stream.ReadByte(); + if (fieldindex == 255) + break; + + if (fieldindex == 0) + { + DVector3 pos; + stream.ReadBuffer(&pos, sizeof(DVector3)); + actor->SetOrigin(pos, true); + } + else if (fieldindex <= (int)mSyncVars.Size()) + { + stream.ReadBuffer(((uint8_t*)actor) + mSyncVars[fieldindex - 1].offset, mSyncVars[fieldindex - 1].size); + } + } +} + +///////////////////////////////////////////////////////////////////////////// + template void IDList::clear() { diff --git a/src/network/netsync.h b/src/network/netsync.h index 668bad55ec..0f217fa063 100644 --- a/src/network/netsync.h +++ b/src/network/netsync.h @@ -5,35 +5,39 @@ #include "r_data/renderstyle.h" class AActor; +class NetCommand; +class ByteInputStream; -struct NetSyncData +class NetSyncVariable { - 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 - uint32_t 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. - int NetID; +public: + size_t offset; + size_t size; +}; + +class NetSyncClass +{ +public: + NetSyncClass(); + + void InitSyncData(AActor *actor); + void WriteSyncUpdate(NetCommand &cmd, AActor *actor); + void ReadSyncUpdate(ByteInputStream &stream, AActor *actor); + +private: + TArray mSyncVars; + + NetSyncClass(const NetSyncClass &) = delete; + NetSyncClass &operator=(const NetSyncClass &) = delete; +}; + +class NetSyncData +{ +public: + int NetID; + DVector3 Pos; + TArray CompareData; + NetSyncClass *SyncClass; // Maybe this should be stored in the actor's PClass }; //========================================================================== From 60e26a0f74c3e0dc85c03d08a77aa838c9393ac7 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 7 Dec 2018 07:03:59 +0100 Subject: [PATCH 45/46] - forgot to call WriteEnd --- src/network/netsync.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/netsync.cpp b/src/network/netsync.cpp index ca81b7a317..9e43f4433e 100644 --- a/src/network/netsync.cpp +++ b/src/network/netsync.cpp @@ -131,6 +131,8 @@ void NetSyncClass::WriteSyncUpdate(NetCommand &cmd, AActor *actor) writer.Write(actor->syncdata.CompareData.Data() + compareoffset, ((uint8_t*)actor) + mSyncVars[i].offset, mSyncVars[i].size); compareoffset += mSyncVars[i].size; } + + writer.WriteEnd(); } void NetSyncClass::ReadSyncUpdate(ByteInputStream &stream, AActor *actor) From 21322acc261c53c3a1d42155ec6d2b8c0751ac5e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 14 Jul 2019 04:24:26 +0200 Subject: [PATCH 46/46] - hook up some more netcommand stuff --- src/g_game.cpp | 4 +- src/g_level.cpp | 10 ++ src/g_level.h | 2 + src/network/netclient.cpp | 253 +++++++++++++++++-------------------- src/network/netclient.h | 24 +--- src/network/netcommand.cpp | 5 + src/network/netcommand.h | 1 + src/network/netserver.cpp | 41 +++--- src/network/netserver.h | 2 +- 9 files changed, 160 insertions(+), 182 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index d8fda3f15c..c2c53b1ada 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2744,7 +2744,7 @@ void G_InitServerNetGame(const char *mapname) GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars D_SetupUserInfo(); - G_DeferedInitNew(mapname); + G_NetGameInitNew(mapname); } void G_InitClientNetGame(int player, const char* mapname) @@ -2767,7 +2767,7 @@ void G_InitClientNetGame(int player, const char* mapname) GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars D_SetupUserInfo(); - G_DeferedInitNew(mapname); + G_NetGameInitNew(mapname); } void G_EndNetGame() diff --git a/src/g_level.cpp b/src/g_level.cpp index e1ef4e0d20..d6c6968bbb 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -104,6 +104,7 @@ EXTERN_CVAR (String, playerclass) #define PCLS_ID MAKE_ID('p','c','L','s') void G_VerifySkill(); +void G_DoNewGame(); CUSTOM_CVAR(Bool, gl_brightfog, false, CVAR_ARCHIVE | CVAR_NOINITCALL) { @@ -184,6 +185,15 @@ void G_DeferedInitNew (FGameStartup *gs) finishstate = FINISH_NoHub; } +void G_NetGameInitNew(const char *mapname, int newskill) +{ + d_mapname = mapname; + d_skill = newskill; + CheckWarpTransMap(d_mapname, true); + gameaction = ga_nothing; + G_DoNewGame(); +} + //========================================================================== // // diff --git a/src/g_level.h b/src/g_level.h index a98a8d415a..caea0a0d6c 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -486,6 +486,8 @@ void G_DeferedInitNew (const char *mapname, int skill = -1); struct FGameStartup; void G_DeferedInitNew (FGameStartup *gs); +void G_NetGameInitNew(const char *mapname, int skill = -1); + void G_ExitLevel (int position, bool keepFacing); void G_SecretExitLevel (int position); const char *G_GetExitMap(); diff --git a/src/network/netclient.cpp b/src/network/netclient.cpp index 92beaf653a..5e423d00d4 100644 --- a/src/network/netclient.cpp +++ b/src/network/netclient.cpp @@ -90,11 +90,6 @@ void NetClient::Update() { while (true) { - // [BB] Don't check net packets while we are supposed to load a map. - // This way the commands from the full update will not be parsed before we loaded the map. - if ( ( gameaction == ga_newgame ) || ( gameaction == ga_newgame2 ) ) - return; - NetInputPacket packet; mComm->PacketGet(packet); if (packet.node == -1) @@ -111,20 +106,18 @@ void NetClient::Update() } else { - while ( packet.stream.IsAtEnd() == false ) + UpdateLastReceivedTic(packet.stream.ReadByte()); + + if (mStatus == NodeStatus::InPreGame) { - NetPacketType type = (NetPacketType)packet.stream.ReadByte(); - switch (type) - { - default: OnClose(); break; - case NetPacketType::ConnectResponse: OnConnectResponse(packet.stream); break; - case NetPacketType::Disconnect: OnDisconnect(); break; - case NetPacketType::Tic: OnTic(packet.stream); break; - case NetPacketType::SpawnActor: OnSpawnActor(packet.stream); break; - case NetPacketType::DestroyActor: OnDestroyActor(packet.stream); break; - } + ProcessCommands(packet.stream); + } + else + { + auto &ticUpdate = mTicUpdates[mLastReceivedTic % BACKUPTICS]; + ticUpdate.Resize(packet.stream.BytesLeft()); + packet.stream.ReadBuffer(ticUpdate.Data(), ticUpdate.Size()); } - break; } if (mStatus == NodeStatus::Closed) @@ -148,75 +141,33 @@ void NetClient::SetCurrentTic(int tictime) gametic = tictime; mSendTic = gametic + 10; - int jitter = 2; - if (mLastReceivedTic == -1) + if (abs(gametic + mServerTicDelta - mLastReceivedTic) > jitter) { - mServerTic = 0; + mServerTicDelta = mLastReceivedTic - gametic - jitter; } - else - { - if (mServerTicDelta == -1 || abs(gametic + mServerTicDelta - mLastReceivedTic) > jitter) - { - //Printf("netcable icon! ;)\n"); - mServerTicDelta = mLastReceivedTic - gametic - jitter; - } - mServerTic = MAX(gametic + mServerTicDelta, 0); - } + mServerTic = MAX(gametic + mServerTicDelta, 0); mCurrentInput[consoleplayer] = mSentInput[gametic % BACKUPTICS]; + + // [BB] Don't check net packets while we are supposed to load a map. + // This way the commands from the full update will not be parsed before we loaded the map. + //if ((gameaction == ga_newgame) || (gameaction == ga_newgame2)) + // return; + + TArray &update = mTicUpdates[mServerTic % BACKUPTICS]; + if (update.Size() > 0) + { + ByteInputStream stream(update.Data(), update.Size()); + ProcessCommands(stream); + update.Clear(); + } } void NetClient::EndCurrentTic() { mCurrentCommands = mSendCommands; mSendCommands.Clear(); - - if (mStatus != NodeStatus::InGame) - return; - - int targettic = (mSendTic + mServerTicDelta); - - NetOutputPacket packet(mServerNode); - - NetCommand cmd ( NetPacketType::Tic ); - cmd.addByte (targettic); // target gametic - cmd.addBuffer ( &mSentInput[(mSendTic - 1) % BACKUPTICS].ucmd, sizeof(usercmd_t) ); - cmd.writeCommandToStream ( packet.stream ); - - mComm->PacketSend(packet); - - TicUpdate &update = mTicUpdates[mServerTic % BACKUPTICS]; - if (update.received) - { - if (playeringame[consoleplayer] && players[consoleplayer].mo) - { - APlayerPawn *pawn = players[consoleplayer].mo; - if ((update.Pos - pawn->Pos()).LengthSquared() > 10.0) - pawn->SetOrigin(update.Pos, false); - else - P_TryMove(pawn, update.Pos.XY(), true); - pawn->Vel = update.Vel; - pawn->Angles.Yaw = update.yaw; - pawn->Angles.Pitch = update.pitch; - } - - for (unsigned int i = 0; i < update.syncUpdates.Size(); i++) - { - const TicSyncData &syncdata = update.syncUpdates[i]; - AActor *netactor = mNetIDList.findPointerByID(syncdata.netID); - if (netactor) - { - netactor->SetOrigin(syncdata.x, syncdata.y, syncdata.z, true); - netactor->Angles.Yaw = syncdata.yaw; - netactor->Angles.Pitch = syncdata.pitch; - netactor->sprite = syncdata.sprite; - netactor->frame = syncdata.frame; - } - } - - update = TicUpdate(); - } } int NetClient::GetSendTick() const @@ -242,9 +193,23 @@ void NetClient::RunCommands(int player) } } -void NetClient::WriteLocalInput(ticcmd_t cmd) +void NetClient::WriteLocalInput(ticcmd_t ticcmd) { - mSentInput[(mSendTic - 1) % BACKUPTICS] = cmd; + mSentInput[(mSendTic - 1) % BACKUPTICS] = ticcmd; + + if (mStatus == NodeStatus::InGame) + { + int targettic = (mSendTic + mServerTicDelta); + + NetOutputPacket packet(mServerNode); + + NetCommand cmd(NetPacketType::Tic); + cmd.addByte(targettic); // target gametic + cmd.addBuffer(&ticcmd.ucmd, sizeof(usercmd_t)); + cmd.writeCommandToStream(packet.stream); + + mComm->PacketSend(packet); + } } void NetClient::WriteBotInput(int player, const ticcmd_t &cmd) @@ -284,6 +249,39 @@ void NetClient::ActorDestroyed(AActor *actor) { } +void NetClient::UpdateLastReceivedTic(int tic) +{ + if (mLastReceivedTic != -1) + { + int delta = tic - (mLastReceivedTic & 0xff); + if (delta > 128) delta -= 256; + else if (delta < -128) delta += 256; + mLastReceivedTic += delta; + } + else + { + mLastReceivedTic = tic; + } + mLastReceivedTic = MAX(mLastReceivedTic, 0); +} + +void NetClient::ProcessCommands(ByteInputStream &stream) +{ + while (stream.IsAtEnd() == false) + { + NetPacketType type = (NetPacketType)stream.ReadByte(); + switch (type) + { + default: OnClose(); break; + case NetPacketType::ConnectResponse: OnConnectResponse(stream); break; + case NetPacketType::Disconnect: OnDisconnect(); break; + case NetPacketType::Tic: OnTic(stream); break; + case NetPacketType::SpawnActor: OnSpawnActor(stream); break; + case NetPacketType::DestroyActor: OnDestroyActor(stream); break; + } + } +} + void NetClient::OnClose() { mComm->Close(mServerNode); @@ -310,6 +308,7 @@ void NetClient::OnConnectResponse(ByteInputStream &stream) { mPlayer = playernum; mStatus = NodeStatus::InGame; + mServerTicDelta = mLastReceivedTic - gametic - jitter; G_InitClientNetGame(mPlayer, "e1m1"); @@ -340,55 +339,55 @@ void NetClient::OnDisconnect() mStatus = NodeStatus::Closed; } -void NetClient::UpdateLastReceivedTic(int tic) -{ - if (mLastReceivedTic != -1) - { - int delta = tic - (mLastReceivedTic & 0xff); - if (delta > 128) delta -= 256; - else if (delta < -128) delta += 256; - mLastReceivedTic += delta; - } - else - { - mLastReceivedTic = tic; - } - mLastReceivedTic = MAX(mLastReceivedTic, 0); -} - void NetClient::OnTic(ByteInputStream &stream) { - UpdateLastReceivedTic(stream.ReadByte()); + DVector3 Pos, Vel; + float yaw, pitch; + Pos.X = stream.ReadFloat(); + Pos.Y = stream.ReadFloat(); + Pos.Z = stream.ReadFloat(); + Vel.X = stream.ReadFloat(); + Vel.Y = stream.ReadFloat(); + Vel.Z = stream.ReadFloat(); + yaw = stream.ReadFloat(); + pitch = stream.ReadFloat(); - TicUpdate update; - update.received = true; - update.Pos.X = stream.ReadFloat(); - update.Pos.Y = stream.ReadFloat(); - update.Pos.Z = stream.ReadFloat(); - update.Vel.X = stream.ReadFloat(); - update.Vel.Y = stream.ReadFloat(); - update.Vel.Z = stream.ReadFloat(); - update.yaw = stream.ReadFloat(); - update.pitch = stream.ReadFloat(); + if (playeringame[consoleplayer] && players[consoleplayer].mo) + { + APlayerPawn *pawn = players[consoleplayer].mo; + if ((Pos - pawn->Pos()).LengthSquared() > 10.0) + pawn->SetOrigin(Pos, false); + else + P_TryMove(pawn, Pos.XY(), true); + pawn->Vel = Vel; + pawn->Angles.Yaw = yaw; + pawn->Angles.Pitch = pitch; + } while (true) { - TicSyncData syncdata; - syncdata.netID = stream.ReadShort(); - if (syncdata.netID == -1) + int netID = stream.ReadShort(); + if (netID == -1) break; - syncdata.x = stream.ReadFloat(); - syncdata.y = stream.ReadFloat(); - syncdata.z = stream.ReadFloat(); - syncdata.yaw = stream.ReadFloat(); - syncdata.pitch = stream.ReadFloat(); - syncdata.sprite = stream.ReadShort(); - syncdata.frame = stream.ReadByte(); - update.syncUpdates.Push(syncdata); - } + float x = stream.ReadFloat(); + float y = stream.ReadFloat(); + float z = stream.ReadFloat(); + float yaw = stream.ReadFloat(); + float pitch = stream.ReadFloat(); + int sprite = stream.ReadShort(); + uint8_t frame = stream.ReadByte(); - mTicUpdates[mLastReceivedTic % BACKUPTICS] = update; + AActor *netactor = mNetIDList.findPointerByID(netID); + if (netactor) + { + netactor->SetOrigin(x, y, z, true); + netactor->Angles.Yaw = yaw; + netactor->Angles.Pitch = pitch; + netactor->sprite = sprite; + netactor->frame = frame; + } + } } void NetClient::OnSpawnActor(ByteInputStream &stream) @@ -419,25 +418,5 @@ void NetClient::OnDestroyActor(ByteInputStream &stream) mNetIDList.freeID(netID); } -#if 0 // Use playerpawn, problematic as client pawn behavior may have to deviate from server side - // This player is now in the game. - playeringame[player] = true; - player_t &p = players[player]; - - if ( cl_showspawnnames ) - Printf ( "Spawning player %d at %f,%f,%f (id %d)\n", player, x, y, z, netID ); - - DVector3 spawn ( x, y, z ); - - p.mo = static_cast(Spawn (p.cls, spawn, NO_REPLACE)); - - if ( p.mo ) - { - // Set the network ID. - p.mo->syncdata.NetID = netID; - mNetIDList.useID ( netID, p.mo ); - } -#endif - IMPLEMENT_CLASS(ANetSyncActor, false, false) diff --git a/src/network/netclient.h b/src/network/netclient.h index 9a1e42a336..20035eeef1 100644 --- a/src/network/netclient.h +++ b/src/network/netclient.h @@ -61,6 +61,7 @@ private: void OnSpawnActor(ByteInputStream &stream); void OnDestroyActor(ByteInputStream &stream); + void ProcessCommands(ByteInputStream &stream); void UpdateLastReceivedTic(int tic); std::unique_ptr mComm; @@ -73,28 +74,9 @@ private: int mServerTicDelta = -1; int mLastReceivedTic = -1; - struct TicSyncData - { - int16_t netID; - float x; - float y; - float z; - float yaw; - float pitch; - int16_t sprite; - uint8_t frame; - }; + int jitter = 2; - struct TicUpdate - { - bool received = false; - DVector3 Pos; - DVector3 Vel; - float yaw; - float pitch; - TArray syncUpdates; - }; - TicUpdate mTicUpdates[BACKUPTICS]; + TArray mTicUpdates[BACKUPTICS]; ticcmd_t mCurrentInput[MAXPLAYERS]; ticcmd_t mSentInput[BACKUPTICS]; diff --git a/src/network/netcommand.cpp b/src/network/netcommand.cpp index 17e8970211..db06d85f3b 100644 --- a/src/network/netcommand.cpp +++ b/src/network/netcommand.cpp @@ -378,6 +378,11 @@ bool ByteInputStream::IsAtEnd() const return (pbStream >= pbStreamEnd); } +int ByteInputStream::BytesLeft() const +{ + return (int)(ptrdiff_t)(pbStreamEnd - pbStream); +} + void ByteInputStream::EnsureBitSpace(int bits, bool writing) { if ((bitBuffer == nullptr) || (bitShift < 0) || (bitShift + bits > 8)) diff --git a/src/network/netcommand.h b/src/network/netcommand.h index 73fb9c0c28..e435a12cb1 100644 --- a/src/network/netcommand.h +++ b/src/network/netcommand.h @@ -39,6 +39,7 @@ public: void ReadBuffer(void* buffer, size_t length); bool IsAtEnd() const; + int BytesLeft() const; private: void EnsureBitSpace(int bits, bool writing); diff --git a/src/network/netserver.cpp b/src/network/netserver.cpp index 738014454f..66ebbdbf56 100644 --- a/src/network/netserver.cpp +++ b/src/network/netserver.cpp @@ -137,14 +137,29 @@ void NetServer::EndCurrentTic() { if (mNodes[i].Status == NodeStatus::InGame) { + int player = mNodes[i].Player; + NetOutputPacket packet(i); + packet.stream.WriteByte(gametic + 1); + + if (mNodes[i].FirstTic) + { + TThinkerIterator it; + AActor *mo; + while (mo = it.Next()) + { + if (mo != players[player].mo) + { + CmdSpawnActor(packet.stream, mo); + } + } + mNodes[i].FirstTic = false; + } packet.stream.WriteBuffer(mBroadcastCommands.GetData(), mBroadcastCommands.GetSize()); NetCommand cmd ( NetPacketType::Tic); - cmd.addByte ( gametic ); - int player = mNodes[i].Player; if (playeringame[player] && players[player].mo) { cmd.addFloat(static_cast (players[player].mo->X())); @@ -310,6 +325,7 @@ void NetServer::OnConnectRequest(NetNode &node, ByteInputStream &stream) for (int i = 0; i < BACKUPTICS; i++) node.TicUpdates[i].received = false; + node.FirstTic = true; node.Status = NodeStatus::InGame; mNodeForPlayer[node.Player] = node.NodeIndex; @@ -317,6 +333,7 @@ void NetServer::OnConnectRequest(NetNode &node, ByteInputStream &stream) players[node.Player].settings_controller = false; NetOutputPacket response(node.NodeIndex); + response.stream.WriteByte(gametic); NetCommand cmd ( NetPacketType::ConnectResponse ); cmd.addByte ( 1 ); // Protocol version @@ -324,14 +341,13 @@ void NetServer::OnConnectRequest(NetNode &node, ByteInputStream &stream) cmd.writeCommandToStream ( response.stream ); mComm->PacketSend(response); - - FullUpdate ( node ); } else // Server is full. { node.Status = NodeStatus::Closed; NetOutputPacket response(node.NodeIndex); + response.stream.WriteByte(gametic); NetCommand cmd ( NetPacketType::ConnectResponse ); cmd.addByte ( 1 ); // Protocol version @@ -404,23 +420,6 @@ void NetServer::CmdDestroyActor(ByteOutputStream &stream, AActor *actor) cmd.writeCommandToStream(stream); } -void NetServer::FullUpdate(NetNode &node) -{ - NetOutputPacket packet(node.NodeIndex); - - TThinkerIterator it; - AActor *mo; - while (mo = it.Next()) - { - if (mo != players[node.Player].mo) - { - CmdSpawnActor(packet.stream, mo); - } - } - - mComm->PacketSend(packet); -} - void NetServer::ActorSpawned(AActor *actor) { actor->syncdata.NetID = mNetIDList.getNewID(); diff --git a/src/network/netserver.h b/src/network/netserver.h index 0be346536d..a5a17d62c5 100644 --- a/src/network/netserver.h +++ b/src/network/netserver.h @@ -39,6 +39,7 @@ struct NetNode int Gametic = 0; int Player = -1; int NodeIndex = -1; + bool FirstTic = true; struct TicUpdate { @@ -87,7 +88,6 @@ private: void CmdSpawnActor(ByteOutputStream &stream, AActor *actor); void CmdDestroyActor(ByteOutputStream &stream, AActor *actor); - void FullUpdate(NetNode &node); std::unique_ptr mComm; NetNode mNodes[MAXNETNODES];