mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2024-11-25 05:41:42 +00:00
Merge branch 'netcode-rerefactor' into 'next'
Re-delete netcode See merge request STJr/SRB2!2083
This commit is contained in:
commit
2a896538d9
79 changed files with 6546 additions and 6604 deletions
|
@ -62,7 +62,6 @@
|
|||
#
|
||||
# Netplay incompatible
|
||||
# --------------------
|
||||
# NONET=1 - Disable online capability.
|
||||
# NOMD5=1 - Disable MD5 checksum (validation tool).
|
||||
# NOPOSTPROCESSING=1 - ?
|
||||
# MOBJCONSISTANCY=1 - ??
|
||||
|
@ -187,6 +186,7 @@ objdir:=$(makedir)/objs
|
|||
sources+=\
|
||||
$(call List,Sourcefile)\
|
||||
$(call List,blua/Sourcefile)\
|
||||
$(call List,netcode/Sourcefile)\
|
||||
|
||||
depends:=$(basename $(filter %.c %.s,$(sources)))
|
||||
objects:=$(basename $(filter %.c %.s %.nas,$(sources)))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
|
||||
passthru_opts+=\
|
||||
NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\
|
||||
NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\
|
||||
MOBJCONSISTANCY PACKETDROP ZDEBUG\
|
||||
HAVE_MINIUPNPC\
|
||||
|
||||
|
@ -39,13 +39,11 @@ sources+=apng.c
|
|||
endif
|
||||
endif
|
||||
|
||||
ifndef NONET
|
||||
ifndef NOCURL
|
||||
CURLCONFIG?=curl-config
|
||||
$(eval $(call Configure,CURL,$(CURLCONFIG)))
|
||||
opts+=-DHAVE_CURL
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef HAVE_MINIUPNPC
|
||||
libs+=-lminiupnpc
|
||||
|
|
|
@ -33,12 +33,10 @@ libs+=-lws2_32
|
|||
endif
|
||||
endif
|
||||
|
||||
ifndef NONET
|
||||
ifndef MINGW64 # miniupnc is broken with MINGW64
|
||||
opts+=-I../libs -DSTATIC_MINIUPNPC
|
||||
libs+=-L../libs/miniupnpc/mingw$(32) -lws2_32 -liphlpapi
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef MINGW64
|
||||
32=32
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
string.c
|
||||
d_main.c
|
||||
d_clisrv.c
|
||||
d_net.c
|
||||
d_netfil.c
|
||||
d_netcmd.c
|
||||
dehacked.c
|
||||
deh_soc.c
|
||||
deh_lua.c
|
||||
|
@ -77,12 +73,10 @@ s_sound.c
|
|||
sounds.c
|
||||
w_wad.c
|
||||
filesrch.c
|
||||
mserv.c
|
||||
http-mserv.c
|
||||
i_tcp.c
|
||||
lzf.c
|
||||
b_bot.c
|
||||
u_list.c
|
||||
snake.c
|
||||
lua_script.c
|
||||
lua_baselib.c
|
||||
lua_mathlib.c
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "../i_net.h"
|
||||
#include "../netcode/i_net.h"
|
||||
|
||||
boolean I_InitNetwork(void)
|
||||
{
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
#include "lualib.h"
|
||||
#include "../i_system.h"
|
||||
#include "../g_game.h"
|
||||
#include "../d_netfil.h"
|
||||
#include "../netcode/d_netfil.h"
|
||||
#include "../netcode/net_command.h"
|
||||
#include "../lua_libs.h"
|
||||
#include "../byteptr.h"
|
||||
#include "../lua_script.h"
|
||||
|
|
|
@ -28,11 +28,12 @@
|
|||
#include "byteptr.h"
|
||||
#include "p_saveg.h"
|
||||
#include "g_game.h" // for player_names
|
||||
#include "d_netcmd.h"
|
||||
#include "netcode/d_netcmd.h"
|
||||
#include "netcode/net_command.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "p_setup.h"
|
||||
#include "lua_script.h"
|
||||
#include "d_netfil.h" // findfile
|
||||
#include "netcode/d_netfil.h" // findfile
|
||||
#include "r_data.h" // Color_cons_t
|
||||
#include "d_main.h" // D_IsPathAllowed
|
||||
|
||||
|
|
5841
src/d_clisrv.c
5841
src/d_clisrv.c
File diff suppressed because it is too large
Load diff
|
@ -34,7 +34,7 @@
|
|||
#include "doomdef.h"
|
||||
#include "am_map.h"
|
||||
#include "console.h"
|
||||
#include "d_net.h"
|
||||
#include "netcode/d_net.h"
|
||||
#include "f_finale.h"
|
||||
#include "g_game.h"
|
||||
#include "hu_stuff.h"
|
||||
|
@ -56,11 +56,11 @@
|
|||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
#include "d_main.h"
|
||||
#include "d_netfil.h"
|
||||
#include "netcode/d_netfil.h"
|
||||
#include "m_cheat.h"
|
||||
#include "y_inter.h"
|
||||
#include "p_local.h" // chasecam
|
||||
#include "mserv.h" // ms_RoomId
|
||||
#include "netcode/mserv.h" // ms_RoomId
|
||||
#include "m_misc.h" // screenshot functionality
|
||||
#include "deh_tables.h" // Dehacked list test
|
||||
#include "m_cond.h" // condition initialization
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "r_sky.h"
|
||||
#include "fastcmp.h"
|
||||
#include "lua_script.h" // Reluctantly included for LUA_EvalMath
|
||||
#include "d_clisrv.h"
|
||||
#include "netcode/d_clisrv.h"
|
||||
|
||||
#ifdef HWRENDER
|
||||
#include "hardware/hw_light.h"
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "r_sky.h"
|
||||
#include "fastcmp.h"
|
||||
#include "lua_script.h" // Reluctantly included for LUA_EvalMath
|
||||
#include "d_clisrv.h"
|
||||
#include "netcode/d_clisrv.h"
|
||||
|
||||
#ifdef HWRENDER
|
||||
#include "hardware/hw_light.h"
|
||||
|
|
|
@ -4883,7 +4883,7 @@ const char *const MENUTYPES_LIST[] = {
|
|||
"MP_SERVER",
|
||||
"MP_CONNECT",
|
||||
"MP_ROOM",
|
||||
"MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET
|
||||
"MP_PLAYERSETUP",
|
||||
"MP_SERVER_OPTIONS",
|
||||
|
||||
// Options
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define NONET
|
||||
#if !defined (HWRENDER) && !defined (NOHW)
|
||||
#define HWRENDER
|
||||
#endif
|
||||
|
@ -724,7 +723,7 @@ extern int
|
|||
/// Maintain compatibility with older 2.2 demos
|
||||
#define OLD22DEMOCOMPAT
|
||||
|
||||
#if defined (HAVE_CURL) && ! defined (NONET)
|
||||
#ifdef HAVE_CURL
|
||||
#define MASTERSERVER
|
||||
#else
|
||||
#undef UPDATE_ALERT
|
||||
|
|
|
@ -634,7 +634,7 @@ extern boolean singletics;
|
|||
// Netgame stuff
|
||||
// =============
|
||||
|
||||
#include "d_clisrv.h"
|
||||
#include "netcode/d_clisrv.h"
|
||||
|
||||
extern consvar_t cv_timetic; // display high resolution timer
|
||||
extern consvar_t cv_powerupdisplay; // display powerups
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "../i_net.h"
|
||||
#include "../netcode/i_net.h"
|
||||
|
||||
boolean I_InitNetwork(void)
|
||||
{
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_main.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "netcode/d_netcmd.h"
|
||||
#include "f_finale.h"
|
||||
#include "g_game.h"
|
||||
#include "hu_stuff.h"
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "filesrch.h"
|
||||
#include "d_netfil.h"
|
||||
#include "netcode/d_netfil.h"
|
||||
#include "m_misc.h"
|
||||
#include "z_zone.h"
|
||||
#include "m_menu.h" // Addons_option_Onchange
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#define __FILESRCH_H__
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "d_netfil.h"
|
||||
#include "netcode/d_netfil.h"
|
||||
#include "m_menu.h" // MAXSTRINGLENGTH
|
||||
#include "w_wad.h"
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "console.h"
|
||||
#include "d_main.h"
|
||||
#include "d_player.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "netcode/d_clisrv.h"
|
||||
#include "p_setup.h"
|
||||
#include "i_time.h"
|
||||
#include "i_system.h"
|
||||
|
@ -39,7 +39,7 @@
|
|||
#include "v_video.h"
|
||||
#include "lua_hook.h"
|
||||
#include "md5.h" // demo checksums
|
||||
#include "d_netfil.h" // G_CheckDemoExtraFiles
|
||||
#include "netcode/d_netfil.h" // G_CheckDemoExtraFiles
|
||||
|
||||
boolean timingdemo; // if true, exit with report on completion
|
||||
boolean nodrawers; // for comparative timing purposes
|
||||
|
@ -1894,7 +1894,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
switch(oldversion) // demoversion
|
||||
{
|
||||
case DEMOVERSION: // latest always supported
|
||||
case 0x000f: // The previous demoversions also supported
|
||||
case 0x000f: // The previous demoversions also supported
|
||||
case 0x000e:
|
||||
case 0x000d: // all that changed between then and now was longer color name
|
||||
case 0x000c:
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
#include "console.h"
|
||||
#include "d_main.h"
|
||||
#include "d_player.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "netcode/d_clisrv.h"
|
||||
#include "netcode/net_command.h"
|
||||
#include "f_finale.h"
|
||||
#include "p_setup.h"
|
||||
#include "p_saveg.h"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "g_input.h"
|
||||
#include "keys.h"
|
||||
#include "hu_stuff.h" // need HUFONT start & end
|
||||
#include "d_net.h"
|
||||
#include "netcode/d_net.h"
|
||||
#include "console.h"
|
||||
|
||||
#define MAXMOUSESENSITIVITY 100 // sensitivity steps
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "../r_patch.h"
|
||||
#include "../r_picformats.h"
|
||||
#include "../r_bsp.h"
|
||||
#include "../d_clisrv.h"
|
||||
#include "../netcode/d_clisrv.h"
|
||||
#include "../w_wad.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../r_splats.h"
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
#include "m_cond.h" // emblems
|
||||
#include "m_misc.h" // word jumping
|
||||
|
||||
#include "d_clisrv.h"
|
||||
#include "netcode/d_clisrv.h"
|
||||
#include "netcode/net_command.h"
|
||||
#include "netcode/gamestate.h"
|
||||
|
||||
#include "g_game.h"
|
||||
#include "g_input.h"
|
||||
|
@ -175,14 +177,12 @@ static huddrawlist_h luahuddrawlist_scores;
|
|||
|
||||
static tic_t resynch_ticker = 0;
|
||||
|
||||
#ifndef NONET
|
||||
// just after
|
||||
static void Command_Say_f(void);
|
||||
static void Command_Sayto_f(void);
|
||||
static void Command_Sayteam_f(void);
|
||||
static void Command_CSay_f(void);
|
||||
static void Got_Saycmd(UINT8 **p, INT32 playernum);
|
||||
#endif
|
||||
|
||||
void HU_LoadGraphics(void)
|
||||
{
|
||||
|
@ -327,13 +327,11 @@ void HU_LoadGraphics(void)
|
|||
//
|
||||
void HU_Init(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
COM_AddCommand("say", Command_Say_f, COM_LUA);
|
||||
COM_AddCommand("sayto", Command_Sayto_f, COM_LUA);
|
||||
COM_AddCommand("sayteam", Command_Sayteam_f, COM_LUA);
|
||||
COM_AddCommand("csay", Command_CSay_f, COM_LUA);
|
||||
RegisterNetXCmd(XD_SAY, Got_Saycmd);
|
||||
#endif
|
||||
|
||||
// set shift translation table
|
||||
shiftxform = english_shiftxform;
|
||||
|
@ -363,8 +361,6 @@ void HU_Start(void)
|
|||
// EXECUTION
|
||||
//======================================================================
|
||||
|
||||
#ifndef NONET
|
||||
|
||||
// EVERY CHANGE IN THIS SCRIPT IS LOL XD! BY VINCYTM
|
||||
|
||||
static UINT32 chat_nummsg_log = 0;
|
||||
|
@ -412,11 +408,9 @@ static void HU_removeChatText_Log(void)
|
|||
}
|
||||
chat_nummsg_log--; // lost 1 msg.
|
||||
}
|
||||
#endif
|
||||
|
||||
void HU_AddChatText(const char *text, boolean playsound)
|
||||
{
|
||||
#ifndef NONET
|
||||
if (playsound && cv_consolechat.value != 2) // Don't play the sound if we're using hidden chat.
|
||||
S_StartSound(NULL, sfx_radio);
|
||||
// reguardless of our preferences, put all of this in the chat buffer in case we decide to change from oldchat mid-game.
|
||||
|
@ -438,14 +432,8 @@ void HU_AddChatText(const char *text, boolean playsound)
|
|||
CONS_Printf("%s\n", text);
|
||||
else // if we aren't, still save the message to log.txt
|
||||
CON_LogMessage(va("%s\n", text));
|
||||
#else
|
||||
(void)playsound;
|
||||
CONS_Printf("%s\n", text);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
|
||||
/** Runs a say command, sending an ::XD_SAY message.
|
||||
* A say command consists of a signed 8-bit integer for the target, an
|
||||
* unsigned 8-bit flag variable, and then the message itself.
|
||||
|
@ -865,8 +853,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
//
|
||||
void HU_Ticker(void)
|
||||
|
@ -882,7 +868,6 @@ void HU_Ticker(void)
|
|||
else
|
||||
hu_showscores = false;
|
||||
|
||||
#ifndef NONET
|
||||
if (chat_on)
|
||||
{
|
||||
// count down the scroll timer.
|
||||
|
@ -910,7 +895,6 @@ void HU_Ticker(void)
|
|||
HU_removeChatText_Mini();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cechotimer > 0) --cechotimer;
|
||||
|
||||
|
@ -918,8 +902,6 @@ void HU_Ticker(void)
|
|||
resynch_ticker++;
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
|
||||
static boolean teamtalk = false;
|
||||
static boolean justscrolleddown;
|
||||
static boolean justscrolledup;
|
||||
|
@ -1027,8 +1009,6 @@ static void HU_sendChatMessage(void)
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void HU_clearChatChars(void)
|
||||
{
|
||||
memset(w_chat, '\0', sizeof(w_chat));
|
||||
|
@ -1043,9 +1023,7 @@ void HU_clearChatChars(void)
|
|||
//
|
||||
boolean HU_Responder(event_t *ev)
|
||||
{
|
||||
#ifndef NONET
|
||||
INT32 c=0;
|
||||
#endif
|
||||
|
||||
if (ev->type != ev_keydown)
|
||||
return false;
|
||||
|
@ -1072,7 +1050,6 @@ boolean HU_Responder(event_t *ev)
|
|||
return false;
|
||||
}*/ //We don't actually care about that unless we get splitscreen netgames. :V
|
||||
|
||||
#ifndef NONET
|
||||
c = (INT32)ev->key;
|
||||
|
||||
if (!chat_on)
|
||||
|
@ -1222,7 +1199,6 @@ boolean HU_Responder(event_t *ev)
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1232,8 +1208,6 @@ boolean HU_Responder(event_t *ev)
|
|||
// HEADS UP DRAWING
|
||||
//======================================================================
|
||||
|
||||
#ifndef NONET
|
||||
|
||||
// Precompile a wordwrapped string to any given width.
|
||||
// This is a muuuch better method than V_WORDWRAP.
|
||||
// again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day.
|
||||
|
@ -1813,7 +1787,6 @@ static void HU_DrawChat_Old(void)
|
|||
if (hu_tick < 4)
|
||||
V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Draw crosshairs at the exact center of the view.
|
||||
// In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them.
|
||||
|
@ -1953,7 +1926,6 @@ static void HU_DrawDemoInfo(void)
|
|||
//
|
||||
void HU_Drawer(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
// draw chat string plus cursor
|
||||
if (chat_on)
|
||||
{
|
||||
|
@ -1970,7 +1942,6 @@ void HU_Drawer(void)
|
|||
if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden)
|
||||
HU_drawMiniChat(); // draw messages in a cool fashion.
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cechotimer)
|
||||
HU_DrawCEcho();
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "command.h"
|
||||
#include "doomtype.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "netcode/d_netcmd.h"
|
||||
#include "m_fixed.h"
|
||||
#include "i_system.h"
|
||||
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
#include "y_inter.h"
|
||||
#include "hu_stuff.h" // HU_AddChatText
|
||||
#include "console.h"
|
||||
#include "d_netcmd.h" // IsPlayerAdmin
|
||||
#include "netcode/d_netcmd.h" // IsPlayerAdmin
|
||||
#include "m_menu.h" // Player Setup menu color stuff
|
||||
#include "m_misc.h" // M_MapNumber
|
||||
#include "b_bot.h" // B_UpdateBotleader
|
||||
#include "d_clisrv.h" // CL_RemovePlayer
|
||||
#include "netcode/d_clisrv.h" // CL_RemovePlayer
|
||||
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
|
||||
|
||||
#include "lua_script.h"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "g_game.h"
|
||||
#include "byteptr.h"
|
||||
#include "z_zone.h"
|
||||
#include "netcode/net_command.h"
|
||||
|
||||
#include "lua_script.h"
|
||||
#include "lua_libs.h"
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "lua_hud.h" // hud_running errors
|
||||
|
||||
#include "m_perfstats.h"
|
||||
#include "d_netcmd.h" // for cv_perfstats
|
||||
#include "netcode/d_netcmd.h" // for cv_perfstats
|
||||
#include "i_system.h" // I_GetPreciseTime
|
||||
|
||||
/* =========================================================================
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "p_slopes.h" // for P_SlopeById and slopelist
|
||||
#include "p_polyobj.h" // polyobj_t, PolyObjects
|
||||
#ifdef LUA_ALLOW_BYTECODE
|
||||
#include "d_netfil.h" // for LUA_DumpFile
|
||||
#include "netcode/d_netfil.h" // for LUA_DumpFile
|
||||
#endif
|
||||
|
||||
#include "lua_script.h"
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "r_local.h"
|
||||
#include "p_local.h"
|
||||
#include "p_setup.h"
|
||||
#include "d_net.h"
|
||||
#include "netcode/d_net.h"
|
||||
|
||||
#include "m_cheat.h"
|
||||
#include "m_menu.h"
|
||||
|
|
65
src/m_menu.c
65
src/m_menu.c
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "doomdef.h"
|
||||
#include "d_main.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "netcode/d_netcmd.h"
|
||||
#include "console.h"
|
||||
#include "r_fps.h"
|
||||
#include "r_local.h"
|
||||
|
@ -53,8 +53,10 @@
|
|||
#include "hardware/hw_main.h"
|
||||
#endif
|
||||
|
||||
#include "d_net.h"
|
||||
#include "mserv.h"
|
||||
#include "netcode/d_net.h"
|
||||
#include "netcode/mserv.h"
|
||||
#include "netcode/server_connection.h"
|
||||
#include "netcode/client_connection.h"
|
||||
#include "m_misc.h"
|
||||
#include "m_anigif.h"
|
||||
#include "byteptr.h"
|
||||
|
@ -149,9 +151,7 @@ levellist_mode_t levellistmode = LLM_CREATESERVER;
|
|||
UINT8 maplistoption = 0;
|
||||
|
||||
static char joystickInfo[MAX_JOYSTICKS+1][29];
|
||||
#ifndef NONET
|
||||
static UINT32 serverlistpage;
|
||||
#endif
|
||||
|
||||
static UINT8 numsaves = 0;
|
||||
static saveinfo_t* savegameinfo = NULL; // Extra info about the save games.
|
||||
|
@ -190,10 +190,8 @@ static void M_GoBack(INT32 choice);
|
|||
static void M_StopMessage(INT32 choice);
|
||||
static boolean stopstopmessage = false;
|
||||
|
||||
#ifndef NONET
|
||||
static void M_HandleServerPage(INT32 choice);
|
||||
static void M_RoomMenu(INT32 choice);
|
||||
#endif
|
||||
|
||||
// Prototyping is fun, innit?
|
||||
// ==========================================================================
|
||||
|
@ -296,7 +294,6 @@ static void M_SetupMultiPlayer2(INT32 choice);
|
|||
static void M_StartSplitServerMenu(INT32 choice);
|
||||
static void M_StartServer(INT32 choice);
|
||||
static void M_ServerOptions(INT32 choice);
|
||||
#ifndef NONET
|
||||
static void M_StartServerMenu(INT32 choice);
|
||||
static void M_ConnectMenu(INT32 choice);
|
||||
static void M_ConnectMenuModChecks(INT32 choice);
|
||||
|
@ -304,7 +301,6 @@ static void M_Refresh(INT32 choice);
|
|||
static void M_Connect(INT32 choice);
|
||||
static void M_ChooseRoom(INT32 choice);
|
||||
menu_t MP_MainDef;
|
||||
#endif
|
||||
|
||||
// Options
|
||||
// Split into multiple parts due to size
|
||||
|
@ -382,11 +378,9 @@ static void M_DrawVideoMode(void);
|
|||
static void M_DrawColorMenu(void);
|
||||
static void M_DrawScreenshotMenu(void);
|
||||
static void M_DrawMonitorToggles(void);
|
||||
#ifndef NONET
|
||||
static void M_DrawConnectMenu(void);
|
||||
static void M_DrawMPMainMenu(void);
|
||||
static void M_DrawRoomMenu(void);
|
||||
#endif
|
||||
static void M_DrawJoystick(void);
|
||||
static void M_DrawSetupMultiPlayerMenu(void);
|
||||
static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t color);
|
||||
|
@ -401,10 +395,8 @@ static void M_HandleImageDef(INT32 choice);
|
|||
static void M_HandleLoadSave(INT32 choice);
|
||||
static void M_HandleLevelStats(INT32 choice);
|
||||
static void M_HandlePlaystyleMenu(INT32 choice);
|
||||
#ifndef NONET
|
||||
static boolean M_CancelConnect(void);
|
||||
static void M_HandleConnectIP(INT32 choice);
|
||||
#endif
|
||||
static void M_HandleSetupMultiPlayer(INT32 choice);
|
||||
static void M_HandleVideoMode(INT32 choice);
|
||||
|
||||
|
@ -503,11 +495,7 @@ consvar_t cv_dummyloadless = CVAR_INIT ("dummyloadless", "In-game", CV_HIDEN, lo
|
|||
static menuitem_t MainMenu[] =
|
||||
{
|
||||
{IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76},
|
||||
#ifndef NONET
|
||||
{IT_STRING|IT_SUBMENU, NULL, "Multiplayer", &MP_MainDef, 84},
|
||||
#else
|
||||
{IT_STRING|IT_CALL, NULL, "Multiplayer", M_StartSplitServerMenu, 84},
|
||||
#endif
|
||||
{IT_STRING|IT_CALL, NULL, "Extras", M_SecretsMenu, 92},
|
||||
{IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 100},
|
||||
{IT_STRING|IT_CALL, NULL, "Options", M_Options, 108},
|
||||
|
@ -930,16 +918,10 @@ static menuitem_t SP_PlayerMenu[] =
|
|||
static menuitem_t MP_SplitServerMenu[] =
|
||||
{
|
||||
{IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100},
|
||||
#ifdef NONET // In order to keep player setup accessible.
|
||||
{IT_STRING|IT_CALL, NULL, "Player 1 setup...", M_SetupMultiPlayer, 110},
|
||||
{IT_STRING|IT_CALL, NULL, "Player 2 setup...", M_SetupMultiPlayer2, 120},
|
||||
#endif
|
||||
{IT_STRING|IT_CALL, NULL, "More Options...", M_ServerOptions, 130},
|
||||
{IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140},
|
||||
};
|
||||
|
||||
#ifndef NONET
|
||||
|
||||
static menuitem_t MP_MainMenu[] =
|
||||
{
|
||||
{IT_HEADER, NULL, "Join a game", NULL, 0},
|
||||
|
@ -1026,8 +1008,6 @@ menuitem_t MP_RoomMenu[] =
|
|||
{IT_DISABLED, NULL, "", M_ChooseRoom, 162},
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static menuitem_t MP_PlayerSetupMenu[] =
|
||||
{
|
||||
{IT_KEYHANDLER, NULL, "", M_HandleSetupMultiPlayer, 0}, // name
|
||||
|
@ -1586,14 +1566,12 @@ enum
|
|||
static menuitem_t OP_ServerOptionsMenu[] =
|
||||
{
|
||||
{IT_HEADER, NULL, "General", NULL, 0},
|
||||
#ifndef NONET
|
||||
{IT_STRING | IT_CVAR | IT_CV_STRING,
|
||||
NULL, "Server name", &cv_servername, 7},
|
||||
{IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21},
|
||||
{IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26},
|
||||
{IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31},
|
||||
{IT_STRING | IT_CVAR, NULL, "Minutes for reconnecting", &cv_rejointimeout, 36},
|
||||
#endif
|
||||
{IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 41},
|
||||
{IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 46},
|
||||
|
||||
|
@ -1632,7 +1610,6 @@ static menuitem_t OP_ServerOptionsMenu[] =
|
|||
{IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 216},
|
||||
{IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 221},
|
||||
|
||||
#ifndef NONET
|
||||
{IT_HEADER, NULL, "Advanced", NULL, 230},
|
||||
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 236},
|
||||
|
||||
|
@ -1640,7 +1617,6 @@ static menuitem_t OP_ServerOptionsMenu[] =
|
|||
{IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 256},
|
||||
|
||||
{IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 261},
|
||||
#endif
|
||||
};
|
||||
|
||||
static menuitem_t OP_MonitorToggleMenu[] =
|
||||
|
@ -1954,11 +1930,7 @@ menu_t MP_SplitServerDef =
|
|||
MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN),
|
||||
"M_MULTI",
|
||||
sizeof (MP_SplitServerMenu)/sizeof (menuitem_t),
|
||||
#ifndef NONET
|
||||
&MP_MainDef,
|
||||
#else
|
||||
&MainDef,
|
||||
#endif
|
||||
MP_SplitServerMenu,
|
||||
M_DrawServerMenu,
|
||||
27, 30 - 50,
|
||||
|
@ -1966,8 +1938,6 @@ menu_t MP_SplitServerDef =
|
|||
NULL
|
||||
};
|
||||
|
||||
#ifndef NONET
|
||||
|
||||
menu_t MP_MainDef =
|
||||
{
|
||||
MN_MP_MAIN,
|
||||
|
@ -2019,15 +1989,10 @@ menu_t MP_RoomDef =
|
|||
0,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
menu_t MP_PlayerSetupDef =
|
||||
{
|
||||
#ifdef NONET
|
||||
MTREE2(MN_MP_MAIN, MN_MP_PLAYERSETUP),
|
||||
#else
|
||||
MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP),
|
||||
#endif
|
||||
"M_SPLAYR",
|
||||
sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t),
|
||||
&MainDef, // doesn't matter
|
||||
|
@ -3956,9 +3921,7 @@ void M_Init(void)
|
|||
OP_JoystickSetMenu[i].itemaction = M_AssignJoystick;
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
CV_RegisterVar(&cv_serversort);
|
||||
#endif
|
||||
}
|
||||
|
||||
void M_InitCharacterTables(void)
|
||||
|
@ -11108,7 +11071,6 @@ static void M_EndGame(INT32 choice)
|
|||
|
||||
#define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT)
|
||||
|
||||
#ifndef NONET
|
||||
static UINT32 localservercount;
|
||||
|
||||
static void M_HandleServerPage(INT32 choice)
|
||||
|
@ -11380,11 +11342,9 @@ static int ServerListEntryComparator_modified(const void *entry1, const void *en
|
|||
// Default to strcmp.
|
||||
return strcmp(sa->info.servername, sb->info.servername);
|
||||
}
|
||||
#endif
|
||||
|
||||
void M_SortServerList(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
switch(cv_serversort.value)
|
||||
{
|
||||
case 0: // Ping.
|
||||
|
@ -11406,10 +11366,8 @@ void M_SortServerList(void)
|
|||
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
#ifdef UPDATE_ALERT
|
||||
static boolean M_CheckMODVersion(int id)
|
||||
{
|
||||
|
@ -11608,7 +11566,6 @@ static void M_ChooseRoom(INT32 choice)
|
|||
if (currentMenu == &MP_ConnectDef)
|
||||
M_Refresh(0);
|
||||
}
|
||||
#endif //NONET
|
||||
|
||||
//===========================================================================
|
||||
// Start Server Menu
|
||||
|
@ -11656,7 +11613,6 @@ static void M_DrawServerMenu(void)
|
|||
{
|
||||
M_DrawGenericMenu();
|
||||
|
||||
#ifndef NONET
|
||||
// Room name
|
||||
if (currentMenu == &MP_ServerDef)
|
||||
{
|
||||
|
@ -11668,15 +11624,10 @@ static void M_DrawServerMenu(void)
|
|||
V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey,
|
||||
V_YELLOWMAP, room_list[menuRoomIndex].name);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cv_nextmap.value)
|
||||
{
|
||||
#ifndef NONET
|
||||
#define imgheight MP_ServerMenu[mp_server_levelgt].alphaKey
|
||||
#else
|
||||
#define imgheight 100
|
||||
#endif
|
||||
patch_t *PictureOfLevel;
|
||||
lumpnum_t lumpnum;
|
||||
char headerstr[40];
|
||||
|
@ -11728,7 +11679,6 @@ static void M_ServerOptions(INT32 choice)
|
|||
{
|
||||
(void)choice;
|
||||
|
||||
#ifndef NONET
|
||||
if ((splitscreen && !netgame) || currentMenu == &MP_SplitServerDef)
|
||||
{
|
||||
OP_ServerOptionsMenu[ 1].status = IT_GRAYEDOUT; // Server name
|
||||
|
@ -11749,7 +11699,6 @@ static void M_ServerOptions(INT32 choice)
|
|||
OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR;
|
||||
OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disable fading because of different menu head. */
|
||||
if (currentMenu == &OP_MainDef)/* from Options menu */
|
||||
|
@ -11761,7 +11710,6 @@ static void M_ServerOptions(INT32 choice)
|
|||
M_SetupNextMenu(&OP_ServerOptionsDef);
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static void M_StartServerMenu(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
|
@ -12028,7 +11976,6 @@ static void M_HandleConnectIP(INT32 choice)
|
|||
M_ClearMenus(true);
|
||||
}
|
||||
}
|
||||
#endif //!NONET
|
||||
|
||||
// ========================
|
||||
// MULTIPLAYER PLAYER SETUP
|
||||
|
@ -12705,7 +12652,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
|
|||
|
||||
multi_frame = 0;
|
||||
multi_tics = 4*FRACUNIT;
|
||||
|
||||
|
||||
strcpy (setupm_name, cv_playername2.string);
|
||||
|
||||
// set for splitscreen secondary player
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "command.h"
|
||||
#include "f_finale.h" // for ttmode_enum
|
||||
#include "i_threads.h"
|
||||
#include "mserv.h"
|
||||
#include "netcode/mserv.h"
|
||||
#include "r_things.h" // for SKINNAMESIZE
|
||||
|
||||
// Compatibility with old-style named NiGHTS replay files.
|
||||
|
@ -74,7 +74,7 @@ typedef enum
|
|||
MN_MP_SERVER,
|
||||
MN_MP_CONNECT,
|
||||
MN_MP_ROOM,
|
||||
MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET
|
||||
MN_MP_PLAYERSETUP,
|
||||
MN_MP_SERVER_OPTIONS,
|
||||
|
||||
// Options
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "m_perfstats.h"
|
||||
#include "v_video.h"
|
||||
#include "i_video.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "netcode/d_netcmd.h"
|
||||
#include "r_main.h"
|
||||
#include "i_system.h"
|
||||
#include "z_zone.h"
|
||||
|
|
13
src/netcode/Sourcefile
Normal file
13
src/netcode/Sourcefile
Normal file
|
@ -0,0 +1,13 @@
|
|||
d_clisrv.c
|
||||
server_connection.c
|
||||
client_connection.c
|
||||
tic_command.c
|
||||
net_command.c
|
||||
gamestate.c
|
||||
commands.c
|
||||
d_net.c
|
||||
d_netcmd.c
|
||||
d_netfil.c
|
||||
http-mserv.c
|
||||
i_tcp.c
|
||||
mserv.c
|
1178
src/netcode/client_connection.c
Normal file
1178
src/netcode/client_connection.c
Normal file
File diff suppressed because it is too large
Load diff
61
src/netcode/client_connection.h
Normal file
61
src/netcode/client_connection.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file client_connection.h
|
||||
/// \brief Client connection handling
|
||||
|
||||
#ifndef __D_CLIENT_CONNECTION__
|
||||
#define __D_CLIENT_CONNECTION__
|
||||
|
||||
#include "../doomtype.h"
|
||||
#include "d_clisrv.h"
|
||||
|
||||
#define MAXSERVERLIST (MAXNETNODES-1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SINT8 node;
|
||||
serverinfo_pak info;
|
||||
} serverelem_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CL_SEARCHING,
|
||||
CL_CHECKFILES,
|
||||
CL_DOWNLOADFILES,
|
||||
CL_ASKJOIN,
|
||||
CL_LOADFILES,
|
||||
CL_WAITJOINRESPONSE,
|
||||
CL_DOWNLOADSAVEGAME,
|
||||
CL_CONNECTED,
|
||||
CL_ABORTED,
|
||||
CL_ASKFULLFILELIST,
|
||||
CL_CONFIRMCONNECT
|
||||
} cl_mode_t;
|
||||
|
||||
extern serverelem_t serverlist[MAXSERVERLIST];
|
||||
extern UINT32 serverlistcount;
|
||||
|
||||
extern cl_mode_t cl_mode;
|
||||
extern boolean serverisfull; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not
|
||||
extern tic_t firstconnectattempttime;
|
||||
extern UINT8 mynode; // my address pointofview server
|
||||
|
||||
void CL_QueryServerList(msg_server_t *list);
|
||||
void CL_UpdateServerList(boolean internetsearch, INT32 room);
|
||||
|
||||
void CL_ConnectToServer(void);
|
||||
boolean CL_SendJoin(void);
|
||||
|
||||
void PT_ServerInfo(SINT8 node);
|
||||
void PT_MoreFilesNeeded(SINT8 node);
|
||||
void PT_ServerRefuse(SINT8 node);
|
||||
void PT_ServerCFG(SINT8 node);
|
||||
|
||||
#endif
|
484
src/netcode/commands.c
Normal file
484
src/netcode/commands.c
Normal file
|
@ -0,0 +1,484 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file commands.c
|
||||
/// \brief Various netgame commands, such as kick and ban
|
||||
|
||||
#include "commands.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "client_connection.h"
|
||||
#include "net_command.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "d_net.h"
|
||||
#include "i_net.h"
|
||||
#include "protocol.h"
|
||||
#include "../byteptr.h"
|
||||
#include "../d_main.h"
|
||||
#include "../g_game.h"
|
||||
#include "../w_wad.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../r_local.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct banreason_s
|
||||
{
|
||||
char *reason;
|
||||
struct banreason_s *prev; //-1
|
||||
struct banreason_s *next; //+1
|
||||
} banreason_t;
|
||||
|
||||
static banreason_t *reasontail = NULL; //last entry, use prev
|
||||
static banreason_t *reasonhead = NULL; //1st entry, use next
|
||||
|
||||
void Ban_Add(const char *reason)
|
||||
{
|
||||
banreason_t *reasonlist = malloc(sizeof(*reasonlist));
|
||||
|
||||
if (!reasonlist)
|
||||
return;
|
||||
if (!reason)
|
||||
reason = "NA";
|
||||
|
||||
reasonlist->next = NULL;
|
||||
reasonlist->reason = Z_StrDup(reason);
|
||||
if ((reasonlist->prev = reasontail) == NULL)
|
||||
reasonhead = reasonlist;
|
||||
else
|
||||
reasontail->next = reasonlist;
|
||||
reasontail = reasonlist;
|
||||
}
|
||||
|
||||
static void Ban_Clear(void)
|
||||
{
|
||||
banreason_t *temp;
|
||||
|
||||
I_ClearBans();
|
||||
|
||||
reasontail = NULL;
|
||||
|
||||
while (reasonhead)
|
||||
{
|
||||
temp = reasonhead->next;
|
||||
Z_Free(reasonhead->reason);
|
||||
free(reasonhead);
|
||||
reasonhead = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void Ban_Load_File(boolean warning)
|
||||
{
|
||||
FILE *f;
|
||||
const char *address, *mask;
|
||||
char buffer[MAX_WADPATH];
|
||||
|
||||
if (!I_ClearBans)
|
||||
return;
|
||||
|
||||
f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
if (warning)
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Could not open ban.txt for ban list\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
Ban_Clear();
|
||||
|
||||
for (size_t i=0; fgets(buffer, (int)sizeof(buffer), f); i++)
|
||||
{
|
||||
address = strtok(buffer, " \t\r\n");
|
||||
mask = strtok(NULL, " \t\r\n");
|
||||
|
||||
I_SetBanAddress(address, mask);
|
||||
|
||||
Ban_Add(strtok(NULL, "\r\n"));
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void D_SaveBan(void)
|
||||
{
|
||||
FILE *f;
|
||||
banreason_t *reasonlist = reasonhead;
|
||||
const char *address, *mask;
|
||||
const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt");
|
||||
|
||||
if (!reasonhead)
|
||||
{
|
||||
remove(path);
|
||||
return;
|
||||
}
|
||||
|
||||
f = fopen(path, "w");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Could not save ban list into ban.txt\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
|
||||
{
|
||||
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
|
||||
fprintf(f, "%s 0", address);
|
||||
else
|
||||
fprintf(f, "%s %s", address, mask);
|
||||
|
||||
if (reasonlist && reasonlist->reason)
|
||||
fprintf(f, " %s\n", reasonlist->reason);
|
||||
else
|
||||
fprintf(f, " %s\n", "NA");
|
||||
|
||||
if (reasonlist) reasonlist = reasonlist->next;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void Command_ShowBan(void) //Print out ban list
|
||||
{
|
||||
size_t i;
|
||||
const char *address, *mask;
|
||||
banreason_t *reasonlist = reasonhead;
|
||||
|
||||
if (I_GetBanAddress)
|
||||
CONS_Printf(M_GetText("Ban List:\n"));
|
||||
else
|
||||
return;
|
||||
|
||||
for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
|
||||
{
|
||||
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
|
||||
CONS_Printf("%s: %s ", sizeu1(i+1), address);
|
||||
else
|
||||
CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask);
|
||||
|
||||
if (reasonlist && reasonlist->reason)
|
||||
CONS_Printf("(%s)\n", reasonlist->reason);
|
||||
else
|
||||
CONS_Printf("\n");
|
||||
|
||||
if (reasonlist) reasonlist = reasonlist->next;
|
||||
}
|
||||
|
||||
if (i == 0 && !address)
|
||||
CONS_Printf(M_GetText("(empty)\n"));
|
||||
}
|
||||
|
||||
void Command_ClearBans(void)
|
||||
{
|
||||
if (!I_ClearBans)
|
||||
return;
|
||||
|
||||
Ban_Clear();
|
||||
D_SaveBan();
|
||||
}
|
||||
|
||||
void Command_Ban(void)
|
||||
{
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!netgame) // Don't kick Tails in splitscreen!
|
||||
{
|
||||
CONS_Printf(M_GetText("This only works in a netgame.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (server || IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
UINT8 buf[3 + MAX_REASONLENGTH];
|
||||
UINT8 *p = buf;
|
||||
const SINT8 pn = nametonum(COM_Argv(1));
|
||||
const INT32 node = playernode[(INT32)pn];
|
||||
|
||||
if (pn == -1 || pn == 0)
|
||||
return;
|
||||
|
||||
WRITEUINT8(p, pn);
|
||||
|
||||
if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
|
||||
WRITEUINT8(p, KICK_MSG_GO_AWAY);
|
||||
SendNetXCmd(XD_KICK, &buf, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server) // only the server is allowed to do this right now
|
||||
{
|
||||
Ban_Add(COM_Argv(2));
|
||||
D_SaveBan(); // save the ban list
|
||||
}
|
||||
|
||||
if (COM_Argc() == 2)
|
||||
{
|
||||
WRITEUINT8(p, KICK_MSG_BANNED);
|
||||
SendNetXCmd(XD_KICK, &buf, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t j = COM_Argc();
|
||||
char message[MAX_REASONLENGTH];
|
||||
|
||||
//Steal from the motd code so you don't have to put the reason in quotes.
|
||||
strlcpy(message, COM_Argv(2), sizeof message);
|
||||
for (size_t i = 3; i < j; i++)
|
||||
{
|
||||
strlcat(message, " ", sizeof message);
|
||||
strlcat(message, COM_Argv(i), sizeof message);
|
||||
}
|
||||
|
||||
WRITEUINT8(p, KICK_MSG_CUSTOM_BAN);
|
||||
WRITESTRINGN(p, message, MAX_REASONLENGTH);
|
||||
SendNetXCmd(XD_KICK, &buf, p - buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
|
||||
}
|
||||
|
||||
void Command_BanIP(void)
|
||||
{
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("banip <ip> <reason>: ban an ip address\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (server) // Only the server can use this, otherwise does nothing.
|
||||
{
|
||||
const char *address = (COM_Argv(1));
|
||||
const char *reason;
|
||||
|
||||
if (COM_Argc() == 2)
|
||||
reason = NULL;
|
||||
else
|
||||
reason = COM_Argv(2);
|
||||
|
||||
|
||||
if (I_SetBanAddress && I_SetBanAddress(address, NULL))
|
||||
{
|
||||
if (reason)
|
||||
CONS_Printf("Banned IP address %s for: %s\n", address, reason);
|
||||
else
|
||||
CONS_Printf("Banned IP address %s\n", address);
|
||||
|
||||
Ban_Add(reason);
|
||||
D_SaveBan();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Command_ReloadBan(void) //recheck ban.txt
|
||||
{
|
||||
Ban_Load_File(true);
|
||||
}
|
||||
|
||||
void Command_Kick(void)
|
||||
{
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf(M_GetText("kick <playername/playernum> <reason>: kick a player\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!netgame) // Don't kick Tails in splitscreen!
|
||||
{
|
||||
CONS_Printf(M_GetText("This only works in a netgame.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (server || IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
UINT8 buf[3 + MAX_REASONLENGTH];
|
||||
UINT8 *p = buf;
|
||||
const SINT8 pn = nametonum(COM_Argv(1));
|
||||
|
||||
if (pn == -1 || pn == 0)
|
||||
return;
|
||||
|
||||
// Special case if we are trying to kick a player who is downloading the game state:
|
||||
// trigger a timeout instead of kicking them, because a kick would only
|
||||
// take effect after they have finished downloading
|
||||
if (server && playernode[pn] != UINT8_MAX && netnodes[playernode[pn]].sendingsavegame)
|
||||
{
|
||||
Net_ConnectionTimeout(playernode[pn]);
|
||||
return;
|
||||
}
|
||||
|
||||
WRITESINT8(p, pn);
|
||||
|
||||
if (COM_Argc() == 2)
|
||||
{
|
||||
WRITEUINT8(p, KICK_MSG_GO_AWAY);
|
||||
SendNetXCmd(XD_KICK, &buf, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t j = COM_Argc();
|
||||
char message[MAX_REASONLENGTH];
|
||||
|
||||
//Steal from the motd code so you don't have to put the reason in quotes.
|
||||
strlcpy(message, COM_Argv(2), sizeof message);
|
||||
for (size_t i = 3; i < j; i++)
|
||||
{
|
||||
strlcat(message, " ", sizeof message);
|
||||
strlcat(message, COM_Argv(i), sizeof message);
|
||||
}
|
||||
|
||||
WRITEUINT8(p, KICK_MSG_CUSTOM_KICK);
|
||||
WRITESTRINGN(p, message, MAX_REASONLENGTH);
|
||||
SendNetXCmd(XD_KICK, &buf, p - buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
}
|
||||
|
||||
void Command_connect(void)
|
||||
{
|
||||
if (COM_Argc() < 2 || *COM_Argv(1) == 0)
|
||||
{
|
||||
CONS_Printf(M_GetText(
|
||||
"Connect <serveraddress> (port): connect to a server\n"
|
||||
"Connect ANY: connect to the first lan server found\n"
|
||||
//"Connect SELF: connect to your own server.\n"
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Playing() || titledemo)
|
||||
{
|
||||
CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
server = false;
|
||||
/*
|
||||
if (!stricmp(COM_Argv(1), "self"))
|
||||
{
|
||||
servernode = 0;
|
||||
server = true;
|
||||
/// \bug should be but...
|
||||
//SV_SpawnServer();
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
// used in menu to connect to a server in the list
|
||||
if (netgame && !stricmp(COM_Argv(1), "node"))
|
||||
{
|
||||
servernode = (SINT8)atoi(COM_Argv(2));
|
||||
}
|
||||
else if (netgame)
|
||||
{
|
||||
CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n"));
|
||||
return;
|
||||
}
|
||||
else if (I_NetOpenSocket)
|
||||
{
|
||||
I_NetOpenSocket();
|
||||
netgame = true;
|
||||
multiplayer = true;
|
||||
|
||||
if (!stricmp(COM_Argv(1), "any"))
|
||||
servernode = BROADCASTADDR;
|
||||
else if (I_NetMakeNodewPort)
|
||||
{
|
||||
if (COM_Argc() >= 3) // address AND port
|
||||
servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2));
|
||||
else // address only, or address:port
|
||||
servernode = I_NetMakeNode(COM_Argv(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n"));
|
||||
D_CloseConnection();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n"));
|
||||
}
|
||||
|
||||
splitscreen = false;
|
||||
SplitScreen_OnChange();
|
||||
botingame = false;
|
||||
botskin = 0;
|
||||
CL_ConnectToServer();
|
||||
}
|
||||
|
||||
void Command_GetPlayerNum(void)
|
||||
{
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
{
|
||||
if (serverplayer == i)
|
||||
CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]);
|
||||
else
|
||||
CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Lists all players and their player numbers.
|
||||
*
|
||||
* \sa Command_GetPlayerNum
|
||||
*/
|
||||
void Command_Nodes(void)
|
||||
{
|
||||
size_t maxlen = 0;
|
||||
const char *address;
|
||||
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
const size_t plen = strlen(player_names[i]);
|
||||
if (playeringame[i] && plen > maxlen)
|
||||
maxlen = plen;
|
||||
}
|
||||
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]);
|
||||
|
||||
if (playernode[i] != UINT8_MAX)
|
||||
{
|
||||
CONS_Printf(" - node %.2d", playernode[i]);
|
||||
if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL)
|
||||
CONS_Printf(" - %s", address);
|
||||
}
|
||||
|
||||
if (IsPlayerAdmin(i))
|
||||
CONS_Printf(M_GetText(" (verified admin)"));
|
||||
|
||||
if (players[i].spectator)
|
||||
CONS_Printf(M_GetText(" (spectator)"));
|
||||
|
||||
CONS_Printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
33
src/netcode/commands.h
Normal file
33
src/netcode/commands.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file commands.h
|
||||
/// \brief Various netgame commands, such as kick and ban
|
||||
|
||||
#ifndef __COMMANDS__
|
||||
#define __COMMANDS__
|
||||
|
||||
#include "../doomdef.h"
|
||||
|
||||
#define MAX_REASONLENGTH 30
|
||||
|
||||
void Ban_Add(const char *reason);
|
||||
void D_SaveBan(void);
|
||||
void Ban_Load_File(boolean warning);
|
||||
void Command_ShowBan(void);
|
||||
void Command_ClearBans(void);
|
||||
void Command_Ban(void);
|
||||
void Command_BanIP(void);
|
||||
void Command_ReloadBan(void);
|
||||
void Command_Kick(void);
|
||||
void Command_connect(void);
|
||||
void Command_GetPlayerNum(void);
|
||||
void Command_Nodes(void);
|
||||
|
||||
#endif
|
1736
src/netcode/d_clisrv.c
Normal file
1736
src/netcode/d_clisrv.c
Normal file
File diff suppressed because it is too large
Load diff
135
src/netcode/d_clisrv.h
Normal file
135
src/netcode/d_clisrv.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file d_clisrv.h
|
||||
/// \brief high level networking stuff
|
||||
|
||||
#ifndef __D_CLISRV__
|
||||
#define __D_CLISRV__
|
||||
|
||||
#include "protocol.h"
|
||||
#include "../d_ticcmd.h"
|
||||
#include "d_net.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "d_net.h"
|
||||
#include "../tables.h"
|
||||
#include "../d_player.h"
|
||||
#include "mserv.h"
|
||||
|
||||
#define CLIENTBACKUPTICS 32
|
||||
|
||||
#ifdef PACKETDROP
|
||||
void Command_Drop(void);
|
||||
void Command_Droprate(void);
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
void Command_Numnodes(void);
|
||||
#endif
|
||||
|
||||
extern INT32 mapchangepending;
|
||||
|
||||
// Points inside doomcom
|
||||
extern doomdata_t *netbuffer;
|
||||
|
||||
#define BASEPACKETSIZE offsetof(doomdata_t, u)
|
||||
#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0])
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KR_KICK = 1, //Kicked by server
|
||||
KR_PINGLIMIT = 2, //Broke Ping Limit
|
||||
KR_SYNCH = 3, //Synch Failure
|
||||
KR_TIMEOUT = 4, //Connection Timeout
|
||||
KR_BAN = 5, //Banned by server
|
||||
KR_LEAVE = 6, //Quit the game
|
||||
|
||||
} kickreason_t;
|
||||
|
||||
/* the max number of name changes in some time period */
|
||||
#define MAXNAMECHANGES (5)
|
||||
#define NAMECHANGERATE (60*TICRATE)
|
||||
|
||||
extern boolean server;
|
||||
extern boolean serverrunning;
|
||||
#define client (!server)
|
||||
extern boolean dedicated; // For dedicated server
|
||||
extern UINT16 software_MAXPACKETLENGTH;
|
||||
extern boolean acceptnewnode;
|
||||
extern SINT8 servernode;
|
||||
extern tic_t maketic;
|
||||
extern tic_t neededtic;
|
||||
extern INT16 consistancy[BACKUPTICS];
|
||||
|
||||
void Command_Ping_f(void);
|
||||
extern tic_t connectiontimeout;
|
||||
extern UINT16 pingmeasurecount;
|
||||
extern UINT32 realpingtable[MAXPLAYERS];
|
||||
extern UINT32 playerpingtable[MAXPLAYERS];
|
||||
extern tic_t servermaxping;
|
||||
|
||||
extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed, cv_dedicatedidletime;
|
||||
|
||||
// Used in d_net, the only dependence
|
||||
void D_ClientServerInit(void);
|
||||
|
||||
// Create any new ticcmds and broadcast to other players.
|
||||
void NetUpdate(void);
|
||||
|
||||
// Maintain connections to nodes without timing them all out.
|
||||
void NetKeepAlive(void);
|
||||
|
||||
void GetPackets(void);
|
||||
void ResetNode(INT32 node);
|
||||
INT16 Consistancy(void);
|
||||
|
||||
void SV_StartSinglePlayerServer(void);
|
||||
void SV_SpawnServer(void);
|
||||
void SV_StopServer(void);
|
||||
void SV_ResetServer(void);
|
||||
void CL_AddSplitscreenPlayer(void);
|
||||
void CL_RemoveSplitscreenPlayer(void);
|
||||
void CL_Reset(void);
|
||||
void CL_ClearPlayer(INT32 playernum);
|
||||
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
|
||||
void CL_HandleTimeout(void);
|
||||
// Is there a game running
|
||||
boolean Playing(void);
|
||||
|
||||
// Broadcasts special packets to other players
|
||||
// to notify of game exit
|
||||
void D_QuitNetGame(void);
|
||||
|
||||
//? How many ticks to run?
|
||||
boolean TryRunTics(tic_t realtic);
|
||||
|
||||
// extra data for lmps
|
||||
// these functions scare me. they contain magic.
|
||||
/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum);
|
||||
void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/
|
||||
|
||||
// translate a playername in a player number return -1 if not found and
|
||||
// print a error message in the console
|
||||
SINT8 nametonum(const char *name);
|
||||
|
||||
extern char motd[254], server_context[8];
|
||||
extern UINT8 playernode[MAXPLAYERS];
|
||||
|
||||
INT32 D_NumPlayers(void);
|
||||
INT32 D_NumBots(void);
|
||||
|
||||
tic_t GetLag(INT32 node);
|
||||
|
||||
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
|
||||
|
||||
extern UINT8 adminpassmd5[16];
|
||||
extern boolean adminpasswordset;
|
||||
|
||||
extern boolean hu_stopped;
|
||||
|
||||
#endif
|
|
@ -16,19 +16,21 @@
|
|||
/// This protocol uses a mix of "goback n" and "selective repeat" implementation
|
||||
/// The NOTHING packet is sent when connection is idle to acknowledge packets
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "g_game.h"
|
||||
#include "i_time.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../g_game.h"
|
||||
#include "../i_time.h"
|
||||
#include "i_net.h"
|
||||
#include "i_system.h"
|
||||
#include "m_argv.h"
|
||||
#include "../i_system.h"
|
||||
#include "../m_argv.h"
|
||||
#include "d_net.h"
|
||||
#include "w_wad.h"
|
||||
#include "../w_wad.h"
|
||||
#include "d_netfil.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "z_zone.h"
|
||||
#include "tic_command.h"
|
||||
#include "net_command.h"
|
||||
#include "../z_zone.h"
|
||||
#include "i_tcp.h"
|
||||
#include "d_main.h" // srb2home
|
||||
#include "../d_main.h" // srb2home
|
||||
|
||||
//
|
||||
// NETWORKING
|
||||
|
@ -138,7 +140,6 @@ boolean Net_GetNetStat(void)
|
|||
#define URGENTFREESLOTNUM 10
|
||||
#define ACKTOSENDTIMEOUT (TICRATE/11)
|
||||
|
||||
#ifndef NONET
|
||||
typedef struct
|
||||
{
|
||||
UINT8 acknum;
|
||||
|
@ -152,7 +153,6 @@ typedef struct
|
|||
doomdata_t data;
|
||||
} pak;
|
||||
} ackpak_t;
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -160,10 +160,8 @@ typedef enum
|
|||
NF_TIMEOUT = 2, // Flag is set when the node got a timeout
|
||||
} node_flags_t;
|
||||
|
||||
#ifndef NONET
|
||||
// Table of packets that were not acknowleged can be resent (the sender window)
|
||||
static ackpak_t ackpak[MAXACKPACKETS];
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -191,7 +189,6 @@ typedef struct
|
|||
static node_t nodes[MAXNETNODES];
|
||||
#define NODETIMEOUT 14
|
||||
|
||||
#ifndef NONET
|
||||
// return <0 if a < b (mod 256)
|
||||
// 0 if a = n (mod 256)
|
||||
// >0 if a > b (mod 256)
|
||||
|
@ -214,7 +211,7 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
|
|||
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||
{
|
||||
node_t *node = &nodes[doomcom->remotenode];
|
||||
INT32 i, numfreeslot = 0;
|
||||
INT32 numfreeslot = 0;
|
||||
|
||||
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
|
||||
{
|
||||
|
@ -222,7 +219,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
if (!ackpak[i].acknum)
|
||||
{
|
||||
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||
|
@ -279,10 +276,10 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
*/
|
||||
INT32 Net_GetFreeAcks(boolean urgent)
|
||||
{
|
||||
INT32 i, numfreeslot = 0;
|
||||
INT32 numfreeslot = 0;
|
||||
INT32 n = 0; // Number of free acks found
|
||||
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
if (!ackpak[i].acknum)
|
||||
{
|
||||
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||
|
@ -318,7 +315,6 @@ static void RemoveAck(INT32 i)
|
|||
// We have got a packet, proceed the ack request and ack return
|
||||
static boolean Processackpak(void)
|
||||
{
|
||||
INT32 i;
|
||||
boolean goodpacket = true;
|
||||
node_t *node = &nodes[doomcom->remotenode];
|
||||
|
||||
|
@ -327,7 +323,7 @@ static boolean Processackpak(void)
|
|||
{
|
||||
node->remotefirstack = netbuffer->ackreturn;
|
||||
// Search the ackbuffer and free it
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
|
||||
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
|
||||
{
|
||||
|
@ -349,7 +345,7 @@ static boolean Processackpak(void)
|
|||
else
|
||||
{
|
||||
// Check if it is not already in the queue
|
||||
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
|
||||
for (INT32 i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
|
||||
if (node->acktosend[i] == ack)
|
||||
{
|
||||
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
|
||||
|
@ -377,7 +373,7 @@ static boolean Processackpak(void)
|
|||
while (change)
|
||||
{
|
||||
change = false;
|
||||
for (i = node->acktosend_tail; i != node->acktosend_head;
|
||||
for (INT32 i = node->acktosend_tail; i != node->acktosend_head;
|
||||
i = (i+1) % MAXACKTOSEND)
|
||||
{
|
||||
if (cmpack(node->acktosend[i], nextfirstack) <= 0)
|
||||
|
@ -426,28 +422,20 @@ static boolean Processackpak(void)
|
|||
}
|
||||
return goodpacket;
|
||||
}
|
||||
#endif
|
||||
|
||||
// send special packet with only ack on it
|
||||
void Net_SendAcks(INT32 node)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)node;
|
||||
#else
|
||||
netbuffer->packettype = PT_NOTHING;
|
||||
M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND);
|
||||
HSendPacket(node, false, 0, MAXACKTOSEND);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static void GotAcks(void)
|
||||
{
|
||||
INT32 i, j;
|
||||
|
||||
for (j = 0; j < MAXACKTOSEND; j++)
|
||||
for (INT32 j = 0; j < MAXACKTOSEND; j++)
|
||||
if (netbuffer->u.textcmd[j])
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
|
||||
{
|
||||
if (ackpak[i].acknum == netbuffer->u.textcmd[j])
|
||||
|
@ -463,7 +451,6 @@ static void GotAcks(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Net_ConnectionTimeout(INT32 node)
|
||||
{
|
||||
|
@ -472,14 +459,10 @@ void Net_ConnectionTimeout(INT32 node)
|
|||
return;
|
||||
nodes[node].flags |= NF_TIMEOUT;
|
||||
|
||||
// Send a very special packet to self (hack the reboundstore queue)
|
||||
// Main code will handle it
|
||||
reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
|
||||
reboundstore[rebound_head].ack = 0;
|
||||
reboundstore[rebound_head].ackreturn = 0;
|
||||
reboundstore[rebound_head].u.textcmd[0] = (UINT8)node;
|
||||
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
|
||||
rebound_head = (rebound_head+1) % MAXREBOUND;
|
||||
if (server)
|
||||
SendKicksForNode(node, KICK_MSG_TIMEOUT | KICK_MSG_KEEP_BODY);
|
||||
else
|
||||
CL_HandleTimeout();
|
||||
|
||||
// Do not redo it quickly (if we do not close connection it is
|
||||
// for a good reason!)
|
||||
|
@ -489,10 +472,8 @@ void Net_ConnectionTimeout(INT32 node)
|
|||
// Resend the data if needed
|
||||
void Net_AckTicker(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
{
|
||||
const INT32 nodei = ackpak[i].destinationnode;
|
||||
node_t *node = &nodes[nodei];
|
||||
|
@ -519,7 +500,7 @@ void Net_AckTicker(void)
|
|||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < MAXNETNODES; i++)
|
||||
for (INT32 i = 1; i < MAXNETNODES; i++)
|
||||
{
|
||||
// This is something like node open flag
|
||||
if (nodes[i].firstacktosend)
|
||||
|
@ -536,16 +517,12 @@ void Net_AckTicker(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Remove last packet received ack before resending the ackreturn
|
||||
// (the higher layer doesn't have room, or something else ....)
|
||||
void Net_UnAcknowledgePacket(INT32 node)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)node;
|
||||
#else
|
||||
INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND;
|
||||
DEBFILE(va("UnAcknowledge node %d\n", node));
|
||||
if (!node)
|
||||
|
@ -577,10 +554,8 @@ void Net_UnAcknowledgePacket(INT32 node)
|
|||
if (!nodes[node].firstacktosend)
|
||||
nodes[node].firstacktosend = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
/** Checks if all acks have been received
|
||||
*
|
||||
* \return True if all acks have been received
|
||||
|
@ -588,15 +563,12 @@ void Net_UnAcknowledgePacket(INT32 node)
|
|||
*/
|
||||
static boolean Net_AllAcksReceived(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Waits for all ackreturns
|
||||
*
|
||||
|
@ -605,9 +577,6 @@ static boolean Net_AllAcksReceived(void)
|
|||
*/
|
||||
void Net_WaitAllAckReceived(UINT32 timeout)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)timeout;
|
||||
#else
|
||||
tic_t tictac = I_GetTime();
|
||||
timeout = tictac + timeout*NEWTICRATE;
|
||||
|
||||
|
@ -623,7 +592,6 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
|||
HGetPacket();
|
||||
Net_AckTicker();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void InitNode(node_t *node)
|
||||
|
@ -637,14 +605,10 @@ static void InitNode(node_t *node)
|
|||
|
||||
static void InitAck(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
#ifndef NONET
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
ackpak[i].acknum = 0;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
for (INT32 i = 0; i < MAXNETNODES; i++)
|
||||
InitNode(&nodes[i]);
|
||||
}
|
||||
|
||||
|
@ -655,17 +619,12 @@ static void InitAck(void)
|
|||
*/
|
||||
void Net_AbortPacketType(UINT8 packettype)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)packettype;
|
||||
#else
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype
|
||||
|| packettype == UINT8_MAX))
|
||||
{
|
||||
ackpak[i].acknum = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
@ -675,10 +634,6 @@ void Net_AbortPacketType(UINT8 packettype)
|
|||
// remove a node, clear all ack from this node and reset askret
|
||||
void Net_CloseConnection(INT32 node)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)node;
|
||||
#else
|
||||
INT32 i;
|
||||
boolean forceclose = (node & FORCECLOSE) != 0;
|
||||
|
||||
if (node == -1)
|
||||
|
@ -708,7 +663,7 @@ void Net_CloseConnection(INT32 node)
|
|||
}
|
||||
|
||||
// check if we are waiting for an ack from this node
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
for (INT32 i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum && ackpak[i].destinationnode == node)
|
||||
{
|
||||
if (!forceclose)
|
||||
|
@ -722,10 +677,8 @@ void Net_CloseConnection(INT32 node)
|
|||
if (server)
|
||||
SV_AbortLuaFileTransfer(node);
|
||||
I_NetFreeNodenum(node);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
//
|
||||
// Checksum
|
||||
//
|
||||
|
@ -734,23 +687,20 @@ static UINT32 NetbufferChecksum(void)
|
|||
UINT32 c = 0x1234567;
|
||||
const INT32 l = doomcom->datalength - 4;
|
||||
const UINT8 *buf = (UINT8 *)netbuffer + 4;
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < l; i++, buf++)
|
||||
for (INT32 i = 0; i < l; i++, buf++)
|
||||
c += (*buf) * (i+1);
|
||||
|
||||
return LONG(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUGFILE
|
||||
|
||||
static void fprintfstring(char *s, size_t len)
|
||||
{
|
||||
INT32 mode = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
for (size_t i = 0; i < len; i++)
|
||||
if (s[i] < 32)
|
||||
{
|
||||
if (!mode)
|
||||
|
@ -810,6 +760,8 @@ static const char *packettypename[NUMPACKETTYPE] =
|
|||
"ASKLUAFILE",
|
||||
"HASLUAFILE",
|
||||
|
||||
"PT_BASICKEEPALIVE",
|
||||
|
||||
"FILEFRAGMENT",
|
||||
"FILEACK",
|
||||
"FILERECEIVED",
|
||||
|
@ -817,7 +769,6 @@ static const char *packettypename[NUMPACKETTYPE] =
|
|||
"TEXTCMD",
|
||||
"TEXTCMD2",
|
||||
"CLIENTJOIN",
|
||||
"NODETIMEOUT",
|
||||
"LOGIN",
|
||||
"TELLFILESNEEDED",
|
||||
"MOREFILESNEEDED",
|
||||
|
@ -921,7 +872,6 @@ void Command_Drop(void)
|
|||
{
|
||||
INT32 packetquantity;
|
||||
const char *packetname;
|
||||
size_t i;
|
||||
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
|
@ -951,11 +901,11 @@ void Command_Drop(void)
|
|||
packetname = COM_Argv(1);
|
||||
|
||||
if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
|
||||
for (i = 0; i < NUMPACKETTYPE; i++)
|
||||
for (size_t i = 0; i < NUMPACKETTYPE; i++)
|
||||
packetdropquantity[i] = packetquantity;
|
||||
else
|
||||
{
|
||||
for (i = 0; i < NUMPACKETTYPE; i++)
|
||||
for (size_t i = 0; i < NUMPACKETTYPE; i++)
|
||||
if (!stricmp(packetname, packettypename[i]))
|
||||
{
|
||||
packetdropquantity[i] = packetquantity;
|
||||
|
@ -986,14 +936,12 @@ void Command_Droprate(void)
|
|||
packetdroprate = droprate;
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static boolean ShouldDropPacket(void)
|
||||
{
|
||||
return (packetdropquantity[netbuffer->packettype])
|
||||
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// HSendPacket
|
||||
|
@ -1028,11 +976,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
if (!netgame)
|
||||
I_Error("Tried to transmit to another node");
|
||||
|
||||
#ifdef NONET
|
||||
(void)node;
|
||||
(void)reliable;
|
||||
(void)acknum;
|
||||
#else
|
||||
// do this before GetFreeAcknum because this function backups
|
||||
// the current packet
|
||||
doomcom->remotenode = (INT16)node;
|
||||
|
@ -1093,8 +1036,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif // ndef NONET
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1112,10 +1053,7 @@ boolean HGetPacket(void)
|
|||
{
|
||||
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
|
||||
doomcom->datalength = reboundsize[rebound_tail];
|
||||
if (netbuffer->packettype == PT_NODETIMEOUT)
|
||||
doomcom->remotenode = netbuffer->u.textcmd[0];
|
||||
else
|
||||
doomcom->remotenode = 0;
|
||||
doomcom->remotenode = 0;
|
||||
|
||||
rebound_tail = (rebound_tail+1) % MAXREBOUND;
|
||||
#ifdef DEBUGFILE
|
||||
|
@ -1128,8 +1066,6 @@ boolean HGetPacket(void)
|
|||
if (!netgame)
|
||||
return false;
|
||||
|
||||
#ifndef NONET
|
||||
|
||||
while(true)
|
||||
{
|
||||
//nodejustjoined = I_NetGet();
|
||||
|
@ -1189,7 +1125,6 @@ boolean HGetPacket(void)
|
|||
}
|
||||
break;
|
||||
}
|
||||
#endif // ndef NONET
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1399,13 +1334,12 @@ void Command_Ping_f(void)
|
|||
int name_width = 0;
|
||||
int ms_width = 0;
|
||||
|
||||
int n;
|
||||
INT32 i;
|
||||
|
||||
pingc = 0;
|
||||
for (i = 1; i < MAXPLAYERS; ++i)
|
||||
for (INT32 i = 1; i < MAXPLAYERS; ++i)
|
||||
if (playeringame[i])
|
||||
{
|
||||
int n;
|
||||
|
||||
n = strlen(player_names[i]);
|
||||
if (n > name_width)
|
||||
name_width = n;
|
||||
|
@ -1425,7 +1359,7 @@ void Command_Ping_f(void)
|
|||
|
||||
qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp);
|
||||
|
||||
for (i = 0; i < pingc; ++i)
|
||||
for (INT32 i = 0; i < pingc; ++i)
|
||||
{
|
||||
CONS_Printf("%02d : %-*s %*d ms\n",
|
||||
pingv[i].num,
|
||||
|
@ -1441,15 +1375,13 @@ void Command_Ping_f(void)
|
|||
|
||||
void D_CloseConnection(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
if (netgame)
|
||||
{
|
||||
// wait the ackreturn with timout of 5 Sec
|
||||
Net_WaitAllAckReceived(5);
|
||||
|
||||
// close all connection
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
for (INT32 i = 0; i < MAXNETNODES; i++)
|
||||
Net_CloseConnection(i|FORCECLOSE);
|
||||
|
||||
InitAck();
|
|
@ -18,6 +18,8 @@
|
|||
#ifndef __D_NET__
|
||||
#define __D_NET__
|
||||
|
||||
#include "../doomtype.h"
|
||||
|
||||
// Max computers in a game
|
||||
// 127 is probably as high as this can go, because
|
||||
// SINT8 is used for nodes sometimes >:(
|
||||
|
@ -37,10 +39,24 @@ boolean Net_GetNetStat(void);
|
|||
extern INT32 getbytes;
|
||||
extern INT64 sendbytes; // Realtime updated
|
||||
|
||||
extern SINT8 nodetoplayer[MAXNETNODES];
|
||||
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
|
||||
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
|
||||
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
|
||||
typedef struct netnode_s
|
||||
{
|
||||
boolean ingame; // set false as nodes leave game
|
||||
tic_t freezetimeout; // Until when can this node freeze the server before getting a timeout?
|
||||
|
||||
SINT8 player;
|
||||
SINT8 player2; // say the numplayer for this node if any (splitscreen)
|
||||
UINT8 numplayers; // used specialy for scplitscreen
|
||||
|
||||
tic_t tic; // what tic the client have received
|
||||
tic_t supposedtic; // nettics prevision for smaller packet
|
||||
|
||||
boolean sendingsavegame; // Are we sending the savegame?
|
||||
boolean resendingsavegame; // Are we resending the savegame?
|
||||
tic_t savegameresendcooldown; // How long before we can resend again?
|
||||
} netnode_t;
|
||||
|
||||
extern netnode_t netnodes[MAXNETNODES];
|
||||
|
||||
extern boolean serverrunning;
|
||||
|
||||
|
@ -52,9 +68,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
|
|||
size_t packetlength);
|
||||
boolean HGetPacket(void);
|
||||
void D_SetDoomcom(void);
|
||||
#ifndef NONET
|
||||
void D_SaveBan(void);
|
||||
#endif
|
||||
boolean D_CheckNetGame(void);
|
||||
void D_CloseConnection(void);
|
||||
void Net_UnAcknowledgePacket(INT32 node);
|
|
@ -12,44 +12,46 @@
|
|||
/// commands are executed through the command buffer
|
||||
/// like console commands, other miscellaneous commands (at the end)
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "../doomdef.h"
|
||||
|
||||
#include "console.h"
|
||||
#include "command.h"
|
||||
#include "i_time.h"
|
||||
#include "i_system.h"
|
||||
#include "g_game.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "g_input.h"
|
||||
#include "m_menu.h"
|
||||
#include "r_local.h"
|
||||
#include "r_skins.h"
|
||||
#include "p_local.h"
|
||||
#include "p_setup.h"
|
||||
#include "s_sound.h"
|
||||
#include "i_sound.h"
|
||||
#include "m_misc.h"
|
||||
#include "am_map.h"
|
||||
#include "byteptr.h"
|
||||
#include "../console.h"
|
||||
#include "../command.h"
|
||||
#include "../i_time.h"
|
||||
#include "../i_system.h"
|
||||
#include "../g_game.h"
|
||||
#include "../hu_stuff.h"
|
||||
#include "../g_input.h"
|
||||
#include "../m_menu.h"
|
||||
#include "../r_local.h"
|
||||
#include "../r_skins.h"
|
||||
#include "../p_local.h"
|
||||
#include "../p_setup.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../i_sound.h"
|
||||
#include "../m_misc.h"
|
||||
#include "../am_map.h"
|
||||
#include "../byteptr.h"
|
||||
#include "d_netfil.h"
|
||||
#include "p_spec.h"
|
||||
#include "m_cheat.h"
|
||||
#include "../p_spec.h"
|
||||
#include "../m_cheat.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "server_connection.h"
|
||||
#include "net_command.h"
|
||||
#include "d_net.h"
|
||||
#include "v_video.h"
|
||||
#include "d_main.h"
|
||||
#include "m_random.h"
|
||||
#include "f_finale.h"
|
||||
#include "filesrch.h"
|
||||
#include "../v_video.h"
|
||||
#include "../d_main.h"
|
||||
#include "../m_random.h"
|
||||
#include "../f_finale.h"
|
||||
#include "../filesrch.h"
|
||||
#include "mserv.h"
|
||||
#include "z_zone.h"
|
||||
#include "lua_script.h"
|
||||
#include "lua_hook.h"
|
||||
#include "m_cond.h"
|
||||
#include "m_anigif.h"
|
||||
#include "md5.h"
|
||||
#include "m_perfstats.h"
|
||||
#include "u_list.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../lua_script.h"
|
||||
#include "../lua_hook.h"
|
||||
#include "../m_cond.h"
|
||||
#include "../m_anigif.h"
|
||||
#include "../md5.h"
|
||||
#include "../m_perfstats.h"
|
||||
#include "../u_list.h"
|
||||
|
||||
#ifdef NETGAME_DEVMODE
|
||||
#define CV_RESTRICT CV_NETVAR
|
||||
|
@ -595,13 +597,10 @@ void D_RegisterServerCommands(void)
|
|||
CV_RegisterVar(&cv_maxsend);
|
||||
CV_RegisterVar(&cv_noticedownload);
|
||||
CV_RegisterVar(&cv_downloadspeed);
|
||||
#ifndef NONET
|
||||
CV_RegisterVar(&cv_allownewplayer);
|
||||
CV_RegisterVar(&cv_joinnextround);
|
||||
CV_RegisterVar(&cv_showjoinaddress);
|
||||
CV_RegisterVar(&cv_blamecfail);
|
||||
CV_RegisterVar(&cv_dedicatedidletime);
|
||||
#endif
|
||||
|
||||
COM_AddCommand("ping", Command_Ping_f, COM_LUA);
|
||||
CV_RegisterVar(&cv_nettimeout);
|
||||
|
@ -1742,8 +1741,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
|
|||
// reset players if there is a new one
|
||||
if (!IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
if (SV_SpawnServer())
|
||||
buf[0] &= ~(1<<1);
|
||||
SV_SpawnServer();
|
||||
if (!Playing()) // you failed to start a server somehow, so cancel the map change
|
||||
return;
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
#ifndef __D_NETCMD__
|
||||
#define __D_NETCMD__
|
||||
|
||||
#include "command.h"
|
||||
#include "../command.h"
|
||||
|
||||
// console vars
|
||||
extern consvar_t cv_playername;
|
|
@ -31,24 +31,25 @@
|
|||
#include <sys/utime.h>
|
||||
#endif
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_main.h"
|
||||
#include "g_game.h"
|
||||
#include "i_time.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../d_main.h"
|
||||
#include "../g_game.h"
|
||||
#include "../i_time.h"
|
||||
#include "i_net.h"
|
||||
#include "i_system.h"
|
||||
#include "m_argv.h"
|
||||
#include "../i_system.h"
|
||||
#include "../m_argv.h"
|
||||
#include "d_net.h"
|
||||
#include "w_wad.h"
|
||||
#include "../w_wad.h"
|
||||
#include "d_netfil.h"
|
||||
#include "z_zone.h"
|
||||
#include "byteptr.h"
|
||||
#include "p_setup.h"
|
||||
#include "m_misc.h"
|
||||
#include "m_menu.h"
|
||||
#include "md5.h"
|
||||
#include "filesrch.h"
|
||||
#include "net_command.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../byteptr.h"
|
||||
#include "../p_setup.h"
|
||||
#include "../m_misc.h"
|
||||
#include "../m_menu.h"
|
||||
#include "../md5.h"
|
||||
#include "../filesrch.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
@ -103,26 +104,31 @@ typedef struct
|
|||
} pauseddownload_t;
|
||||
static pauseddownload_t *pauseddownload = NULL;
|
||||
|
||||
#ifndef NONET
|
||||
// for cl loading screen
|
||||
INT32 lastfilenum = -1;
|
||||
INT32 downloadcompletednum = 0;
|
||||
UINT32 downloadcompletedsize = 0;
|
||||
INT32 totalfilesrequestednum = 0;
|
||||
UINT32 totalfilesrequestedsize = 0;
|
||||
#endif
|
||||
|
||||
luafiletransfer_t *luafiletransfers = NULL;
|
||||
boolean waitingforluafiletransfer = false;
|
||||
boolean waitingforluafilecommand = false;
|
||||
char luafiledir[256 + 16] = "luafiles";
|
||||
|
||||
// max file size to send to a player (in kilobytes)
|
||||
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {204800, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL);
|
||||
|
||||
consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
// Speed of file downloading (in packets per tic)
|
||||
static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL);
|
||||
|
||||
static UINT16 GetWadNumFromFileNeededId(UINT8 id)
|
||||
{
|
||||
UINT16 wadnum;
|
||||
|
||||
for (wadnum = mainwads; wadnum < numwadfiles; wadnum++)
|
||||
for (UINT16 wadnum = mainwads; wadnum < numwadfiles; wadnum++)
|
||||
{
|
||||
if (!wadfiles[wadnum]->important)
|
||||
continue;
|
||||
|
@ -142,14 +148,13 @@ static UINT16 GetWadNumFromFileNeededId(UINT8 id)
|
|||
*/
|
||||
UINT8 *PutFileNeeded(UINT16 firstfile)
|
||||
{
|
||||
size_t i;
|
||||
UINT8 count = 0;
|
||||
UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded;
|
||||
UINT8 *p = p_start;
|
||||
char wadfilename[MAX_WADPATH] = "";
|
||||
UINT8 filestatus, folder;
|
||||
|
||||
for (i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad
|
||||
for (size_t i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad
|
||||
{
|
||||
// If it has only music/sound lumps, don't put it in the list
|
||||
if (!wadfiles[i]->important)
|
||||
|
@ -224,7 +229,6 @@ void FreeFileNeeded(void)
|
|||
*/
|
||||
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile)
|
||||
{
|
||||
INT32 i;
|
||||
UINT8 *p;
|
||||
UINT8 filestatus;
|
||||
|
||||
|
@ -233,7 +237,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
|
|||
|
||||
AllocFileNeeded(fileneedednum);
|
||||
|
||||
for (i = firstfile; i < fileneedednum; i++)
|
||||
for (INT32 i = firstfile; i < fileneedednum; i++)
|
||||
{
|
||||
fileneeded[i].type = FILENEEDED_WAD;
|
||||
fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet
|
||||
|
@ -250,9 +254,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
|
|||
|
||||
void CL_PrepareDownloadSaveGame(const char *tmpsave)
|
||||
{
|
||||
#ifndef NONET
|
||||
lastfilenum = -1;
|
||||
#endif
|
||||
|
||||
FreeFileNeeded();
|
||||
AllocFileNeeded(1);
|
||||
|
@ -275,9 +277,9 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
|
|||
*/
|
||||
boolean CL_CheckDownloadable(void)
|
||||
{
|
||||
UINT8 i,dlstatus = 0;
|
||||
UINT8 dlstatus = 0;
|
||||
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
for (UINT8 i = 0; i < fileneedednum; i++)
|
||||
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
|
||||
{
|
||||
if (fileneeded[i].willsend == 1)
|
||||
|
@ -298,7 +300,7 @@ boolean CL_CheckDownloadable(void)
|
|||
|
||||
// not downloadable, put reason in console
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n"));
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
for (UINT8 i = 0; i < fileneedednum; i++)
|
||||
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
|
||||
{
|
||||
CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10);
|
||||
|
@ -368,14 +370,13 @@ void CL_AbortDownloadResume(void)
|
|||
boolean CL_SendFileRequest(void)
|
||||
{
|
||||
char *p;
|
||||
INT32 i;
|
||||
INT64 totalfreespaceneeded = 0, availablefreespace;
|
||||
|
||||
#ifdef PARANOIA
|
||||
if (M_CheckParm("-nodownload"))
|
||||
I_Error("Attempted to download files in -nodownload mode");
|
||||
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
for (INT32 i = 0; i < fileneedednum; i++)
|
||||
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN
|
||||
&& (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2))
|
||||
{
|
||||
|
@ -385,7 +386,7 @@ boolean CL_SendFileRequest(void)
|
|||
|
||||
netbuffer->packettype = PT_REQUESTFILE;
|
||||
p = (char *)netbuffer->u.textcmd;
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
for (INT32 i = 0; i < fileneedednum; i++)
|
||||
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD))
|
||||
{
|
||||
totalfreespaceneeded += fileneeded[i].totalsize;
|
||||
|
@ -413,26 +414,31 @@ boolean CL_SendFileRequest(void)
|
|||
}
|
||||
|
||||
// get request filepak and put it on the send queue
|
||||
// returns false if a requested file was not found or cannot be sent
|
||||
boolean PT_RequestFile(INT32 node)
|
||||
void PT_RequestFile(SINT8 node)
|
||||
{
|
||||
UINT8 *p = netbuffer->u.textcmd;
|
||||
UINT8 id;
|
||||
|
||||
if (client || !cv_downloading.value)
|
||||
{
|
||||
Net_CloseConnection(node); // close connection if you are not the server or disabled downloading
|
||||
return;
|
||||
}
|
||||
|
||||
while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow
|
||||
{
|
||||
id = READUINT8(p);
|
||||
UINT8 id = READUINT8(p);
|
||||
if (id == 0xFF)
|
||||
break;
|
||||
|
||||
if (!AddFileToSendQueue(node, id))
|
||||
{
|
||||
SV_AbortSendFiles(node);
|
||||
return false; // don't read the rest of the files
|
||||
Net_CloseConnection(node); // close connection if one of the requested files could not be sent
|
||||
return; // don't read the rest of the files
|
||||
}
|
||||
}
|
||||
|
||||
return true; // no problems with any files
|
||||
return; // no problems with any files
|
||||
}
|
||||
|
||||
/** Checks if the files needed aren't already loaded or on the disk
|
||||
|
@ -531,9 +537,7 @@ INT32 CL_CheckFiles(void)
|
|||
// Load it now
|
||||
boolean CL_LoadServerFiles(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
for (INT32 i = 0; i < fileneedednum; i++)
|
||||
{
|
||||
if (fileneeded[i].status == FS_OPEN)
|
||||
continue; // Already loaded
|
||||
|
@ -629,11 +633,10 @@ void AddLuaFileTransfer(const char *filename, const char *mode)
|
|||
|
||||
static void SV_PrepareSendLuaFileToNextNode(void)
|
||||
{
|
||||
INT32 i;
|
||||
UINT8 success = 1;
|
||||
|
||||
// Find a client to send the file to
|
||||
for (i = 1; i < MAXNETNODES; i++)
|
||||
for (INT32 i = 1; i < MAXNETNODES; i++)
|
||||
if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting
|
||||
{
|
||||
// Tell the client we're about to send them the file
|
||||
|
@ -655,13 +658,12 @@ static void SV_PrepareSendLuaFileToNextNode(void)
|
|||
void SV_PrepareSendLuaFile(void)
|
||||
{
|
||||
char *binfilename;
|
||||
INT32 i;
|
||||
|
||||
luafiletransfers->ongoing = true;
|
||||
|
||||
// Set status to "waiting" for everyone
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
luafiletransfers->nodestatus[i] = (nodeingame[i] ? LFTNS_WAITING : LFTNS_NONE);
|
||||
for (INT32 i = 0; i < MAXNETNODES; i++)
|
||||
luafiletransfers->nodestatus[i] = (netnodes[i].ingame ? LFTNS_WAITING : LFTNS_NONE);
|
||||
|
||||
if (FIL_ReadFileOK(luafiletransfers->realfilename))
|
||||
{
|
||||
|
@ -1137,12 +1139,13 @@ void FileSendTicker(void)
|
|||
}
|
||||
}
|
||||
|
||||
void PT_FileAck(void)
|
||||
void PT_FileAck(SINT8 node)
|
||||
{
|
||||
fileack_pak *packet = &netbuffer->u.fileack;
|
||||
INT32 node = doomcom->remotenode;
|
||||
filetran_t *trans = &transfer[node];
|
||||
INT32 i, j;
|
||||
|
||||
if (client)
|
||||
return;
|
||||
|
||||
// Wrong file id? Ignore it, it's probably a late packet
|
||||
if (!(trans->txlist && packet->fileid == trans->txlist->fileid))
|
||||
|
@ -1161,11 +1164,11 @@ void PT_FileAck(void)
|
|||
trans->dontsenduntil = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < packet->numsegments; i++)
|
||||
for (INT32 i = 0; i < packet->numsegments; i++)
|
||||
{
|
||||
fileacksegment_t *segment = &packet->segments[i];
|
||||
|
||||
for (j = 0; j < 32; j++)
|
||||
for (INT32 j = 0; j < 32; j++)
|
||||
if (LONG(segment->acks) & (1 << j))
|
||||
{
|
||||
if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size)
|
||||
|
@ -1190,24 +1193,23 @@ void PT_FileAck(void)
|
|||
}
|
||||
}
|
||||
|
||||
void PT_FileReceived(void)
|
||||
void PT_FileReceived(SINT8 node)
|
||||
{
|
||||
filetx_t *trans = transfer[doomcom->remotenode].txlist;
|
||||
filetx_t *trans = transfer[node].txlist;
|
||||
|
||||
if (trans && netbuffer->u.filereceived == trans->fileid)
|
||||
SV_EndFileSend(doomcom->remotenode);
|
||||
if (server && trans && netbuffer->u.filereceived == trans->fileid)
|
||||
SV_EndFileSend(node);
|
||||
}
|
||||
|
||||
static void SendAckPacket(fileack_pak *packet, UINT8 fileid)
|
||||
{
|
||||
size_t packetsize;
|
||||
INT32 i;
|
||||
|
||||
packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments);
|
||||
|
||||
// Finalise the packet
|
||||
packet->fileid = fileid;
|
||||
for (i = 0; i < packet->numsegments; i++)
|
||||
for (INT32 i = 0; i < packet->numsegments; i++)
|
||||
{
|
||||
packet->segments[i].start = LONG(packet->segments[i].start);
|
||||
packet->segments[i].acks = LONG(packet->segments[i].acks);
|
||||
|
@ -1247,9 +1249,7 @@ static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32
|
|||
|
||||
void FileReceiveTicker(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
for (INT32 i = 0; i < fileneedednum; i++)
|
||||
{
|
||||
fileneeded_t *file = &fileneeded[i];
|
||||
|
||||
|
@ -1263,8 +1263,7 @@ void FileReceiveTicker(void)
|
|||
if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING)
|
||||
{
|
||||
// Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s
|
||||
INT32 j;
|
||||
for (j = 0; j < 2048; j++)
|
||||
for (INT32 j = 0; j < 2048; j++)
|
||||
{
|
||||
if (file->receivedfragments[file->ackresendposition])
|
||||
AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i);
|
||||
|
@ -1281,8 +1280,27 @@ void FileReceiveTicker(void)
|
|||
}
|
||||
}
|
||||
|
||||
void PT_FileFragment(void)
|
||||
void PT_FileFragment(SINT8 node, INT32 netconsole)
|
||||
{
|
||||
if (netnodes[node].ingame)
|
||||
{
|
||||
// Only accept PT_FILEFRAGMENT from the server.
|
||||
if (node != servernode)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node);
|
||||
if (server)
|
||||
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
|
||||
return;
|
||||
}
|
||||
if (server)
|
||||
return;
|
||||
}
|
||||
else if (server || node != servernode)
|
||||
{
|
||||
Net_CloseConnection(node);
|
||||
return;
|
||||
}
|
||||
|
||||
INT32 filenum = netbuffer->u.filetxpak.fileid;
|
||||
fileneeded_t *file = &fileneeded[filenum];
|
||||
UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position);
|
||||
|
@ -1439,9 +1457,7 @@ void PT_FileFragment(void)
|
|||
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
lastfilenum = filenum;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \brief Checks if a node is downloading a file
|
||||
|
@ -1469,15 +1485,14 @@ void SV_AbortSendFiles(INT32 node)
|
|||
|
||||
void CloseNetFile(void)
|
||||
{
|
||||
INT32 i;
|
||||
// Is sending?
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
for (INT32 i = 0; i < MAXNETNODES; i++)
|
||||
SV_AbortSendFiles(i);
|
||||
|
||||
// Receiving a file?
|
||||
if (fileneeded)
|
||||
{
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
for (INT32 i = 0; i < fileneedednum; i++)
|
||||
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
|
||||
{
|
||||
fclose(fileneeded[i].file);
|
||||
|
@ -1510,9 +1525,7 @@ void CloseNetFile(void)
|
|||
|
||||
void Command_Downloads_f(void)
|
||||
{
|
||||
INT32 node;
|
||||
|
||||
for (node = 0; node < MAXNETNODES; node++)
|
||||
for (INT32 node = 0; node < MAXNETNODES; node++)
|
||||
if (transfer[node].txlist
|
||||
&& transfer[node].txlist->ram == SF_FILE) // Node is downloading a file?
|
||||
{
|
||||
|
@ -1546,14 +1559,11 @@ void Command_Downloads_f(void)
|
|||
|
||||
void nameonly(char *s)
|
||||
{
|
||||
size_t j, len;
|
||||
void *ns;
|
||||
|
||||
for (j = strlen(s); j != (size_t)-1; j--)
|
||||
for (size_t j = strlen(s); j != (size_t)-1; j--)
|
||||
if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
|
||||
{
|
||||
ns = &(s[j+1]);
|
||||
len = strlen(ns);
|
||||
void *ns = &(s[j+1]);
|
||||
size_t len = strlen(ns);
|
||||
#if 0
|
||||
M_Memcpy(s, ns, len+1);
|
||||
#else
|
||||
|
@ -1566,9 +1576,9 @@ void nameonly(char *s)
|
|||
// Returns the length in characters of the last element of a path.
|
||||
size_t nameonlylength(const char *s)
|
||||
{
|
||||
size_t j, len = strlen(s);
|
||||
size_t len = strlen(s);
|
||||
|
||||
for (j = len; j != (size_t)-1; j--)
|
||||
for (size_t j = len; j != (size_t)-1; j--)
|
||||
if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
|
||||
return len - j - 1;
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "d_net.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "w_wad.h"
|
||||
#include "../w_wad.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -70,13 +70,13 @@ extern INT32 fileneedednum;
|
|||
extern fileneeded_t *fileneeded;
|
||||
extern char downloaddir[512];
|
||||
|
||||
#ifndef NONET
|
||||
extern INT32 lastfilenum;
|
||||
extern INT32 downloadcompletednum;
|
||||
extern UINT32 downloadcompletedsize;
|
||||
extern INT32 totalfilesrequestednum;
|
||||
extern UINT32 totalfilesrequestedsize;
|
||||
#endif
|
||||
|
||||
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
|
||||
|
||||
void AllocFileNeeded(INT32 size);
|
||||
void FreeFileNeeded(void);
|
||||
|
@ -90,16 +90,16 @@ void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemet
|
|||
UINT8 fileid);
|
||||
|
||||
void FileSendTicker(void);
|
||||
void PT_FileAck(void);
|
||||
void PT_FileReceived(void);
|
||||
void PT_FileAck(SINT8 node);
|
||||
void PT_FileReceived(SINT8 node);
|
||||
boolean SendingFile(INT32 node);
|
||||
|
||||
void FileReceiveTicker(void);
|
||||
void PT_FileFragment(void);
|
||||
void PT_FileFragment(SINT8 node, INT32 netconsole);
|
||||
|
||||
boolean CL_CheckDownloadable(void);
|
||||
boolean CL_SendFileRequest(void);
|
||||
boolean PT_RequestFile(INT32 node);
|
||||
void PT_RequestFile(SINT8 node);
|
||||
|
||||
typedef enum
|
||||
{
|
336
src/netcode/gamestate.c
Normal file
336
src/netcode/gamestate.c
Normal file
|
@ -0,0 +1,336 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file gamestate.c
|
||||
/// \brief Gamestate (re)sending
|
||||
|
||||
#include "d_clisrv.h"
|
||||
#include "d_netfil.h"
|
||||
#include "gamestate.h"
|
||||
#include "i_net.h"
|
||||
#include "protocol.h"
|
||||
#include "server_connection.h"
|
||||
#include "../am_map.h"
|
||||
#include "../byteptr.h"
|
||||
#include "../console.h"
|
||||
#include "../d_main.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../doomtype.h"
|
||||
#include "../f_finale.h"
|
||||
#include "../g_demo.h"
|
||||
#include "../g_game.h"
|
||||
#include "../i_time.h"
|
||||
#include "../lua_script.h"
|
||||
#include "../lzf.h"
|
||||
#include "../m_misc.h"
|
||||
#include "../p_local.h"
|
||||
#include "../p_saveg.h"
|
||||
#include "../r_main.h"
|
||||
#include "../tables.h"
|
||||
#include "../z_zone.h"
|
||||
#if defined (__GNUC__) || defined (__unix__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define SAVEGAMESIZE (768*1024)
|
||||
|
||||
UINT8 hu_redownloadinggamestate = 0;
|
||||
boolean cl_redownloadinggamestate = false;
|
||||
|
||||
boolean SV_ResendingSavegameToAnyone(void)
|
||||
{
|
||||
for (INT32 i = 0; i < MAXNETNODES; i++)
|
||||
if (netnodes[i].resendingsavegame)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SV_SendSaveGame(INT32 node, boolean resending)
|
||||
{
|
||||
size_t length, compressedlen;
|
||||
UINT8 *savebuffer;
|
||||
UINT8 *compressedsave;
|
||||
UINT8 *buffertosend;
|
||||
|
||||
// first save it in a malloced buffer
|
||||
savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
|
||||
if (!savebuffer)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Leave room for the uncompressed length.
|
||||
save_p = savebuffer + sizeof(UINT32);
|
||||
|
||||
P_SaveNetGame(resending);
|
||||
|
||||
length = save_p - savebuffer;
|
||||
if (length > SAVEGAMESIZE)
|
||||
{
|
||||
free(savebuffer);
|
||||
save_p = NULL;
|
||||
I_Error("Savegame buffer overrun");
|
||||
}
|
||||
|
||||
// Allocate space for compressed save: one byte fewer than for the
|
||||
// uncompressed data to ensure that the compression is worthwhile.
|
||||
compressedsave = malloc(length - 1);
|
||||
if (!compressedsave)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to compress it.
|
||||
if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1)))
|
||||
{
|
||||
// Compressing succeeded; send compressed data
|
||||
|
||||
free(savebuffer);
|
||||
|
||||
// State that we're compressed.
|
||||
buffertosend = compressedsave;
|
||||
WRITEUINT32(compressedsave, length - sizeof(UINT32));
|
||||
length = compressedlen + sizeof(UINT32);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compression failed to make it smaller; send original
|
||||
|
||||
free(compressedsave);
|
||||
|
||||
// State that we're not compressed
|
||||
buffertosend = savebuffer;
|
||||
WRITEUINT32(savebuffer, 0);
|
||||
}
|
||||
|
||||
AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0);
|
||||
save_p = NULL;
|
||||
|
||||
// Remember when we started sending the savegame so we can handle timeouts
|
||||
netnodes[node].sendingsavegame = true;
|
||||
netnodes[node].freezetimeout = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte
|
||||
}
|
||||
|
||||
#ifdef DUMPCONSISTENCY
|
||||
#define TMPSAVENAME "badmath.sav"
|
||||
static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
void SV_SavedGame(void)
|
||||
{
|
||||
size_t length;
|
||||
UINT8 *savebuffer;
|
||||
char tmpsave[256];
|
||||
|
||||
if (!cv_dumpconsistency.value)
|
||||
return;
|
||||
|
||||
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
|
||||
|
||||
// first save it in a malloced buffer
|
||||
save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
|
||||
if (!save_p)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
P_SaveNetGame(false);
|
||||
|
||||
length = save_p - savebuffer;
|
||||
if (length > SAVEGAMESIZE)
|
||||
{
|
||||
free(savebuffer);
|
||||
save_p = NULL;
|
||||
I_Error("Savegame buffer overrun");
|
||||
}
|
||||
|
||||
// then save it!
|
||||
if (!FIL_WriteFile(tmpsave, savebuffer, length))
|
||||
CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave);
|
||||
|
||||
free(savebuffer);
|
||||
save_p = NULL;
|
||||
}
|
||||
|
||||
#undef TMPSAVENAME
|
||||
#endif
|
||||
#define TMPSAVENAME "$$$.sav"
|
||||
|
||||
|
||||
void CL_LoadReceivedSavegame(boolean reloading)
|
||||
{
|
||||
UINT8 *savebuffer = NULL;
|
||||
size_t length, decompressedlen;
|
||||
char tmpsave[256];
|
||||
|
||||
FreeFileNeeded();
|
||||
|
||||
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
|
||||
|
||||
length = FIL_ReadFile(tmpsave, &savebuffer);
|
||||
|
||||
CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length));
|
||||
if (!length)
|
||||
{
|
||||
I_Error("Can't read savegame sent");
|
||||
return;
|
||||
}
|
||||
|
||||
save_p = savebuffer;
|
||||
|
||||
// Decompress saved game if necessary.
|
||||
decompressedlen = READUINT32(save_p);
|
||||
if(decompressedlen > 0)
|
||||
{
|
||||
UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL);
|
||||
lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen);
|
||||
Z_Free(savebuffer);
|
||||
save_p = savebuffer = decompressedbuffer;
|
||||
}
|
||||
|
||||
paused = false;
|
||||
demoplayback = false;
|
||||
titlemapinaction = TITLEMAP_OFF;
|
||||
titledemo = false;
|
||||
automapactive = false;
|
||||
|
||||
// load a base level
|
||||
if (P_LoadNetGame(reloading))
|
||||
{
|
||||
const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum;
|
||||
CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap));
|
||||
if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, ""))
|
||||
{
|
||||
CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl);
|
||||
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
|
||||
CONS_Printf(M_GetText(" Zone"));
|
||||
if (actnum > 0)
|
||||
CONS_Printf(" %2d", actnum);
|
||||
}
|
||||
CONS_Printf("\"\n");
|
||||
}
|
||||
|
||||
// done
|
||||
Z_Free(savebuffer);
|
||||
save_p = NULL;
|
||||
if (unlink(tmpsave) == -1)
|
||||
CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave);
|
||||
consistancy[gametic%BACKUPTICS] = Consistancy();
|
||||
CON_ToggleOff();
|
||||
|
||||
// Tell the server we have received and reloaded the gamestate
|
||||
// so they know they can resume the game
|
||||
netbuffer->packettype = PT_RECEIVEDGAMESTATE;
|
||||
HSendPacket(servernode, true, 0, 0);
|
||||
}
|
||||
|
||||
void CL_ReloadReceivedSavegame(void)
|
||||
{
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
LUA_InvalidatePlayer(&players[i]);
|
||||
sprintf(player_names[i], "Player %d", i + 1);
|
||||
}
|
||||
|
||||
CL_LoadReceivedSavegame(true);
|
||||
|
||||
neededtic = max(neededtic, gametic);
|
||||
maketic = neededtic;
|
||||
|
||||
ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn;
|
||||
P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16));
|
||||
if (splitscreen)
|
||||
{
|
||||
ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn;
|
||||
P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16));
|
||||
}
|
||||
|
||||
camera.subsector = R_PointInSubsector(camera.x, camera.y);
|
||||
camera2.subsector = R_PointInSubsector(camera2.x, camera2.y);
|
||||
|
||||
cl_redownloadinggamestate = false;
|
||||
|
||||
CONS_Printf(M_GetText("Game state reloaded\n"));
|
||||
}
|
||||
|
||||
void Command_ResendGamestate(void)
|
||||
{
|
||||
SINT8 playernum;
|
||||
|
||||
if (COM_Argc() == 1)
|
||||
{
|
||||
CONS_Printf(M_GetText("resendgamestate <playername/playernum>: resend the game state to a player\n"));
|
||||
return;
|
||||
}
|
||||
else if (client)
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
playernum = nametonum(COM_Argv(1));
|
||||
if (playernum == -1 || playernum == 0)
|
||||
return;
|
||||
|
||||
// Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on
|
||||
netbuffer->packettype = PT_WILLRESENDGAMESTATE;
|
||||
if (!HSendPacket(playernode[playernum], true, 0, 0))
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PT_CanReceiveGamestate(SINT8 node)
|
||||
{
|
||||
if (client || netnodes[node].sendingsavegame)
|
||||
return;
|
||||
|
||||
CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[netnodes[node].player]);
|
||||
|
||||
SV_SendSaveGame(node, true); // Resend a complete game state
|
||||
netnodes[node].resendingsavegame = true;
|
||||
}
|
||||
|
||||
void PT_ReceivedGamestate(SINT8 node)
|
||||
{
|
||||
netnodes[node].sendingsavegame = false;
|
||||
netnodes[node].resendingsavegame = false;
|
||||
netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE;
|
||||
}
|
||||
|
||||
void PT_WillResendGamestate(SINT8 node)
|
||||
{
|
||||
(void)node;
|
||||
|
||||
char tmpsave[256];
|
||||
|
||||
if (server || cl_redownloadinggamestate)
|
||||
return;
|
||||
|
||||
// Send back a PT_CANRECEIVEGAMESTATE packet to the server
|
||||
// so they know they can start sending the game state
|
||||
netbuffer->packettype = PT_CANRECEIVEGAMESTATE;
|
||||
if (!HSendPacket(servernode, true, 0, 0))
|
||||
return;
|
||||
|
||||
CONS_Printf(M_GetText("Reloading game state...\n"));
|
||||
|
||||
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
|
||||
|
||||
// Don't get a corrupt savegame error because tmpsave already exists
|
||||
if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1)
|
||||
I_Error("Can't delete %s\n", tmpsave);
|
||||
|
||||
CL_PrepareDownloadSaveGame(tmpsave);
|
||||
|
||||
cl_redownloadinggamestate = true;
|
||||
}
|
31
src/netcode/gamestate.h
Normal file
31
src/netcode/gamestate.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file gamestate.h
|
||||
/// \brief Gamestate (re)sending
|
||||
|
||||
#ifndef __GAMESTATE__
|
||||
#define __GAMESTATE__
|
||||
|
||||
#include "../doomtype.h"
|
||||
|
||||
extern UINT8 hu_redownloadinggamestate;
|
||||
extern boolean cl_redownloadinggamestate;
|
||||
|
||||
boolean SV_ResendingSavegameToAnyone(void);
|
||||
void SV_SendSaveGame(INT32 node, boolean resending);
|
||||
void SV_SavedGame(void);
|
||||
void CL_LoadReceivedSavegame(boolean reloading);
|
||||
void CL_ReloadReceivedSavegame(void);
|
||||
void Command_ResendGamestate(void);
|
||||
void PT_CanReceiveGamestate(SINT8 node);
|
||||
void PT_ReceivedGamestate(SINT8 node);
|
||||
void PT_WillResendGamestate(SINT8 node);
|
||||
|
||||
#endif
|
|
@ -18,14 +18,15 @@ Documentation available here.
|
|||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "../doomdef.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "command.h"
|
||||
#include "m_argv.h"
|
||||
#include "m_menu.h"
|
||||
#include "client_connection.h"
|
||||
#include "../command.h"
|
||||
#include "../m_argv.h"
|
||||
#include "../m_menu.h"
|
||||
#include "mserv.h"
|
||||
#include "i_tcp.h"/* for current_port */
|
||||
#include "i_threads.h"
|
||||
#include "../i_threads.h"
|
||||
|
||||
/* reasonable default I guess?? */
|
||||
#define DEFAULT_BUFFER_SIZE (4096)
|
||||
|
@ -95,7 +96,7 @@ init_user_agent_once(void)
|
|||
{
|
||||
if (hms_useragent[0] != '\0')
|
||||
return;
|
||||
|
||||
|
||||
get_user_agent(hms_useragent, 512);
|
||||
}
|
||||
|
|
@ -18,8 +18,8 @@
|
|||
#pragma interface
|
||||
#endif
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "command.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../command.h"
|
||||
|
||||
/// \brief program net id
|
||||
#define DOOMCOM_ID (INT32)0x12345678l
|
|
@ -36,109 +36,100 @@
|
|||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "../doomdef.h"
|
||||
|
||||
#if defined (NOMD5) && !defined (NONET)
|
||||
//#define NONET
|
||||
#ifdef USE_WINSOCK1
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#ifndef USE_WINSOCK
|
||||
#include <arpa/inet.h>
|
||||
#ifdef __APPLE_CC__
|
||||
#ifndef _BSD_SOCKLEN_T_
|
||||
#define _BSD_SOCKLEN_T_
|
||||
#endif //_BSD_SOCKLEN_T_
|
||||
#endif //__APPLE_CC__
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif //normal BSD API
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)
|
||||
#include <sys/time.h>
|
||||
#endif // UNIXCOMMON
|
||||
#endif
|
||||
|
||||
#ifdef NONET
|
||||
#undef HAVE_MINIUPNPC
|
||||
#else
|
||||
#ifdef USE_WINSOCK1
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#ifndef USE_WINSOCK
|
||||
#include <arpa/inet.h>
|
||||
#ifdef __APPLE_CC__
|
||||
#ifndef _BSD_SOCKLEN_T_
|
||||
#define _BSD_SOCKLEN_T_
|
||||
#endif //_BSD_SOCKLEN_T_
|
||||
#endif //__APPLE_CC__
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif //normal BSD API
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)
|
||||
#include <sys/time.h>
|
||||
#endif // UNIXCOMMON
|
||||
#ifdef USE_WINSOCK
|
||||
// some undefined under win32
|
||||
#undef errno
|
||||
//#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right?
|
||||
#define errno h_errno // some very strange things happen when not using h_error?!?
|
||||
#ifdef EWOULDBLOCK
|
||||
#undef EWOULDBLOCK
|
||||
#endif
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
// some undefined under win32
|
||||
#undef errno
|
||||
//#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right?
|
||||
#define errno h_errno // some very strange things happen when not using h_error?!?
|
||||
#ifdef EWOULDBLOCK
|
||||
#undef EWOULDBLOCK
|
||||
#endif
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#ifdef EMSGSIZE
|
||||
#undef EMSGSIZE
|
||||
#endif
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#ifdef ECONNREFUSED
|
||||
#undef ECONNREFUSED
|
||||
#endif
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#ifdef ETIMEDOUT
|
||||
#undef ETIMEDOUT
|
||||
#endif
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#ifndef IOC_VENDOR
|
||||
#define IOC_VENDOR 0x18000000
|
||||
#endif
|
||||
#ifndef _WSAIOW
|
||||
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
|
||||
#endif
|
||||
#ifndef SIO_UDP_CONNRESET
|
||||
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
|
||||
#endif
|
||||
#ifndef AI_ADDRCONFIG
|
||||
#define AI_ADDRCONFIG 0x00000400
|
||||
#endif
|
||||
#ifndef STATUS_INVALID_PARAMETER
|
||||
#define STATUS_INVALID_PARAMETER 0xC000000D
|
||||
#endif
|
||||
#endif // USE_WINSOCK
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct sockaddr any;
|
||||
struct sockaddr_in ip4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct sockaddr_in6 ip6;
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#ifdef EMSGSIZE
|
||||
#undef EMSGSIZE
|
||||
#endif
|
||||
} mysockaddr_t;
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#ifdef ECONNREFUSED
|
||||
#undef ECONNREFUSED
|
||||
#endif
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#ifdef ETIMEDOUT
|
||||
#undef ETIMEDOUT
|
||||
#endif
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#ifndef IOC_VENDOR
|
||||
#define IOC_VENDOR 0x18000000
|
||||
#endif
|
||||
#ifndef _WSAIOW
|
||||
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
|
||||
#endif
|
||||
#ifndef SIO_UDP_CONNRESET
|
||||
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
|
||||
#endif
|
||||
#ifndef AI_ADDRCONFIG
|
||||
#define AI_ADDRCONFIG 0x00000400
|
||||
#endif
|
||||
#ifndef STATUS_INVALID_PARAMETER
|
||||
#define STATUS_INVALID_PARAMETER 0xC000000D
|
||||
#endif
|
||||
#endif // USE_WINSOCK
|
||||
|
||||
#ifdef HAVE_MINIUPNPC
|
||||
#ifdef STATIC_MINIUPNPC
|
||||
#define STATICLIB
|
||||
#endif
|
||||
#include "miniupnpc/miniwget.h"
|
||||
#include "miniupnpc/miniupnpc.h"
|
||||
#include "miniupnpc/upnpcommands.h"
|
||||
#undef STATICLIB
|
||||
static UINT8 UPNP_support = TRUE;
|
||||
#endif // HAVE_MINIUPNC
|
||||
typedef union
|
||||
{
|
||||
struct sockaddr any;
|
||||
struct sockaddr_in ip4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct sockaddr_in6 ip6;
|
||||
#endif
|
||||
} mysockaddr_t;
|
||||
|
||||
#endif // !NONET
|
||||
#ifdef HAVE_MINIUPNPC
|
||||
#ifdef STATIC_MINIUPNPC
|
||||
#define STATICLIB
|
||||
#endif
|
||||
#include "miniupnpc/miniwget.h"
|
||||
#include "miniupnpc/miniupnpc.h"
|
||||
#include "miniupnpc/upnpcommands.h"
|
||||
#undef STATICLIB
|
||||
static UINT8 UPNP_support = TRUE;
|
||||
#endif // HAVE_MINIUPNC
|
||||
|
||||
#define MAXBANS 100
|
||||
|
||||
#include "i_system.h"
|
||||
#include "../i_system.h"
|
||||
#include "i_net.h"
|
||||
#include "d_net.h"
|
||||
#include "d_netfil.h"
|
||||
#include "i_tcp.h"
|
||||
#include "m_argv.h"
|
||||
#include "../m_argv.h"
|
||||
|
||||
#include "doomstat.h"
|
||||
#include "../doomstat.h"
|
||||
|
||||
// win32
|
||||
#ifdef USE_WINSOCK
|
||||
|
@ -151,7 +142,7 @@
|
|||
#define SELECTTEST
|
||||
#define DEFAULTPORT "5029"
|
||||
|
||||
#if defined (USE_WINSOCK) && !defined (NONET)
|
||||
#ifdef USE_WINSOCK
|
||||
typedef SOCKET SOCKET_TYPE;
|
||||
#define ERRSOCKET (SOCKET_ERROR)
|
||||
#else
|
||||
|
@ -163,22 +154,20 @@
|
|||
#define ERRSOCKET (-1)
|
||||
#endif
|
||||
|
||||
#ifndef NONET
|
||||
// define socklen_t in DOS/Windows if it is not already defined
|
||||
#ifdef USE_WINSOCK1
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET};
|
||||
static size_t mysocketses = 0;
|
||||
static int myfamily[MAXNETNODES+1] = {0};
|
||||
static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET};
|
||||
static mysockaddr_t clientaddress[MAXNETNODES+1];
|
||||
static mysockaddr_t broadcastaddress[MAXNETNODES+1];
|
||||
static size_t broadcastaddresses = 0;
|
||||
static boolean nodeconnected[MAXNETNODES+1];
|
||||
static mysockaddr_t banned[MAXBANS];
|
||||
static UINT8 bannedmask[MAXBANS];
|
||||
// define socklen_t in DOS/Windows if it is not already defined
|
||||
#ifdef USE_WINSOCK1
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET};
|
||||
static size_t mysocketses = 0;
|
||||
static int myfamily[MAXNETNODES+1] = {0};
|
||||
static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET};
|
||||
static mysockaddr_t clientaddress[MAXNETNODES+1];
|
||||
static mysockaddr_t broadcastaddress[MAXNETNODES+1];
|
||||
static size_t broadcastaddresses = 0;
|
||||
static boolean nodeconnected[MAXNETNODES+1];
|
||||
static mysockaddr_t banned[MAXBANS];
|
||||
static UINT8 bannedmask[MAXBANS];
|
||||
|
||||
static size_t numbans = 0;
|
||||
static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
|
||||
|
@ -187,7 +176,6 @@ static boolean init_tcp_driver = false;
|
|||
static const char *serverport_name = DEFAULTPORT;
|
||||
static const char *clientport_name;/* any port */
|
||||
|
||||
#ifndef NONET
|
||||
#ifdef USE_WINSOCK
|
||||
// stupid microsoft makes things complicated
|
||||
static char *get_WSAErrorStr(int e)
|
||||
|
@ -387,47 +375,33 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
|
|||
#endif
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *SOCK_GetNodeAddress(INT32 node)
|
||||
{
|
||||
if (node == 0)
|
||||
return "self";
|
||||
#ifdef NONET
|
||||
return NULL;
|
||||
#else
|
||||
if (!nodeconnected[node])
|
||||
return NULL;
|
||||
return SOCK_AddrToStr(&clientaddress[node]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *SOCK_GetBanAddress(size_t ban)
|
||||
{
|
||||
if (ban >= numbans)
|
||||
return NULL;
|
||||
#ifdef NONET
|
||||
return NULL;
|
||||
#else
|
||||
return SOCK_AddrToStr(&banned[ban]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *SOCK_GetBanMask(size_t ban)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)ban;
|
||||
#else
|
||||
static char s[16]; //255.255.255.255 netmask? no, just CDIR for only
|
||||
if (ban >= numbans)
|
||||
return NULL;
|
||||
if (sprintf(s,"%d",bannedmask[ban]) > 0)
|
||||
return s;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
||||
{
|
||||
UINT32 bitmask = INADDR_NONE;
|
||||
|
@ -455,24 +429,20 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
|||
*/
|
||||
static void cleanupnodes(void)
|
||||
{
|
||||
SINT8 j;
|
||||
|
||||
if (!Playing())
|
||||
return;
|
||||
|
||||
// Why can't I start at zero?
|
||||
for (j = 1; j < MAXNETNODES; j++)
|
||||
if (!(nodeingame[j] || SendingFile(j)))
|
||||
for (SINT8 j = 1; j < MAXNETNODES; j++)
|
||||
if (!(netnodes[j].ingame || SendingFile(j)))
|
||||
nodeconnected[j] = false;
|
||||
}
|
||||
|
||||
static SINT8 getfreenode(void)
|
||||
{
|
||||
SINT8 j;
|
||||
|
||||
cleanupnodes();
|
||||
|
||||
for (j = 0; j < MAXNETNODES; j++)
|
||||
for (SINT8 j = 0; j < MAXNETNODES; j++)
|
||||
if (!nodeconnected[j])
|
||||
{
|
||||
nodeconnected[j] = true;
|
||||
|
@ -485,8 +455,8 @@ static SINT8 getfreenode(void)
|
|||
* downloading a needed wad, but it's better than not letting anyone join...
|
||||
*/
|
||||
/*I_Error("No more free nodes!!1!11!11!!1111\n");
|
||||
for (j = 1; j < MAXNETNODES; j++)
|
||||
if (!nodeingame[j])
|
||||
for (SINT8 j = 1; j < MAXNETNODES; j++)
|
||||
if (!netnodes[j].ingame)
|
||||
return j;*/
|
||||
|
||||
return -1;
|
||||
|
@ -497,28 +467,27 @@ void Command_Numnodes(void)
|
|||
{
|
||||
INT32 connected = 0;
|
||||
INT32 ingame = 0;
|
||||
INT32 i;
|
||||
|
||||
for (i = 1; i < MAXNETNODES; i++)
|
||||
for (INT32 i = 1; i < MAXNETNODES; i++)
|
||||
{
|
||||
if (!(nodeconnected[i] || nodeingame[i]))
|
||||
if (!(nodeconnected[i] || netnodes[i].ingame))
|
||||
continue;
|
||||
|
||||
if (nodeconnected[i])
|
||||
connected++;
|
||||
if (nodeingame[i])
|
||||
if (netnodes[i].ingame)
|
||||
ingame++;
|
||||
|
||||
CONS_Printf("%2d - ", i);
|
||||
if (nodetoplayer[i] != -1)
|
||||
CONS_Printf("player %.2d", nodetoplayer[i]);
|
||||
if (netnodes[i].player != -1)
|
||||
CONS_Printf("player %.2d", netnodes[i].player);
|
||||
else
|
||||
CONS_Printf(" ");
|
||||
if (nodeconnected[i])
|
||||
CONS_Printf(" - connected");
|
||||
else
|
||||
CONS_Printf(" - ");
|
||||
if (nodeingame[i])
|
||||
if (netnodes[i].ingame)
|
||||
CONS_Printf(" - ingame");
|
||||
else
|
||||
CONS_Printf(" - ");
|
||||
|
@ -531,19 +500,17 @@ void Command_Numnodes(void)
|
|||
connected, ingame);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NONET
|
||||
// Returns true if a packet was received from a new node, false in all other cases
|
||||
static boolean SOCK_Get(void)
|
||||
{
|
||||
size_t i, n;
|
||||
size_t i;
|
||||
int j;
|
||||
ssize_t c;
|
||||
mysockaddr_t fromaddress;
|
||||
socklen_t fromlen;
|
||||
|
||||
for (n = 0; n < mysocketses; n++)
|
||||
for (size_t n = 0; n < mysocketses; n++)
|
||||
{
|
||||
fromlen = (socklen_t)sizeof(fromaddress);
|
||||
c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0,
|
||||
|
@ -596,20 +563,17 @@ static boolean SOCK_Get(void)
|
|||
doomcom->remotenode = -1; // no packet
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// check if we can send (do not go over the buffer)
|
||||
#ifndef NONET
|
||||
|
||||
static fd_set masterset;
|
||||
|
||||
#ifdef SELECTTEST
|
||||
static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
boolean testset = false;
|
||||
FD_ZERO(dst);
|
||||
for (i = 0; i < len;i++)
|
||||
for (size_t i = 0; i < len;i++)
|
||||
{
|
||||
if(fd[i] != (SOCKET_TYPE)ERRSOCKET &&
|
||||
FD_ISSET(fd[i], src) && !FD_ISSET(fd[i], dst)) // no checking for dups
|
||||
|
@ -649,9 +613,7 @@ static boolean SOCK_CanGet(void)
|
|||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NONET
|
||||
static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr)
|
||||
{
|
||||
socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in);
|
||||
|
@ -675,16 +637,15 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr
|
|||
static void SOCK_Send(void)
|
||||
{
|
||||
ssize_t c = ERRSOCKET;
|
||||
size_t i, j;
|
||||
|
||||
if (!nodeconnected[doomcom->remotenode])
|
||||
return;
|
||||
|
||||
if (doomcom->remotenode == BROADCASTADDR)
|
||||
{
|
||||
for (i = 0; i < mysocketses; i++)
|
||||
for (size_t i = 0; i < mysocketses; i++)
|
||||
{
|
||||
for (j = 0; j < broadcastaddresses; j++)
|
||||
for (size_t j = 0; j < broadcastaddresses; j++)
|
||||
{
|
||||
if (myfamily[i] == broadcastaddress[j].any.sa_family)
|
||||
SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]);
|
||||
|
@ -694,7 +655,7 @@ static void SOCK_Send(void)
|
|||
}
|
||||
else if (nodesocket[doomcom->remotenode] == (SOCKET_TYPE)ERRSOCKET)
|
||||
{
|
||||
for (i = 0; i < mysocketses; i++)
|
||||
for (size_t i = 0; i < mysocketses; i++)
|
||||
{
|
||||
if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family)
|
||||
SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]);
|
||||
|
@ -714,9 +675,7 @@ static void SOCK_Send(void)
|
|||
SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NONET
|
||||
static void SOCK_FreeNodenum(INT32 numnode)
|
||||
{
|
||||
// can't disconnect from self :)
|
||||
|
@ -731,12 +690,10 @@ static void SOCK_FreeNodenum(INT32 numnode)
|
|||
// put invalid address
|
||||
memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode]));
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// UDPsocket
|
||||
//
|
||||
#ifndef NONET
|
||||
|
||||
// allocate a socket
|
||||
static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen)
|
||||
|
@ -1061,12 +1018,10 @@ static boolean UDP_Socket(void)
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
boolean I_InitTcpDriver(void)
|
||||
{
|
||||
boolean tcp_was_up = init_tcp_driver;
|
||||
#ifndef NONET
|
||||
if (!init_tcp_driver)
|
||||
{
|
||||
#ifdef USE_WINSOCK
|
||||
|
@ -1121,7 +1076,7 @@ boolean I_InitTcpDriver(void)
|
|||
#endif
|
||||
init_tcp_driver = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!tcp_was_up && init_tcp_driver)
|
||||
{
|
||||
I_AddExitFunc(I_ShutdownTcpDriver);
|
||||
|
@ -1135,11 +1090,9 @@ boolean I_InitTcpDriver(void)
|
|||
return init_tcp_driver;
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static void SOCK_CloseSocket(void)
|
||||
{
|
||||
size_t i;
|
||||
for (i=0; i < MAXNETNODES+1; i++)
|
||||
for (size_t i=0; i < MAXNETNODES+1; i++)
|
||||
{
|
||||
if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET
|
||||
&& FD_ISSET(mysockets[i], &masterset))
|
||||
|
@ -1150,11 +1103,9 @@ static void SOCK_CloseSocket(void)
|
|||
mysockets[i] = ERRSOCKET;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void I_ShutdownTcpDriver(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
SOCK_CloseSocket();
|
||||
|
||||
CONS_Printf("I_ShutdownTcpDriver: ");
|
||||
|
@ -1164,10 +1115,8 @@ void I_ShutdownTcpDriver(void)
|
|||
#endif
|
||||
CONS_Printf("shut down\n");
|
||||
init_tcp_driver = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
|
||||
{
|
||||
SINT8 newnode = -1;
|
||||
|
@ -1223,17 +1172,13 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
|
|||
I_freeaddrinfo(ai);
|
||||
return newnode;
|
||||
}
|
||||
#endif
|
||||
|
||||
static boolean SOCK_OpenSocket(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
size_t i;
|
||||
|
||||
memset(clientaddress, 0, sizeof (clientaddress));
|
||||
|
||||
nodeconnected[0] = true; // always connected to self
|
||||
for (i = 1; i < MAXNETNODES; i++)
|
||||
for (size_t i = 1; i < MAXNETNODES; i++)
|
||||
nodeconnected[i] = false;
|
||||
nodeconnected[BROADCASTADDR] = true;
|
||||
I_NetSend = SOCK_Send;
|
||||
|
@ -1251,18 +1196,12 @@ static boolean SOCK_OpenSocket(void)
|
|||
// build the socket but close it first
|
||||
SOCK_CloseSocket();
|
||||
return UDP_Socket();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean SOCK_Ban(INT32 node)
|
||||
{
|
||||
if (node > MAXNETNODES)
|
||||
return false;
|
||||
#ifdef NONET
|
||||
return false;
|
||||
#else
|
||||
if (numbans == MAXBANS)
|
||||
return false;
|
||||
|
||||
|
@ -1281,16 +1220,10 @@ static boolean SOCK_Ban(INT32 node)
|
|||
#endif
|
||||
numbans++;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static boolean SOCK_SetBanAddress(const char *address, const char *mask)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)address;
|
||||
(void)mask;
|
||||
return false;
|
||||
#else
|
||||
struct my_addrinfo *ai, *runp, hints;
|
||||
int gaie;
|
||||
|
||||
|
@ -1335,7 +1268,6 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
|
|||
I_freeaddrinfo(ai);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SOCK_ClearBans(void)
|
|
@ -15,13 +15,14 @@
|
|||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "doomstat.h"
|
||||
#include "doomdef.h"
|
||||
#include "command.h"
|
||||
#include "i_threads.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../command.h"
|
||||
#include "../i_threads.h"
|
||||
#include "mserv.h"
|
||||
#include "m_menu.h"
|
||||
#include "z_zone.h"
|
||||
#include "client_connection.h"
|
||||
#include "../m_menu.h"
|
||||
#include "../z_zone.h"
|
||||
|
||||
#ifdef MASTERSERVER
|
||||
|
||||
|
@ -45,9 +46,7 @@ static I_cond MSCond;
|
|||
# define Unlock_state()
|
||||
#endif/*HAVE_THREADS*/
|
||||
|
||||
#ifndef NONET
|
||||
static void Command_Listserv_f(void);
|
||||
#endif
|
||||
|
||||
#endif/*MASTERSERVER*/
|
||||
|
||||
|
@ -89,7 +88,6 @@ msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test
|
|||
*/
|
||||
void AddMServCommands(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
CV_RegisterVar(&cv_masterserver);
|
||||
CV_RegisterVar(&cv_masterserver_update_rate);
|
||||
CV_RegisterVar(&cv_masterserver_timeout);
|
||||
|
@ -100,7 +98,6 @@ void AddMServCommands(void)
|
|||
COM_AddCommand("listserv", Command_Listserv_f, 0);
|
||||
COM_AddCommand("masterserver_update", Update_parameters, COM_LUA); // allows people to updates manually in case you were delisted by accident
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MASTERSERVER
|
||||
|
@ -189,7 +186,6 @@ void GetMODVersion_Console(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef NONET
|
||||
/** Gets a list of game servers. Called from console.
|
||||
*/
|
||||
static void Command_Listserv_f(void)
|
||||
|
@ -200,7 +196,6 @@ static void Command_Listserv_f(void)
|
|||
HMS_list_servers();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
Finish_registration (void)
|
|
@ -14,7 +14,7 @@
|
|||
#ifndef _MSERV_H_
|
||||
#define _MSERV_H_
|
||||
|
||||
#include "i_threads.h"
|
||||
#include "../i_threads.h"
|
||||
|
||||
// lowered from 32 due to menu changes
|
||||
#define NUM_LIST_ROOMS 16
|
382
src/netcode/net_command.c
Normal file
382
src/netcode/net_command.c
Normal file
|
@ -0,0 +1,382 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2022 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file net_command.c
|
||||
/// \brief Net command handling
|
||||
|
||||
#include "net_command.h"
|
||||
#include "tic_command.h"
|
||||
#include "gamestate.h"
|
||||
#include "server_connection.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "i_net.h"
|
||||
#include "../byteptr.h"
|
||||
#include "../g_game.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../doomtype.h"
|
||||
|
||||
textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL};
|
||||
UINT8 localtextcmd[MAXTEXTCMD];
|
||||
UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen
|
||||
static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum);
|
||||
|
||||
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum))
|
||||
{
|
||||
#ifdef PARANOIA
|
||||
if (id >= MAXNETXCMD)
|
||||
I_Error("Command id %d too big", id);
|
||||
if (listnetxcmd[id] != 0)
|
||||
I_Error("Command id %d already used", id);
|
||||
#endif
|
||||
listnetxcmd[id] = cmd_f;
|
||||
}
|
||||
|
||||
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam)
|
||||
{
|
||||
if (localtextcmd[0]+2+nparam > MAXTEXTCMD)
|
||||
{
|
||||
// for future reference: if (cv_debug) != debug disabled.
|
||||
CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam));
|
||||
return;
|
||||
}
|
||||
localtextcmd[0]++;
|
||||
localtextcmd[localtextcmd[0]] = (UINT8)id;
|
||||
if (param && nparam)
|
||||
{
|
||||
M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam);
|
||||
localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam);
|
||||
}
|
||||
}
|
||||
|
||||
// splitscreen player
|
||||
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam)
|
||||
{
|
||||
if (localtextcmd2[0]+2+nparam > MAXTEXTCMD)
|
||||
{
|
||||
I_Error("No more place in the buffer for netcmd %d\n",id);
|
||||
return;
|
||||
}
|
||||
localtextcmd2[0]++;
|
||||
localtextcmd2[localtextcmd2[0]] = (UINT8)id;
|
||||
if (param && nparam)
|
||||
{
|
||||
M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam);
|
||||
localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam);
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 GetFreeXCmdSize(void)
|
||||
{
|
||||
// -1 for the size and another -1 for the ID.
|
||||
return (UINT8)(localtextcmd[0] - 2);
|
||||
}
|
||||
|
||||
// Frees all textcmd memory for the specified tic
|
||||
void D_FreeTextcmd(tic_t tic)
|
||||
{
|
||||
textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
|
||||
textcmdtic_t *textcmdtic = *tctprev;
|
||||
|
||||
while (textcmdtic && textcmdtic->tic != tic)
|
||||
{
|
||||
tctprev = &textcmdtic->next;
|
||||
textcmdtic = textcmdtic->next;
|
||||
}
|
||||
|
||||
if (textcmdtic)
|
||||
{
|
||||
// Remove this tic from the list.
|
||||
*tctprev = textcmdtic->next;
|
||||
|
||||
// Free all players.
|
||||
for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++)
|
||||
{
|
||||
textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i];
|
||||
|
||||
while (textcmdplayer)
|
||||
{
|
||||
textcmdplayer_t *tcpnext = textcmdplayer->next;
|
||||
Z_Free(textcmdplayer);
|
||||
textcmdplayer = tcpnext;
|
||||
}
|
||||
}
|
||||
|
||||
// Free this tic's own memory.
|
||||
Z_Free(textcmdtic);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the buffer for the specified ticcmd, or NULL if there isn't one
|
||||
UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum)
|
||||
{
|
||||
textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
|
||||
while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next;
|
||||
|
||||
// Do we have an entry for the tic? If so, look for player.
|
||||
if (textcmdtic)
|
||||
{
|
||||
textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)];
|
||||
while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next;
|
||||
|
||||
if (textcmdplayer) return textcmdplayer->cmd;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Gets the buffer for the specified ticcmd, creating one if necessary
|
||||
UINT8* D_GetTextcmd(tic_t tic, INT32 playernum)
|
||||
{
|
||||
textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
|
||||
textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
|
||||
textcmdplayer_t *textcmdplayer, **tcpprev;
|
||||
|
||||
// Look for the tic.
|
||||
while (textcmdtic && textcmdtic->tic != tic)
|
||||
{
|
||||
tctprev = &textcmdtic->next;
|
||||
textcmdtic = textcmdtic->next;
|
||||
}
|
||||
|
||||
// If we don't have an entry for the tic, make it.
|
||||
if (!textcmdtic)
|
||||
{
|
||||
textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL);
|
||||
textcmdtic->tic = tic;
|
||||
}
|
||||
|
||||
tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)];
|
||||
textcmdplayer = *tcpprev;
|
||||
|
||||
// Look for the player.
|
||||
while (textcmdplayer && textcmdplayer->playernum != playernum)
|
||||
{
|
||||
tcpprev = &textcmdplayer->next;
|
||||
textcmdplayer = textcmdplayer->next;
|
||||
}
|
||||
|
||||
// If we don't have an entry for the player, make it.
|
||||
if (!textcmdplayer)
|
||||
{
|
||||
textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL);
|
||||
textcmdplayer->playernum = playernum;
|
||||
}
|
||||
|
||||
return textcmdplayer->cmd;
|
||||
}
|
||||
|
||||
void ExtraDataTicker(void)
|
||||
{
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] || i == 0)
|
||||
{
|
||||
UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i);
|
||||
|
||||
if (bufferstart)
|
||||
{
|
||||
UINT8 *curpos = bufferstart;
|
||||
UINT8 *bufferend = &curpos[curpos[0]+1];
|
||||
|
||||
curpos++;
|
||||
while (curpos < bufferend)
|
||||
{
|
||||
if (*curpos < MAXNETXCMD && listnetxcmd[*curpos])
|
||||
{
|
||||
const UINT8 id = *curpos;
|
||||
curpos++;
|
||||
DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i));
|
||||
(listnetxcmd[id])(&curpos, i);
|
||||
DEBFILE("done\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server)
|
||||
{
|
||||
SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
|
||||
DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic));
|
||||
}
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If you are a client, you can safely forget the net commands for this tic
|
||||
// If you are the server, you need to remember them until every client has been acknowledged,
|
||||
// because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it
|
||||
if (client)
|
||||
D_FreeTextcmd(gametic);
|
||||
}
|
||||
|
||||
// used at txtcmds received to check packetsize bound
|
||||
size_t TotalTextCmdPerTic(tic_t tic)
|
||||
{
|
||||
size_t total = 1; // num of textcmds in the tic (ntextcmd byte)
|
||||
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
UINT8 *textcmd = D_GetExistingTextcmd(tic, i);
|
||||
if ((!i || playeringame[i]) && textcmd)
|
||||
total += 2 + textcmd[0]; // "+2" for size and playernum
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void PT_TextCmd(SINT8 node, INT32 netconsole)
|
||||
{
|
||||
if (client)
|
||||
return;
|
||||
|
||||
// splitscreen special
|
||||
if (netbuffer->packettype == PT_TEXTCMD2)
|
||||
netconsole = netnodes[node].player2;
|
||||
|
||||
if (netconsole < 0 || netconsole >= MAXPLAYERS)
|
||||
Net_UnAcknowledgePacket(node);
|
||||
else
|
||||
{
|
||||
size_t j;
|
||||
tic_t tic = maketic;
|
||||
UINT8 *textcmd;
|
||||
|
||||
// ignore if the textcmd has a reported size of zero
|
||||
// this shouldn't be sent at all
|
||||
if (!netbuffer->u.textcmd[0])
|
||||
{
|
||||
DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n",
|
||||
node, netconsole));
|
||||
Net_UnAcknowledgePacket(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore if the textcmd size var is actually larger than it should be
|
||||
// BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength
|
||||
if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1)
|
||||
{
|
||||
DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n",
|
||||
netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1),
|
||||
node, netconsole));
|
||||
Net_UnAcknowledgePacket(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if tic that we are making isn't too large else we cannot send it :(
|
||||
// doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time
|
||||
j = software_MAXPACKETLENGTH
|
||||
- (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE
|
||||
+ (doomcom->numslots+1)*sizeof(ticcmd_t));
|
||||
|
||||
// search a tic that have enougth space in the ticcmd
|
||||
while ((textcmd = D_GetExistingTextcmd(tic, netconsole)),
|
||||
(TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD)
|
||||
&& tic < firstticstosend + BACKUPTICS)
|
||||
tic++;
|
||||
|
||||
if (tic >= firstticstosend + BACKUPTICS)
|
||||
{
|
||||
DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, "
|
||||
"tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)),
|
||||
maketic, firstticstosend, node, netconsole));
|
||||
Net_UnAcknowledgePacket(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we have a buffer
|
||||
if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole);
|
||||
|
||||
DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n",
|
||||
tic, textcmd[0]+1, netconsole, firstticstosend, maketic));
|
||||
|
||||
M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
|
||||
textcmd[0] += (UINT8)netbuffer->u.textcmd[0];
|
||||
}
|
||||
}
|
||||
|
||||
void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf)
|
||||
{
|
||||
UINT8 *numcmds;
|
||||
|
||||
numcmds = (*buf)++;
|
||||
*numcmds = 0;
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
UINT8 *cmd = D_GetExistingTextcmd(tic, i);
|
||||
INT32 size = cmd ? cmd[0] : 0;
|
||||
|
||||
if ((!i || playeringame[i]) && size)
|
||||
{
|
||||
(*numcmds)++;
|
||||
WRITEUINT8(*buf, i);
|
||||
M_Memcpy(*buf, cmd, size + 1);
|
||||
*buf += size + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CL_CopyNetCommandsFromServerPacket(tic_t tic, UINT8 **buf)
|
||||
{
|
||||
UINT8 numcmds = *(*buf)++;
|
||||
|
||||
for (UINT32 i = 0; i < numcmds; i++)
|
||||
{
|
||||
INT32 playernum = *(*buf)++; // playernum
|
||||
size_t size = (*buf)[0]+1;
|
||||
|
||||
if (tic >= gametic) // Don't copy old net commands
|
||||
M_Memcpy(D_GetTextcmd(tic, playernum), *buf, size);
|
||||
*buf += size;
|
||||
}
|
||||
}
|
||||
|
||||
void CL_SendNetCommands(void)
|
||||
{
|
||||
// Send extra data if needed
|
||||
if (localtextcmd[0])
|
||||
{
|
||||
netbuffer->packettype = PT_TEXTCMD;
|
||||
M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1);
|
||||
// All extra data have been sent
|
||||
if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail...
|
||||
localtextcmd[0] = 0;
|
||||
}
|
||||
|
||||
// Send extra data if needed for player 2 (splitscreen)
|
||||
if (localtextcmd2[0])
|
||||
{
|
||||
netbuffer->packettype = PT_TEXTCMD2;
|
||||
M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1);
|
||||
// All extra data have been sent
|
||||
if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail...
|
||||
localtextcmd2[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SendKick(UINT8 playernum, UINT8 msg)
|
||||
{
|
||||
UINT8 buf[2];
|
||||
|
||||
if (!(server && cv_rejointimeout.value))
|
||||
msg &= ~KICK_MSG_KEEP_BODY;
|
||||
|
||||
buf[0] = playernum;
|
||||
buf[1] = msg;
|
||||
SendNetXCmd(XD_KICK, &buf, 2);
|
||||
}
|
||||
|
||||
void SendKicksForNode(SINT8 node, UINT8 msg)
|
||||
{
|
||||
if (!netnodes[node].ingame)
|
||||
return;
|
||||
|
||||
for (INT32 playernum = netnodes[node].player; playernum != -1; playernum = netnodes[node].player2)
|
||||
if (playernum != -1 && playeringame[playernum])
|
||||
SendKick(playernum, msg);
|
||||
}
|
66
src/netcode/net_command.h
Normal file
66
src/netcode/net_command.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2022 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file net_command.h
|
||||
/// \brief Net command handling
|
||||
|
||||
#ifndef __D_NET_COMMAND__
|
||||
#define __D_NET_COMMAND__
|
||||
|
||||
#include "d_clisrv.h"
|
||||
#include "../doomtype.h"
|
||||
|
||||
// Must be a power of two
|
||||
#define TEXTCMD_HASH_SIZE 4
|
||||
|
||||
typedef struct textcmdplayer_s
|
||||
{
|
||||
INT32 playernum;
|
||||
UINT8 cmd[MAXTEXTCMD];
|
||||
struct textcmdplayer_s *next;
|
||||
} textcmdplayer_t;
|
||||
|
||||
typedef struct textcmdtic_s
|
||||
{
|
||||
tic_t tic;
|
||||
textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE];
|
||||
struct textcmdtic_s *next;
|
||||
} textcmdtic_t;
|
||||
|
||||
extern textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE];
|
||||
|
||||
extern UINT8 localtextcmd[MAXTEXTCMD];
|
||||
extern UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen
|
||||
|
||||
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
|
||||
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
|
||||
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
|
||||
|
||||
UINT8 GetFreeXCmdSize(void);
|
||||
void D_FreeTextcmd(tic_t tic);
|
||||
|
||||
// Gets the buffer for the specified ticcmd, or NULL if there isn't one
|
||||
UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum);
|
||||
|
||||
// Gets the buffer for the specified ticcmd, creating one if necessary
|
||||
UINT8* D_GetTextcmd(tic_t tic, INT32 playernum);
|
||||
|
||||
void ExtraDataTicker(void);
|
||||
|
||||
// used at txtcmds received to check packetsize bound
|
||||
size_t TotalTextCmdPerTic(tic_t tic);
|
||||
|
||||
void PT_TextCmd(SINT8 node, INT32 netconsole);
|
||||
void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf);
|
||||
void CL_CopyNetCommandsFromServerPacket(tic_t tic, UINT8 **buf);
|
||||
void CL_SendNetCommands(void);
|
||||
void SendKick(UINT8 playernum, UINT8 msg);
|
||||
void SendKicksForNode(SINT8 node, UINT8 msg);
|
||||
|
||||
#endif
|
|
@ -7,19 +7,15 @@
|
|||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file d_clisrv.h
|
||||
/// \brief high level networking stuff
|
||||
/// \file protocol.h
|
||||
/// \brief Data exchanged through the network
|
||||
|
||||
#ifndef __D_CLISRV__
|
||||
#define __D_CLISRV__
|
||||
#ifndef __PROTOCOL__
|
||||
#define __PROTOCOL__
|
||||
|
||||
#include "d_ticcmd.h"
|
||||
#include "d_net.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "d_net.h"
|
||||
#include "tables.h"
|
||||
#include "d_player.h"
|
||||
#include "mserv.h"
|
||||
#include "../d_ticcmd.h"
|
||||
#include "../doomdef.h"
|
||||
|
||||
/*
|
||||
The 'packet version' is used to distinguish packet
|
||||
|
@ -38,10 +34,9 @@ therein, increment this number.
|
|||
// one that defines the actual packets to
|
||||
// be transmitted.
|
||||
|
||||
// Networking and tick handling related.
|
||||
#define BACKUPTICS 1024
|
||||
#define CLIENTBACKUPTICS 32
|
||||
#define MAXTEXTCMD 256
|
||||
|
||||
//
|
||||
// Packet structure
|
||||
//
|
||||
|
@ -77,7 +72,7 @@ typedef enum
|
|||
PT_ASKLUAFILE, // Client telling the server they don't have the file
|
||||
PT_HASLUAFILE, // Client telling the server they have the file
|
||||
|
||||
PT_BASICKEEPALIVE,// Keep the network alive during wipes, as tics aren't advanced and NetUpdate isn't called
|
||||
PT_BASICKEEPALIVE, // Keep the network alive during wipes, as tics aren't advanced and NetUpdate isn't called
|
||||
|
||||
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
|
||||
|
||||
|
@ -92,7 +87,6 @@ typedef enum
|
|||
PT_TEXTCMD, // Extra text commands from the client.
|
||||
PT_TEXTCMD2, // Splitscreen text commands.
|
||||
PT_CLIENTJOIN, // Client wants to join; used in start game.
|
||||
PT_NODETIMEOUT, // Packet sent to self if the connection times out.
|
||||
|
||||
PT_LOGIN, // Login attempt from the client.
|
||||
|
||||
|
@ -103,14 +97,6 @@ typedef enum
|
|||
NUMPACKETTYPE
|
||||
} packettype_t;
|
||||
|
||||
#ifdef PACKETDROP
|
||||
void Command_Drop(void);
|
||||
void Command_Droprate(void);
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
void Command_Numnodes(void);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
@ -139,13 +125,12 @@ typedef struct
|
|||
#endif
|
||||
|
||||
// Server to client packet
|
||||
// this packet is too large
|
||||
typedef struct
|
||||
{
|
||||
tic_t starttic;
|
||||
UINT8 numtics;
|
||||
UINT8 numslots; // "Slots filled": Highest player number in use plus one.
|
||||
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
|
||||
ticcmd_t cmds[45];
|
||||
} ATTRPACK servertics_pak;
|
||||
|
||||
typedef struct
|
||||
|
@ -215,6 +200,7 @@ enum {
|
|||
|
||||
#define MAXSERVERNAME 32
|
||||
#define MAXFILENEEDED 915
|
||||
|
||||
// This packet is too large
|
||||
typedef struct
|
||||
{
|
||||
|
@ -275,7 +261,7 @@ typedef struct
|
|||
UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused.
|
||||
UINT32 score;
|
||||
UINT16 timeinserver; // In seconds.
|
||||
} ATTRPACK plrinfo;
|
||||
} ATTRPACK plrinfo_pak;
|
||||
|
||||
// Shortest player information for join during intermission.
|
||||
typedef struct
|
||||
|
@ -286,7 +272,7 @@ typedef struct
|
|||
UINT32 pflags;
|
||||
UINT32 score;
|
||||
UINT8 ctfteam;
|
||||
} ATTRPACK plrconfig;
|
||||
} ATTRPACK plrconfig_pak;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -309,25 +295,25 @@ typedef struct
|
|||
UINT8 reserved; // Padding
|
||||
union
|
||||
{
|
||||
clientcmd_pak clientpak; // 144 bytes
|
||||
client2cmd_pak client2pak; // 200 bytes
|
||||
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
|
||||
serverconfig_pak servercfg; // 773 bytes
|
||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
|
||||
filetx_pak filetxpak; // 139 bytes
|
||||
clientcmd_pak clientpak;
|
||||
client2cmd_pak client2pak;
|
||||
servertics_pak serverpak;
|
||||
serverconfig_pak servercfg;
|
||||
UINT8 textcmd[MAXTEXTCMD+1];
|
||||
filetx_pak filetxpak;
|
||||
fileack_pak fileack;
|
||||
UINT8 filereceived;
|
||||
clientconfig_pak clientcfg; // 136 bytes
|
||||
clientconfig_pak clientcfg;
|
||||
UINT8 md5sum[16];
|
||||
serverinfo_pak serverinfo; // 1024 bytes
|
||||
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
|
||||
askinfo_pak askinfo; // 61 bytes
|
||||
msaskinfo_pak msaskinfo; // 22 bytes
|
||||
plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?)
|
||||
plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?)
|
||||
INT32 filesneedednum; // 4 bytes
|
||||
filesneededconfig_pak filesneededcfg; // ??? bytes
|
||||
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
|
||||
serverinfo_pak serverinfo;
|
||||
serverrefuse_pak serverrefuse;
|
||||
askinfo_pak askinfo;
|
||||
msaskinfo_pak msaskinfo;
|
||||
plrinfo_pak playerinfo[MAXPLAYERS];
|
||||
plrconfig_pak playerconfig[MAXPLAYERS];
|
||||
INT32 filesneedednum;
|
||||
filesneededconfig_pak filesneededcfg;
|
||||
UINT32 pingtable[MAXPLAYERS+1];
|
||||
} u; // This is needed to pack diff packet types data together
|
||||
} ATTRPACK doomdata_t;
|
||||
|
||||
|
@ -335,26 +321,7 @@ typedef struct
|
|||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#define MAXSERVERLIST (MAXNETNODES-1)
|
||||
typedef struct
|
||||
{
|
||||
SINT8 node;
|
||||
serverinfo_pak info;
|
||||
} serverelem_t;
|
||||
|
||||
extern serverelem_t serverlist[MAXSERVERLIST];
|
||||
extern UINT32 serverlistcount;
|
||||
extern INT32 mapchangepending;
|
||||
|
||||
// Points inside doomcom
|
||||
extern doomdata_t *netbuffer;
|
||||
|
||||
extern consvar_t cv_showjoinaddress;
|
||||
extern consvar_t cv_playbackspeed;
|
||||
|
||||
#define BASEPACKETSIZE offsetof(doomdata_t, u)
|
||||
#define FILETXHEADER offsetof(filetx_pak, data)
|
||||
#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0])
|
||||
|
||||
#define KICK_MSG_GO_AWAY 1
|
||||
#define KICK_MSG_CON_FAIL 2
|
||||
|
@ -366,107 +333,4 @@ extern consvar_t cv_playbackspeed;
|
|||
#define KICK_MSG_CUSTOM_BAN 8
|
||||
#define KICK_MSG_KEEP_BODY 0x80
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KR_KICK = 1, //Kicked by server
|
||||
KR_PINGLIMIT = 2, //Broke Ping Limit
|
||||
KR_SYNCH = 3, //Synch Failure
|
||||
KR_TIMEOUT = 4, //Connection Timeout
|
||||
KR_BAN = 5, //Banned by server
|
||||
KR_LEAVE = 6, //Quit the game
|
||||
|
||||
} kickreason_t;
|
||||
|
||||
/* the max number of name changes in some time period */
|
||||
#define MAXNAMECHANGES (5)
|
||||
#define NAMECHANGERATE (60*TICRATE)
|
||||
|
||||
extern boolean server;
|
||||
extern boolean serverrunning;
|
||||
#define client (!server)
|
||||
extern boolean dedicated; // For dedicated server
|
||||
extern UINT16 software_MAXPACKETLENGTH;
|
||||
extern boolean acceptnewnode;
|
||||
extern SINT8 servernode;
|
||||
|
||||
void Command_Ping_f(void);
|
||||
extern tic_t connectiontimeout;
|
||||
extern tic_t jointimeout;
|
||||
extern UINT16 pingmeasurecount;
|
||||
extern UINT32 realpingtable[MAXPLAYERS];
|
||||
extern UINT32 playerpingtable[MAXPLAYERS];
|
||||
extern tic_t servermaxping;
|
||||
|
||||
extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_joindelay, cv_rejointimeout;
|
||||
extern consvar_t cv_resynchattempts, cv_blamecfail;
|
||||
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
|
||||
extern consvar_t cv_dedicatedidletime;
|
||||
|
||||
// Used in d_net, the only dependence
|
||||
tic_t ExpandTics(INT32 low, INT32 node);
|
||||
void D_ClientServerInit(void);
|
||||
|
||||
// Initialise the other field
|
||||
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
|
||||
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
|
||||
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
|
||||
void SendKick(UINT8 playernum, UINT8 msg);
|
||||
|
||||
// Create any new ticcmds and broadcast to other players.
|
||||
void NetUpdate(void);
|
||||
|
||||
// Maintain connections to nodes without timing them all out.
|
||||
void NetKeepAlive(void);
|
||||
|
||||
void SV_StartSinglePlayerServer(void);
|
||||
boolean SV_SpawnServer(void);
|
||||
void SV_StopServer(void);
|
||||
void SV_ResetServer(void);
|
||||
void CL_AddSplitscreenPlayer(void);
|
||||
void CL_RemoveSplitscreenPlayer(void);
|
||||
void CL_Reset(void);
|
||||
void CL_ClearPlayer(INT32 playernum);
|
||||
void CL_QueryServerList(msg_server_t *list);
|
||||
void CL_UpdateServerList(boolean internetsearch, INT32 room);
|
||||
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
|
||||
// Is there a game running
|
||||
boolean Playing(void);
|
||||
|
||||
// Broadcasts special packets to other players
|
||||
// to notify of game exit
|
||||
void D_QuitNetGame(void);
|
||||
|
||||
//? How many ticks to run?
|
||||
boolean TryRunTics(tic_t realtic);
|
||||
|
||||
// extra data for lmps
|
||||
// these functions scare me. they contain magic.
|
||||
/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum);
|
||||
void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/
|
||||
|
||||
#ifndef NONET
|
||||
// translate a playername in a player number return -1 if not found and
|
||||
// print a error message in the console
|
||||
SINT8 nametonum(const char *name);
|
||||
#endif
|
||||
|
||||
extern char motd[254], server_context[8];
|
||||
extern UINT8 playernode[MAXPLAYERS];
|
||||
|
||||
INT32 D_NumPlayers(void);
|
||||
INT32 D_NumBots(void);
|
||||
void D_ResetTiccmds(void);
|
||||
|
||||
tic_t GetLag(INT32 node);
|
||||
UINT8 GetFreeXCmdSize(void);
|
||||
|
||||
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
|
||||
|
||||
extern UINT8 hu_redownloadinggamestate;
|
||||
|
||||
extern UINT8 adminpassmd5[16];
|
||||
extern boolean adminpasswordset;
|
||||
|
||||
extern boolean hu_stopped;
|
||||
|
||||
#endif
|
507
src/netcode/server_connection.c
Normal file
507
src/netcode/server_connection.c
Normal file
|
@ -0,0 +1,507 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file server_connection.c
|
||||
/// \brief Server-side part of connection handling
|
||||
|
||||
#include "server_connection.h"
|
||||
#include "i_net.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "d_netfil.h"
|
||||
#include "mserv.h"
|
||||
#include "net_command.h"
|
||||
#include "gamestate.h"
|
||||
#include "../byteptr.h"
|
||||
#include "../g_game.h"
|
||||
#include "../g_state.h"
|
||||
#include "../p_setup.h"
|
||||
#include "../p_tick.h"
|
||||
#include "../command.h"
|
||||
#include "../doomstat.h"
|
||||
|
||||
// Minimum timeout for sending the savegame
|
||||
// The actual timeout will be longer depending on the savegame length
|
||||
tic_t jointimeout = (10*TICRATE);
|
||||
|
||||
// Incremented by cv_joindelay when a client joins, decremented each tic.
|
||||
// If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled.
|
||||
tic_t joindelay = 0;
|
||||
|
||||
// Minimum timeout for sending the savegame
|
||||
// The actual timeout will be longer depending on the savegame length
|
||||
char playeraddress[MAXPLAYERS][64];
|
||||
|
||||
consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR|CV_ALLOWLUA, CV_OnOff, NULL);
|
||||
|
||||
static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR|CV_ALLOWLUA, maxplayers_cons_t, NULL);
|
||||
|
||||
static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}};
|
||||
consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL);
|
||||
|
||||
static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}};
|
||||
consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL);
|
||||
|
||||
static INT32 FindRejoinerNum(SINT8 node)
|
||||
{
|
||||
char addressbuffer[64];
|
||||
const char *nodeaddress;
|
||||
const char *strippednodeaddress;
|
||||
|
||||
// Make sure there is no dead dress before proceeding to the stripping
|
||||
if (!I_GetNodeAddress)
|
||||
return -1;
|
||||
nodeaddress = I_GetNodeAddress(node);
|
||||
if (!nodeaddress)
|
||||
return -1;
|
||||
|
||||
// Strip the address of its port
|
||||
strcpy(addressbuffer, nodeaddress);
|
||||
strippednodeaddress = I_NetSplitAddress(addressbuffer, NULL);
|
||||
|
||||
// Check if any player matches the stripped address
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX
|
||||
&& !strcmp(playeraddress[i], strippednodeaddress))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static UINT8
|
||||
GetRefuseReason (INT32 node)
|
||||
{
|
||||
if (!node || FindRejoinerNum(node) != -1)
|
||||
return 0;
|
||||
else if (bannednode && bannednode[node])
|
||||
return REFUSE_BANNED;
|
||||
else if (!cv_allownewplayer.value)
|
||||
return REFUSE_JOINS_DISABLED;
|
||||
else if (D_NumPlayers() >= cv_maxplayers.value)
|
||||
return REFUSE_SLOTS_FULL;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SV_SendServerInfo(INT32 node, tic_t servertime)
|
||||
{
|
||||
UINT8 *p;
|
||||
|
||||
netbuffer->packettype = PT_SERVERINFO;
|
||||
netbuffer->u.serverinfo._255 = 255;
|
||||
netbuffer->u.serverinfo.packetversion = PACKETVERSION;
|
||||
netbuffer->u.serverinfo.version = VERSION;
|
||||
netbuffer->u.serverinfo.subversion = SUBVERSION;
|
||||
strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION,
|
||||
sizeof netbuffer->u.serverinfo.application);
|
||||
// return back the time value so client can compute their ping
|
||||
netbuffer->u.serverinfo.time = (tic_t)LONG(servertime);
|
||||
netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime);
|
||||
|
||||
// Exclude bots from both counts
|
||||
netbuffer->u.serverinfo.numberofplayer = (UINT8)(D_NumPlayers() - D_NumBots());
|
||||
netbuffer->u.serverinfo.maxplayer = (UINT8)(cv_maxplayers.value - D_NumBots());
|
||||
|
||||
netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
|
||||
|
||||
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
|
||||
sizeof netbuffer->u.serverinfo.gametypename);
|
||||
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
|
||||
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
|
||||
netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0);
|
||||
strncpy(netbuffer->u.serverinfo.servername, cv_servername.string,
|
||||
MAXSERVERNAME);
|
||||
strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7);
|
||||
|
||||
M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16);
|
||||
|
||||
memset(netbuffer->u.serverinfo.maptitle, 0, sizeof netbuffer->u.serverinfo.maptitle);
|
||||
|
||||
if (mapheaderinfo[gamemap-1] && *mapheaderinfo[gamemap-1]->lvlttl)
|
||||
{
|
||||
char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle;
|
||||
while (writ < (netbuffer->u.serverinfo.maptitle+32) && *read != '\0')
|
||||
{
|
||||
if (!(*read & 0x80))
|
||||
{
|
||||
*writ = toupper(*read);
|
||||
writ++;
|
||||
}
|
||||
read++;
|
||||
}
|
||||
*writ = '\0';
|
||||
//strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33);
|
||||
}
|
||||
else
|
||||
strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32);
|
||||
|
||||
if (mapheaderinfo[gamemap-1] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
|
||||
netbuffer->u.serverinfo.iszone = 1;
|
||||
else
|
||||
netbuffer->u.serverinfo.iszone = 0;
|
||||
|
||||
if (mapheaderinfo[gamemap-1])
|
||||
netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum;
|
||||
|
||||
p = PutFileNeeded(0);
|
||||
|
||||
HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
|
||||
}
|
||||
|
||||
static void SV_SendPlayerInfo(INT32 node)
|
||||
{
|
||||
netbuffer->packettype = PT_PLAYERINFO;
|
||||
|
||||
for (UINT8 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
{
|
||||
netbuffer->u.playerinfo[i].num = 255; // This slot is empty.
|
||||
continue;
|
||||
}
|
||||
|
||||
netbuffer->u.playerinfo[i].num = i;
|
||||
strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1);
|
||||
netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0';
|
||||
|
||||
//fetch IP address
|
||||
//No, don't do that, you fuckface.
|
||||
memset(netbuffer->u.playerinfo[i].address, 0, 4);
|
||||
|
||||
if (G_GametypeHasTeams())
|
||||
{
|
||||
if (!players[i].ctfteam)
|
||||
netbuffer->u.playerinfo[i].team = 255;
|
||||
else
|
||||
netbuffer->u.playerinfo[i].team = (UINT8)players[i].ctfteam;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (players[i].spectator)
|
||||
netbuffer->u.playerinfo[i].team = 255;
|
||||
else
|
||||
netbuffer->u.playerinfo[i].team = 0;
|
||||
}
|
||||
|
||||
netbuffer->u.playerinfo[i].score = LONG(players[i].score);
|
||||
netbuffer->u.playerinfo[i].timeinserver = SHORT((UINT16)(players[i].jointime / TICRATE));
|
||||
netbuffer->u.playerinfo[i].skin = (UINT8)(players[i].skin
|
||||
#ifdef DEVELOP // it's safe to do this only because PLAYERINFO isn't read by the game itself
|
||||
% 3
|
||||
#endif
|
||||
);
|
||||
|
||||
// Extra data
|
||||
netbuffer->u.playerinfo[i].data = 0; //players[i].skincolor;
|
||||
|
||||
if (players[i].pflags & PF_TAGIT)
|
||||
netbuffer->u.playerinfo[i].data |= 0x20;
|
||||
|
||||
if (players[i].gotflag)
|
||||
netbuffer->u.playerinfo[i].data |= 0x40;
|
||||
|
||||
if (players[i].powers[pw_super])
|
||||
netbuffer->u.playerinfo[i].data |= 0x80;
|
||||
}
|
||||
|
||||
HSendPacket(node, false, 0, sizeof(plrinfo_pak) * MAXPLAYERS);
|
||||
}
|
||||
|
||||
/** Sends a PT_SERVERCFG packet
|
||||
*
|
||||
* \param node The destination
|
||||
* \return True if the packet was successfully sent
|
||||
*
|
||||
*/
|
||||
static boolean SV_SendServerConfig(INT32 node)
|
||||
{
|
||||
boolean waspacketsent;
|
||||
|
||||
netbuffer->packettype = PT_SERVERCFG;
|
||||
|
||||
netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer;
|
||||
netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots);
|
||||
netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic);
|
||||
netbuffer->u.servercfg.clientnode = (UINT8)node;
|
||||
netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
|
||||
netbuffer->u.servercfg.gametype = (UINT8)gametype;
|
||||
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
|
||||
netbuffer->u.servercfg.usedCheats = (UINT8)usedCheats;
|
||||
|
||||
memcpy(netbuffer->u.servercfg.server_context, server_context, 8);
|
||||
|
||||
{
|
||||
const size_t len = sizeof (serverconfig_pak);
|
||||
|
||||
#ifdef DEBUGFILE
|
||||
if (debugfile)
|
||||
{
|
||||
fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n",
|
||||
sizeu1(len), node);
|
||||
}
|
||||
#endif
|
||||
|
||||
waspacketsent = HSendPacket(node, true, 0, len);
|
||||
}
|
||||
|
||||
#ifdef DEBUGFILE
|
||||
if (debugfile)
|
||||
{
|
||||
if (waspacketsent)
|
||||
{
|
||||
fprintf(debugfile, "ServerConfig Packet was sent\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(debugfile, "ServerConfig Packet could not be sent right now\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return waspacketsent;
|
||||
}
|
||||
|
||||
// Adds a node to the game (player will follow at map change or at savegame....)
|
||||
static inline void SV_AddNode(INT32 node)
|
||||
{
|
||||
netnodes[node].tic = gametic;
|
||||
netnodes[node].supposedtic = gametic;
|
||||
// little hack because the server connects to itself and puts
|
||||
// nodeingame when connected not here
|
||||
if (node)
|
||||
netnodes[node].ingame = true;
|
||||
}
|
||||
|
||||
static void SV_AddPlayer(SINT8 node, const char *name)
|
||||
{
|
||||
INT32 n;
|
||||
UINT8 buf[2 + MAXPLAYERNAME];
|
||||
UINT8 *p;
|
||||
INT32 newplayernum;
|
||||
|
||||
newplayernum = FindRejoinerNum(node);
|
||||
if (newplayernum == -1)
|
||||
{
|
||||
// search for a free playernum
|
||||
// we can't use playeringame since it is not updated here
|
||||
for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++)
|
||||
{
|
||||
if (playeringame[newplayernum])
|
||||
continue;
|
||||
for (n = 0; n < MAXNETNODES; n++)
|
||||
if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum)
|
||||
break;
|
||||
if (n == MAXNETNODES)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// should never happen since we check the playernum
|
||||
// before accepting the join
|
||||
I_Assert(newplayernum < MAXPLAYERS);
|
||||
|
||||
playernode[newplayernum] = (UINT8)node;
|
||||
|
||||
p = buf + 2;
|
||||
buf[0] = (UINT8)node;
|
||||
buf[1] = newplayernum;
|
||||
if (netnodes[node].numplayers < 1)
|
||||
{
|
||||
netnodes[node].player = newplayernum;
|
||||
}
|
||||
else
|
||||
{
|
||||
netnodes[node].player2 = newplayernum;
|
||||
buf[1] |= 0x80;
|
||||
}
|
||||
WRITESTRINGN(p, name, MAXPLAYERNAME);
|
||||
netnodes[node].numplayers++;
|
||||
|
||||
SendNetXCmd(XD_ADDPLAYER, &buf, p - buf);
|
||||
|
||||
DEBFILE(va("Server added player %d node %d\n", newplayernum, node));
|
||||
}
|
||||
|
||||
static void SV_SendRefuse(INT32 node, const char *reason)
|
||||
{
|
||||
strcpy(netbuffer->u.serverrefuse.reason, reason);
|
||||
|
||||
netbuffer->packettype = PT_SERVERREFUSE;
|
||||
HSendPacket(node, true, 0, strlen(netbuffer->u.serverrefuse.reason) + 1);
|
||||
Net_CloseConnection(node);
|
||||
}
|
||||
|
||||
static const char *
|
||||
GetRefuseMessage (SINT8 node, INT32 rejoinernum)
|
||||
{
|
||||
clientconfig_pak *cc = &netbuffer->u.clientcfg;
|
||||
|
||||
boolean rejoining = (rejoinernum != -1);
|
||||
|
||||
if (!node)/* server connecting to itself */
|
||||
return NULL;
|
||||
|
||||
if (
|
||||
cc->modversion != MODVERSION ||
|
||||
strncmp(cc->application, SRB2APPLICATION,
|
||||
sizeof cc->application)
|
||||
){
|
||||
return/* this is probably client's fault */
|
||||
"Incompatible.";
|
||||
}
|
||||
else if (bannednode && bannednode[node])
|
||||
{
|
||||
return
|
||||
"You have been banned\n"
|
||||
"from the server.";
|
||||
}
|
||||
else if (cc->localplayers != 1)
|
||||
{
|
||||
return
|
||||
"Wrong player count.";
|
||||
}
|
||||
|
||||
if (!rejoining)
|
||||
{
|
||||
if (!cv_allownewplayer.value)
|
||||
{
|
||||
return
|
||||
"The server is not accepting\n"
|
||||
"joins for the moment.";
|
||||
}
|
||||
else if (D_NumPlayers() >= cv_maxplayers.value)
|
||||
{
|
||||
return va(
|
||||
"Maximum players reached: %d",
|
||||
cv_maxplayers.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (luafiletransfers)
|
||||
{
|
||||
return
|
||||
"The serveris broadcasting a file\n"
|
||||
"requested by a Lua script.\n"
|
||||
"Please wait a bit and then\n"
|
||||
"try rejoining.";
|
||||
}
|
||||
|
||||
if (netgame)
|
||||
{
|
||||
const tic_t th = 2 * cv_joindelay.value * TICRATE;
|
||||
|
||||
if (joindelay > th)
|
||||
{
|
||||
return va(
|
||||
"Too many people are connecting.\n"
|
||||
"Please wait %d seconds and then\n"
|
||||
"try rejoining.",
|
||||
(joindelay - th) / TICRATE);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Called when a PT_CLIENTJOIN packet is received
|
||||
*
|
||||
* \param node The packet sender
|
||||
*
|
||||
*/
|
||||
void PT_ClientJoin(SINT8 node)
|
||||
{
|
||||
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1];
|
||||
INT32 numplayers = netbuffer->u.clientcfg.localplayers;
|
||||
INT32 rejoinernum;
|
||||
|
||||
// Ignore duplicate packets
|
||||
if (client || netnodes[node].ingame)
|
||||
return;
|
||||
|
||||
rejoinernum = FindRejoinerNum(node);
|
||||
|
||||
const char *refuse = GetRefuseMessage(node, rejoinernum);
|
||||
if (refuse)
|
||||
{
|
||||
SV_SendRefuse(node, refuse);
|
||||
return;
|
||||
}
|
||||
|
||||
for (INT32 i = 0; i < numplayers; i++)
|
||||
{
|
||||
strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1);
|
||||
if (!EnsurePlayerNameIsGood(names[i], rejoinernum))
|
||||
{
|
||||
SV_SendRefuse(node, "Bad player name");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SV_AddNode(node);
|
||||
|
||||
if (!SV_SendServerConfig(node))
|
||||
{
|
||||
/// \note Shouldn't SV_SendRefuse be called before ResetNode?
|
||||
ResetNode(node);
|
||||
SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again"));
|
||||
/// \todo fix this !!!
|
||||
return;
|
||||
}
|
||||
DEBFILE("new node joined\n");
|
||||
|
||||
if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)
|
||||
{
|
||||
SV_SendSaveGame(node, false); // send a complete game state
|
||||
DEBFILE("send savegame\n");
|
||||
}
|
||||
|
||||
// Splitscreen can allow 2 players in one node
|
||||
for (INT32 i = 0; i < numplayers; i++)
|
||||
SV_AddPlayer(node, names[i]);
|
||||
|
||||
joindelay += cv_joindelay.value * TICRATE;
|
||||
}
|
||||
|
||||
void PT_AskInfoViaMS(SINT8 node)
|
||||
{
|
||||
Net_CloseConnection(node);
|
||||
}
|
||||
|
||||
void PT_TellFilesNeeded(SINT8 node)
|
||||
{
|
||||
if (server && serverrunning)
|
||||
{
|
||||
UINT8 *p;
|
||||
INT32 firstfile = netbuffer->u.filesneedednum;
|
||||
|
||||
netbuffer->packettype = PT_MOREFILESNEEDED;
|
||||
netbuffer->u.filesneededcfg.first = firstfile;
|
||||
netbuffer->u.filesneededcfg.more = 0;
|
||||
|
||||
p = PutFileNeeded(firstfile);
|
||||
|
||||
HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
|
||||
}
|
||||
else // Shouldn't get this if you aren't the server...?
|
||||
Net_CloseConnection(node);
|
||||
}
|
||||
|
||||
void PT_AskInfo(SINT8 node)
|
||||
{
|
||||
if (server && serverrunning)
|
||||
{
|
||||
SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
|
||||
SV_SendPlayerInfo(node); // Send extra info
|
||||
}
|
||||
Net_CloseConnection(node);
|
||||
}
|
30
src/netcode/server_connection.h
Normal file
30
src/netcode/server_connection.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file server_connection.h
|
||||
/// \brief Server-side part of connection handling
|
||||
|
||||
#ifndef __D_SERVER_CONNECTION__
|
||||
#define __D_SERVER_CONNECTION__
|
||||
|
||||
#include "../command.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../doomtype.h"
|
||||
|
||||
void PT_ClientJoin(SINT8 node);
|
||||
void PT_AskInfoViaMS(SINT8 node);
|
||||
void PT_TellFilesNeeded(SINT8 node);
|
||||
void PT_AskInfo(SINT8 node);
|
||||
|
||||
extern tic_t jointimeout;
|
||||
extern tic_t joindelay;
|
||||
extern char playeraddress[MAXPLAYERS][64];
|
||||
extern consvar_t cv_showjoinaddress, cv_allownewplayer, cv_maxplayers, cv_joindelay, cv_rejointimeout;
|
||||
|
||||
#endif
|
471
src/netcode/tic_command.c
Normal file
471
src/netcode/tic_command.c
Normal file
|
@ -0,0 +1,471 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file tic_command.c
|
||||
/// \brief Tic command handling
|
||||
|
||||
#include "tic_command.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "net_command.h"
|
||||
#include "client_connection.h"
|
||||
#include "gamestate.h"
|
||||
#include "i_net.h"
|
||||
#include "../d_main.h"
|
||||
#include "../g_game.h"
|
||||
#include "../i_system.h"
|
||||
#include "../i_time.h"
|
||||
#include "../byteptr.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../doomtype.h"
|
||||
|
||||
tic_t firstticstosend; // Smallest netnode.tic
|
||||
tic_t tictoclear = 0; // Optimize D_ClearTiccmd
|
||||
ticcmd_t localcmds;
|
||||
ticcmd_t localcmds2;
|
||||
boolean cl_packetmissed;
|
||||
ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
|
||||
|
||||
static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
|
||||
{
|
||||
const size_t d = n / sizeof(ticcmd_t);
|
||||
const size_t r = n % sizeof(ticcmd_t);
|
||||
UINT8 *ret = dest;
|
||||
|
||||
if (r)
|
||||
M_Memcpy(dest, src, n);
|
||||
else if (d)
|
||||
G_MoveTiccmd(dest, src, d);
|
||||
return ret+n;
|
||||
}
|
||||
|
||||
static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n)
|
||||
{
|
||||
const size_t d = n / sizeof(ticcmd_t);
|
||||
const size_t r = n % sizeof(ticcmd_t);
|
||||
UINT8 *ret = src;
|
||||
|
||||
if (r)
|
||||
M_Memcpy(dest, src, n);
|
||||
else if (d)
|
||||
G_MoveTiccmd(dest, src, d);
|
||||
return ret+n;
|
||||
}
|
||||
|
||||
/** Guesses the full value of a tic from its lowest byte, for a specific node
|
||||
*
|
||||
* \param low The lowest byte of the tic value
|
||||
* \param node The node to deduce the tic for
|
||||
* \return The full tic value
|
||||
*
|
||||
*/
|
||||
tic_t ExpandTics(INT32 low, INT32 node)
|
||||
{
|
||||
INT32 delta;
|
||||
|
||||
delta = low - (netnodes[node].tic & UINT8_MAX);
|
||||
|
||||
if (delta >= -64 && delta <= 64)
|
||||
return (netnodes[node].tic & ~UINT8_MAX) + low;
|
||||
else if (delta > 64)
|
||||
return (netnodes[node].tic & ~UINT8_MAX) - 256 + low;
|
||||
else //if (delta < -64)
|
||||
return (netnodes[node].tic & ~UINT8_MAX) + 256 + low;
|
||||
}
|
||||
|
||||
void D_Clearticcmd(tic_t tic)
|
||||
{
|
||||
D_FreeTextcmd(tic);
|
||||
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
netcmds[tic%BACKUPTICS][i].angleturn = 0;
|
||||
|
||||
DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS));
|
||||
}
|
||||
|
||||
void D_ResetTiccmds(void)
|
||||
{
|
||||
memset(&localcmds, 0, sizeof(ticcmd_t));
|
||||
memset(&localcmds2, 0, sizeof(ticcmd_t));
|
||||
|
||||
// Reset the net command list
|
||||
for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++)
|
||||
while (textcmds[i])
|
||||
D_Clearticcmd(textcmds[i]->tic);
|
||||
}
|
||||
|
||||
// Check ticcmd for "speed hacks"
|
||||
static void CheckTiccmdHacks(INT32 playernum, tic_t tic)
|
||||
{
|
||||
ticcmd_t *cmd = &netcmds[tic%BACKUPTICS][playernum];
|
||||
if (cmd->forwardmove > MAXPLMOVE || cmd->forwardmove < -MAXPLMOVE
|
||||
|| cmd->sidemove > MAXPLMOVE || cmd->sidemove < -MAXPLMOVE)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernum);
|
||||
SendKick(playernum, KICK_MSG_CON_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
// Check player consistancy during the level
|
||||
static void CheckConsistancy(SINT8 nodenum, tic_t tic)
|
||||
{
|
||||
netnode_t *node = &netnodes[nodenum];
|
||||
INT16 neededconsistancy = consistancy[tic%BACKUPTICS];
|
||||
INT16 clientconsistancy = SHORT(netbuffer->u.clientpak.consistancy);
|
||||
|
||||
if (tic > gametic || tic + BACKUPTICS - 1 <= gametic || gamestate != GS_LEVEL
|
||||
|| neededconsistancy == clientconsistancy || SV_ResendingSavegameToAnyone()
|
||||
|| node->resendingsavegame || node->savegameresendcooldown > I_GetTime())
|
||||
return;
|
||||
|
||||
if (cv_resynchattempts.value)
|
||||
{
|
||||
// Tell the client we are about to resend them the gamestate
|
||||
netbuffer->packettype = PT_WILLRESENDGAMESTATE;
|
||||
HSendPacket(nodenum, true, 0, 0);
|
||||
|
||||
node->resendingsavegame = true;
|
||||
|
||||
if (cv_blamecfail.value)
|
||||
CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"),
|
||||
node->player+1, player_names[node->player],
|
||||
neededconsistancy, clientconsistancy);
|
||||
|
||||
DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n",
|
||||
node->player, tic, neededconsistancy, clientconsistancy));
|
||||
}
|
||||
else
|
||||
{
|
||||
SendKick(node->player, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
|
||||
|
||||
DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n",
|
||||
node->player, tic, neededconsistancy, clientconsistancy));
|
||||
}
|
||||
}
|
||||
|
||||
void PT_ClientCmd(SINT8 nodenum, INT32 netconsole)
|
||||
{
|
||||
netnode_t *node = &netnodes[nodenum];
|
||||
tic_t realend, realstart;
|
||||
|
||||
if (client)
|
||||
return;
|
||||
|
||||
// To save bytes, only the low byte of tic numbers are sent
|
||||
// Use ExpandTics to figure out what the rest of the bytes are
|
||||
realstart = ExpandTics(netbuffer->u.clientpak.client_tic, nodenum);
|
||||
realend = ExpandTics(netbuffer->u.clientpak.resendfrom, nodenum);
|
||||
|
||||
if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS
|
||||
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS
|
||||
|| node->supposedtic < realend)
|
||||
{
|
||||
node->supposedtic = realend;
|
||||
}
|
||||
// Discard out of order packet
|
||||
if (node->tic > realend)
|
||||
{
|
||||
DEBFILE(va("out of order ticcmd discarded nettics = %u\n", node->tic));
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the nettics
|
||||
node->tic = realend;
|
||||
|
||||
// This should probably still timeout though, as the node should always have a player 1 number
|
||||
if (netconsole == -1)
|
||||
return;
|
||||
|
||||
// As long as clients send valid ticcmds, the server can keep running, so reset the timeout
|
||||
/// \todo Use a separate cvar for that kind of timeout?
|
||||
node->freezetimeout = I_GetTime() + connectiontimeout;
|
||||
|
||||
// Don't do anything for packets of type NODEKEEPALIVE?
|
||||
// Sryder 2018/07/01: Update the freezetimeout still!
|
||||
if (netbuffer->packettype == PT_NODEKEEPALIVE
|
||||
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
|
||||
return;
|
||||
|
||||
// If we've alredy received a ticcmd for this tic, just submit it for the next one.
|
||||
tic_t faketic = maketic;
|
||||
if ((!!(netcmds[maketic % BACKUPTICS][netconsole].angleturn & TICCMD_RECEIVED))
|
||||
&& (maketic - firstticstosend < BACKUPTICS - 1))
|
||||
faketic++;
|
||||
|
||||
// Copy ticcmd
|
||||
G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
|
||||
|
||||
// Splitscreen cmd
|
||||
if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
|
||||
&& node->player2 >= 0)
|
||||
G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)node->player2],
|
||||
&netbuffer->u.client2pak.cmd2, 1);
|
||||
|
||||
CheckTiccmdHacks(netconsole, faketic);
|
||||
CheckConsistancy(nodenum, realstart);
|
||||
}
|
||||
|
||||
void PT_ServerTics(SINT8 node, INT32 netconsole)
|
||||
{
|
||||
tic_t realend, realstart;
|
||||
servertics_pak *packet = &netbuffer->u.serverpak;
|
||||
|
||||
if (!netnodes[node].ingame)
|
||||
{
|
||||
// Do not remove my own server (we have just get a out of order packet)
|
||||
if (node != servernode)
|
||||
{
|
||||
DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype));
|
||||
Net_CloseConnection(node);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Only accept PT_SERVERTICS from the server.
|
||||
if (node != servernode)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node);
|
||||
if (server)
|
||||
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
|
||||
return;
|
||||
}
|
||||
|
||||
realstart = packet->starttic;
|
||||
realend = realstart + packet->numtics;
|
||||
|
||||
realend = min(realend, gametic + CLIENTBACKUPTICS);
|
||||
cl_packetmissed = realstart > neededtic;
|
||||
|
||||
if (realstart <= neededtic && realend > neededtic)
|
||||
{
|
||||
UINT8 *pak = (UINT8 *)&packet->cmds;
|
||||
UINT8 *txtpak = (UINT8 *)&packet->cmds[packet->numslots * packet->numtics];
|
||||
|
||||
for (tic_t i = realstart; i < realend; i++)
|
||||
{
|
||||
// clear first
|
||||
D_Clearticcmd(i);
|
||||
|
||||
// copy the tics
|
||||
pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak,
|
||||
packet->numslots*sizeof (ticcmd_t));
|
||||
|
||||
CL_CopyNetCommandsFromServerPacket(i, &txtpak);
|
||||
}
|
||||
|
||||
neededtic = realend;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBFILE(va("frame not in bound: %u\n", neededtic));
|
||||
}
|
||||
}
|
||||
|
||||
// send the client packet to the server
|
||||
void CL_SendClientCmd(void)
|
||||
{
|
||||
size_t packetsize = 0;
|
||||
boolean mis = false;
|
||||
|
||||
netbuffer->packettype = PT_CLIENTCMD;
|
||||
|
||||
if (cl_packetmissed)
|
||||
{
|
||||
netbuffer->packettype = PT_CLIENTMIS;
|
||||
mis = true;
|
||||
}
|
||||
|
||||
netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX);
|
||||
netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX);
|
||||
|
||||
if (gamestate == GS_WAITINGPLAYERS)
|
||||
{
|
||||
// Send PT_NODEKEEPALIVE packet
|
||||
netbuffer->packettype = (mis ? PT_NODEKEEPALIVEMIS : PT_NODEKEEPALIVE);
|
||||
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
|
||||
HSendPacket(servernode, false, 0, packetsize);
|
||||
}
|
||||
else if (gamestate != GS_NULL && (addedtogame || dedicated))
|
||||
{
|
||||
packetsize = sizeof (clientcmd_pak);
|
||||
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
|
||||
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
|
||||
|
||||
// Send a special packet with 2 cmd for splitscreen
|
||||
if (splitscreen || botingame)
|
||||
{
|
||||
netbuffer->packettype = (mis ? PT_CLIENT2MIS : PT_CLIENT2CMD);
|
||||
packetsize = sizeof (client2cmd_pak);
|
||||
G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1);
|
||||
}
|
||||
|
||||
HSendPacket(servernode, false, 0, packetsize);
|
||||
}
|
||||
|
||||
if (cl_mode == CL_CONNECTED || dedicated)
|
||||
CL_SendNetCommands();
|
||||
}
|
||||
|
||||
// PT_SERVERTICS packets can grow too large for a single UDP packet,
|
||||
// So this checks how many tics worth of data can be sent in one packet.
|
||||
// The rest can be sent later, usually the next tic.
|
||||
static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t lasttic)
|
||||
{
|
||||
size_t size = BASESERVERTICSSIZE;
|
||||
|
||||
for (tic_t tic = firsttic; tic < lasttic; tic++)
|
||||
{
|
||||
size += sizeof (ticcmd_t) * doomcom->numslots;
|
||||
size += TotalTextCmdPerTic(tic);
|
||||
|
||||
if (size > software_MAXPACKETLENGTH)
|
||||
{
|
||||
DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n",
|
||||
sizeu1(size), tic, firsttic, lasttic));
|
||||
lasttic = tic;
|
||||
|
||||
// Too bad: too many players have sent extra data
|
||||
// and there is too much data for a single tic.
|
||||
// To avoid that, keep the data for the next tic (see PT_TEXTCMD).
|
||||
if (lasttic == firsttic)
|
||||
{
|
||||
if (size > MAXPACKETLENGTH)
|
||||
I_Error("Too many players: can't send %s data for %d players to node %d\n"
|
||||
"Well sorry nobody is perfect....\n",
|
||||
sizeu1(size), doomcom->numslots, nodenum);
|
||||
else
|
||||
{
|
||||
lasttic++; // send it anyway!
|
||||
DEBFILE("sending it anyway\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return lasttic - firsttic;
|
||||
}
|
||||
|
||||
// Sends the server packet
|
||||
// Sends tic/net commands from firstticstosend to maketic-1
|
||||
void SV_SendTics(void)
|
||||
{
|
||||
tic_t realfirsttic, lasttictosend;
|
||||
|
||||
// Send to all clients except yourself
|
||||
// For each node, create a packet with x tics and send it
|
||||
// x is computed using node.supposedtic, max packet size and maketic
|
||||
for (INT32 n = 1; n < MAXNETNODES; n++)
|
||||
if (netnodes[n].ingame)
|
||||
{
|
||||
netnode_t *node = &netnodes[n];
|
||||
|
||||
// assert node->supposedtic>=node->tic
|
||||
realfirsttic = node->supposedtic;
|
||||
lasttictosend = min(maketic, node->tic + CLIENTBACKUPTICS);
|
||||
|
||||
if (realfirsttic >= lasttictosend)
|
||||
{
|
||||
// Well, we have sent all the tics, so we will use extra bandwidth
|
||||
// to resend packets that are supposed lost.
|
||||
// This is necessary since lost packet detection
|
||||
// works when we receive a packet with firsttic > neededtic (PT_SERVERTICS)
|
||||
DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n",
|
||||
n, maketic, node->supposedtic, node->tic));
|
||||
|
||||
realfirsttic = node->tic;
|
||||
|
||||
if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3)
|
||||
// All tics are Ok
|
||||
continue;
|
||||
|
||||
DEBFILE(va("Sent %d anyway\n", realfirsttic));
|
||||
}
|
||||
realfirsttic = max(realfirsttic, firstticstosend);
|
||||
|
||||
lasttictosend = realfirsttic + SV_CalculateNumTicsForPacket(n, realfirsttic, lasttictosend);
|
||||
|
||||
// Prepare the packet header
|
||||
netbuffer->packettype = PT_SERVERTICS;
|
||||
netbuffer->u.serverpak.starttic = realfirsttic;
|
||||
netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic);
|
||||
netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots);
|
||||
|
||||
// Fill and send the packet
|
||||
UINT8 *bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds;
|
||||
for (tic_t i = realfirsttic; i < lasttictosend; i++)
|
||||
bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t));
|
||||
for (tic_t i = realfirsttic; i < lasttictosend; i++)
|
||||
SV_WriteNetCommandsForTic(i, &bufpos);
|
||||
size_t packsize = bufpos - (UINT8 *)&(netbuffer->u);
|
||||
HSendPacket(n, false, 0, packsize);
|
||||
|
||||
// When tics are too large, only one tic is sent so don't go backwards!
|
||||
if (lasttictosend-doomcom->extratics > realfirsttic)
|
||||
node->supposedtic = lasttictosend-doomcom->extratics;
|
||||
else
|
||||
node->supposedtic = lasttictosend;
|
||||
node->supposedtic = max(node->supposedtic, node->tic);
|
||||
}
|
||||
|
||||
// node 0 is me!
|
||||
netnodes[0].supposedtic = maketic;
|
||||
}
|
||||
|
||||
void Local_Maketic(INT32 realtics)
|
||||
{
|
||||
I_OsPolling(); // I_Getevent
|
||||
D_ProcessEvents(); // menu responder, cons responder,
|
||||
// game responder calls HU_Responder, AM_Responder,
|
||||
// and G_MapEventsToControls
|
||||
if (!dedicated)
|
||||
rendergametic = gametic;
|
||||
// translate inputs (keyboard/mouse/joystick) into game controls
|
||||
G_BuildTiccmd(&localcmds, realtics, 1);
|
||||
if (splitscreen || botingame)
|
||||
G_BuildTiccmd(&localcmds2, realtics, 2);
|
||||
|
||||
localcmds.angleturn |= TICCMD_RECEIVED;
|
||||
localcmds2.angleturn |= TICCMD_RECEIVED;
|
||||
}
|
||||
|
||||
// create missed tic
|
||||
void SV_Maketic(void)
|
||||
{
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
|
||||
// We didn't receive this tic
|
||||
if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0)
|
||||
{
|
||||
ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i];
|
||||
ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i];
|
||||
|
||||
if (players[i].quittime)
|
||||
{
|
||||
// Copy the angle/aiming from the previous tic
|
||||
// and empty the other inputs
|
||||
memset(ticcmd, 0, sizeof(netcmds[0][0]));
|
||||
ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED;
|
||||
ticcmd->aiming = prevticcmd->aiming;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBFILE(va("MISS tic%4d for player %d\n", maketic, i));
|
||||
// Copy the input from the previous tic
|
||||
*ticcmd = *prevticcmd;
|
||||
ticcmd->angleturn &= ~TICCMD_RECEIVED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All tics have been processed, make the next
|
||||
maketic++;
|
||||
}
|
44
src/netcode/tic_command.h
Normal file
44
src/netcode/tic_command.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file tic_command.h
|
||||
/// \brief Tic command handling
|
||||
|
||||
#ifndef __D_TIC_COMMAND__
|
||||
#define __D_TIC_COMMAND__
|
||||
|
||||
#include "d_clisrv.h"
|
||||
#include "../d_ticcmd.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../doomtype.h"
|
||||
|
||||
extern tic_t firstticstosend; // min of the nettics
|
||||
extern tic_t tictoclear; // optimize d_clearticcmd
|
||||
|
||||
extern ticcmd_t localcmds;
|
||||
extern ticcmd_t localcmds2;
|
||||
extern boolean cl_packetmissed;
|
||||
|
||||
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
|
||||
|
||||
tic_t ExpandTics(INT32 low, INT32 node);
|
||||
void D_Clearticcmd(tic_t tic);
|
||||
void D_ResetTiccmds(void);
|
||||
|
||||
void PT_ClientCmd(SINT8 nodenum, INT32 netconsole);
|
||||
void PT_ServerTics(SINT8 node, INT32 netconsole);
|
||||
|
||||
// send the client packet to the server
|
||||
void CL_SendClientCmd(void);
|
||||
|
||||
void SV_SendTics(void);
|
||||
void Local_Maketic(INT32 realtics);
|
||||
void SV_Maketic(void);
|
||||
|
||||
#endif
|
|
@ -17,7 +17,7 @@
|
|||
#include "r_main.h"
|
||||
#include "s_sound.h"
|
||||
#include "z_zone.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "netcode/d_netcmd.h"
|
||||
|
||||
// ==========================================================================
|
||||
// CEILINGS
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "m_misc.h"
|
||||
#include "v_video.h" // video flags for CEchos
|
||||
#include "f_finale.h"
|
||||
#include "netcode/net_command.h"
|
||||
|
||||
// CTF player names
|
||||
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "r_state.h"
|
||||
#include "z_zone.h"
|
||||
#include "m_random.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "netcode/d_netcmd.h"
|
||||
|
||||
/** Removes any active lighting effects in a sector.
|
||||
*
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "p_slopes.h"
|
||||
#include "f_finale.h"
|
||||
#include "m_cond.h"
|
||||
#include "netcode/net_command.h"
|
||||
|
||||
static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL);
|
||||
|
|
|
@ -88,6 +88,8 @@
|
|||
|
||||
#include "taglist.h"
|
||||
|
||||
#include "netcode/net_command.h"
|
||||
|
||||
//
|
||||
// Map MD5, calculated on level load.
|
||||
// Sent to clients in PT_SERVERINFO.
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "r_main.h"
|
||||
#include "r_fps.h"
|
||||
#include "i_video.h" // rendermode
|
||||
#include "netcode/net_command.h"
|
||||
#include "netcode/server_connection.h"
|
||||
|
||||
// Object place
|
||||
#include "m_cheat.h"
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
#include "doomdef.h"
|
||||
#include "i_system.h"
|
||||
#include "d_event.h"
|
||||
#include "d_net.h"
|
||||
#include "netcode/d_net.h"
|
||||
#include "netcode/net_command.h"
|
||||
#include "g_game.h"
|
||||
#include "p_local.h"
|
||||
#include "r_fps.h"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "netcode/d_netcmd.h"
|
||||
#include "m_misc.h"
|
||||
#include "p_local.h" // Camera...
|
||||
#include "p_slopes.h"
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "p_tick.h"
|
||||
#include "p_local.h"
|
||||
#include "p_slopes.h"
|
||||
#include "d_netfil.h" // blargh. for nameonly().
|
||||
#include "netcode/d_netfil.h" // blargh. for nameonly().
|
||||
#include "m_cheat.h" // objectplace
|
||||
#ifdef HWRENDER
|
||||
#include "hardware/hw_md2.h"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "hu_stuff.h"
|
||||
#include "z_zone.h"
|
||||
#include "d_main.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "netcode/d_clisrv.h"
|
||||
#include "f_finale.h"
|
||||
#include "y_inter.h" // usebuffer
|
||||
#include "i_sound.h" // closed captions
|
||||
|
|
|
@ -21,16 +21,16 @@
|
|||
|
||||
#include "../i_system.h"
|
||||
#include "../d_event.h"
|
||||
#include "../d_net.h"
|
||||
#include "../netcode/d_net.h"
|
||||
#include "../m_argv.h"
|
||||
|
||||
#include "../doomstat.h"
|
||||
|
||||
#include "../i_net.h"
|
||||
#include "../netcode/i_net.h"
|
||||
|
||||
#include "../z_zone.h"
|
||||
|
||||
#include "../i_tcp.h"
|
||||
#include "../netcode/i_tcp.h"
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
|
||||
|
|
|
@ -187,7 +187,8 @@ static char returnWadPath[256];
|
|||
#include "../i_system.h"
|
||||
#include "../i_threads.h"
|
||||
#include "../screen.h" //vid.WndParent
|
||||
#include "../d_net.h"
|
||||
#include "../netcode/d_net.h"
|
||||
#include "../netcode/commands.h"
|
||||
#include "../g_game.h"
|
||||
#include "../filesrch.h"
|
||||
#include "endtxt.h"
|
||||
|
@ -208,7 +209,7 @@ static char returnWadPath[256];
|
|||
|
||||
#if !defined(NOMUMBLE) && defined(HAVE_MUMBLE)
|
||||
// Mumble context string
|
||||
#include "../d_clisrv.h"
|
||||
#include "../netcode/d_clisrv.h"
|
||||
#include "../byteptr.h"
|
||||
#endif
|
||||
|
||||
|
@ -2387,9 +2388,7 @@ void I_Quit(void)
|
|||
SDLforceUngrabMouse();
|
||||
quiting = SDL_FALSE;
|
||||
M_SaveConfig(NULL); //save game config, cvars..
|
||||
#ifndef NONET
|
||||
D_SaveBan(); // save the ban list
|
||||
#endif
|
||||
G_SaveGameData(clientGamedata); // Tails 12-08-2002
|
||||
//added:16-02-98: when recording a demo, should exit using 'q' key,
|
||||
// but sometimes we forget and use 'F10'.. so save here too.
|
||||
|
@ -2504,9 +2503,7 @@ void I_Error(const char *error, ...)
|
|||
// ---
|
||||
|
||||
M_SaveConfig(NULL); // save game config, cvars..
|
||||
#ifndef NONET
|
||||
D_SaveBan(); // save the ban list
|
||||
#endif
|
||||
G_SaveGameData(clientGamedata); // Tails 12-08-2002
|
||||
|
||||
// Shutdown. Here might be other errors.
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "SDL_ttf.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../d_netfil.h"
|
||||
#include "../netcode/d_netfil.h"
|
||||
#include "../filesrch.h"
|
||||
#include "i_ttf.h"
|
||||
|
||||
|
|
593
src/snake.c
Normal file
593
src/snake.c
Normal file
|
@ -0,0 +1,593 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023-2023 by Louis-Antoine de Moulins de Rochefort.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file snake.c
|
||||
/// \brief Snake minigame for the download screen.
|
||||
|
||||
#include "snake.h"
|
||||
#include "g_input.h"
|
||||
#include "g_game.h"
|
||||
#include "i_joy.h"
|
||||
#include "m_random.h"
|
||||
#include "s_sound.h"
|
||||
#include "screen.h"
|
||||
#include "v_video.h"
|
||||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
#define SPEED 5
|
||||
|
||||
#define NUM_BLOCKS_X 20
|
||||
#define NUM_BLOCKS_Y 10
|
||||
#define BLOCK_SIZE 12
|
||||
#define BORDER_SIZE 12
|
||||
|
||||
#define MAP_WIDTH (NUM_BLOCKS_X * BLOCK_SIZE)
|
||||
#define MAP_HEIGHT (NUM_BLOCKS_Y * BLOCK_SIZE)
|
||||
|
||||
#define LEFT_X ((BASEVIDWIDTH - MAP_WIDTH) / 2 - BORDER_SIZE)
|
||||
#define RIGHT_X (LEFT_X + MAP_WIDTH + BORDER_SIZE * 2 - 1)
|
||||
#define BOTTOM_Y (BASEVIDHEIGHT - 48)
|
||||
#define TOP_Y (BOTTOM_Y - MAP_HEIGHT - BORDER_SIZE * 2 + 1)
|
||||
|
||||
enum bonustype_s {
|
||||
BONUS_NONE = 0,
|
||||
BONUS_SLOW,
|
||||
BONUS_FAST,
|
||||
BONUS_GHOST,
|
||||
BONUS_NUKE,
|
||||
BONUS_SCISSORS,
|
||||
BONUS_REVERSE,
|
||||
BONUS_EGGMAN,
|
||||
NUM_BONUSES,
|
||||
};
|
||||
|
||||
typedef struct snake_s
|
||||
{
|
||||
boolean paused;
|
||||
boolean pausepressed;
|
||||
tic_t time;
|
||||
tic_t nextupdate;
|
||||
boolean gameover;
|
||||
UINT8 background;
|
||||
|
||||
UINT16 snakelength;
|
||||
enum bonustype_s snakebonus;
|
||||
tic_t snakebonustime;
|
||||
UINT8 snakex[NUM_BLOCKS_X * NUM_BLOCKS_Y];
|
||||
UINT8 snakey[NUM_BLOCKS_X * NUM_BLOCKS_Y];
|
||||
UINT8 snakedir[NUM_BLOCKS_X * NUM_BLOCKS_Y];
|
||||
|
||||
UINT8 applex;
|
||||
UINT8 appley;
|
||||
|
||||
enum bonustype_s bonustype;
|
||||
UINT8 bonusx;
|
||||
UINT8 bonusy;
|
||||
|
||||
event_t *joyevents[MAXEVENTS];
|
||||
UINT16 joyeventcount;
|
||||
} snake_t;
|
||||
|
||||
static const char *bonuspatches[] = {
|
||||
NULL,
|
||||
"DL_SLOW",
|
||||
"TVSSC0",
|
||||
"TVIVC0",
|
||||
"TVARC0",
|
||||
"DL_SCISSORS",
|
||||
"TVRCC0",
|
||||
"TVEGC0",
|
||||
};
|
||||
|
||||
static const char *backgrounds[] = {
|
||||
"RVPUMICF",
|
||||
"FRSTRCKF",
|
||||
"TAR",
|
||||
"MMFLRB4",
|
||||
"RVDARKF1",
|
||||
"RVZWALF1",
|
||||
"RVZWALF4",
|
||||
"RVZWALF5",
|
||||
"RVZGRS02",
|
||||
"RVZGRS04",
|
||||
};
|
||||
|
||||
static void Initialise(snake_t *snake)
|
||||
{
|
||||
snake->paused = false;
|
||||
snake->pausepressed = false;
|
||||
snake->time = 0;
|
||||
snake->nextupdate = SPEED;
|
||||
snake->gameover = false;
|
||||
snake->background = M_RandomKey(sizeof(backgrounds) / sizeof(*backgrounds));
|
||||
|
||||
snake->snakelength = 1;
|
||||
snake->snakebonus = BONUS_NONE;
|
||||
snake->snakex[0] = M_RandomKey(NUM_BLOCKS_X);
|
||||
snake->snakey[0] = M_RandomKey(NUM_BLOCKS_Y);
|
||||
snake->snakedir[0] = 0;
|
||||
snake->snakedir[1] = 0;
|
||||
|
||||
snake->applex = M_RandomKey(NUM_BLOCKS_X);
|
||||
snake->appley = M_RandomKey(NUM_BLOCKS_Y);
|
||||
|
||||
snake->bonustype = BONUS_NONE;
|
||||
|
||||
snake->joyeventcount = 0;
|
||||
}
|
||||
|
||||
static UINT8 GetOppositeDir(UINT8 dir)
|
||||
{
|
||||
if (dir == 1 || dir == 3)
|
||||
return dir + 1;
|
||||
else if (dir == 2 || dir == 4)
|
||||
return dir - 1;
|
||||
else
|
||||
return 12 + 5 - dir;
|
||||
}
|
||||
|
||||
static void FindFreeSlot(snake_t *snake, UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady)
|
||||
{
|
||||
UINT8 x, y;
|
||||
UINT16 i;
|
||||
|
||||
do
|
||||
{
|
||||
x = M_RandomKey(NUM_BLOCKS_X);
|
||||
y = M_RandomKey(NUM_BLOCKS_Y);
|
||||
|
||||
for (i = 0; i < snake->snakelength; i++)
|
||||
if (x == snake->snakex[i] && y == snake->snakey[i])
|
||||
break;
|
||||
} while (i < snake->snakelength || (x == headx && y == heady)
|
||||
|| (x == snake->applex && y == snake->appley)
|
||||
|| (snake->bonustype != BONUS_NONE && x == snake->bonusx && y == snake->bonusy));
|
||||
|
||||
*freex = x;
|
||||
*freey = y;
|
||||
}
|
||||
|
||||
void Snake_Allocate(void **opaque)
|
||||
{
|
||||
if (*opaque)
|
||||
Snake_Free(opaque);
|
||||
*opaque = malloc(sizeof(snake_t));
|
||||
Initialise(*opaque);
|
||||
}
|
||||
|
||||
void Snake_Update(void *opaque)
|
||||
{
|
||||
UINT8 x, y;
|
||||
UINT8 oldx, oldy;
|
||||
UINT16 i;
|
||||
UINT16 joystate = 0;
|
||||
static INT32 pjoyx = 0, pjoyy = 0;
|
||||
|
||||
snake_t *snake = opaque;
|
||||
|
||||
// Handle retry
|
||||
if (snake->gameover && (PLAYER1INPUTDOWN(GC_JUMP) || gamekeydown[KEY_ENTER]))
|
||||
{
|
||||
Initialise(snake);
|
||||
snake->pausepressed = true; // Avoid accidental pause on respawn
|
||||
}
|
||||
|
||||
// Handle pause
|
||||
if (PLAYER1INPUTDOWN(GC_PAUSE) || gamekeydown[KEY_ENTER])
|
||||
{
|
||||
if (!snake->pausepressed)
|
||||
snake->paused = !snake->paused;
|
||||
snake->pausepressed = true;
|
||||
}
|
||||
else
|
||||
snake->pausepressed = false;
|
||||
|
||||
if (snake->paused)
|
||||
return;
|
||||
|
||||
snake->time++;
|
||||
|
||||
x = snake->snakex[0];
|
||||
y = snake->snakey[0];
|
||||
oldx = snake->snakex[1];
|
||||
oldy = snake->snakey[1];
|
||||
|
||||
// Process the input events in here dear lord
|
||||
for (UINT16 j = 0; j < snake->joyeventcount; j++)
|
||||
{
|
||||
event_t *ev = snake->joyevents[j];
|
||||
const INT32 jdeadzone = (JOYAXISRANGE * cv_digitaldeadzone.value) / FRACUNIT;
|
||||
if (ev->y != INT32_MAX)
|
||||
{
|
||||
if (Joystick.bGamepadStyle || abs(ev->y) > jdeadzone)
|
||||
{
|
||||
if (ev->y < 0 && pjoyy >= 0)
|
||||
joystate = 1;
|
||||
else if (ev->y > 0 && pjoyy <= 0)
|
||||
joystate = 2;
|
||||
pjoyy = ev->y;
|
||||
}
|
||||
else
|
||||
pjoyy = 0;
|
||||
}
|
||||
|
||||
if (ev->x != INT32_MAX)
|
||||
{
|
||||
if (Joystick.bGamepadStyle || abs(ev->x) > jdeadzone)
|
||||
{
|
||||
if (ev->x < 0 && pjoyx >= 0)
|
||||
joystate = 3;
|
||||
else if (ev->x > 0 && pjoyx <= 0)
|
||||
joystate = 4;
|
||||
pjoyx = ev->x;
|
||||
}
|
||||
else
|
||||
pjoyx = 0;
|
||||
}
|
||||
}
|
||||
snake->joyeventcount = 0;
|
||||
|
||||
// Update direction
|
||||
if (PLAYER1INPUTDOWN(GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3)
|
||||
{
|
||||
if (snake->snakelength < 2 || x <= oldx)
|
||||
snake->snakedir[0] = 1;
|
||||
}
|
||||
else if (PLAYER1INPUTDOWN(GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4)
|
||||
{
|
||||
if (snake->snakelength < 2 || x >= oldx)
|
||||
snake->snakedir[0] = 2;
|
||||
}
|
||||
else if (PLAYER1INPUTDOWN(GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1)
|
||||
{
|
||||
if (snake->snakelength < 2 || y <= oldy)
|
||||
snake->snakedir[0] = 3;
|
||||
}
|
||||
else if (PLAYER1INPUTDOWN(GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2)
|
||||
{
|
||||
if (snake->snakelength < 2 || y >= oldy)
|
||||
snake->snakedir[0] = 4;
|
||||
}
|
||||
|
||||
if (snake->snakebonustime)
|
||||
{
|
||||
snake->snakebonustime--;
|
||||
if (!snake->snakebonustime)
|
||||
snake->snakebonus = BONUS_NONE;
|
||||
}
|
||||
|
||||
snake->nextupdate--;
|
||||
if (snake->nextupdate)
|
||||
return;
|
||||
if (snake->snakebonus == BONUS_SLOW)
|
||||
snake->nextupdate = SPEED * 2;
|
||||
else if (snake->snakebonus == BONUS_FAST)
|
||||
snake->nextupdate = SPEED * 2 / 3;
|
||||
else
|
||||
snake->nextupdate = SPEED;
|
||||
|
||||
if (snake->gameover)
|
||||
return;
|
||||
|
||||
// Find new position
|
||||
switch (snake->snakedir[0])
|
||||
{
|
||||
case 1:
|
||||
if (x > 0)
|
||||
x--;
|
||||
else
|
||||
snake->gameover = true;
|
||||
break;
|
||||
case 2:
|
||||
if (x < NUM_BLOCKS_X - 1)
|
||||
x++;
|
||||
else
|
||||
snake->gameover = true;
|
||||
break;
|
||||
case 3:
|
||||
if (y > 0)
|
||||
y--;
|
||||
else
|
||||
snake->gameover = true;
|
||||
break;
|
||||
case 4:
|
||||
if (y < NUM_BLOCKS_Y - 1)
|
||||
y++;
|
||||
else
|
||||
snake->gameover = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check collision with snake
|
||||
if (snake->snakebonus != BONUS_GHOST)
|
||||
for (i = 1; i < snake->snakelength - 1; i++)
|
||||
if (x == snake->snakex[i] && y == snake->snakey[i])
|
||||
{
|
||||
if (snake->snakebonus == BONUS_SCISSORS)
|
||||
{
|
||||
snake->snakebonus = BONUS_NONE;
|
||||
snake->snakelength = i;
|
||||
S_StartSound(NULL, sfx_adderr);
|
||||
}
|
||||
else
|
||||
snake->gameover = true;
|
||||
}
|
||||
|
||||
if (snake->gameover)
|
||||
{
|
||||
S_StartSound(NULL, sfx_lose);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check collision with apple
|
||||
if (x == snake->applex && y == snake->appley)
|
||||
{
|
||||
if (snake->snakelength + 3 < NUM_BLOCKS_X * NUM_BLOCKS_Y)
|
||||
{
|
||||
snake->snakelength++;
|
||||
snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2];
|
||||
snake->snakey [snake->snakelength - 1] = snake->snakey [snake->snakelength - 2];
|
||||
snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2];
|
||||
}
|
||||
|
||||
// Spawn new apple
|
||||
FindFreeSlot(snake, &snake->applex, &snake->appley, x, y);
|
||||
|
||||
// Spawn new bonus
|
||||
if (!(snake->snakelength % 5))
|
||||
{
|
||||
do
|
||||
{
|
||||
snake->bonustype = M_RandomKey(NUM_BONUSES - 1) + 1;
|
||||
} while (snake->snakelength > NUM_BLOCKS_X * NUM_BLOCKS_Y * 3 / 4
|
||||
&& (snake->bonustype == BONUS_EGGMAN || snake->bonustype == BONUS_FAST || snake->bonustype == BONUS_REVERSE));
|
||||
|
||||
FindFreeSlot(snake, &snake->bonusx, &snake->bonusy, x, y);
|
||||
}
|
||||
|
||||
S_StartSound(NULL, sfx_s3k6b);
|
||||
}
|
||||
|
||||
if (snake->snakelength > 1 && snake->snakedir[0])
|
||||
{
|
||||
UINT8 dir = snake->snakedir[0];
|
||||
|
||||
oldx = snake->snakex[1];
|
||||
oldy = snake->snakey[1];
|
||||
|
||||
// Move
|
||||
for (i = snake->snakelength - 1; i > 0; i--)
|
||||
{
|
||||
snake->snakex[i] = snake->snakex[i - 1];
|
||||
snake->snakey[i] = snake->snakey[i - 1];
|
||||
snake->snakedir[i] = snake->snakedir[i - 1];
|
||||
}
|
||||
|
||||
// Handle corners
|
||||
if (x < oldx && dir == 3)
|
||||
dir = 5;
|
||||
else if (x > oldx && dir == 3)
|
||||
dir = 6;
|
||||
else if (x < oldx && dir == 4)
|
||||
dir = 7;
|
||||
else if (x > oldx && dir == 4)
|
||||
dir = 8;
|
||||
else if (y < oldy && dir == 1)
|
||||
dir = 9;
|
||||
else if (y < oldy && dir == 2)
|
||||
dir = 10;
|
||||
else if (y > oldy && dir == 1)
|
||||
dir = 11;
|
||||
else if (y > oldy && dir == 2)
|
||||
dir = 12;
|
||||
snake->snakedir[1] = dir;
|
||||
}
|
||||
|
||||
snake->snakex[0] = x;
|
||||
snake->snakey[0] = y;
|
||||
|
||||
// Check collision with bonus
|
||||
if (snake->bonustype != BONUS_NONE && x == snake->bonusx && y == snake->bonusy)
|
||||
{
|
||||
S_StartSound(NULL, sfx_ncchip);
|
||||
|
||||
switch (snake->bonustype)
|
||||
{
|
||||
case BONUS_SLOW:
|
||||
snake->snakebonus = BONUS_SLOW;
|
||||
snake->snakebonustime = 20 * TICRATE;
|
||||
break;
|
||||
case BONUS_FAST:
|
||||
snake->snakebonus = BONUS_FAST;
|
||||
snake->snakebonustime = 20 * TICRATE;
|
||||
break;
|
||||
case BONUS_GHOST:
|
||||
snake->snakebonus = BONUS_GHOST;
|
||||
snake->snakebonustime = 10 * TICRATE;
|
||||
break;
|
||||
case BONUS_NUKE:
|
||||
for (i = 0; i < snake->snakelength; i++)
|
||||
{
|
||||
snake->snakex [i] = snake->snakex [0];
|
||||
snake->snakey [i] = snake->snakey [0];
|
||||
snake->snakedir[i] = snake->snakedir[0];
|
||||
}
|
||||
|
||||
S_StartSound(NULL, sfx_bkpoof);
|
||||
break;
|
||||
case BONUS_SCISSORS:
|
||||
snake->snakebonus = BONUS_SCISSORS;
|
||||
snake->snakebonustime = 60 * TICRATE;
|
||||
break;
|
||||
case BONUS_REVERSE:
|
||||
for (i = 0; i < (snake->snakelength + 1) / 2; i++)
|
||||
{
|
||||
UINT16 i2 = snake->snakelength - 1 - i;
|
||||
UINT8 tmpx = snake->snakex [i];
|
||||
UINT8 tmpy = snake->snakey [i];
|
||||
UINT8 tmpdir = snake->snakedir[i];
|
||||
|
||||
// Swap first segment with last segment
|
||||
snake->snakex [i] = snake->snakex [i2];
|
||||
snake->snakey [i] = snake->snakey [i2];
|
||||
snake->snakedir[i] = GetOppositeDir(snake->snakedir[i2]);
|
||||
snake->snakex [i2] = tmpx;
|
||||
snake->snakey [i2] = tmpy;
|
||||
snake->snakedir[i2] = GetOppositeDir(tmpdir);
|
||||
}
|
||||
|
||||
snake->snakedir[0] = 0;
|
||||
|
||||
S_StartSound(NULL, sfx_gravch);
|
||||
break;
|
||||
default:
|
||||
if (snake->snakebonus != BONUS_GHOST)
|
||||
{
|
||||
snake->gameover = true;
|
||||
S_StartSound(NULL, sfx_lose);
|
||||
}
|
||||
}
|
||||
|
||||
snake->bonustype = BONUS_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void Snake_Draw(void *opaque)
|
||||
{
|
||||
INT16 i;
|
||||
|
||||
snake_t *snake = opaque;
|
||||
|
||||
// Background
|
||||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
||||
|
||||
V_DrawFlatFill(
|
||||
LEFT_X + BORDER_SIZE,
|
||||
TOP_Y + BORDER_SIZE,
|
||||
MAP_WIDTH,
|
||||
MAP_HEIGHT,
|
||||
W_GetNumForName(backgrounds[snake->background])
|
||||
);
|
||||
|
||||
// Borders
|
||||
V_DrawFill(LEFT_X, TOP_Y, BORDER_SIZE + MAP_WIDTH, BORDER_SIZE, 242); // Top
|
||||
V_DrawFill(LEFT_X + BORDER_SIZE + MAP_WIDTH, TOP_Y, BORDER_SIZE, BORDER_SIZE + MAP_HEIGHT, 242); // Right
|
||||
V_DrawFill(LEFT_X + BORDER_SIZE, TOP_Y + BORDER_SIZE + MAP_HEIGHT, BORDER_SIZE + MAP_WIDTH, BORDER_SIZE, 242); // Bottom
|
||||
V_DrawFill(LEFT_X, TOP_Y + BORDER_SIZE, BORDER_SIZE, BORDER_SIZE + MAP_HEIGHT, 242); // Left
|
||||
|
||||
// Apple
|
||||
V_DrawFixedPatch(
|
||||
(LEFT_X + BORDER_SIZE + snake->applex * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT,
|
||||
(TOP_Y + BORDER_SIZE + snake->appley * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT,
|
||||
FRACUNIT / 4,
|
||||
0,
|
||||
W_CachePatchLongName("DL_APPLE", PU_HUDGFX),
|
||||
NULL
|
||||
);
|
||||
|
||||
// Bonus
|
||||
if (snake->bonustype != BONUS_NONE)
|
||||
V_DrawFixedPatch(
|
||||
(LEFT_X + BORDER_SIZE + snake->bonusx * BLOCK_SIZE + BLOCK_SIZE / 2 ) * FRACUNIT,
|
||||
(TOP_Y + BORDER_SIZE + snake->bonusy * BLOCK_SIZE + BLOCK_SIZE / 2 + 4) * FRACUNIT,
|
||||
FRACUNIT / 2,
|
||||
0,
|
||||
W_CachePatchLongName(bonuspatches[snake->bonustype], PU_HUDGFX),
|
||||
NULL
|
||||
);
|
||||
|
||||
// Snake
|
||||
if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over
|
||||
{
|
||||
for (i = snake->snakelength - 1; i >= 0; i--)
|
||||
{
|
||||
const char *patchname;
|
||||
UINT8 dir = snake->snakedir[i];
|
||||
|
||||
if (i == 0) // Head
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case 1: patchname = "DL_SNAKEHEAD_L"; break;
|
||||
case 2: patchname = "DL_SNAKEHEAD_R"; break;
|
||||
case 3: patchname = "DL_SNAKEHEAD_T"; break;
|
||||
case 4: patchname = "DL_SNAKEHEAD_B"; break;
|
||||
default: patchname = "DL_SNAKEHEAD_M";
|
||||
}
|
||||
}
|
||||
else // Body
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case 1: patchname = "DL_SNAKEBODY_L"; break;
|
||||
case 2: patchname = "DL_SNAKEBODY_R"; break;
|
||||
case 3: patchname = "DL_SNAKEBODY_T"; break;
|
||||
case 4: patchname = "DL_SNAKEBODY_B"; break;
|
||||
case 5: patchname = "DL_SNAKEBODY_LT"; break;
|
||||
case 6: patchname = "DL_SNAKEBODY_RT"; break;
|
||||
case 7: patchname = "DL_SNAKEBODY_LB"; break;
|
||||
case 8: patchname = "DL_SNAKEBODY_RB"; break;
|
||||
case 9: patchname = "DL_SNAKEBODY_TL"; break;
|
||||
case 10: patchname = "DL_SNAKEBODY_TR"; break;
|
||||
case 11: patchname = "DL_SNAKEBODY_BL"; break;
|
||||
case 12: patchname = "DL_SNAKEBODY_BR"; break;
|
||||
default: patchname = "DL_SNAKEBODY_B";
|
||||
}
|
||||
}
|
||||
|
||||
V_DrawFixedPatch(
|
||||
(LEFT_X + BORDER_SIZE + snake->snakex[i] * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT,
|
||||
(TOP_Y + BORDER_SIZE + snake->snakey[i] * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT,
|
||||
i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2,
|
||||
snake->snakebonus == BONUS_GHOST ? V_TRANSLUCENT : 0,
|
||||
W_CachePatchLongName(patchname, PU_HUDGFX),
|
||||
NULL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Length
|
||||
V_DrawString(RIGHT_X + 4, TOP_Y, V_MONOSPACE, va("%u", snake->snakelength));
|
||||
|
||||
// Bonus
|
||||
if (snake->snakebonus != BONUS_NONE
|
||||
&& (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2))
|
||||
V_DrawFixedPatch(
|
||||
(RIGHT_X + 10) * FRACUNIT,
|
||||
(TOP_Y + 24) * FRACUNIT,
|
||||
FRACUNIT / 2,
|
||||
0,
|
||||
W_CachePatchLongName(bonuspatches[snake->snakebonus], PU_HUDGFX),
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
void Snake_Free(void **opaque)
|
||||
{
|
||||
if (*opaque)
|
||||
{
|
||||
free(*opaque);
|
||||
*opaque = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// I'm screaming the hack is clean - ashi
|
||||
boolean Snake_JoyGrabber(void *opaque, event_t *ev)
|
||||
{
|
||||
snake_t *snake = opaque;
|
||||
|
||||
if (ev->type == ev_joystick && ev->key == 0)
|
||||
{
|
||||
snake->joyevents[snake->joyeventcount] = ev;
|
||||
snake->joyeventcount++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
23
src/snake.h
Normal file
23
src/snake.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023-2023 by Louis-Antoine de Moulins de Rochefort.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file snake.h
|
||||
/// \brief Snake minigame for the download screen.
|
||||
|
||||
#ifndef __SNAKE__
|
||||
#define __SNAKE__
|
||||
|
||||
#include "d_event.h"
|
||||
|
||||
void Snake_Allocate(void **opaque);
|
||||
void Snake_Update(void *opaque);
|
||||
void Snake_Draw(void *opaque);
|
||||
void Snake_Free(void **opaque);
|
||||
boolean Snake_JoyGrabber(void *opaque, event_t *ev);
|
||||
|
||||
#endif
|
|
@ -51,8 +51,8 @@
|
|||
#include "filesrch.h"
|
||||
|
||||
#include "d_main.h"
|
||||
#include "d_netfil.h"
|
||||
#include "d_clisrv.h"
|
||||
#include "netcode/d_netfil.h"
|
||||
#include "netcode/d_clisrv.h"
|
||||
#include "dehacked.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_data.h"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "f_finale.h"
|
||||
#include "g_game.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "i_net.h"
|
||||
#include "netcode/i_net.h"
|
||||
#include "i_video.h"
|
||||
#include "p_tick.h"
|
||||
#include "r_defs.h"
|
||||
|
|
Loading…
Reference in a new issue