mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-27 06:12:02 +00:00
Merge remote-tracking branch 'remotes/origin/clientserver' into clientserver
This commit is contained in:
commit
8595e4e02f
94 changed files with 4814 additions and 1796 deletions
|
@ -697,6 +697,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
|
||||
|
@ -952,7 +953,13 @@ set (PCH_SOURCES
|
|||
d_iwad.cpp
|
||||
d_main.cpp
|
||||
d_anonstats.cpp
|
||||
d_net.cpp
|
||||
network/net.cpp
|
||||
network/netsingle.cpp
|
||||
network/netserver.cpp
|
||||
network/netsync.cpp
|
||||
network/netclient.cpp
|
||||
network/netcommand.cpp
|
||||
network/i_net.cpp
|
||||
d_netinfo.cpp
|
||||
d_protocol.cpp
|
||||
dobject.cpp
|
||||
|
@ -967,7 +974,6 @@ set (PCH_SOURCES
|
|||
gameconfigfile.cpp
|
||||
gitinfo.cpp
|
||||
hu_scores.cpp
|
||||
i_net.cpp
|
||||
m_cheat.cpp
|
||||
m_joy.cpp
|
||||
m_misc.cpp
|
||||
|
@ -1580,6 +1586,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("Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/.+")
|
||||
source_group("Utility\\Node Builder" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/nodebuilder/.+")
|
||||
source_group("Utility\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/math/.+")
|
||||
|
|
|
@ -61,7 +61,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"
|
||||
|
@ -123,8 +123,8 @@ CCMD (god)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_GOD);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_GOD);
|
||||
}
|
||||
|
||||
CCMD(god2)
|
||||
|
@ -132,8 +132,8 @@ CCMD(god2)
|
|||
if (CheckCheatmode())
|
||||
return;
|
||||
|
||||
Net_WriteByte(DEM_GENERICCHEAT);
|
||||
Net_WriteByte(CHT_GOD2);
|
||||
network->WriteByte(DEM_GENERICCHEAT);
|
||||
network->WriteByte(CHT_GOD2);
|
||||
}
|
||||
|
||||
CCMD (iddqd)
|
||||
|
@ -141,8 +141,8 @@ CCMD (iddqd)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_IDDQD);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_IDDQD);
|
||||
}
|
||||
|
||||
CCMD (buddha)
|
||||
|
@ -150,8 +150,8 @@ CCMD (buddha)
|
|||
if (CheckCheatmode())
|
||||
return;
|
||||
|
||||
Net_WriteByte(DEM_GENERICCHEAT);
|
||||
Net_WriteByte(CHT_BUDDHA);
|
||||
network->WriteByte(DEM_GENERICCHEAT);
|
||||
network->WriteByte(CHT_BUDDHA);
|
||||
}
|
||||
|
||||
CCMD(buddha2)
|
||||
|
@ -159,8 +159,8 @@ CCMD(buddha2)
|
|||
if (CheckCheatmode())
|
||||
return;
|
||||
|
||||
Net_WriteByte(DEM_GENERICCHEAT);
|
||||
Net_WriteByte(CHT_BUDDHA2);
|
||||
network->WriteByte(DEM_GENERICCHEAT);
|
||||
network->WriteByte(CHT_BUDDHA2);
|
||||
}
|
||||
|
||||
CCMD (notarget)
|
||||
|
@ -168,8 +168,8 @@ CCMD (notarget)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_NOTARGET);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_NOTARGET);
|
||||
}
|
||||
|
||||
CCMD (fly)
|
||||
|
@ -177,8 +177,8 @@ CCMD (fly)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_FLY);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_FLY);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -193,8 +193,8 @@ CCMD (noclip)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_NOCLIP);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_NOCLIP);
|
||||
}
|
||||
|
||||
CCMD (noclip2)
|
||||
|
@ -202,8 +202,8 @@ CCMD (noclip2)
|
|||
if (CheckCheatmode())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_NOCLIP2);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_NOCLIP2);
|
||||
}
|
||||
|
||||
CCMD (powerup)
|
||||
|
@ -211,8 +211,8 @@ CCMD (powerup)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_POWER);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_POWER);
|
||||
}
|
||||
|
||||
CCMD (morphme)
|
||||
|
@ -222,13 +222,13 @@ CCMD (morphme)
|
|||
|
||||
if (argv.argc() == 1)
|
||||
{
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_MORPH);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_MORPH);
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte (DEM_MORPHEX);
|
||||
Net_WriteString (argv[1]);
|
||||
network->WriteByte (DEM_MORPHEX);
|
||||
network->WriteString (argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,8 +237,8 @@ CCMD (anubis)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_ANUBIS);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_ANUBIS);
|
||||
}
|
||||
|
||||
// [GRB]
|
||||
|
@ -247,8 +247,8 @@ CCMD (resurrect)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_RESSURECT);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_RESSURECT);
|
||||
}
|
||||
|
||||
EXTERN_CVAR (Bool, chasedemo)
|
||||
|
@ -279,8 +279,8 @@ CCMD (chase)
|
|||
if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && deathmatch && CheckCheatmode ()))
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_CHASECAM);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_CHASECAM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,14 +378,14 @@ CCMD (changemap)
|
|||
{
|
||||
if (argv.argc() > 2)
|
||||
{
|
||||
Net_WriteByte (DEM_CHANGEMAP2);
|
||||
Net_WriteByte (atoi(argv[2]));
|
||||
network->WriteByte (DEM_CHANGEMAP2);
|
||||
network->WriteByte (atoi(argv[2]));
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte (DEM_CHANGEMAP);
|
||||
network->WriteByte (DEM_CHANGEMAP);
|
||||
}
|
||||
Net_WriteString (mapname);
|
||||
network->WriteString (mapname);
|
||||
}
|
||||
}
|
||||
catch(CRecoverableError &error)
|
||||
|
@ -405,12 +405,12 @@ CCMD (give)
|
|||
if (CheckCheatmode () || argv.argc() < 2)
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GIVECHEAT);
|
||||
Net_WriteString (argv[1]);
|
||||
network->WriteByte (DEM_GIVECHEAT);
|
||||
network->WriteString (argv[1]);
|
||||
if (argv.argc() > 2)
|
||||
Net_WriteLong(atoi(argv[2]));
|
||||
network->WriteLong(atoi(argv[2]));
|
||||
else
|
||||
Net_WriteLong(0);
|
||||
network->WriteLong(0);
|
||||
}
|
||||
|
||||
CCMD (take)
|
||||
|
@ -418,12 +418,12 @@ CCMD (take)
|
|||
if (CheckCheatmode () || argv.argc() < 2)
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_TAKECHEAT);
|
||||
Net_WriteString (argv[1]);
|
||||
network->WriteByte (DEM_TAKECHEAT);
|
||||
network->WriteString (argv[1]);
|
||||
if (argv.argc() > 2)
|
||||
Net_WriteLong(atoi (argv[2]));
|
||||
network->WriteLong(atoi (argv[2]));
|
||||
else
|
||||
Net_WriteLong (0);
|
||||
network->WriteLong (0);
|
||||
}
|
||||
|
||||
CCMD(setinv)
|
||||
|
@ -431,17 +431,17 @@ CCMD(setinv)
|
|||
if (CheckCheatmode() || argv.argc() < 2)
|
||||
return;
|
||||
|
||||
Net_WriteByte(DEM_SETINV);
|
||||
Net_WriteString(argv[1]);
|
||||
network->WriteByte(DEM_SETINV);
|
||||
network->WriteString(argv[1]);
|
||||
if (argv.argc() > 2)
|
||||
Net_WriteLong(atoi(argv[2]));
|
||||
network->WriteLong(atoi(argv[2]));
|
||||
else
|
||||
Net_WriteLong(0);
|
||||
network->WriteLong(0);
|
||||
|
||||
if (argv.argc() > 3)
|
||||
Net_WriteByte(!!atoi(argv[3]));
|
||||
network->WriteByte(!!atoi(argv[3]));
|
||||
else
|
||||
Net_WriteByte(0);
|
||||
network->WriteByte(0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -539,18 +539,18 @@ CCMD (puke)
|
|||
|
||||
if (script > 0)
|
||||
{
|
||||
Net_WriteByte (DEM_RUNSCRIPT);
|
||||
Net_WriteWord (script);
|
||||
network->WriteByte (DEM_RUNSCRIPT);
|
||||
network->WriteWord (script);
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte (DEM_RUNSCRIPT2);
|
||||
Net_WriteWord (-script);
|
||||
network->WriteByte (DEM_RUNSCRIPT2);
|
||||
network->WriteWord (-script);
|
||||
}
|
||||
Net_WriteByte (argn);
|
||||
network->WriteByte (argn);
|
||||
for (i = 0; i < argn; ++i)
|
||||
{
|
||||
Net_WriteLong (arg[i]);
|
||||
network->WriteLong (arg[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -583,12 +583,12 @@ CCMD (pukename)
|
|||
arg[i] = atoi(argv[argstart + i]);
|
||||
}
|
||||
}
|
||||
Net_WriteByte(DEM_RUNNAMEDSCRIPT);
|
||||
Net_WriteString(argv[1]);
|
||||
Net_WriteByte(argn | (always << 7));
|
||||
network->WriteByte(DEM_RUNNAMEDSCRIPT);
|
||||
network->WriteString(argv[1]);
|
||||
network->WriteByte(argn | (always << 7));
|
||||
for (i = 0; i < argn; ++i)
|
||||
{
|
||||
Net_WriteLong(arg[i]);
|
||||
network->WriteLong(arg[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -629,12 +629,12 @@ CCMD (special)
|
|||
return;
|
||||
}
|
||||
}
|
||||
Net_WriteByte(DEM_RUNSPECIAL);
|
||||
Net_WriteWord(specnum);
|
||||
Net_WriteByte(argc - 2);
|
||||
network->WriteByte(DEM_RUNSPECIAL);
|
||||
network->WriteWord(specnum);
|
||||
network->WriteByte(argc - 2);
|
||||
for (int i = 2; i < argc; ++i)
|
||||
{
|
||||
Net_WriteLong(atoi(argv[i]));
|
||||
network->WriteLong(atoi(argv[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -780,10 +780,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->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;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_CLEARFROZENPROPS);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_CLEARFROZENPROPS);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -56,7 +56,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"
|
||||
|
@ -1243,7 +1243,7 @@ void C_FullConsole ()
|
|||
{
|
||||
if (demoplayback)
|
||||
G_CheckDemoStatus ();
|
||||
D_QuitNetGame ();
|
||||
network->D_QuitNetGame ();
|
||||
advancedemo = false;
|
||||
ConsoleState = c_down;
|
||||
HistPos = NULL;
|
||||
|
|
|
@ -988,7 +988,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)
|
||||
|
|
|
@ -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"
|
||||
|
@ -617,7 +617,7 @@ void C_DoCommand (const char *cmd, int keynum)
|
|||
button->ReleaseKey (keynum);
|
||||
if (button == &Button_Mlook && lookspring)
|
||||
{
|
||||
Net_WriteByte (DEM_CENTERVIEW);
|
||||
network->WriteByte (DEM_CENTERVIEW);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -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"
|
||||
#include "v_video.h"
|
||||
|
@ -355,16 +355,16 @@ static void ShoveChatStr (const char *str, uint8_t who)
|
|||
who |= 2;
|
||||
}
|
||||
|
||||
Net_WriteByte (DEM_SAY);
|
||||
Net_WriteByte (who);
|
||||
network->WriteByte (DEM_SAY);
|
||||
network->WriteByte (who);
|
||||
|
||||
if (!chat_substitution || !DoSubstitution (substBuff, str))
|
||||
{
|
||||
Net_WriteString(MakeUTF8(str));
|
||||
network->WriteString(MakeUTF8(str));
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteString(MakeUTF8(substBuff));
|
||||
network->WriteString(MakeUTF8(substBuff));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,15 +122,13 @@ typedef enum
|
|||
void D_PostEvent (const event_t* ev);
|
||||
void D_RemoveNextCharEvent();
|
||||
void D_Render(std::function<void()> action, bool interpolate);
|
||||
|
||||
void D_AddPostedEvents();
|
||||
|
||||
//
|
||||
// GLOBAL VARIABLES
|
||||
//
|
||||
#define MAXEVENTS 128
|
||||
|
||||
extern event_t events[MAXEVENTS];
|
||||
|
||||
extern gameaction_t gameaction;
|
||||
|
||||
|
||||
|
|
254
src/d_main.cpp
254
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"
|
||||
|
@ -102,6 +102,7 @@
|
|||
#include "i_system.h"
|
||||
#include "g_cvars.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
#include "network/netsingle.h"
|
||||
#include "atterm.h"
|
||||
|
||||
EXTERN_CVAR(Bool, hud_althud)
|
||||
|
@ -126,9 +127,7 @@ const FIWADInfo *D_FindIWAD(TArray<FString> &wadfiles, const char *iwad, const c
|
|||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
void D_CheckNetGame ();
|
||||
void D_ProcessEvents ();
|
||||
void G_BuildTiccmd (ticcmd_t* cmd);
|
||||
void D_DoAdvanceDemo ();
|
||||
void D_AddWildFile (TArray<FString> &wadfiles, const char *pattern);
|
||||
void D_LoadWadSettings ();
|
||||
|
@ -222,9 +221,10 @@ FString StoredWarp;
|
|||
bool advancedemo;
|
||||
FILE *debugfile;
|
||||
FILE *hashfile;
|
||||
event_t events[MAXEVENTS];
|
||||
int eventhead;
|
||||
int eventtail;
|
||||
static TArray<event_t> 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 *Advisory;
|
||||
|
@ -292,33 +292,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 && !primaryLevel->localEventManager->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 && !primaryLevel->localEventManager->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();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -399,14 +412,14 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO | CVAR_NOINITCALL)
|
|||
|
||||
if (self & DF_NO_FREELOOK)
|
||||
{
|
||||
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;
|
||||
|
||||
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
|
||||
|
@ -416,7 +429,7 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO | CVAR_NOINITCALL)
|
|||
{
|
||||
fov = 90;
|
||||
}
|
||||
Net_WriteFloat (fov);
|
||||
network->WriteFloat (fov);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -898,9 +911,6 @@ void D_Display ()
|
|||
|
||||
if (!wipe || NoWipe < 0 || wipe_type == wipe_None)
|
||||
{
|
||||
if (wipe != nullptr) delete wipe;
|
||||
wipe = nullptr;
|
||||
NetUpdate (); // send out any new accumulation
|
||||
// normal update
|
||||
// draw ZScript UI stuff
|
||||
C_DrawConsole (); // draw console
|
||||
|
@ -922,7 +932,6 @@ void D_Display ()
|
|||
wiper->SetTextures(wipe, wipend);
|
||||
|
||||
wipestart = I_msTime();
|
||||
NetUpdate(); // send out any new accumulation
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -938,7 +947,6 @@ void D_Display ()
|
|||
C_DrawConsole (); // console and
|
||||
M_Drawer (); // menu are drawn even on top of wipes
|
||||
screen->End2DAndUpdate ();
|
||||
NetUpdate (); // [RH] not sure this is needed anymore
|
||||
} while (!done);
|
||||
delete wiper;
|
||||
I_FreezeTime(false);
|
||||
|
@ -959,10 +967,10 @@ void D_ErrorCleanup ()
|
|||
{
|
||||
savegamerestore = false;
|
||||
primaryLevel->BotInfo.RemoveAllBots (primaryLevel, true);
|
||||
D_QuitNetGame ();
|
||||
network->D_QuitNetGame ();
|
||||
if (demorecording || demoplayback)
|
||||
G_CheckDemoStatus ();
|
||||
Net_ClearBuffers ();
|
||||
network->Net_ClearBuffers ();
|
||||
G_NewInit ();
|
||||
M_ClearMenus ();
|
||||
singletics = false;
|
||||
|
@ -986,10 +994,106 @@ void D_ErrorCleanup ()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void D_DoomLoop ()
|
||||
class GameTime
|
||||
{
|
||||
int lasttic = 0;
|
||||
public:
|
||||
void Update()
|
||||
{
|
||||
LastTic = CurrentTic;
|
||||
I_SetFrameTime();
|
||||
CurrentTic = I_GetTime();
|
||||
}
|
||||
|
||||
int TicsElapsed() const
|
||||
{
|
||||
return CurrentTic - LastTic;
|
||||
}
|
||||
|
||||
int BaseGameTic() const
|
||||
{
|
||||
return LastTic;
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
network->SetCurrentTic(gametime.BaseGameTic() + i);
|
||||
network->WriteLocalInput(G_BuildTiccmd());
|
||||
|
||||
if (advancedemo)
|
||||
D_DoAdvanceDemo();
|
||||
|
||||
C_Ticker();
|
||||
M_Ticker();
|
||||
G_Ticker();
|
||||
|
||||
network->EndCurrentTic();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
// Clamp the timer to TICRATE until the playloop has been entered.
|
||||
r_NoInterpolate = true;
|
||||
Page.SetInvalid();
|
||||
|
@ -998,56 +1102,36 @@ void D_DoomLoop ()
|
|||
|
||||
vid_cursor.Callback();
|
||||
|
||||
for (;;)
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
// frame syncronous IO operations
|
||||
if (gametic > lasttic)
|
||||
{
|
||||
lasttic = gametic;
|
||||
I_StartFrame ();
|
||||
}
|
||||
I_SetFrameTime();
|
||||
gametime.Update();
|
||||
if (netconnect)
|
||||
netconnect->Update();
|
||||
network->Update();
|
||||
input.Update();
|
||||
playsim.Update();
|
||||
input.BeforeDisplayUpdate();
|
||||
display.Update();
|
||||
|
||||
GC::CheckGC();
|
||||
|
||||
// process one or more tics
|
||||
if (singletics)
|
||||
{
|
||||
I_StartTic ();
|
||||
D_ProcessEvents ();
|
||||
G_BuildTiccmd (&netcmds[consoleplayer][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++;
|
||||
maketic++;
|
||||
GC::CheckGC ();
|
||||
Net_NewMakeTic ();
|
||||
}
|
||||
else
|
||||
{
|
||||
TryRunTics (); // will run at least one tic
|
||||
}
|
||||
// Update display, next frame, with current state.
|
||||
I_StartTic ();
|
||||
D_Display ();
|
||||
if (wantToRestart)
|
||||
{
|
||||
P_UnPredictPlayer();
|
||||
|
||||
wantToRestart = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (CRecoverableError &error)
|
||||
{
|
||||
if (error.GetMessage ())
|
||||
if (error.GetMessage())
|
||||
{
|
||||
Printf (PRINT_BOLD, "\n%s\n", error.GetMessage());
|
||||
Printf(PRINT_BOLD, "\n%s\n", error.GetMessage());
|
||||
}
|
||||
D_ErrorCleanup ();
|
||||
D_ErrorCleanup();
|
||||
}
|
||||
catch (CVMAbortException &error)
|
||||
{
|
||||
|
@ -2325,6 +2409,8 @@ void D_DoomMain (void)
|
|||
|
||||
D_DoomInit();
|
||||
|
||||
network.reset(new NetSinglePlayer());
|
||||
|
||||
extern void D_ConfirmSendStats();
|
||||
D_ConfirmSendStats();
|
||||
|
||||
|
@ -2603,9 +2689,7 @@ void D_DoomMain (void)
|
|||
|
||||
if (!restart)
|
||||
{
|
||||
if (!batchrun) Printf ("D_CheckNetGame: Checking network game status.\n");
|
||||
StartScreen->LoadingStatus ("Checking network game status.", 0x3f);
|
||||
D_CheckNetGame ();
|
||||
D_SetupUserInfo();
|
||||
}
|
||||
|
||||
// [SP] Force vanilla transparency auto-detection to re-detect our game lumps now
|
||||
|
@ -2620,7 +2704,7 @@ void D_DoomMain (void)
|
|||
|
||||
// [RH] Run any saved commands from the command line or autoexec.cfg now.
|
||||
gamestate = GS_FULLCONSOLE;
|
||||
Net_NewMakeTic ();
|
||||
network->Startup();
|
||||
C_RunDelayedCommands();
|
||||
gamestate = GS_STARTUP;
|
||||
|
||||
|
@ -2703,7 +2787,7 @@ void D_DoomMain (void)
|
|||
G_BeginRecording(NULL);
|
||||
}
|
||||
|
||||
atterm(D_QuitNetGame); // killough
|
||||
atterm([] { network->D_QuitNetGame(); }); // killough
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2876,7 +2960,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<bool()> callback) { return false; }
|
||||
|
||||
DEFINE_FIELD_X(InputEventData, event_t, type)
|
||||
DEFINE_FIELD_X(InputEventData, event_t, subtype)
|
||||
|
|
186
src/d_net.h
186
src/d_net.h
|
@ -1,186 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright 1993-1996 id Software
|
||||
// Copyright 1999-2016 Randy Heit
|
||||
// Copyright 2002-2016 Christoph Oelckers
|
||||
//
|
||||
// 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/
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Networking stuff.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __D_NET__
|
||||
#define __D_NET__
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "doomdef.h"
|
||||
#include "d_protocol.h"
|
||||
|
||||
|
||||
//
|
||||
// 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 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:
|
||||
FDynamicBuffer ();
|
||||
~FDynamicBuffer ();
|
||||
|
||||
void SetData (const uint8_t *data, int len);
|
||||
uint8_t *GetData (int *len = NULL);
|
||||
|
||||
private:
|
||||
uint8_t *m_Data;
|
||||
int m_Len, m_BufferLen;
|
||||
};
|
||||
|
||||
extern FDynamicBuffer NetSpecs[MAXPLAYERS][BACKUPTICS];
|
||||
|
||||
// Create any new ticcmds and broadcast to other players.
|
||||
void NetUpdate (void);
|
||||
|
||||
// Broadcasts special packets to other players
|
||||
// to notify of game exit
|
||||
void D_QuitNetGame (void);
|
||||
|
||||
//? how many ticks to run?
|
||||
void TryRunTics (void);
|
||||
|
||||
//Use for checking to see if the netgame has stalled
|
||||
void Net_CheckLastReceived(int);
|
||||
|
||||
// [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);
|
||||
|
||||
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:
|
||||
//
|
||||
// Header:
|
||||
// One byte with following flags.
|
||||
// One byte with starttic
|
||||
// One byte with master's maketic (master -> slave only!)
|
||||
// If NCMD_RETRANSMIT set, one byte with retransmitfrom
|
||||
// If NCMD_XTICS set, one byte with number of tics (minus 3, so theoretically up to 258 tics in one packet)
|
||||
// If NCMD_QUITTERS, one byte with number of players followed by one byte with each player's consolenum
|
||||
// If NCMD_MULTI, one byte with number of players followed by one byte with each player's consolenum
|
||||
// - 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
|
||||
//
|
||||
// Setup packets are different, and are described just before D_ArbitrateNetStart().
|
||||
|
||||
#define NCMD_EXIT 0x80
|
||||
#define NCMD_RETRANSMIT 0x40
|
||||
#define NCMD_SETUP 0x20
|
||||
#define NCMD_MULTI 0x10 // multiple players in this packet
|
||||
#define NCMD_QUITTERS 0x08 // one or more players just quit (packet server only)
|
||||
#define NCMD_COMPRESSED 0x04 // remainder of packet is compressed
|
||||
|
||||
#define NCMD_XTICS 0x03 // packet contains >2 tics
|
||||
#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
|
|
@ -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"
|
||||
|
@ -544,8 +544,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->WriteByte (DEM_UINFCHANGED);
|
||||
network->WriteString (foo);
|
||||
}
|
||||
|
||||
static const char *SetServerVar (char *name, ECVarType type, uint8_t **stream, bool singlebit)
|
||||
|
@ -628,15 +628,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->WriteByte (DEM_SINFCHANGED);
|
||||
network->WriteByte ((uint8_t)(namelen | (type << 6)));
|
||||
network->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->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
|
||||
}
|
||||
}
|
||||
|
@ -647,10 +647,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->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)
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
|
||||
#include "d_protocol.h"
|
||||
#include "d_net.h"
|
||||
#include "network/net.h"
|
||||
#include "doomstat.h"
|
||||
#include "cmdlib.h"
|
||||
#include "serializer.h"
|
||||
|
@ -290,7 +290,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();
|
||||
}
|
||||
|
@ -360,7 +360,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++;
|
||||
|
@ -407,68 +407,6 @@ int SkipTicCmd (uint8_t **stream, int count)
|
|||
return skip;
|
||||
}
|
||||
|
||||
extern short consistancy[MAXPLAYERS][BACKUPTICS];
|
||||
void 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->consistancy = 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(consistancy[player][ticmod] == tcmd->consistancy);
|
||||
}
|
||||
|
||||
void RunNetSpecs (int player, int buf)
|
||||
{
|
||||
uint8_t *stream;
|
||||
int len;
|
||||
|
||||
if (gametic % ticdup == 0)
|
||||
{
|
||||
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 (NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *lenspot;
|
||||
|
||||
// Write the header of an IFF chunk and leave space
|
||||
|
|
|
@ -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 consistancy; // 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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include "gi.h"
|
||||
#include "actor.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "d_net.h"
|
||||
#include "network/net.h"
|
||||
#include "g_game.h"
|
||||
#include "info.h"
|
||||
#include "utf8.h"
|
||||
|
@ -165,13 +165,13 @@ bool EventManager::SendNetworkEvent(FString name, int arg1, int arg2, int arg3,
|
|||
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->WriteByte(DEM_NETEVENT);
|
||||
network->WriteString(name);
|
||||
network->WriteByte(3);
|
||||
network->WriteLong(arg1);
|
||||
network->WriteLong(arg2);
|
||||
network->WriteLong(arg3);
|
||||
network->WriteByte(manual);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include "g_levellocals.h"
|
||||
#include "a_dynlight.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "d_net.h"
|
||||
#include "network/net.h"
|
||||
#include "p_setup.h"
|
||||
#include "w_wad.h"
|
||||
#include "v_text.h"
|
||||
|
@ -127,8 +127,8 @@ CCMD (spray)
|
|||
return;
|
||||
}
|
||||
|
||||
Net_WriteByte (DEM_SPRAY);
|
||||
Net_WriteString (argv[1]);
|
||||
network->WriteByte (DEM_SPRAY);
|
||||
network->WriteString (argv[1]);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
215
src/g_game.cpp
215
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"
|
||||
|
@ -79,6 +79,7 @@
|
|||
#include "g_hub.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "events.h"
|
||||
#include "gameconfigfile.h"
|
||||
|
||||
|
||||
static FRandom pr_dmspawn ("DMSpawn");
|
||||
|
@ -86,7 +87,7 @@ static FRandom pr_pspawn ("PlayerSpawn");
|
|||
|
||||
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);
|
||||
|
@ -152,6 +153,8 @@ bool viewactive;
|
|||
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];
|
||||
|
||||
|
@ -176,9 +179,6 @@ uint8_t* zdembodyend; // end of ZDEM BODY chunk
|
|||
bool singledemo; // quit after playing a demo from cmdline
|
||||
|
||||
bool precache = true; // if true, load all graphics at start
|
||||
|
||||
short consistancy[MAXPLAYERS][BACKUPTICS];
|
||||
|
||||
|
||||
#define MAXPLMOVE (forwardmove[1])
|
||||
|
||||
|
@ -310,12 +310,12 @@ CCMD (slot)
|
|||
|
||||
CCMD (centerview)
|
||||
{
|
||||
Net_WriteByte (DEM_CENTERVIEW);
|
||||
network->WriteByte (DEM_CENTERVIEW);
|
||||
}
|
||||
|
||||
CCMD(crouch)
|
||||
{
|
||||
Net_WriteByte(DEM_CROUCH);
|
||||
network->WriteByte(DEM_CROUCH);
|
||||
}
|
||||
|
||||
CCMD (land)
|
||||
|
@ -525,7 +525,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;
|
||||
|
@ -533,12 +533,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->consistancy = consistancy[consoleplayer][(maketic/ticdup)%BACKUPTICS];
|
||||
cmd.consistency = network->GetConsoleConsistency();
|
||||
|
||||
strafe = Button_Strafe.bDown;
|
||||
speed = Button_Speed.bDown ^ (int)cl_run;
|
||||
|
@ -549,7 +546,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;
|
||||
|
||||
|
@ -613,32 +610,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];
|
||||
|
@ -676,7 +673,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)
|
||||
{
|
||||
|
@ -699,10 +696,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;
|
||||
|
||||
|
@ -710,42 +707,44 @@ void G_BuildTiccmd (ticcmd_t *cmd)
|
|||
if (sendturn180)
|
||||
{
|
||||
sendturn180 = false;
|
||||
cmd->ucmd.buttons |= BT_TURN180;
|
||||
cmd.ucmd.buttons |= BT_TURN180;
|
||||
}
|
||||
if (sendpause)
|
||||
{
|
||||
sendpause = false;
|
||||
Net_WriteByte (DEM_PAUSE);
|
||||
network->WriteByte (DEM_PAUSE);
|
||||
}
|
||||
if (sendsave)
|
||||
{
|
||||
sendsave = false;
|
||||
Net_WriteByte (DEM_SAVEGAME);
|
||||
Net_WriteString (savegamefile);
|
||||
Net_WriteString (savedescription);
|
||||
network->WriteByte (DEM_SAVEGAME);
|
||||
network->WriteString (savegamefile);
|
||||
network->WriteString (savedescription);
|
||||
savegamefile = "";
|
||||
}
|
||||
if (SendItemUse == (const AActor *)1)
|
||||
{
|
||||
Net_WriteByte (DEM_INVUSEALL);
|
||||
network->WriteByte (DEM_INVUSEALL);
|
||||
SendItemUse = NULL;
|
||||
}
|
||||
else if (SendItemUse != NULL)
|
||||
{
|
||||
Net_WriteByte (DEM_INVUSE);
|
||||
Net_WriteLong (SendItemUse->InventoryID);
|
||||
network->WriteByte (DEM_INVUSE);
|
||||
network->WriteLong (SendItemUse->InventoryID);
|
||||
SendItemUse = NULL;
|
||||
}
|
||||
if (SendItemDrop != NULL)
|
||||
{
|
||||
Net_WriteByte (DEM_INVDROP);
|
||||
Net_WriteLong (SendItemDrop->InventoryID);
|
||||
Net_WriteLong(SendItemDropAmount);
|
||||
network->WriteByte (DEM_INVDROP);
|
||||
network->WriteLong (SendItemDrop->InventoryID);
|
||||
network->WriteLong(SendItemDropAmount);
|
||||
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!
|
||||
|
@ -853,7 +852,7 @@ static void ChangeSpy (int changespy)
|
|||
// has done this for you, since it could desync otherwise.
|
||||
if (!demoplayback)
|
||||
{
|
||||
Net_WriteByte(DEM_REVERTCAMERA);
|
||||
network->WriteByte(DEM_REVERTCAMERA);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1115,10 +1114,7 @@ void G_Ticker ()
|
|||
}
|
||||
}
|
||||
|
||||
// get commands, check consistancy, and build new consistancy check
|
||||
int buf = (gametic/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 ();
|
||||
|
||||
|
@ -1130,15 +1126,13 @@ void G_Ticker ()
|
|||
if (playeringame[i])
|
||||
{
|
||||
ticcmd_t *cmd = &players[i].cmd;
|
||||
ticcmd_t *newcmd = &netcmds[i][buf];
|
||||
ticcmd_t newcmd = network->GetPlayerInput(i);
|
||||
|
||||
network->RunCommands(i);
|
||||
|
||||
if ((gametic % 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,
|
||||
|
@ -1150,7 +1144,7 @@ void G_Ticker ()
|
|||
}
|
||||
else
|
||||
{
|
||||
memcpy(cmd, newcmd, sizeof(ticcmd_t));
|
||||
*cmd = newcmd;
|
||||
}
|
||||
|
||||
// check for turbo cheats
|
||||
|
@ -1160,22 +1154,21 @@ 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 (network->IsInconsistent(i, cmd->consistency))
|
||||
{
|
||||
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->SetConsistency(i, sum);
|
||||
}
|
||||
else
|
||||
{
|
||||
consistancy[i][buf] = rngsum;
|
||||
network->SetConsistency(i, rngsum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2374,11 +2367,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 ();
|
||||
|
@ -2390,12 +2380,7 @@ 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)
|
||||
{
|
||||
memcpy (demo_p, specdata, speclen);
|
||||
demo_p += speclen;
|
||||
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);
|
||||
|
@ -2796,6 +2781,68 @@ void G_TimeDemo (const char* name)
|
|||
gameaction = (gameaction == ga_loadgame) ? ga_loadgameplaydemo : ga_playdemo;
|
||||
}
|
||||
|
||||
void G_InitServerNetGame(const char *mapname)
|
||||
{
|
||||
netgame = true;
|
||||
netserver = true;
|
||||
netclient = false;
|
||||
multiplayer = true;
|
||||
multiplayernext = true;
|
||||
consoleplayer = 0;
|
||||
players[consoleplayer].settings_controller = true;
|
||||
playeringame[consoleplayer] = true;
|
||||
|
||||
GameConfig->ReadNetVars(); // [RH] Read network ServerInfo cvars
|
||||
D_SetupUserInfo();
|
||||
|
||||
G_NetGameInitNew(mapname);
|
||||
}
|
||||
|
||||
void G_InitClientNetGame(int player, const char* mapname)
|
||||
{
|
||||
netgame = true;
|
||||
netserver = false;
|
||||
netclient = true;
|
||||
multiplayer = true;
|
||||
multiplayernext = true;
|
||||
consoleplayer = player;
|
||||
|
||||
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
|
||||
D_SetupUserInfo();
|
||||
|
||||
G_NetGameInitNew(mapname);
|
||||
}
|
||||
|
||||
void G_EndNetGame()
|
||||
{
|
||||
gameaction = ga_fullconsole;
|
||||
|
||||
// Should we do this?
|
||||
//C_RestoreCVars(); // Is this a good idea?
|
||||
|
||||
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;
|
||||
players[0].camera = NULL;
|
||||
if (StatusBar != NULL)
|
||||
{
|
||||
StatusBar->AttachToPlayer(&players[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
|
|
|
@ -92,6 +92,10 @@ 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_Ticker (void);
|
||||
bool G_Responder (event_t* ev);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
@ -108,6 +108,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)
|
||||
{
|
||||
|
@ -167,6 +168,9 @@ extern bool sendpause, sendsave, sendturn180, SendLand;
|
|||
|
||||
void *statcopy; // for statistics driver
|
||||
|
||||
extern bool netserver; // serverside playsim
|
||||
extern bool netclient; // clientside playsim
|
||||
|
||||
FLevelLocals level; // info about current level
|
||||
FLevelLocals *primaryLevel = &level; // level for which to display the user interface.
|
||||
FLevelLocals *currentVMLevel = &level; // level which currently ticks. Used as global input to the VM and some functions called by it.
|
||||
|
@ -201,6 +205,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();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -370,7 +383,7 @@ void G_NewInit ()
|
|||
}
|
||||
|
||||
G_ClearSnapshots ();
|
||||
netgame = false;
|
||||
netgame = (netclient || netserver);
|
||||
multiplayer = multiplayernext;
|
||||
multiplayernext = false;
|
||||
if (demoplayback)
|
||||
|
@ -1007,7 +1020,7 @@ IMPLEMENT_CLASS(DAutosaver, false, false)
|
|||
|
||||
void DAutosaver::Tick ()
|
||||
{
|
||||
Net_WriteByte (DEM_CHECKAUTOSAVE);
|
||||
network->WriteByte (DEM_CHECKAUTOSAVE);
|
||||
Destroy ();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,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);
|
||||
|
||||
enum
|
||||
{
|
||||
CHANGELEVEL_KEEPFACING = 1,
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include "p_local.h"
|
||||
#include "doomstat.h"
|
||||
#include "g_level.h"
|
||||
#include "d_net.h"
|
||||
#include "d_player.h"
|
||||
#include "r_utility.h"
|
||||
#include "cmdlib.h"
|
||||
|
|
|
@ -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"
|
||||
|
@ -1380,7 +1380,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,
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -464,15 +464,15 @@ void FWeaponSlots::SendDifferences(int playernum, const FWeaponSlots &other)
|
|||
// The slots differ. Send mine.
|
||||
if (playernum == consoleplayer)
|
||||
{
|
||||
Net_WriteByte(DEM_SETSLOT);
|
||||
network->WriteByte(DEM_SETSLOT);
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte(DEM_SETSLOTPNUM);
|
||||
Net_WriteByte(playernum);
|
||||
network->WriteByte(DEM_SETSLOTPNUM);
|
||||
network->WriteByte(playernum);
|
||||
}
|
||||
Net_WriteByte(i);
|
||||
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));
|
||||
|
@ -602,9 +602,9 @@ CCMD (setslot)
|
|||
Printf ("Slot %d cleared\n", slot);
|
||||
}
|
||||
|
||||
Net_WriteByte(DEM_SETSLOT);
|
||||
Net_WriteByte(slot);
|
||||
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]));
|
||||
|
@ -653,8 +653,8 @@ CCMD (addslot)
|
|||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte(DEM_ADDSLOT);
|
||||
Net_WriteByte(slot);
|
||||
network->WriteByte(DEM_ADDSLOT);
|
||||
network->WriteByte(slot);
|
||||
Net_WriteWeapon(type);
|
||||
}
|
||||
}
|
||||
|
@ -729,8 +729,8 @@ CCMD (addslotdefault)
|
|||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte(DEM_ADDSLOTDEFAULT);
|
||||
Net_WriteByte(slot);
|
||||
network->WriteByte(DEM_ADDSLOTDEFAULT);
|
||||
network->WriteByte(slot);
|
||||
Net_WriteWeapon(type);
|
||||
}
|
||||
}
|
||||
|
@ -929,12 +929,12 @@ void Net_WriteWeapon(PClassActor *type)
|
|||
assert(index >= 0 && index <= 32767);
|
||||
if (index < 128)
|
||||
{
|
||||
Net_WriteByte(index);
|
||||
network->WriteByte(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte(0x80 | index);
|
||||
Net_WriteByte(index >> 7);
|
||||
network->WriteByte(0x80 | index);
|
||||
network->WriteByte(index >> 7);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
@ -707,17 +707,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->WriteByte (argv.argc() > 2 ? command2 : command);
|
||||
network->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->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]
|
||||
Net_WriteLong((i < argv.argc()) ? atoi(argv[i]) : 0);
|
||||
network->WriteLong((i < argv.argc()) ? atoi(argv[i]) : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
@ -591,7 +591,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->WriteByte(DEM_FINISHGAME);
|
||||
}
|
||||
|
||||
ADD_STAT(statistics)
|
||||
|
|
|
@ -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 "g_game.h"
|
||||
|
@ -436,14 +436,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
|
|||
|
||||
HU_DrawFontScaled(col4, y + ypadding, color, player->userinfo.GetName());
|
||||
|
||||
int avgdelay = 0;
|
||||
for (int i = 0; i < BACKUPTICS; i++)
|
||||
{
|
||||
avgdelay += netdelay[nodeforplayer[(int)(player - players)]][i];
|
||||
}
|
||||
avgdelay /= BACKUPTICS;
|
||||
|
||||
mysnprintf(str, countof(str), "%d", (avgdelay * ticdup) * (1000 / TICRATE));
|
||||
mysnprintf(str, countof(str), "%d", network->GetPing((int)(player - players)));
|
||||
|
||||
HU_DrawFontScaled(col5, y + ypadding, color, str);
|
||||
|
||||
|
|
1065
src/i_net.cpp
1065
src/i_net.cpp
File diff suppressed because it is too large
Load diff
|
@ -1,8 +0,0 @@
|
|||
#ifndef __I_NET_H__
|
||||
#define __I_NET_H__
|
||||
|
||||
// Called by D_DoomMain.
|
||||
bool I_InitNetwork (void);
|
||||
void I_NetCmd (void);
|
||||
|
||||
#endif
|
|
@ -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"
|
||||
#include "utf8.h"
|
||||
#include "templates.h"
|
||||
|
@ -866,7 +866,7 @@ bool DIntermissionController::Responder (event_t *ev)
|
|||
int res = mScreen->Responder(ev);
|
||||
if (res == -1 && !mSentAdvance)
|
||||
{
|
||||
Net_WriteByte(DEM_ADVANCEINTER);
|
||||
network->WriteByte(DEM_ADVANCEINTER);
|
||||
mSentAdvance = true;
|
||||
}
|
||||
return !!res;
|
||||
|
|
|
@ -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"
|
||||
|
@ -673,6 +673,6 @@ CCMD (mdk)
|
|||
return;
|
||||
|
||||
const char *name = argv.argc() > 1 ? argv[1] : "";
|
||||
Net_WriteByte (DEM_MDK);
|
||||
Net_WriteString(name);
|
||||
network->WriteByte (DEM_MDK);
|
||||
network->WriteString(name);
|
||||
}
|
||||
|
|
|
@ -1423,6 +1423,10 @@ void MapLoader::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 = Level->SpawnMapThing (i, &MapThingsConverted[i], position);
|
||||
unsigned *udi = MapThingsUserDataIndex.CheckKey((unsigned)i);
|
||||
if (udi != nullptr)
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include "p_enemy.h"
|
||||
#include "gstrings.h"
|
||||
#include "p_setup.h"
|
||||
#include "d_net.h"
|
||||
#include "network/net.h"
|
||||
#include "d_event.h"
|
||||
#include "doomstat.h"
|
||||
#include "c_console.h"
|
||||
|
|
445
src/network/i_net.cpp
Normal file
445
src/network/i_net.cpp
Normal file
|
@ -0,0 +1,445 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright 1993-1996 id Software
|
||||
// Copyright 1999-2016 Randy Heit
|
||||
//
|
||||
// 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/
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Low-level networking code. Uses BSD sockets for UDP networking.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/* [Petteri] Check if compiling for Win32: */
|
||||
#if defined(__WINDOWS__) || defined(__NT__) || defined(_MSC_VER) || defined(_WIN32)
|
||||
#ifndef __WIN32__
|
||||
# define __WIN32__
|
||||
#endif
|
||||
#endif
|
||||
/* Follow #ifdef __WIN32__ marks */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* [Petteri] Use Winsock for Win32: */
|
||||
#ifdef __WIN32__
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <winsock.h>
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <errno.h>
|
||||
# include <unistd.h>
|
||||
# include <netdb.h>
|
||||
# include <sys/ioctl.h>
|
||||
# ifdef __sun
|
||||
# include <fcntl.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "i_system.h"
|
||||
#include "net.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_crc32.h"
|
||||
#include "d_player.h"
|
||||
#include "st_start.h"
|
||||
#include "m_misc.h"
|
||||
#include "doomerrors.h"
|
||||
#include "atterm.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.
|
||||
#define TRANSMIT_SIZE 8000
|
||||
|
||||
/* [Petteri] Get more portable: */
|
||||
#ifndef __WIN32__
|
||||
typedef int SOCKET;
|
||||
#define SOCKET_ERROR -1
|
||||
#define INVALID_SOCKET -1
|
||||
#define closesocket close
|
||||
#define ioctlsocket ioctl
|
||||
#define Sleep(x) usleep (x * 1000)
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define WSAECONNRESET ECONNRESET
|
||||
#define WSAGetLastError() errno
|
||||
#endif
|
||||
|
||||
#ifndef IPPORT_USERRESERVED
|
||||
#define IPPORT_USERRESERVED 5000
|
||||
#endif
|
||||
|
||||
#ifdef __WIN32__
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
#ifdef __WIN32__
|
||||
const char *neterror (void);
|
||||
#else
|
||||
#define neterror() strerror(errno)
|
||||
#endif
|
||||
|
||||
class DoomComImpl : public doomcom_t
|
||||
{
|
||||
public:
|
||||
DoomComImpl(int port);
|
||||
~DoomComImpl();
|
||||
|
||||
void PacketSend(const NetOutputPacket &packet) override;
|
||||
void PacketGet(NetInputPacket &packet) override;
|
||||
|
||||
int Connect(const char *name) override;
|
||||
void Close(int node) override;
|
||||
|
||||
private:
|
||||
void BuildAddress(sockaddr_in *address, const char *name);
|
||||
int FindNode(const sockaddr_in *address);
|
||||
|
||||
SOCKET mSocket = INVALID_SOCKET;
|
||||
|
||||
sockaddr_in mNodeEndpoints[MAXNETNODES];
|
||||
uint64_t mNodeLastUpdate[MAXNETNODES];
|
||||
|
||||
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<doomcom_t> I_InitNetwork(int port)
|
||||
{
|
||||
static InitSockets initsockets;
|
||||
return std::unique_ptr<doomcom_t>(new DoomComImpl(port));
|
||||
}
|
||||
|
||||
DoomComImpl::DoomComImpl(int port)
|
||||
{
|
||||
memset(mNodeEndpoints, 0, sizeof(mNodeEndpoints));
|
||||
memset(mNodeLastUpdate, 0, sizeof(mNodeLastUpdate));
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
#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()
|
||||
{
|
||||
if (mSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(mSocket);
|
||||
mSocket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
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 slot = -1;
|
||||
for (int i = 0; i < MAXNETNODES; i++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (slot == -1)
|
||||
slot = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == -1)
|
||||
return -1;
|
||||
|
||||
mNodeEndpoints[slot] = *address;
|
||||
mNodeLastUpdate[slot] = I_nsTime();
|
||||
return slot;
|
||||
}
|
||||
|
||||
void DoomComImpl::PacketSend(const NetOutputPacket &packet)
|
||||
{
|
||||
assert(!(packet.buffer[0] & NCMD_COMPRESSED));
|
||||
|
||||
int packetSize = packet.stream.GetSize() + 1;
|
||||
if (packetSize >= 10)
|
||||
{
|
||||
mTransmitBuffer[0] = packet.buffer[0] | NCMD_COMPRESSED;
|
||||
|
||||
uLong size = TRANSMIT_SIZE - 1;
|
||||
int c = compress2(mTransmitBuffer + 1, &size, packet.buffer + 1, packetSize - 1, 9);
|
||||
size += 1;
|
||||
|
||||
if (c == Z_OK && size < (uLong)packetSize)
|
||||
{
|
||||
sendto(mSocket, (char *)mTransmitBuffer, size, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (packetSize <= TRANSMIT_SIZE)
|
||||
{
|
||||
sendto(mSocket, (char *)packet.buffer, packetSize, 0, (sockaddr *)&mNodeEndpoints[packet.node], sizeof(mNodeEndpoints[packet.node]));
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("NetPacket is too large to be transmitted");
|
||||
}
|
||||
}
|
||||
|
||||
void DoomComImpl::PacketGet(NetInputPacket &packet)
|
||||
{
|
||||
// First check if anything timed out. Treat this as a close.
|
||||
uint64_t nowtime = I_nsTime();
|
||||
for (int i = 0; i < MAXNETNODES; i++)
|
||||
{
|
||||
if (mNodeLastUpdate[i] != 0 && nowtime - mNodeLastUpdate[i] > 5'000'000'000) // 5 second timeout
|
||||
{
|
||||
Close(i);
|
||||
packet.node = i;
|
||||
packet.stream.SetBuffer(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
sockaddr_in fromaddress;
|
||||
socklen_t fromlen = sizeof(fromaddress);
|
||||
int size = recvfrom(mSocket, (char*)mTransmitBuffer, TRANSMIT_SIZE, 0, (sockaddr *)&fromaddress, &fromlen);
|
||||
if (size == SOCKET_ERROR)
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
|
||||
if (err == WSAECONNRESET) // The remote node aborted unexpectedly. Treat this as a close.
|
||||
{
|
||||
int node = FindNode(&fromaddress);
|
||||
if (node == -1)
|
||||
continue;
|
||||
|
||||
Close(node);
|
||||
packet.node = node;
|
||||
packet.stream.SetBuffer(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
else if (err != WSAEWOULDBLOCK)
|
||||
{
|
||||
I_Error("GetPacket: %s", neterror());
|
||||
}
|
||||
else // no packet
|
||||
{
|
||||
packet.node = -1;
|
||||
packet.stream.SetBuffer(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (size > 0)
|
||||
{
|
||||
int node = FindNode(&fromaddress);
|
||||
if (node == -1)
|
||||
continue;
|
||||
|
||||
packet.buffer[0] = mTransmitBuffer[0] & ~NCMD_COMPRESSED;
|
||||
if ((mTransmitBuffer[0] & NCMD_COMPRESSED) && size > 1)
|
||||
{
|
||||
uLongf msgsize = MAX_MSGLEN - 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());
|
||||
continue;
|
||||
}
|
||||
size = msgsize + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(packet.buffer + 1, mTransmitBuffer + 1, size - 1);
|
||||
}
|
||||
|
||||
packet.node = node;
|
||||
packet.stream.SetBuffer(packet.buffer + 1, size - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoomComImpl::BuildAddress(sockaddr_in *address, const char *name)
|
||||
{
|
||||
hostent *hostentry; // host information entry
|
||||
u_short port;
|
||||
const char *portpart;
|
||||
bool isnamed = false;
|
||||
int curchar;
|
||||
char c;
|
||||
FString target;
|
||||
|
||||
address->sin_family = AF_INET;
|
||||
|
||||
if ((portpart = strchr(name, ':')))
|
||||
{
|
||||
target = FString(name, portpart - name);
|
||||
port = atoi(portpart + 1);
|
||||
if (!port)
|
||||
{
|
||||
Printf("Weird port: %s (using %d)\n", portpart + 1, DOOMPORT);
|
||||
port = DOOMPORT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
target = name;
|
||||
port = DOOMPORT;
|
||||
}
|
||||
address->sin_port = htons(port);
|
||||
|
||||
for (curchar = 0; (c = target[curchar]); curchar++)
|
||||
{
|
||||
if ((c < '0' || c > '9') && c != '.')
|
||||
{
|
||||
isnamed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isnamed)
|
||||
{
|
||||
address->sin_addr.s_addr = inet_addr(target);
|
||||
// Printf("Node number %d, address %s\n", numnodes, target.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
hostentry = gethostbyname(target);
|
||||
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", numnodes, hostentry->h_name);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
const char *neterror (void)
|
||||
{
|
||||
static char neterr[16];
|
||||
int code;
|
||||
|
||||
switch (code = WSAGetLastError ()) {
|
||||
case WSAEACCES: return "EACCES";
|
||||
case WSAEADDRINUSE: return "EADDRINUSE";
|
||||
case WSAEADDRNOTAVAIL: return "EADDRNOTAVAIL";
|
||||
case WSAEAFNOSUPPORT: return "EAFNOSUPPORT";
|
||||
case WSAEALREADY: return "EALREADY";
|
||||
case WSAECONNABORTED: return "ECONNABORTED";
|
||||
case WSAECONNREFUSED: return "ECONNREFUSED";
|
||||
case WSAECONNRESET: return "ECONNRESET";
|
||||
case WSAEDESTADDRREQ: return "EDESTADDRREQ";
|
||||
case WSAEFAULT: return "EFAULT";
|
||||
case WSAEHOSTDOWN: return "EHOSTDOWN";
|
||||
case WSAEHOSTUNREACH: return "EHOSTUNREACH";
|
||||
case WSAEINPROGRESS: return "EINPROGRESS";
|
||||
case WSAEINTR: return "EINTR";
|
||||
case WSAEINVAL: return "EINVAL";
|
||||
case WSAEISCONN: return "EISCONN";
|
||||
case WSAEMFILE: return "EMFILE";
|
||||
case WSAEMSGSIZE: return "EMSGSIZE";
|
||||
case WSAENETDOWN: return "ENETDOWN";
|
||||
case WSAENETRESET: return "ENETRESET";
|
||||
case WSAENETUNREACH: return "ENETUNREACH";
|
||||
case WSAENOBUFS: return "ENOBUFS";
|
||||
case WSAENOPROTOOPT: return "ENOPROTOOPT";
|
||||
case WSAENOTCONN: return "ENOTCONN";
|
||||
case WSAENOTSOCK: return "ENOTSOCK";
|
||||
case WSAEOPNOTSUPP: return "EOPNOTSUPP";
|
||||
case WSAEPFNOSUPPORT: return "EPFNOSUPPORT";
|
||||
case WSAEPROCLIM: return "EPROCLIM";
|
||||
case WSAEPROTONOSUPPORT: return "EPROTONOSUPPORT";
|
||||
case WSAEPROTOTYPE: return "EPROTOTYPE";
|
||||
case WSAESHUTDOWN: return "ESHUTDOWN";
|
||||
case WSAESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
|
||||
case WSAETIMEDOUT: return "ETIMEDOUT";
|
||||
case WSAEWOULDBLOCK: return "EWOULDBLOCK";
|
||||
case WSAHOST_NOT_FOUND: return "HOST_NOT_FOUND";
|
||||
case WSANOTINITIALISED: return "NOTINITIALISED";
|
||||
case WSANO_DATA: return "NO_DATA";
|
||||
case WSANO_RECOVERY: return "NO_RECOVERY";
|
||||
case WSASYSNOTREADY: return "SYSNOTREADY";
|
||||
case WSATRY_AGAIN: return "TRY_AGAIN";
|
||||
case WSAVERNOTSUPPORTED: return "VERNOTSUPPORTED";
|
||||
case WSAEDISCON: return "EDISCON";
|
||||
|
||||
default:
|
||||
mysnprintf (neterr, countof(neterr), "%d", code);
|
||||
return neterr;
|
||||
}
|
||||
}
|
||||
#endif
|
54
src/network/i_net.h
Normal file
54
src/network/i_net.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "netcommand.h"
|
||||
|
||||
#define MAX_MSGLEN 14000
|
||||
#define DOOMPORT 5029
|
||||
|
||||
class NetOutputPacket
|
||||
{
|
||||
public:
|
||||
NetOutputPacket(int node) : node(node), stream(buffer + 1, MAX_MSGLEN - 1) { buffer[0] = 0; }
|
||||
|
||||
int node = 0;
|
||||
ByteOutputStream stream;
|
||||
|
||||
private:
|
||||
uint8_t buffer[MAX_MSGLEN];
|
||||
|
||||
NetOutputPacket(const NetOutputPacket &) = delete;
|
||||
NetOutputPacket &operator=(const NetOutputPacket &) = delete;
|
||||
friend class DoomComImpl;
|
||||
};
|
||||
|
||||
class NetInputPacket
|
||||
{
|
||||
public:
|
||||
NetInputPacket() = default;
|
||||
|
||||
int node = -1; // -1 = no packet available
|
||||
ByteInputStream stream;
|
||||
|
||||
private:
|
||||
uint8_t buffer[MAX_MSGLEN];
|
||||
|
||||
NetInputPacket(const NetInputPacket &) = delete;
|
||||
NetInputPacket &operator=(const NetInputPacket &) = delete;
|
||||
friend class DoomComImpl;
|
||||
};
|
||||
|
||||
// Network packet data.
|
||||
struct doomcom_t
|
||||
{
|
||||
virtual ~doomcom_t() { }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
std::unique_ptr<doomcom_t> I_InitNetwork(int port);
|
1278
src/network/net.cpp
Normal file
1278
src/network/net.cpp
Normal file
File diff suppressed because it is too large
Load diff
171
src/network/net.h
Normal file
171
src/network/net.h
Normal file
|
@ -0,0 +1,171 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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 "doomtype.h"
|
||||
#include "doomdef.h"
|
||||
#include "d_protocol.h"
|
||||
#include "i_net.h"
|
||||
#include <memory>
|
||||
|
||||
#define MAXNETNODES 8 // max computers in a game
|
||||
#define BACKUPTICS 36 // number of tics to remember
|
||||
#define MAXTICDUP 5
|
||||
#define LOCALCMDTICS (BACKUPTICS*MAXTICDUP)
|
||||
|
||||
class AActor;
|
||||
|
||||
class FDynamicBuffer
|
||||
{
|
||||
public:
|
||||
FDynamicBuffer();
|
||||
FDynamicBuffer(const FDynamicBuffer &src);
|
||||
~FDynamicBuffer();
|
||||
|
||||
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 = nullptr;
|
||||
int m_Len = 0;
|
||||
int m_BufferLen = 0;
|
||||
};
|
||||
|
||||
class Network
|
||||
{
|
||||
public:
|
||||
virtual ~Network() { }
|
||||
|
||||
// Check for incoming packets
|
||||
virtual void Update() = 0;
|
||||
|
||||
// Set current tic time
|
||||
virtual void SetCurrentTic(int localtic) = 0;
|
||||
|
||||
// Send any pending outgoing data
|
||||
virtual void EndCurrentTic() = 0;
|
||||
|
||||
// Retrieve data about the current tic
|
||||
virtual int GetSendTick() const = 0;
|
||||
virtual ticcmd_t GetPlayerInput(int player) const = 0;
|
||||
virtual ticcmd_t GetSentInput(int tic) const = 0;
|
||||
|
||||
// Run network commands for the current tic
|
||||
virtual void RunCommands(int player) = 0;
|
||||
|
||||
// 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;
|
||||
void WriteByte(uint8_t it);
|
||||
void WriteWord(short it);
|
||||
void WriteLong(int it);
|
||||
void WriteFloat(float it);
|
||||
void WriteString(const char *it);
|
||||
|
||||
// Statistics
|
||||
virtual int GetPing(int player) const = 0;
|
||||
virtual int GetServerPing() const = 0;
|
||||
int GetHighPingThreshold() const;
|
||||
|
||||
// CCMDs
|
||||
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() { }
|
||||
void D_QuitNetGame() { }
|
||||
|
||||
// Demo recording
|
||||
size_t CopySpecData(int player, uint8_t *dest, size_t dest_size) { return 0; }
|
||||
|
||||
// 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; }
|
||||
|
||||
// Should probably be removed.
|
||||
int ticdup = 1;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<Network> network;
|
||||
extern std::unique_ptr<Network> netconnect;
|
||||
|
||||
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:
|
||||
//
|
||||
// Header:
|
||||
// One byte with following flags.
|
||||
// One byte with starttic
|
||||
// One byte with master's maketic (master -> slave only!)
|
||||
// If NCMD_RETRANSMIT set, one byte with retransmitfrom
|
||||
// If NCMD_XTICS set, one byte with number of tics (minus 3, so theoretically up to 258 tics in one packet)
|
||||
// If NCMD_QUITTERS, one byte with number of players followed by one byte with each player's consolenum
|
||||
// If NCMD_MULTI, one byte with number of players followed by one byte with each player's consolenum
|
||||
// - The first player's consolenum is not included in this list, because it always matches the sender
|
||||
//
|
||||
// For each tic:
|
||||
// Two bytes with consistency check, followed by tic data
|
||||
//
|
||||
// Setup packets are different, and are described just before D_ArbitrateNetStart().
|
||||
|
||||
#define NCMD_EXIT 0x80
|
||||
#define NCMD_RETRANSMIT 0x40
|
||||
#define NCMD_SETUP 0x20
|
||||
#define NCMD_MULTI 0x10 // multiple players in this packet
|
||||
#define NCMD_QUITTERS 0x08 // one or more players just quit (packet server only)
|
||||
#define NCMD_COMPRESSED 0x04 // remainder of packet is compressed
|
||||
|
||||
#define NCMD_XTICS 0x03 // packet contains >2 tics
|
||||
#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
|
||||
};
|
422
src/network/netclient.cpp
Normal file
422
src/network/netclient.cpp
Normal file
|
@ -0,0 +1,422 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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 <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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 "netclient.h"
|
||||
#include "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"
|
||||
#include <cmath>
|
||||
|
||||
CVAR( Int, cl_showspawnnames, 0, CVAR_ARCHIVE )
|
||||
|
||||
NetClient::NetClient(FString server)
|
||||
{
|
||||
Printf("Connecting to %s..\n", server.GetChars());
|
||||
|
||||
mComm = I_InitNetwork(0);
|
||||
mServerNode = mComm->Connect(server);
|
||||
mStatus = NodeStatus::InPreGame;
|
||||
|
||||
NetOutputPacket packet(mServerNode);
|
||||
|
||||
NetCommand cmd ( NetPacketType::ConnectRequest );
|
||||
cmd.addString("ZDoom Connect Request");
|
||||
cmd.writeCommandToStream (packet.stream);
|
||||
|
||||
mComm->PacketSend(packet);
|
||||
}
|
||||
|
||||
void NetClient::Update()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
NetInputPacket packet;
|
||||
mComm->PacketGet(packet);
|
||||
if (packet.node == -1)
|
||||
break;
|
||||
|
||||
if (packet.node != mServerNode)
|
||||
{
|
||||
mComm->Close(packet.node);
|
||||
}
|
||||
else if (packet.stream.IsAtEnd())
|
||||
{
|
||||
OnClose();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateLastReceivedTic(packet.stream.ReadByte());
|
||||
|
||||
if (mStatus == NodeStatus::InPreGame)
|
||||
{
|
||||
ProcessCommands(packet.stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto &ticUpdate = mTicUpdates[mLastReceivedTic % BACKUPTICS];
|
||||
ticUpdate.Resize(packet.stream.BytesLeft());
|
||||
packet.stream.ReadBuffer(ticUpdate.Data(), ticUpdate.Size());
|
||||
}
|
||||
}
|
||||
|
||||
if (mStatus == NodeStatus::Closed)
|
||||
{
|
||||
if (network.get() == this)
|
||||
{
|
||||
network.reset(new NetSinglePlayer());
|
||||
G_EndNetGame();
|
||||
}
|
||||
else
|
||||
{
|
||||
netconnect.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetClient::SetCurrentTic(int tictime)
|
||||
{
|
||||
gametic = tictime;
|
||||
mSendTic = gametic + 10;
|
||||
|
||||
if (abs(gametic + mServerTicDelta - mLastReceivedTic) > jitter)
|
||||
{
|
||||
mServerTicDelta = mLastReceivedTic - gametic - jitter;
|
||||
}
|
||||
|
||||
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<uint8_t> &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();
|
||||
}
|
||||
|
||||
int NetClient::GetSendTick() const
|
||||
{
|
||||
return mSendTic;
|
||||
}
|
||||
|
||||
ticcmd_t NetClient::GetPlayerInput(int player) const
|
||||
{
|
||||
return mCurrentInput[player];
|
||||
}
|
||||
|
||||
ticcmd_t NetClient::GetSentInput(int tic) const
|
||||
{
|
||||
return mSentInput[tic % BACKUPTICS];
|
||||
}
|
||||
|
||||
void NetClient::RunCommands(int player)
|
||||
{
|
||||
if (player == consoleplayer)
|
||||
{
|
||||
Net_RunCommands(mCurrentCommands, consoleplayer);
|
||||
}
|
||||
}
|
||||
|
||||
void NetClient::WriteLocalInput(ticcmd_t ticcmd)
|
||||
{
|
||||
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)
|
||||
{
|
||||
mCurrentInput[player] = cmd;
|
||||
}
|
||||
|
||||
void NetClient::WriteBytes(const uint8_t *block, int len)
|
||||
{
|
||||
mSendCommands.AppendData(block, 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::ActorSpawned(AActor *actor)
|
||||
{
|
||||
actor->syncdata.NetID = -1;
|
||||
}
|
||||
|
||||
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);
|
||||
mServerNode = -1;
|
||||
mStatus = NodeStatus::Closed;
|
||||
|
||||
if (network.get() == this)
|
||||
{
|
||||
Printf("Disconnected\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Could not connect\n");
|
||||
}
|
||||
}
|
||||
|
||||
void NetClient::OnConnectResponse(ByteInputStream &stream)
|
||||
{
|
||||
int version = stream.ReadByte(); // Protocol version
|
||||
if (version == 1)
|
||||
{
|
||||
int playernum = stream.ReadByte();
|
||||
if (playernum > 0 && playernum < MAXPLAYERS) // Join accepted
|
||||
{
|
||||
mPlayer = playernum;
|
||||
mStatus = NodeStatus::InGame;
|
||||
mServerTicDelta = mLastReceivedTic - gametic - jitter;
|
||||
|
||||
G_InitClientNetGame(mPlayer, "e1m1");
|
||||
|
||||
network = std::move(netconnect);
|
||||
}
|
||||
else // Server full
|
||||
{
|
||||
mComm->Close(mServerNode);
|
||||
mServerNode = -1;
|
||||
mStatus = NodeStatus::Closed;
|
||||
|
||||
Printf("Could not connect: server is full!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Could not connect: version mismatch.\n");
|
||||
mComm->Close(mServerNode);
|
||||
mServerNode = -1;
|
||||
mStatus = NodeStatus::Closed;
|
||||
}
|
||||
}
|
||||
|
||||
void NetClient::OnDisconnect()
|
||||
{
|
||||
mComm->Close(mServerNode);
|
||||
mServerNode = -1;
|
||||
mStatus = NodeStatus::Closed;
|
||||
}
|
||||
|
||||
void NetClient::OnTic(ByteInputStream &stream)
|
||||
{
|
||||
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();
|
||||
|
||||
if (playeringame[consoleplayer] && players[consoleplayer].mo)
|
||||
{
|
||||
AActor *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)
|
||||
{
|
||||
int netID = stream.ReadShort();
|
||||
if (netID == -1)
|
||||
break;
|
||||
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
const int16_t netID = stream.ReadShort();
|
||||
const float x = stream.ReadFloat();
|
||||
const float y = stream.ReadFloat();
|
||||
const float z = stream.ReadFloat();
|
||||
|
||||
AActor *oldNetActor = mNetIDList.findPointerByID(netID);
|
||||
|
||||
// If there's already an actor with this net ID, destroy it.
|
||||
if (oldNetActor)
|
||||
{
|
||||
oldNetActor->Destroy();
|
||||
mNetIDList.freeID(netID);
|
||||
}
|
||||
|
||||
ANetSyncActor *actor = Spawn<ANetSyncActor>(primaryLevel, DVector3(x, y, z), NO_REPLACE);
|
||||
mNetIDList.useID(netID, actor);
|
||||
}
|
||||
|
||||
void NetClient::OnDestroyActor(ByteInputStream &stream)
|
||||
{
|
||||
const int16_t netID = stream.ReadShort();
|
||||
AActor *actor = mNetIDList.findPointerByID(netID);
|
||||
actor->Destroy();
|
||||
mNetIDList.freeID(netID);
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(ANetSyncActor, false, false)
|
||||
|
94
src/network/netclient.h
Normal file
94
src/network/netclient.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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 "netserver.h"
|
||||
#include "netcommand.h"
|
||||
#include "g_shared/a_dynlight.h"
|
||||
|
||||
class NetClient : public Network
|
||||
{
|
||||
public:
|
||||
NetClient(FString server);
|
||||
|
||||
void Update() override;
|
||||
|
||||
void SetCurrentTic(int tictime) override;
|
||||
void EndCurrentTic() override;
|
||||
|
||||
int GetSendTick() const override;
|
||||
ticcmd_t GetPlayerInput(int player) const override;
|
||||
ticcmd_t GetSentInput(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;
|
||||
|
||||
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 ProcessCommands(ByteInputStream &stream);
|
||||
void UpdateLastReceivedTic(int tic);
|
||||
|
||||
std::unique_ptr<doomcom_t> mComm;
|
||||
int mServerNode = -1;
|
||||
int mPlayer = -1;
|
||||
NodeStatus mStatus = NodeStatus::Closed;
|
||||
|
||||
int mSendTic = 0;
|
||||
int mServerTic = 0;
|
||||
int mServerTicDelta = -1;
|
||||
int mLastReceivedTic = -1;
|
||||
|
||||
int jitter = 2;
|
||||
|
||||
TArray<uint8_t> mTicUpdates[BACKUPTICS];
|
||||
|
||||
ticcmd_t mCurrentInput[MAXPLAYERS];
|
||||
ticcmd_t mSentInput[BACKUPTICS];
|
||||
FDynamicBuffer mCurrentCommands;
|
||||
FDynamicBuffer mSendCommands;
|
||||
|
||||
IDList<AActor> mNetIDList;
|
||||
};
|
||||
|
||||
class ANetSyncActor : public AActor
|
||||
{
|
||||
DECLARE_CLASS(ANetSyncActor, AActor)
|
||||
public:
|
||||
};
|
505
src/network/netcommand.cpp
Normal file
505
src/network/netcommand.cpp
Normal file
|
@ -0,0 +1,505 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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(int size)
|
||||
{
|
||||
SetBuffer(size);
|
||||
}
|
||||
|
||||
ByteOutputStream::ByteOutputStream(void *buffer, int size)
|
||||
{
|
||||
SetBuffer(buffer, size);
|
||||
}
|
||||
|
||||
void ByteOutputStream::SetBuffer(int size)
|
||||
{
|
||||
mBuffer = std::make_shared<DataBuffer>(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;
|
||||
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<char> (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);
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
// 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
|
||||
mStream.SetBuffer(MAX_UDP_PACKET);
|
||||
|
||||
addByte(static_cast<int>(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<uint8_t> (ByteValue), sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void NetCommand::addShort(const int ShortValue)
|
||||
{
|
||||
addInteger(static_cast<int16_t> (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<const uint8_t*>(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();
|
||||
}
|
127
src/network/netcommand.h
Normal file
127
src/network/netcommand.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
|
||||
#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,
|
||||
SpawnActor,
|
||||
DestroyActor
|
||||
};
|
||||
|
||||
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;
|
||||
int BytesLeft() 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(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);
|
||||
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;
|
||||
|
||||
struct DataBuffer
|
||||
{
|
||||
DataBuffer(int size) : data(new uint8_t[size]), size(size) { }
|
||||
~DataBuffer() { delete[] data; }
|
||||
|
||||
uint8_t *data;
|
||||
int size;
|
||||
};
|
||||
std::shared_ptr<DataBuffer> mBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* \author Benjamin Berkels
|
||||
*/
|
||||
class NetCommand
|
||||
{
|
||||
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;
|
||||
};
|
435
src/network/netserver.cpp
Normal file
435
src/network/netserver.cpp
Normal file
|
@ -0,0 +1,435 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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 <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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 "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()
|
||||
{
|
||||
Printf("Started hosting multiplayer game..\n");
|
||||
|
||||
mBroadcastCommands.SetBuffer(MAX_MSGLEN);
|
||||
|
||||
for (int i = 0; i < MAXNETNODES; i++)
|
||||
mNodes[i].NodeIndex = i;
|
||||
|
||||
mComm = I_InitNetwork(DOOMPORT);
|
||||
|
||||
G_InitServerNetGame("e1m1");
|
||||
}
|
||||
|
||||
void NetServer::Update()
|
||||
{
|
||||
// Read all packets currently available from clients
|
||||
while (true)
|
||||
{
|
||||
NetInputPacket packet;
|
||||
mComm->PacketGet(packet);
|
||||
if (packet.node == -1)
|
||||
break; // No more packets. We are done.
|
||||
|
||||
NetNode &node = mNodes[packet.node];
|
||||
|
||||
if (packet.stream.IsAtEnd()) // Connection to node closed (timed out)
|
||||
{
|
||||
OnClose(node, packet.stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (packet.stream.IsAtEnd() == false)
|
||||
{
|
||||
NetPacketType type = (NetPacketType)packet.stream.ReadByte();
|
||||
switch (type)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetServer::SetCurrentTic(int tictime)
|
||||
{
|
||||
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()
|
||||
{
|
||||
for (int i = 0; i < MAXNETNODES; i++)
|
||||
{
|
||||
if (mNodes[i].Status == NodeStatus::InGame)
|
||||
{
|
||||
int player = mNodes[i].Player;
|
||||
|
||||
NetOutputPacket packet(i);
|
||||
packet.stream.WriteByte(gametic + 1);
|
||||
|
||||
if (mNodes[i].FirstTic)
|
||||
{
|
||||
TThinkerIterator<AActor> it = primaryLevel->GetThinkerIterator<AActor>();
|
||||
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);
|
||||
|
||||
if (playeringame[player] && players[player].mo)
|
||||
{
|
||||
cmd.addFloat(static_cast<float> (players[player].mo->X()));
|
||||
cmd.addFloat(static_cast<float> (players[player].mo->Y()));
|
||||
cmd.addFloat(static_cast<float> (players[player].mo->Z()));
|
||||
cmd.addFloat(static_cast<float> (players[player].mo->Vel.X));
|
||||
cmd.addFloat(static_cast<float> (players[player].mo->Vel.Y));
|
||||
cmd.addFloat(static_cast<float> (players[player].mo->Vel.Z));
|
||||
cmd.addFloat(static_cast<float> (players[player].mo->Angles.Yaw.Degrees));
|
||||
cmd.addFloat(static_cast<float> (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);
|
||||
}
|
||||
|
||||
TThinkerIterator<AActor> it = primaryLevel->GetThinkerIterator<AActor>();
|
||||
AActor *mo;
|
||||
while (mo = it.Next())
|
||||
{
|
||||
if (mo != players[player].mo && mo->syncdata.NetID)
|
||||
{
|
||||
cmd.addShort(mo->syncdata.NetID);
|
||||
cmd.addFloat(static_cast<float> (mo->X()));
|
||||
cmd.addFloat(static_cast<float> (mo->Y()));
|
||||
cmd.addFloat(static_cast<float> (mo->Z()));
|
||||
cmd.addFloat(static_cast<float> (mo->Angles.Yaw.Degrees));
|
||||
cmd.addFloat(static_cast<float> (mo->Angles.Pitch.Degrees));
|
||||
cmd.addShort(mo->sprite);
|
||||
cmd.addByte(mo->frame);
|
||||
}
|
||||
}
|
||||
cmd.addShort(-1);
|
||||
|
||||
cmd.writeCommandToStream(packet.stream);
|
||||
mComm->PacketSend(packet);
|
||||
}
|
||||
}
|
||||
|
||||
mBroadcastCommands.ResetPos();
|
||||
|
||||
mCurrentCommands = mSendCommands;
|
||||
mSendCommands.Clear();
|
||||
}
|
||||
|
||||
int NetServer::GetSendTick() const
|
||||
{
|
||||
return gametic;
|
||||
}
|
||||
|
||||
ticcmd_t NetServer::GetPlayerInput(int player) const
|
||||
{
|
||||
return mCurrentInput[player];
|
||||
}
|
||||
|
||||
ticcmd_t NetServer::GetSentInput(int tic) const
|
||||
{
|
||||
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
|
||||
{
|
||||
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, ByteInputStream &stream)
|
||||
{
|
||||
if (node.Status == NodeStatus::InGame)
|
||||
{
|
||||
Printf("Player %d left the server\n", node.Player);
|
||||
|
||||
playeringame[node.Player] = false;
|
||||
players[node.Player].settings_controller = false;
|
||||
node.Player = -1;
|
||||
}
|
||||
|
||||
node.Status = NodeStatus::Closed;
|
||||
mComm->Close(node.NodeIndex);
|
||||
}
|
||||
|
||||
void NetServer::OnConnectRequest(NetNode &node, ByteInputStream &stream)
|
||||
{
|
||||
// Make the initial connect packet a bit more complex than a bunch of zeros..
|
||||
if (strcmp(stream.ReadString(), "ZDoom Connect Request") != 0)
|
||||
{
|
||||
if (node.Status == NodeStatus::InGame)
|
||||
{
|
||||
Printf("Junk data received from a joined player\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Status = NodeStatus::Closed;
|
||||
mComm->Close(node.NodeIndex);
|
||||
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\n", node.Player);
|
||||
|
||||
for (int i = 0; i < BACKUPTICS; i++)
|
||||
node.TicUpdates[i].received = false;
|
||||
|
||||
node.FirstTic = true;
|
||||
node.Status = NodeStatus::InGame;
|
||||
mNodeForPlayer[node.Player] = node.NodeIndex;
|
||||
|
||||
playeringame[node.Player] = true;
|
||||
players[node.Player].settings_controller = false;
|
||||
|
||||
NetOutputPacket response(node.NodeIndex);
|
||||
response.stream.WriteByte(gametic);
|
||||
|
||||
NetCommand cmd ( NetPacketType::ConnectResponse );
|
||||
cmd.addByte ( 1 ); // Protocol version
|
||||
cmd.addByte ( node.Player );
|
||||
cmd.writeCommandToStream ( response.stream );
|
||||
|
||||
mComm->PacketSend(response);
|
||||
}
|
||||
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
|
||||
cmd.addByte ( 255 );
|
||||
cmd.writeCommandToStream (response.stream);
|
||||
|
||||
mComm->PacketSend(response);
|
||||
|
||||
node.Status = NodeStatus::Closed;
|
||||
mComm->Close(node.NodeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void NetServer::OnDisconnect(NetNode &node, ByteInputStream &stream)
|
||||
{
|
||||
if (node.Status == NodeStatus::InGame)
|
||||
{
|
||||
Printf("Player %d left the server\n", node.Player);
|
||||
|
||||
playeringame[node.Player] = false;
|
||||
players[node.Player].settings_controller = false;
|
||||
node.Player = -1;
|
||||
}
|
||||
|
||||
node.Status = NodeStatus::Closed;
|
||||
mComm->Close(node.NodeIndex);
|
||||
}
|
||||
|
||||
void NetServer::OnTic(NetNode &node, ByteInputStream &stream)
|
||||
{
|
||||
if (node.Status != NodeStatus::InGame)
|
||||
return;
|
||||
|
||||
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.
|
||||
tic = gametic + 1;
|
||||
|
||||
if (tic < 0 || node.TicUpdates[tic % BACKUPTICS].received)
|
||||
return; // We already received the proper packet.
|
||||
}
|
||||
|
||||
node.TicUpdates[tic % BACKUPTICS] = update;
|
||||
}
|
||||
|
||||
void NetServer::CmdSpawnActor(ByteOutputStream &stream, AActor *actor)
|
||||
{
|
||||
NetCommand cmd(NetPacketType::SpawnActor);
|
||||
cmd.addShort(actor->syncdata.NetID);
|
||||
cmd.addFloat(static_cast<float>(actor->X()));
|
||||
cmd.addFloat(static_cast<float>(actor->Y()));
|
||||
cmd.addFloat(static_cast<float>(actor->Z()));
|
||||
cmd.writeCommandToStream(stream);
|
||||
}
|
||||
|
||||
void NetServer::CmdDestroyActor(ByteOutputStream &stream, AActor *actor)
|
||||
{
|
||||
NetCommand cmd(NetPacketType::DestroyActor);
|
||||
cmd.addShort(actor->syncdata.NetID);
|
||||
cmd.writeCommandToStream(stream);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
103
src/network/netserver.h
Normal file
103
src/network/netserver.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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 "net.h"
|
||||
#include "netcommand.h"
|
||||
|
||||
enum class NodeStatus
|
||||
{
|
||||
Closed,
|
||||
InPreGame,
|
||||
InGame
|
||||
};
|
||||
|
||||
struct NetNode
|
||||
{
|
||||
NodeStatus Status = NodeStatus::Closed;
|
||||
|
||||
int Ping = 0;
|
||||
int Gametic = 0;
|
||||
int Player = -1;
|
||||
int NodeIndex = -1;
|
||||
bool FirstTic = true;
|
||||
|
||||
struct TicUpdate
|
||||
{
|
||||
bool received = false;
|
||||
usercmd_t input;
|
||||
};
|
||||
TicUpdate TicUpdates[BACKUPTICS];
|
||||
|
||||
FDynamicBuffer Commands; // "NetSpecs"
|
||||
};
|
||||
|
||||
class NetServer : public Network
|
||||
{
|
||||
public:
|
||||
NetServer();
|
||||
|
||||
void Update() override;
|
||||
|
||||
void SetCurrentTic(int tictime) override;
|
||||
void EndCurrentTic() override;
|
||||
|
||||
int GetSendTick() const override;
|
||||
ticcmd_t GetPlayerInput(int player) const override;
|
||||
ticcmd_t GetSentInput(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;
|
||||
|
||||
void ActorSpawned(AActor *actor) override;
|
||||
void ActorDestroyed(AActor *actor) override;
|
||||
|
||||
private:
|
||||
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 CmdSpawnActor(ByteOutputStream &stream, AActor *actor);
|
||||
void CmdDestroyActor(ByteOutputStream &stream, AActor *actor);
|
||||
|
||||
std::unique_ptr<doomcom_t> mComm;
|
||||
NetNode mNodes[MAXNETNODES];
|
||||
int mNodeForPlayer[MAXPLAYERS];
|
||||
|
||||
ticcmd_t mCurrentInput[MAXPLAYERS];
|
||||
FDynamicBuffer mCurrentCommands;
|
||||
FDynamicBuffer mSendCommands;
|
||||
|
||||
IDList<AActor> mNetIDList;
|
||||
|
||||
ByteOutputStream mBroadcastCommands; // Playsim events everyone should hear about
|
||||
};
|
150
src/network/netsingle.cpp
Normal file
150
src/network/netsingle.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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 <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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 "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"
|
||||
|
||||
extern bool netserver, netclient;
|
||||
|
||||
NetSinglePlayer::NetSinglePlayer()
|
||||
{
|
||||
netgame = false;
|
||||
netclient = false;
|
||||
netserver = false;
|
||||
multiplayer = false;
|
||||
consoleplayer = 0;
|
||||
players[0].settings_controller = true;
|
||||
playeringame[0] = true;
|
||||
}
|
||||
|
||||
void NetSinglePlayer::Update()
|
||||
{
|
||||
}
|
||||
|
||||
void NetSinglePlayer::SetCurrentTic(int tictime)
|
||||
{
|
||||
gametic = tictime;
|
||||
}
|
||||
|
||||
void NetSinglePlayer::EndCurrentTic()
|
||||
{
|
||||
mCurrentCommands = mSendCommands;
|
||||
mSendCommands.Clear();
|
||||
}
|
||||
|
||||
int NetSinglePlayer::GetSendTick() const
|
||||
{
|
||||
return gametic;
|
||||
}
|
||||
|
||||
ticcmd_t NetSinglePlayer::GetPlayerInput(int player) const
|
||||
{
|
||||
return mCurrentInput[player];
|
||||
}
|
||||
|
||||
ticcmd_t NetSinglePlayer::GetSentInput(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)
|
||||
{
|
||||
}
|
57
src/network/netsingle.h
Normal file
57
src/network/netsingle.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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 "network/net.h"
|
||||
|
||||
class NetSinglePlayer : public Network
|
||||
{
|
||||
public:
|
||||
NetSinglePlayer();
|
||||
|
||||
void Update() override;
|
||||
|
||||
void SetCurrentTic(int tictime) override;
|
||||
void EndCurrentTic() override;
|
||||
|
||||
int GetSendTick() const override;
|
||||
ticcmd_t GetPlayerInput(int player) const override;
|
||||
ticcmd_t GetSentInput(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;
|
||||
|
||||
FDynamicBuffer mSendCommands;
|
||||
};
|
270
src/network/netsync.cpp
Normal file
270
src/network/netsync.cpp
Normal file
|
@ -0,0 +1,270 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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 "netsync.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "actor.h"
|
||||
#include "doomstat.h"
|
||||
#include "i_net.h"
|
||||
#include "cmdlib.h"
|
||||
#include "g_levellocals.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;
|
||||
}
|
||||
|
||||
writer.WriteEnd();
|
||||
}
|
||||
|
||||
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 <typename T>
|
||||
void IDList<T>::clear()
|
||||
{
|
||||
for (unsigned int ulIdx = 0; ulIdx < MAX_NETID; ulIdx++)
|
||||
freeID(ulIdx);
|
||||
|
||||
_firstFreeID = 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void IDList<T>::rebuild()
|
||||
{
|
||||
clear();
|
||||
|
||||
T *pActor;
|
||||
|
||||
TThinkerIterator<T> it = primaryLevel->GetThinkerIterator<T>();
|
||||
|
||||
while ((pActor = it.Next()))
|
||||
{
|
||||
if ((pActor->syncdata.NetID > 0) && (pActor->syncdata.NetID < MAX_NETID))
|
||||
useID(pActor->syncdata.NetID, pActor);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void IDList<T>::useID(const int lNetID, T *pActor)
|
||||
{
|
||||
if (isIndexValid(lNetID))
|
||||
{
|
||||
if ((_entries[lNetID].bFree == false) && (_entries[lNetID].pActor != pActor))
|
||||
Printf("IDList<T>::useID is using an already used ID.\n");
|
||||
|
||||
_entries[lNetID].bFree = false;
|
||||
_entries[lNetID].pActor = pActor;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
unsigned int IDList<T>::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<AActor>;
|
||||
|
||||
//*****************************************************************************
|
||||
|
||||
void CountActors()
|
||||
{
|
||||
TMap<FName, int> actorCountMap;
|
||||
AActor * mo;
|
||||
int numActors = 0;
|
||||
int numActorsWithNetID = 0;
|
||||
|
||||
TThinkerIterator<AActor> it = primaryLevel->GetThinkerIterator<AActor>();
|
||||
|
||||
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<FName, int>::Pair *pair;
|
||||
|
||||
Printf("%d actors in total found, %d have a NetID. Detailed listing:\n", numActors, numActorsWithNetID);
|
||||
|
||||
TMap<FName, int>::ConstIterator mapit(actorCountMap);
|
||||
while (mapit.NextPair(pair))
|
||||
{
|
||||
Printf("%s %d\n", pair->Key.GetChars(), pair->Value);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(countactors)
|
||||
{
|
||||
CountActors();
|
||||
}
|
114
src/network/netsync.h
Normal file
114
src/network/netsync.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "vectors.h"
|
||||
#include "r_data/renderstyle.h"
|
||||
|
||||
class AActor;
|
||||
class NetCommand;
|
||||
class ByteInputStream;
|
||||
|
||||
class NetSyncVariable
|
||||
{
|
||||
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<NetSyncVariable> mSyncVars;
|
||||
|
||||
NetSyncClass(const NetSyncClass &) = delete;
|
||||
NetSyncClass &operator=(const NetSyncClass &) = delete;
|
||||
};
|
||||
|
||||
class NetSyncData
|
||||
{
|
||||
public:
|
||||
int NetID;
|
||||
DVector3 Pos;
|
||||
TArray<uint8_t> CompareData;
|
||||
NetSyncClass *SyncClass; // Maybe this should be stored in the actor's PClass
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 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 <typename T>
|
||||
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 = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int getNewID();
|
||||
|
||||
T* findPointerByID(const int lNetID) const
|
||||
{
|
||||
if (isIndexValid(lNetID) == false)
|
||||
return nullptr;
|
||||
|
||||
if ((_entries[lNetID].bFree == false) && (_entries[lNetID].pActor))
|
||||
return _entries[lNetID].pActor;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
|
@ -45,7 +45,7 @@
|
|||
#include "gstrings.h"
|
||||
#include "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"
|
||||
|
@ -255,17 +255,17 @@ DEFINE_ACTION_FUNCTION(DConversationMenu, SendConversationReply)
|
|||
switch (node)
|
||||
{
|
||||
case -1:
|
||||
Net_WriteByte(DEM_CONVNULL);
|
||||
network->WriteByte(DEM_CONVNULL);
|
||||
break;
|
||||
|
||||
case -2:
|
||||
Net_WriteByte(DEM_CONVCLOSE);
|
||||
network->WriteByte(DEM_CONVCLOSE);
|
||||
break;
|
||||
|
||||
default:
|
||||
Net_WriteByte(DEM_CONVREPLY);
|
||||
Net_WriteWord(node);
|
||||
Net_WriteByte(reply);
|
||||
network->WriteByte(DEM_CONVREPLY);
|
||||
network->WriteWord(node);
|
||||
network->WriteByte(reply);
|
||||
break;
|
||||
}
|
||||
StaticLastReply = reply;
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "p_trace.h"
|
||||
#include "decallib.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "d_net.h"
|
||||
#include "serializer.h"
|
||||
#include "doomdata.h"
|
||||
#include "g_levellocals.h"
|
||||
|
|
|
@ -48,6 +48,8 @@
|
|||
#include "tflags.h"
|
||||
#include "portal.h"
|
||||
|
||||
#include "network/netsync.h"
|
||||
|
||||
struct subsector_t;
|
||||
struct FBlockNode;
|
||||
struct FPortalGroupArray;
|
||||
|
@ -645,6 +647,8 @@ public:
|
|||
AActor &operator= (const AActor &other);
|
||||
~AActor ();
|
||||
|
||||
NetSyncData syncdata;
|
||||
|
||||
virtual void OnDestroy() override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual void PostSerialize() override;
|
||||
|
|
|
@ -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 "w_wad.h"
|
||||
|
@ -212,7 +212,7 @@ CCMD (removebots)
|
|||
return;
|
||||
}
|
||||
|
||||
Net_WriteByte (DEM_KILLBOTS);
|
||||
network->WriteByte (DEM_KILLBOTS);
|
||||
}
|
||||
|
||||
CCMD (freeze)
|
||||
|
@ -226,8 +226,8 @@ CCMD (freeze)
|
|||
return;
|
||||
}
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_FREEZE);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_FREEZE);
|
||||
}
|
||||
|
||||
CCMD (listbots)
|
||||
|
|
|
@ -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"
|
||||
|
@ -292,8 +292,8 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
|
|||
|
||||
thebot->inuse = BOTINUSE_Waiting;
|
||||
|
||||
Net_WriteByte (DEM_ADDBOT);
|
||||
Net_WriteByte (botshift);
|
||||
network->WriteByte (DEM_ADDBOT);
|
||||
network->WriteByte (botshift);
|
||||
{
|
||||
//Set color.
|
||||
char concat[512];
|
||||
|
@ -307,12 +307,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->WriteString (concat);
|
||||
}
|
||||
Net_WriteByte(thebot->skill.aiming);
|
||||
Net_WriteByte(thebot->skill.perfection);
|
||||
Net_WriteByte(thebot->skill.reaction);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
@ -58,9 +58,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];
|
||||
|
||||
memset (cmd, 0, sizeof(*cmd));
|
||||
ticcmd_t cmd;
|
||||
|
||||
if (enemy && enemy->health <= 0)
|
||||
enemy = nullptr;
|
||||
|
@ -75,16 +73,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)) / 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.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--;
|
||||
|
@ -101,8 +99,10 @@ void DBot::Think ()
|
|||
}
|
||||
else if (player->mo->health <= 0)
|
||||
{ // Time to respawn
|
||||
cmd->ucmd.buttons |= BT_USE;
|
||||
cmd.ucmd.buttons |= BT_USE;
|
||||
}
|
||||
|
||||
network->WriteBotInput((int)(player - players), cmd);
|
||||
}
|
||||
|
||||
#define THINKDISTSQ (50000.*50000./(65536.*65536.))
|
||||
|
|
|
@ -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"
|
||||
|
@ -1836,8 +1836,8 @@ CCMD (kill)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_MASSACRE);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_MASSACRE);
|
||||
}
|
||||
else if (!stricmp (argv[1], "baddies"))
|
||||
{
|
||||
|
@ -1845,13 +1845,13 @@ CCMD (kill)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_MASSACRE2);
|
||||
network->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (CHT_MASSACRE2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte (DEM_KILLCLASSCHEAT);
|
||||
Net_WriteString (argv[1]);
|
||||
network->WriteByte (DEM_KILLCLASSCHEAT);
|
||||
network->WriteString (argv[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1861,7 +1861,7 @@ CCMD (kill)
|
|||
return;
|
||||
|
||||
// Kill the player
|
||||
Net_WriteByte (DEM_SUICIDE);
|
||||
network->WriteByte (DEM_SUICIDE);
|
||||
}
|
||||
C_HideConsole ();
|
||||
}
|
||||
|
@ -1873,8 +1873,8 @@ CCMD(remove)
|
|||
if (CheckCheatmode())
|
||||
return;
|
||||
|
||||
Net_WriteByte(DEM_REMOVE);
|
||||
Net_WriteString(argv[1]);
|
||||
network->WriteByte(DEM_REMOVE);
|
||||
network->WriteString(argv[1]);
|
||||
C_HideConsole();
|
||||
}
|
||||
else
|
||||
|
@ -1882,5 +1882,4 @@ CCMD(remove)
|
|||
Printf("Usage: remove <actor class name>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
@ -3125,7 +3125,7 @@ FUNC(LS_Autosave)
|
|||
if (gameaction != ga_savegame)
|
||||
{
|
||||
Level->flags2 &= ~LEVEL2_NOAUTOSAVEHINT;
|
||||
Net_WriteByte (DEM_CHECKAUTOSAVE);
|
||||
network->WriteByte (DEM_CHECKAUTOSAVE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
#include "events.h"
|
||||
#include "actorinlines.h"
|
||||
#include "a_dynlight.h"
|
||||
#include "network/net.h"
|
||||
#include "fragglescript/t_fs.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
@ -4550,6 +4551,9 @@ void ConstructActor(AActor *actor, const DVector3 &pos, bool SpawningMapThing)
|
|||
}
|
||||
// force scroller check in the first tic.
|
||||
actor->flags8 |= MF8_INSCROLLSEC;
|
||||
|
||||
// notify network that we got a new actor
|
||||
network->ActorSpawned(actor);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4819,6 +4823,9 @@ void AActor::CallDeactivate(AActor *activator)
|
|||
|
||||
void AActor::OnDestroy ()
|
||||
{
|
||||
// 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.
|
||||
// but you can't really do that without utterly breaking the game, so it's ok.
|
||||
|
|
|
@ -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"
|
||||
|
@ -478,7 +478,7 @@ void player_t::SetFOV(float fov)
|
|||
{
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
Net_WriteByte(DEM_MYFOV);
|
||||
network->WriteByte(DEM_MYFOV);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -488,9 +488,9 @@ void player_t::SetFOV(float fov)
|
|||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte(DEM_MYFOV);
|
||||
network->WriteByte(DEM_MYFOV);
|
||||
}
|
||||
Net_WriteFloat(clamp<float>(fov, 5.f, 179.f));
|
||||
network->WriteFloat(clamp<float>(fov, 5.f, 179.f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -637,9 +637,9 @@ void player_t::SendPitchLimits() const
|
|||
uppitch = downpitch = (int)maxviewpitch;
|
||||
}
|
||||
|
||||
Net_WriteByte(DEM_SETPITCHLIMIT);
|
||||
Net_WriteByte(uppitch);
|
||||
Net_WriteByte(downpitch);
|
||||
network->WriteByte(DEM_SETPITCHLIMIT);
|
||||
network->WriteByte(uppitch);
|
||||
network->WriteByte(downpitch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1392,7 +1392,7 @@ void P_PredictPlayer (player_t *player)
|
|||
return;
|
||||
}
|
||||
|
||||
maxtic = maketic;
|
||||
maxtic = network->GetSendTick();
|
||||
|
||||
if (gametic == maxtic)
|
||||
{
|
||||
|
@ -1446,13 +1446,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->GetSentInput(i);
|
||||
P_PlayerThink (player);
|
||||
player->mo->Tick ();
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include "cmdlib.h"
|
||||
#include "atterm.h"
|
||||
|
||||
|
||||
void I_Tactile(int /*on*/, int /*off*/, int /*total*/)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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<bool()> 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<bool()> callback)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (timerCallback(userData))
|
||||
if (callback())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -71,17 +71,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);
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include "x86.h"
|
||||
|
||||
#include "d_main.h"
|
||||
#include "d_net.h"
|
||||
#include "network/net.h"
|
||||
#include "g_game.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "atterm.h"
|
||||
|
@ -75,12 +75,6 @@ void I_Tactile (int /*on*/, int /*off*/, int /*total*/)
|
|||
{
|
||||
}
|
||||
|
||||
ticcmd_t emptycmd;
|
||||
ticcmd_t *I_BaseTiccmd(void)
|
||||
{
|
||||
return &emptycmd;
|
||||
}
|
||||
|
||||
void I_BeginRead(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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<bool()> 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<bool()> 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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
** Actual implementation is system-specific.
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
|
||||
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<bool()> callback);
|
||||
protected:
|
||||
int MaxPos, CurPos, NotchPos;
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
@ -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->WriteByte (DEM_GENERICCHEAT);
|
||||
network->WriteByte (cheat->Args[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<unsigned>( Index ) < countof( PredefinedNames );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -73,7 +73,6 @@
|
|||
#include "utf8.h"
|
||||
|
||||
#include "d_main.h"
|
||||
#include "d_net.h"
|
||||
#include "g_game.h"
|
||||
#include "i_input.h"
|
||||
#include "c_dispatch.h"
|
||||
|
@ -144,7 +143,6 @@ int sys_ostype = 0;
|
|||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static ticcmd_t emptycmd;
|
||||
static bool HasExited;
|
||||
|
||||
static WadStuff *WadList;
|
||||
|
@ -168,20 +166,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
|
||||
|
|
|
@ -62,16 +62,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.
|
||||
|
|
|
@ -121,7 +121,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<bool()> callback);
|
||||
protected:
|
||||
LRESULT NetMarqueeMode;
|
||||
int NetMaxPos, NetCurPos;
|
||||
|
@ -529,7 +529,7 @@ void FBasicStartupScreen :: NetProgress(int count)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FBasicStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata)
|
||||
bool FBasicStartupScreen::NetLoop(std::function<bool()> callback)
|
||||
{
|
||||
BOOL bRet;
|
||||
MSG msg;
|
||||
|
@ -550,7 +550,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;
|
||||
|
|
|
@ -7,6 +7,7 @@ version "4.2"
|
|||
#include "zscript/events.zs"
|
||||
#include "zscript/destructible.zs"
|
||||
#include "zscript/level_compatibility.zs"
|
||||
#include "zscript/network.txt"
|
||||
|
||||
#include "zscript/actors/actor.zs"
|
||||
#include "zscript/actors/checks.zs"
|
||||
|
|
4
wadsrc/static/zscript/network.txt
Normal file
4
wadsrc/static/zscript/network.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
class NetSyncActor : Actor native
|
||||
{
|
||||
}
|
Loading…
Reference in a new issue