Reapply recent netcode changes

This commit is contained in:
LJ Sonic 2023-08-01 18:24:07 +02:00
parent 7f4e82e7d9
commit b2441114e8
32 changed files with 846 additions and 473 deletions

View file

@ -39,7 +39,7 @@
#include "v_video.h" #include "v_video.h"
#include "lua_hook.h" #include "lua_hook.h"
#include "md5.h" // demo checksums #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 timingdemo; // if true, exit with report on completion
boolean nodrawers; // for comparative timing purposes boolean nodrawers; // for comparative timing purposes

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -17,11 +17,12 @@
#include "../d_main.h" #include "../d_main.h"
#include "../f_finale.h" #include "../f_finale.h"
#include "../g_game.h" #include "../g_game.h"
#include "../i_gamepad.h" #include "../g_input.h"
#include "i_net.h" #include "i_net.h"
#include "../i_system.h" #include "../i_system.h"
#include "../i_time.h" #include "../i_time.h"
#include "../i_video.h" #include "../i_video.h"
#include "../keys.h"
#include "../m_menu.h" #include "../m_menu.h"
#include "../m_misc.h" #include "../m_misc.h"
#include "../snake.h" #include "../snake.h"
@ -233,6 +234,7 @@ static boolean CL_AskFileList(INT32 firstfile)
boolean CL_SendJoin(void) boolean CL_SendJoin(void)
{ {
UINT8 localplayers = 1; UINT8 localplayers = 1;
char const *player2name;
if (netgame) if (netgame)
CONS_Printf(M_GetText("Sending join request...\n")); CONS_Printf(M_GetText("Sending join request...\n"));
netbuffer->packettype = PT_CLIENTJOIN; netbuffer->packettype = PT_CLIENTJOIN;
@ -250,8 +252,14 @@ boolean CL_SendJoin(void)
if (splitscreen) if (splitscreen)
CleanupPlayerName(1, cv_playername2.zstring); // 1 is a HACK? oh no CleanupPlayerName(1, cv_playername2.zstring); // 1 is a HACK? oh no
// Avoid empty string on bots to avoid softlocking in singleplayer
if (botingame)
player2name = strcmp(cv_playername.zstring, "Tails") == 0 ? "Tail" : "Tails";
else
player2name = cv_playername2.zstring;
strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME); strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME);
strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME); strncpy(netbuffer->u.clientcfg.names[1], player2name, MAXPLAYERNAME);
return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak));
} }
@ -470,9 +478,9 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
static void M_ConfirmConnect(event_t *ev) static void M_ConfirmConnect(event_t *ev)
{ {
if (ev->type == ev_keydown || ev->type == ev_gamepad_down) if (ev->type == ev_keydown)
{ {
if ((ev->type == ev_keydown && (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_A)) if (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER || ev->key == KEY_JOY1)
{ {
if (totalfilesrequestednum > 0) if (totalfilesrequestednum > 0)
{ {
@ -487,7 +495,7 @@ static void M_ConfirmConnect(event_t *ev)
M_ClearMenus(true); M_ClearMenus(true);
} }
else if ((ev->type == ev_keydown && (ev->key == 'n' || ev->key == KEY_ESCAPE)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_B)) else if (ev->key == 'n' || ev->key == KEY_ESCAPE || ev->key == KEY_JOY1 + 3)
{ {
cl_mode = CL_ABORTED; cl_mode = CL_ABORTED;
M_ClearMenus(true); M_ClearMenus(true);
@ -663,7 +671,7 @@ static const char * InvalidServerReason (serverinfo_pak *info)
case REFUSE_SLOTS_FULL: case REFUSE_SLOTS_FULL:
return va( return va(
"Maximum players reached: %d\n" EOT, "Maximum players reached: %d\n" EOT,
info->maxplayer); info->maxplayer - D_NumBots());
default: default:
if (info->refusereason) if (info->refusereason)
{ {
@ -893,11 +901,12 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
// my hand has been forced and I am dearly sorry for this awful hack :vomit: // my hand has been forced and I am dearly sorry for this awful hack :vomit:
for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
{ {
if (!Snake_JoyGrabber(snake, &events[eventtail]))
G_MapEventsToControls(&events[eventtail]); G_MapEventsToControls(&events[eventtail]);
} }
} }
if (gamekeydown[KEY_ESCAPE] || gamepads[0].buttons[GAMEPAD_BUTTON_B] || cl_mode == CL_ABORTED) if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1] || cl_mode == CL_ABORTED)
{ {
CONS_Printf(M_GetText("Network game synchronization aborted.\n")); CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
@ -922,7 +931,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{ {
if (!snake) if (!snake)
{ {
F_MenuPresTicker(true); // title sky F_MenuPresTicker(); // title sky
F_TitleScreenTicker(true); F_TitleScreenTicker(true);
F_TitleScreenDrawer(); F_TitleScreenDrawer();
} }
@ -1020,6 +1029,9 @@ void CL_ConnectToServer(void)
} }
while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes)))); while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes))));
if (netgame)
F_StartWaitingPlayers();
DEBFILE(va("Synchronisation Finished\n")); DEBFILE(va("Synchronisation Finished\n"));
displayplayer = consoleplayer; displayplayer = consoleplayer;
@ -1136,6 +1148,8 @@ void PT_ServerCFG(SINT8 node)
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
G_SetGametype(netbuffer->u.servercfg.gametype); G_SetGametype(netbuffer->u.servercfg.gametype);
modifiedgame = netbuffer->u.servercfg.modifiedgame; modifiedgame = netbuffer->u.servercfg.modifiedgame;
if (netbuffer->u.servercfg.usedCheats)
G_SetUsedCheats(true);
memcpy(server_context, netbuffer->u.servercfg.server_context, 8); memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
} }

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -25,8 +25,6 @@
#include "../st_stuff.h" #include "../st_stuff.h"
#include "../hu_stuff.h" #include "../hu_stuff.h"
#include "../keys.h" #include "../keys.h"
#include "../g_input.h"
#include "../i_gamepad.h"
#include "../m_menu.h" #include "../m_menu.h"
#include "../console.h" #include "../console.h"
#include "d_netfil.h" #include "d_netfil.h"
@ -34,7 +32,6 @@
#include "../p_saveg.h" #include "../p_saveg.h"
#include "../z_zone.h" #include "../z_zone.h"
#include "../p_local.h" #include "../p_local.h"
#include "../p_haptic.h"
#include "../m_misc.h" #include "../m_misc.h"
#include "../am_map.h" #include "../am_map.h"
#include "../m_random.h" #include "../m_random.h"
@ -103,6 +100,8 @@ boolean acceptnewnode = true;
UINT16 software_MAXPACKETLENGTH; UINT16 software_MAXPACKETLENGTH;
static tic_t gametime = 0;
static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}};
consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL);
@ -114,6 +113,8 @@ consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_
static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}};
consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL);
consvar_t cv_dedicatedidletime = CVAR_INIT ("dedicatedidletime", "10", CV_SAVE, CV_Unsigned, NULL);
void ResetNode(INT32 node) void ResetNode(INT32 node)
{ {
memset(&netnodes[node], 0, sizeof(*netnodes)); memset(&netnodes[node], 0, sizeof(*netnodes));
@ -210,14 +211,13 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
if (server && I_GetNodeAddress) if (server && I_GetNodeAddress)
{ {
char addressbuffer[64];
const char *address = I_GetNodeAddress(node); const char *address = I_GetNodeAddress(node);
char *port = NULL;
if (address) // MI: fix msvcrt.dll!_mbscat crash? if (address) // MI: fix msvcrt.dll!_mbscat crash?
{ {
strcpy(playeraddress[newplayernum], address); strcpy(addressbuffer, address);
port = strchr(playeraddress[newplayernum], ':'); strcpy(playeraddress[newplayernum],
if (port) I_NetSplitAddress(addressbuffer, NULL));
*port = '\0';
} }
} }
} }
@ -744,6 +744,9 @@ void SV_ResetServer(void)
CV_RevertNetVars(); CV_RevertNetVars();
// Ensure synched when creating a new server
M_CopyGameData(serverGamedata, clientGamedata);
DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n");
} }
@ -997,6 +1000,45 @@ static void PT_Ping(SINT8 node, INT32 netconsole)
} }
} }
static void PT_BasicKeepAlive(SINT8 node, INT32 netconsole)
{
if (client)
return;
// This should probably still timeout though, as the node should always have a player 1 number
if (netconsole == -1)
return;
// If a client sends this it should mean they are done receiving the savegame
netnodes[node].sendingsavegame = false;
// As long as clients send keep alives, the server can keep running, so reset the timeout
/// \todo Use a separate cvar for that kind of timeout?
netnodes[node].freezetimeout = I_GetTime() + connectiontimeout;
return;
}
// Confusing, but this DOESN'T send PT_NODEKEEPALIVE, it sends PT_BASICKEEPALIVE
// Used during wipes to tell the server that a node is still connected
static void CL_SendClientKeepAlive(void)
{
netbuffer->packettype = PT_BASICKEEPALIVE;
HSendPacket(servernode, false, 0, 0);
}
static void SV_SendServerKeepAlive(void)
{
for (INT32 n = 1; n < MAXNETNODES; n++)
{
if (netnodes[n].ingame)
{
netbuffer->packettype = PT_BASICKEEPALIVE;
HSendPacket(n, false, 0, 0);
}
}
}
/** Handles a packet received from a node that isn't in game /** Handles a packet received from a node that isn't in game
* *
* \param node The packet sender * \param node The packet sender
@ -1052,6 +1094,7 @@ static void HandlePacketFromPlayer(SINT8 node)
netconsole = 0; netconsole = 0;
else else
netconsole = netnodes[node].player; netconsole = netnodes[node].player;
#ifdef PARANOIA #ifdef PARANOIA
if (netconsole >= MAXPLAYERS) if (netconsole >= MAXPLAYERS)
I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole);
@ -1068,6 +1111,7 @@ static void HandlePacketFromPlayer(SINT8 node)
case PT_NODEKEEPALIVEMIS: case PT_NODEKEEPALIVEMIS:
PT_ClientCmd(node, netconsole); PT_ClientCmd(node, netconsole);
break; break;
case PT_BASICKEEPALIVE : PT_BasicKeepAlive (node, netconsole); break;
case PT_TEXTCMD : PT_TextCmd (node, netconsole); break; case PT_TEXTCMD : PT_TextCmd (node, netconsole); break;
case PT_TEXTCMD2 : PT_TextCmd (node, netconsole); break; case PT_TEXTCMD2 : PT_TextCmd (node, netconsole); break;
case PT_LOGIN : PT_Login (node, netconsole); break; case PT_LOGIN : PT_Login (node, netconsole); break;
@ -1209,28 +1253,8 @@ boolean TryRunTics(tic_t realtics)
} }
} }
void NetUpdate(void) static void UpdatePingTable(void)
{ {
static tic_t gametime = 0;
static tic_t resptime = 0;
tic_t nowtime;
INT32 realtics;
nowtime = I_GetTime();
realtics = nowtime - gametime;
if (realtics <= 0) // nothing new to update
return;
if (realtics > 5)
{
if (server)
realtics = 1;
else
realtics = 5;
}
gametime = nowtime;
if (server) if (server)
{ {
if (netgame && !(gametime % 35)) // update once per second. if (netgame && !(gametime % 35)) // update once per second.
@ -1241,6 +1265,149 @@ void NetUpdate(void)
realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i]));
pingmeasurecount++; pingmeasurecount++;
} }
}
// Handle timeouts to prevent definitive freezes from happenning
static void HandleNodeTimeouts(void)
{
if (server)
{
for (INT32 i = 1; i < MAXNETNODES; i++)
if (netnodes[i].ingame && netnodes[i].freezetimeout < I_GetTime())
Net_ConnectionTimeout(i);
// In case the cvar value was lowered
if (joindelay)
joindelay = min(joindelay - 1, 3 * (tic_t)cv_joindelay.value * TICRATE);
}
}
// Keep the network alive while not advancing tics!
void NetKeepAlive(void)
{
tic_t nowtime;
INT32 realtics;
nowtime = I_GetTime();
realtics = nowtime - gametime;
// return if there's no time passed since the last call
if (realtics <= 0) // nothing new to update
return;
UpdatePingTable();
GetPackets();
#ifdef MASTERSERVER
MasterClient_Ticker();
#endif
if (client)
{
// send keep alive
CL_SendClientKeepAlive();
// No need to check for resynch because we aren't running any tics
}
else
{
SV_SendServerKeepAlive();
}
// No else because no tics are being run and we can't resynch during this
Net_AckTicker();
HandleNodeTimeouts();
FileSendTicker();
}
void NetUpdate(void)
{
static tic_t resptime = 0;
tic_t nowtime;
INT32 realtics;
nowtime = I_GetTime();
realtics = nowtime - gametime;
if (realtics <= 0) // nothing new to update
return;
if (realtics > 5)
{
if (server)
realtics = 1;
else
realtics = 5;
}
if (server && dedicated && gamestate == GS_LEVEL)
{
const tic_t dedicatedidletime = cv_dedicatedidletime.value * TICRATE;
static tic_t dedicatedidletimeprev = 0;
static tic_t dedicatedidle = 0;
if (dedicatedidletime > 0)
{
INT32 i;
for (i = 1; i < MAXNETNODES; ++i)
if (netnodes[i].ingame)
{
if (dedicatedidle >= dedicatedidletime)
{
CONS_Printf("DEDICATED: Awakening from idle (Node %d detected...)\n", i);
dedicatedidle = 0;
}
break;
}
if (i == MAXNETNODES)
{
if (leveltime == 2)
{
// On next tick...
dedicatedidle = dedicatedidletime-1;
}
else if (dedicatedidle >= dedicatedidletime)
{
if (D_GetExistingTextcmd(gametic, 0) || D_GetExistingTextcmd(gametic+1, 0))
{
CONS_Printf("DEDICATED: Awakening from idle (Netxcmd detected...)\n");
dedicatedidle = 0;
}
else
{
realtics = 0;
}
}
else if ((dedicatedidle += realtics) >= dedicatedidletime)
{
const char *idlereason = "at round start";
if (leveltime > 3)
idlereason = va("for %d seconds", dedicatedidle/TICRATE);
CONS_Printf("DEDICATED: No nodes %s, idling...\n", idlereason);
realtics = 0;
dedicatedidle = dedicatedidletime;
}
}
}
else
{
if (dedicatedidletimeprev > 0 && dedicatedidle >= dedicatedidletimeprev)
{
CONS_Printf("DEDICATED: Awakening from idle (Idle disabled...)\n");
}
dedicatedidle = 0;
}
dedicatedidletimeprev = dedicatedidletime;
}
gametime = nowtime;
UpdatePingTable();
if (client) if (client)
maketic = neededtic; maketic = neededtic;
@ -1270,17 +1437,18 @@ void NetUpdate(void)
} }
else else
{ {
if (!demoplayback) if (!demoplayback && realtics > 0)
{ {
hu_redownloadinggamestate = false; hu_redownloadinggamestate = false;
firstticstosend = gametic; firstticstosend = gametic;
for (INT32 i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
if (netnodes[i].ingame && netnodes[i].tic < firstticstosend) if (netnodes[i].ingame)
{ {
if (netnodes[i].tic < firstticstosend)
firstticstosend = netnodes[i].tic; firstticstosend = netnodes[i].tic;
if (maketic + 1 >= netnodes[i].tic + BACKUPTICS) if (maketic + realtics >= netnodes[i].tic + BACKUPTICS - TICRATE)
Net_ConnectionTimeout(i); Net_ConnectionTimeout(i);
} }
@ -1302,20 +1470,10 @@ void NetUpdate(void)
} }
Net_AckTicker(); Net_AckTicker();
HandleNodeTimeouts();
// Handle timeouts to prevent definitive freezes from happenning
if (server)
{
for (INT32 i = 1; i < MAXNETNODES; i++)
if (netnodes[i].ingame && netnodes[i].freezetimeout < I_GetTime())
Net_ConnectionTimeout(i);
// In case the cvar value was lowered
if (joindelay)
joindelay = min(joindelay - 1, 3 * (tic_t)cv_joindelay.value * TICRATE);
}
nowtime /= NEWTICRATERATIO; nowtime /= NEWTICRATERATIO;
if (nowtime > resptime) if (nowtime > resptime)
{ {
resptime = nowtime; resptime = nowtime;
@ -1338,22 +1496,22 @@ void D_ClientServerInit(void)
DEBFILE(va("- - -== SRB2 v%d.%.2d.%d "VERSIONSTRING" debugfile ==- - -\n", DEBFILE(va("- - -== SRB2 v%d.%.2d.%d "VERSIONSTRING" debugfile ==- - -\n",
VERSION/100, VERSION%100, SUBVERSION)); VERSION/100, VERSION%100, SUBVERSION));
COM_AddCommand("getplayernum", Command_GetPlayerNum); COM_AddCommand("getplayernum", Command_GetPlayerNum, COM_LUA);
COM_AddCommand("kick", Command_Kick); COM_AddCommand("kick", Command_Kick, COM_LUA);
COM_AddCommand("ban", Command_Ban); COM_AddCommand("ban", Command_Ban, COM_LUA);
COM_AddCommand("banip", Command_BanIP); COM_AddCommand("banip", Command_BanIP, COM_LUA);
COM_AddCommand("clearbans", Command_ClearBans); COM_AddCommand("clearbans", Command_ClearBans, COM_LUA);
COM_AddCommand("showbanlist", Command_ShowBan); COM_AddCommand("showbanlist", Command_ShowBan, COM_LUA);
COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("reloadbans", Command_ReloadBan, COM_LUA);
COM_AddCommand("connect", Command_connect); COM_AddCommand("connect", Command_connect, COM_LUA);
COM_AddCommand("nodes", Command_Nodes); COM_AddCommand("nodes", Command_Nodes, COM_LUA);
COM_AddCommand("resendgamestate", Command_ResendGamestate); COM_AddCommand("resendgamestate", Command_ResendGamestate, COM_LUA);
#ifdef PACKETDROP #ifdef PACKETDROP
COM_AddCommand("drop", Command_Drop); COM_AddCommand("drop", Command_Drop, COM_LUA);
COM_AddCommand("droprate", Command_Droprate); COM_AddCommand("droprate", Command_Droprate, COM_LUA);
#endif #endif
#ifdef _DEBUG #ifdef _DEBUG
COM_AddCommand("numnodes", Command_Numnodes); COM_AddCommand("numnodes", Command_Numnodes, COM_LUA);
#endif #endif
RegisterNetXCmd(XD_KICK, Got_KickCmd); RegisterNetXCmd(XD_KICK, Got_KickCmd);
@ -1422,6 +1580,20 @@ INT32 D_NumPlayers(void)
return num; return num;
} }
/** Similar to the above, but counts only bots.
* Purpose is to remove bots from both the player count and the
* max player count on the server view
*/
INT32 D_NumBots(void)
{
INT32 num = 0, ix;
for (ix = 0; ix < MAXPLAYERS; ix++)
if (playeringame[ix] && players[ix].bot)
num++;
return num;
}
// //
// Consistancy // Consistancy
// //

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -73,7 +73,7 @@ extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping; extern tic_t servermaxping;
extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed; extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed, cv_dedicatedidletime;
// Used in d_net, the only dependence // Used in d_net, the only dependence
void D_ClientServerInit(void); void D_ClientServerInit(void);
@ -81,6 +81,9 @@ void D_ClientServerInit(void);
// Create any new ticcmds and broadcast to other players. // Create any new ticcmds and broadcast to other players.
void NetUpdate(void); void NetUpdate(void);
// Maintain connections to nodes without timing them all out.
void NetKeepAlive(void);
void GetPackets(void); void GetPackets(void);
void ResetNode(INT32 node); void ResetNode(INT32 node);
INT16 Consistancy(void); INT16 Consistancy(void);
@ -118,6 +121,7 @@ extern char motd[254], server_context[8];
extern UINT8 playernode[MAXPLAYERS]; extern UINT8 playernode[MAXPLAYERS];
INT32 D_NumPlayers(void); INT32 D_NumPlayers(void);
INT32 D_NumBots(void);
tic_t GetLag(INT32 node); tic_t GetLag(INT32 node);

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -760,6 +760,8 @@ static const char *packettypename[NUMPACKETTYPE] =
"ASKLUAFILE", "ASKLUAFILE",
"HASLUAFILE", "HASLUAFILE",
"PT_BASICKEEPALIVE",
"FILEFRAGMENT", "FILEFRAGMENT",
"FILEACK", "FILEACK",
"FILERECEIVED", "FILERECEIVED",
@ -818,6 +820,9 @@ static void DebugPrintpacket(const char *header)
(UINT32)ExpandTics(netbuffer->u.clientpak.client_tic, doomcom->remotenode), (UINT32)ExpandTics(netbuffer->u.clientpak.client_tic, doomcom->remotenode),
(UINT32)ExpandTics (netbuffer->u.clientpak.resendfrom, doomcom->remotenode)); (UINT32)ExpandTics (netbuffer->u.clientpak.resendfrom, doomcom->remotenode));
break; break;
case PT_BASICKEEPALIVE:
fprintf(debugfile, " wipetime\n");
break;
case PT_TEXTCMD: case PT_TEXTCMD:
case PT_TEXTCMD2: case PT_TEXTCMD2:
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]); fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
@ -1140,26 +1145,32 @@ static void Internal_FreeNodenum(INT32 nodenum)
(void)nodenum; (void)nodenum;
} }
char *I_NetSplitAddress(char *host, char **port)
{
boolean v4 = (strchr(host, '.') != NULL);
host = strtok(host, v4 ? ":" : "[]");
if (port)
*port = strtok(NULL, ":");
return host;
}
SINT8 I_NetMakeNode(const char *hostname) SINT8 I_NetMakeNode(const char *hostname)
{ {
SINT8 newnode = -1; SINT8 newnode = -1;
if (I_NetMakeNodewPort) if (I_NetMakeNodewPort)
{ {
char *localhostname = strdup(hostname); char *localhostname = strdup(hostname);
char *t = localhostname; char *port;
const char *port;
if (!localhostname) if (!localhostname)
return newnode; return newnode;
// retrieve portnum from address! // retrieve portnum from address!
strtok(localhostname, ":"); hostname = I_NetSplitAddress(localhostname, &port);
port = strtok(NULL, ":");
// remove the port in the hostname as we've it already newnode = I_NetMakeNodewPort(hostname, port);
while ((*t != ':') && (*t != '\0'))
t++;
*t = '\0';
newnode = I_NetMakeNodewPort(localhostname, port);
free(localhostname); free(localhostname);
} }
return newnode; return newnode;

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -33,10 +33,14 @@ extern consvar_t cv_defaultskin2;
extern consvar_t cv_seenames, cv_allowseenames; extern consvar_t cv_seenames, cv_allowseenames;
extern consvar_t cv_usemouse; extern consvar_t cv_usemouse;
extern consvar_t cv_usegamepad[2]; extern consvar_t cv_usejoystick;
extern consvar_t cv_gamepad_scale[2]; extern consvar_t cv_usejoystick2;
extern consvar_t cv_gamepad_rumble[2]; #ifdef LJOYSTICK
extern consvar_t cv_gamepad_autopause; extern consvar_t cv_joyport;
extern consvar_t cv_joyport2;
#endif
extern consvar_t cv_joyscale;
extern consvar_t cv_joyscale2;
// splitscreen with second mouse // splitscreen with second mouse
extern consvar_t cv_mouse2port; extern consvar_t cv_mouse2port;

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -504,7 +504,7 @@ INT32 CL_CheckFiles(void)
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// Check in already loaded files // Check in already loaded files
for (j = mainwads; wadfiles[j]; j++) for (j = mainwads; j < numwadfiles; j++)
{ {
nameonly(strcpy(wadfilename, wadfiles[j]->filename)); nameonly(strcpy(wadfilename, wadfiles[j]->filename));
if (!stricmp(wadfilename, fileneeded[i].filename) && if (!stricmp(wadfilename, fileneeded[i].filename) &&

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -29,7 +29,6 @@
#include "../lua_script.h" #include "../lua_script.h"
#include "../lzf.h" #include "../lzf.h"
#include "../m_misc.h" #include "../m_misc.h"
#include "../p_haptic.h"
#include "../p_local.h" #include "../p_local.h"
#include "../p_saveg.h" #include "../p_saveg.h"
#include "../r_main.h" #include "../r_main.h"
@ -200,8 +199,6 @@ void CL_LoadReceivedSavegame(boolean reloading)
titledemo = false; titledemo = false;
automapactive = false; automapactive = false;
P_StopRumble(NULL);
// load a base level // load a base level
if (P_LoadNetGame(reloading)) if (P_LoadNetGame(reloading))
{ {

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020-2022 by James R. // Copyright (C) 2020-2023 by James R.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -66,6 +66,8 @@ static I_mutex hms_api_mutex;
static char *hms_server_token; static char *hms_server_token;
static char hms_useragent[512];
struct HMS_buffer struct HMS_buffer
{ {
CURL *curl; CURL *curl;
@ -82,6 +84,22 @@ Contact_error (void)
); );
} }
static void
get_user_agent(char *buf, size_t len)
{
if (snprintf(buf, len, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 0)
I_Error("http-mserv: get_user_agent failed");
}
static void
init_user_agent_once(void)
{
if (hms_useragent[0] != '\0')
return;
get_user_agent(hms_useragent, 512);
}
static size_t static size_t
HMS_on_read (char *s, size_t _1, size_t n, void *userdata) HMS_on_read (char *s, size_t _1, size_t n, void *userdata)
{ {
@ -157,6 +175,8 @@ HMS_connect (const char *format, ...)
I_lock_mutex(&hms_api_mutex); I_lock_mutex(&hms_api_mutex);
#endif #endif
init_user_agent_once();
seek = strlen(hms_api) + 1;/* + '/' */ seek = strlen(hms_api) + 1;/* + '/' */
va_start (ap, format); va_start (ap, format);
@ -197,12 +217,18 @@ HMS_connect (const char *format, ...)
curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
#ifndef NO_IPV6
if (M_CheckParm("-noipv6"))
#endif
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value); curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
curl_easy_setopt(curl, CURLOPT_USERAGENT, hms_useragent);
curl_free(quack_token); curl_free(quack_token);
free(url); free(url);

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2011-2022 by Sonic Team Junior. // Copyright (C) 2011-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2011-2022 by Sonic Team Junior. // Copyright (C) 2011-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -109,6 +109,17 @@ extern boolean (*I_NetCanSend)(void);
*/ */
extern void (*I_NetFreeNodenum)(INT32 nodenum); extern void (*I_NetFreeNodenum)(INT32 nodenum);
/**
\brief split a string into address and port
\param address string to split
\param port double pointer to hold port component (optional)
\return address component
*/
extern char *I_NetSplitAddress(char *address, char **port);
/** \brief open a connection with specified address /** \brief open a connection with specified address
\param address address to connect to \param address address to connect to

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -328,8 +328,14 @@ static inline void I_UPnP_rem(const char *port, const char * servicetype)
static const char *SOCK_AddrToStr(mysockaddr_t *sk) static const char *SOCK_AddrToStr(mysockaddr_t *sk)
{ {
static char s[64]; // 255.255.255.255:65535 or IPv6:65535 static char s[64]; // 255.255.255.255:65535 or
// [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535
#ifdef HAVE_NTOP #ifdef HAVE_NTOP
#ifdef HAVE_IPV6
int v6 = (sk->any.sa_family == AF_INET6);
#else
int v6 = 0;
#endif
void *addr; void *addr;
if(sk->any.sa_family == AF_INET) if(sk->any.sa_family == AF_INET)
@ -343,14 +349,21 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
if(addr == NULL) if(addr == NULL)
sprintf(s, "No address"); sprintf(s, "No address");
else if(inet_ntop(sk->any.sa_family, addr, s, sizeof (s)) == NULL) else if(inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL)
sprintf(s, "Unknown family type, error #%u", errno); sprintf(s, "Unknown family type, error #%u", errno);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if(sk->any.sa_family == AF_INET6 && sk->ip6.sin6_port != 0) else if(sk->any.sa_family == AF_INET6)
{
s[0] = '[';
strcat(s, "]");
if (sk->ip6.sin6_port != 0)
strcat(s, va(":%d", ntohs(sk->ip6.sin6_port))); strcat(s, va(":%d", ntohs(sk->ip6.sin6_port)));
}
#endif #endif
else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0) else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0)
strcat(s, va(":%d", ntohs(sk->ip4.sin_port))); strcat(s, va(":%d", ntohs(sk->ip4.sin_port)));
#else #else
if (sk->any.sa_family == AF_INET) if (sk->any.sa_family == AF_INET)
{ {
@ -401,7 +414,7 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
&& (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port)); && (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port));
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (b->any.sa_family == AF_INET6) else if (b->any.sa_family == AF_INET6)
return memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr)) return !memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr))
&& (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port)); && (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port));
#endif #endif
else else
@ -692,8 +705,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
unsigned long trueval = true; unsigned long trueval = true;
#endif #endif
mysockaddr_t straddr; mysockaddr_t straddr;
struct sockaddr_in sin; socklen_t len = sizeof(straddr);
socklen_t len = sizeof(sin);
if (s == (SOCKET_TYPE)ERRSOCKET) if (s == (SOCKET_TYPE)ERRSOCKET)
return (SOCKET_TYPE)ERRSOCKET; return (SOCKET_TYPE)ERRSOCKET;
@ -711,14 +723,12 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
} }
#endif #endif
straddr.any = *addr; memcpy(&straddr, addr, addrlen);
I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr)); I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr));
if (family == AF_INET) if (family == AF_INET)
{ {
mysockaddr_t tmpaddr; if (straddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY))
tmpaddr.any = *addr ;
if (tmpaddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY))
{ {
opt = true; opt = true;
opts = (socklen_t)sizeof(opt); opts = (socklen_t)sizeof(opt);
@ -735,7 +745,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (family == AF_INET6) else if (family == AF_INET6)
{ {
if (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL if (memcmp(&straddr.ip6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL
{ {
opt = true; opt = true;
opts = (socklen_t)sizeof(opt); opts = (socklen_t)sizeof(opt);
@ -745,7 +755,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
// make it IPv6 ony // make it IPv6 ony
opt = true; opt = true;
opts = (socklen_t)sizeof(opt); opts = (socklen_t)sizeof(opt);
if (setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *)&opt, opts)) if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, opts))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore
} }
@ -787,10 +797,17 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10); CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10);
} }
if (getsockname(s, (struct sockaddr *)&sin, &len) == -1) if (getsockname(s, &straddr.any, &len) == -1)
CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n")); CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n"));
else else
current_port = (UINT16)ntohs(sin.sin_port); {
if (family == AF_INET)
current_port = (UINT16)ntohs(straddr.ip4.sin_port);
#ifdef HAVE_IPV6
else if (family == AF_INET6)
current_port = (UINT16)ntohs(straddr.ip6.sin6_port);
#endif
}
return s; return s;
} }
@ -801,7 +818,7 @@ static boolean UDP_Socket(void)
struct my_addrinfo *ai, *runp, hints; struct my_addrinfo *ai, *runp, hints;
int gaie; int gaie;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
const INT32 b_ipv6 = M_CheckParm("-ipv6"); const INT32 b_ipv6 = !M_CheckParm("-noipv6");
#endif #endif
const char *serv; const char *serv;
@ -1105,6 +1122,7 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
SINT8 newnode = -1; SINT8 newnode = -1;
struct my_addrinfo *ai = NULL, *runp, hints; struct my_addrinfo *ai = NULL, *runp, hints;
int gaie; int gaie;
size_t i;
if (!port || !port[0]) if (!port || !port[0])
port = DEFAULTPORT; port = DEFAULTPORT;
@ -1132,13 +1150,24 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
while (runp != NULL) while (runp != NULL)
{ {
// find ip of the server // test ip address of server
if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0) for (i = 0; i < mysocketses; ++i)
{
/* sendto tests that there is a network to this
address */
if (runp->ai_addr->sa_family == myfamily[i] &&
sendto(mysockets[i], NULL, 0, 0,
runp->ai_addr, runp->ai_addrlen) == 0)
{ {
memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen); memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
break; break;
} }
}
if (i < mysocketses)
runp = runp->ai_next; runp = runp->ai_next;
else
break;
} }
I_freeaddrinfo(ai); I_freeaddrinfo(ai);
return newnode; return newnode;

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,8 +1,8 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 2020-2022 by James R. // Copyright (C) 2020-2023 by James R.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -61,7 +61,7 @@ static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
}; };
consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://mb.srb2.org/MS/0", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange); consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://mb.srb2.org/MS/0", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange);
consvar_t cv_servername = CVAR_INIT ("servername", "SRB2 server", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, NULL, Update_parameters); consvar_t cv_servername = CVAR_INIT ("servername", "SRB2 server", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT|CV_ALLOWLUA, NULL, Update_parameters);
consvar_t cv_masterserver_update_rate = CVAR_INIT ("masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters); consvar_t cv_masterserver_update_rate = CVAR_INIT ("masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters);
@ -95,8 +95,8 @@ void AddMServCommands(void)
CV_RegisterVar(&cv_masterserver_token); CV_RegisterVar(&cv_masterserver_token);
CV_RegisterVar(&cv_servername); CV_RegisterVar(&cv_servername);
#ifdef MASTERSERVER #ifdef MASTERSERVER
COM_AddCommand("listserv", Command_Listserv_f); COM_AddCommand("listserv", Command_Listserv_f, 0);
COM_AddCommand("masterserver_update", Update_parameters); // allows people to updates manually in case you were delisted by accident COM_AddCommand("masterserver_update", Update_parameters, COM_LUA); // allows people to updates manually in case you were delisted by accident
#endif #endif
} }

View file

@ -1,8 +1,8 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 2020-2022 by James R. // Copyright (C) 2020-2023 by James R.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -33,7 +33,7 @@ typedef union
typedef struct typedef struct
{ {
msg_header_t header; msg_header_t header;
char ip[16]; char ip[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
char port[8]; char port[8];
char name[32]; char name[32];
INT32 room; INT32 room;

View file

@ -321,22 +321,18 @@ void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf)
} }
} }
void CL_CopyNetCommandsFromServerPacket(tic_t tic) void CL_CopyNetCommandsFromServerPacket(tic_t tic, UINT8 **buf)
{ {
servertics_pak *packet = &netbuffer->u.serverpak; UINT8 numcmds = *(*buf)++;
UINT8 *cmds = (UINT8*)&packet->cmds[packet->numslots * packet->numtics];
UINT8 numcmds;
numcmds = *cmds++;
for (UINT32 i = 0; i < numcmds; i++) for (UINT32 i = 0; i < numcmds; i++)
{ {
INT32 playernum = *cmds++; // playernum INT32 playernum = *(*buf)++; // playernum
size_t size = cmds[0]+1; size_t size = (*buf)[0]+1;
if (tic >= gametic) // Don't copy old net commands if (tic >= gametic) // Don't copy old net commands
M_Memcpy(D_GetTextcmd(tic, playernum), cmds, size); M_Memcpy(D_GetTextcmd(tic, playernum), *buf, size);
cmds += size; *buf += size;
} }
} }

View file

@ -58,7 +58,7 @@ size_t TotalTextCmdPerTic(tic_t tic);
void PT_TextCmd(SINT8 node, INT32 netconsole); void PT_TextCmd(SINT8 node, INT32 netconsole);
void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf); void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf);
void CL_CopyNetCommandsFromServerPacket(tic_t tic); void CL_CopyNetCommandsFromServerPacket(tic_t tic, UINT8 **buf);
void CL_SendNetCommands(void); void CL_SendNetCommands(void);
void SendKick(UINT8 playernum, UINT8 msg); void SendKick(UINT8 playernum, UINT8 msg);
void SendKicksForNode(SINT8 node, UINT8 msg); void SendKicksForNode(SINT8 node, UINT8 msg);

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -72,6 +72,8 @@ typedef enum
PT_ASKLUAFILE, // Client telling the server they don't have the file PT_ASKLUAFILE, // Client telling the server they don't have the file
PT_HASLUAFILE, // Client telling the server they 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
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
@ -143,6 +145,7 @@ typedef struct
UINT8 gametype; UINT8 gametype;
UINT8 modifiedgame; UINT8 modifiedgame;
UINT8 usedCheats;
char server_context[8]; // Unique context id, generated at server startup. char server_context[8]; // Unique context id, generated at server startup.
} ATTRPACK serverconfig_pak; } ATTRPACK serverconfig_pak;

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -39,10 +39,10 @@ char playeraddress[MAXPLAYERS][64];
consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); 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_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}}; 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, maxplayers_cons_t, 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}}; 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); consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL);
@ -52,9 +52,9 @@ consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|
static INT32 FindRejoinerNum(SINT8 node) static INT32 FindRejoinerNum(SINT8 node)
{ {
char strippednodeaddress[64]; char addressbuffer[64];
const char *nodeaddress; const char *nodeaddress;
char *port; const char *strippednodeaddress;
// Make sure there is no dead dress before proceeding to the stripping // Make sure there is no dead dress before proceeding to the stripping
if (!I_GetNodeAddress) if (!I_GetNodeAddress)
@ -64,10 +64,8 @@ static INT32 FindRejoinerNum(SINT8 node)
return -1; return -1;
// Strip the address of its port // Strip the address of its port
strcpy(strippednodeaddress, nodeaddress); strcpy(addressbuffer, nodeaddress);
port = strchr(strippednodeaddress, ':'); strippednodeaddress = I_NetSplitAddress(addressbuffer, NULL);
if (port)
*port = '\0';
// Check if any player matches the stripped address // Check if any player matches the stripped address
for (INT32 i = 0; i < MAXPLAYERS; i++) for (INT32 i = 0; i < MAXPLAYERS; i++)
@ -110,8 +108,9 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
netbuffer->u.serverinfo.time = (tic_t)LONG(servertime); netbuffer->u.serverinfo.time = (tic_t)LONG(servertime);
netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime); netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime);
netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); // Exclude bots from both counts
netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; 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); netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
@ -237,6 +236,7 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->u.servercfg.gamestate = (UINT8)gamestate; netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
netbuffer->u.servercfg.gametype = (UINT8)gametype; netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.usedCheats = (UINT8)usedCheats;
memcpy(netbuffer->u.servercfg.server_context, server_context, 8); memcpy(netbuffer->u.servercfg.server_context, server_context, 8);

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -100,9 +100,9 @@ void D_ResetTiccmds(void)
} }
// Check ticcmd for "speed hacks" // Check ticcmd for "speed hacks"
static void CheckTiccmdHacks(INT32 playernum) static void CheckTiccmdHacks(INT32 playernum, tic_t tic)
{ {
ticcmd_t *cmd = &netcmds[maketic%BACKUPTICS][playernum]; ticcmd_t *cmd = &netcmds[tic%BACKUPTICS][playernum];
if (cmd->forwardmove > MAXPLMOVE || cmd->forwardmove < -MAXPLMOVE if (cmd->forwardmove > MAXPLMOVE || cmd->forwardmove < -MAXPLMOVE
|| cmd->sidemove > MAXPLMOVE || cmd->sidemove < -MAXPLMOVE) || cmd->sidemove > MAXPLMOVE || cmd->sidemove < -MAXPLMOVE)
{ {
@ -177,31 +177,43 @@ void PT_ClientCmd(SINT8 nodenum, INT32 netconsole)
// Update the nettics // Update the nettics
node->tic = realend; node->tic = realend;
// Don't do anything for packets of type NODEKEEPALIVE? // This should probably still timeout though, as the node should always have a player 1 number
if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE if (netconsole == -1)
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
return; return;
// As long as clients send valid ticcmds, the server can keep running, so reset the timeout // 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? /// \todo Use a separate cvar for that kind of timeout?
node->freezetimeout = I_GetTime() + connectiontimeout; 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 // Copy ticcmd
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
// Splitscreen cmd // Splitscreen cmd
if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
&& node->player2 >= 0) && node->player2 >= 0)
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)node->player2], G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)node->player2],
&netbuffer->u.client2pak.cmd2, 1); &netbuffer->u.client2pak.cmd2, 1);
CheckTiccmdHacks(netconsole); CheckTiccmdHacks(netconsole, faketic);
CheckConsistancy(nodenum, realstart); CheckConsistancy(nodenum, realstart);
} }
void PT_ServerTics(SINT8 node, INT32 netconsole) void PT_ServerTics(SINT8 node, INT32 netconsole)
{ {
tic_t realend, realstart; tic_t realend, realstart;
servertics_pak *packet = &netbuffer->u.serverpak;
if (!netnodes[node].ingame) if (!netnodes[node].ingame)
{ {
@ -223,15 +235,16 @@ void PT_ServerTics(SINT8 node, INT32 netconsole)
return; return;
} }
realstart = netbuffer->u.serverpak.starttic; realstart = packet->starttic;
realend = realstart + netbuffer->u.serverpak.numtics; realend = realstart + packet->numtics;
realend = min(realend, gametic + CLIENTBACKUPTICS); realend = min(realend, gametic + CLIENTBACKUPTICS);
cl_packetmissed = realstart > neededtic; cl_packetmissed = realstart > neededtic;
if (realstart <= neededtic && realend > neededtic) if (realstart <= neededtic && realend > neededtic)
{ {
UINT8 *pak = (UINT8 *)&netbuffer->u.serverpak.cmds; UINT8 *pak = (UINT8 *)&packet->cmds;
UINT8 *txtpak = (UINT8 *)&packet->cmds[packet->numslots * packet->numtics];
for (tic_t i = realstart; i < realend; i++) for (tic_t i = realstart; i < realend; i++)
{ {
@ -240,9 +253,9 @@ void PT_ServerTics(SINT8 node, INT32 netconsole)
// copy the tics // copy the tics
pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak,
netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); packet->numslots*sizeof (ticcmd_t));
CL_CopyNetCommandsFromServerPacket(i); CL_CopyNetCommandsFromServerPacket(i, &txtpak);
} }
neededtic = realend; neededtic = realend;
@ -257,35 +270,39 @@ void PT_ServerTics(SINT8 node, INT32 netconsole)
void CL_SendClientCmd(void) void CL_SendClientCmd(void)
{ {
size_t packetsize = 0; size_t packetsize = 0;
boolean mis = false;
netbuffer->packettype = PT_CLIENTCMD; netbuffer->packettype = PT_CLIENTCMD;
if (cl_packetmissed) if (cl_packetmissed)
netbuffer->packettype++; {
netbuffer->packettype = PT_CLIENTMIS;
mis = true;
}
netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX);
netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX);
if (gamestate == GS_WAITINGPLAYERS) if (gamestate == GS_WAITINGPLAYERS)
{ {
// Send PT_NODEKEEPALIVE packet // Send PT_NODEKEEPALIVE packet
netbuffer->packettype += 4; netbuffer->packettype = (mis ? PT_NODEKEEPALIVEMIS : PT_NODEKEEPALIVE);
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
HSendPacket(servernode, false, 0, packetsize); HSendPacket(servernode, false, 0, packetsize);
} }
else if (gamestate != GS_NULL && (addedtogame || dedicated)) else if (gamestate != GS_NULL && (addedtogame || dedicated))
{ {
packetsize = sizeof (clientcmd_pak);
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
// Send a special packet with 2 cmd for splitscreen // Send a special packet with 2 cmd for splitscreen
if (splitscreen || botingame) if (splitscreen || botingame)
{ {
netbuffer->packettype += 2; netbuffer->packettype = (mis ? PT_CLIENT2MIS : PT_CLIENT2CMD);
G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1);
packetsize = sizeof (client2cmd_pak); packetsize = sizeof (client2cmd_pak);
G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1);
} }
else
packetsize = sizeof (clientcmd_pak);
HSendPacket(servernode, false, 0, packetsize); HSendPacket(servernode, false, 0, packetsize);
} }
@ -346,7 +363,7 @@ void SV_SendTics(void)
for (INT32 n = 1; n < MAXNETNODES; n++) for (INT32 n = 1; n < MAXNETNODES; n++)
if (netnodes[n].ingame) if (netnodes[n].ingame)
{ {
netnode_t *node = netnodes[n]; netnode_t *node = &netnodes[n];
// assert node->supposedtic>=node->tic // assert node->supposedtic>=node->tic
realfirsttic = node->supposedtic; realfirsttic = node->supposedtic;
@ -408,7 +425,7 @@ void Local_Maketic(INT32 realtics)
// and G_MapEventsToControls // and G_MapEventsToControls
if (!dedicated) if (!dedicated)
rendergametic = gametic; rendergametic = gametic;
// translate inputs (keyboard/mouse/gamepad) into game controls // translate inputs (keyboard/mouse/joystick) into game controls
G_BuildTiccmd(&localcmds, realtics, 1); G_BuildTiccmd(&localcmds, realtics, 1);
if (splitscreen || botingame) if (splitscreen || botingame)
G_BuildTiccmd(&localcmds2, realtics, 2); G_BuildTiccmd(&localcmds2, realtics, 2);

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior. // Copyright (C) 1999-2023 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -11,6 +11,8 @@
#include "snake.h" #include "snake.h"
#include "g_input.h" #include "g_input.h"
#include "g_game.h"
#include "i_joy.h"
#include "m_random.h" #include "m_random.h"
#include "s_sound.h" #include "s_sound.h"
#include "screen.h" #include "screen.h"
@ -67,6 +69,9 @@ typedef struct snake_s
enum bonustype_s bonustype; enum bonustype_s bonustype;
UINT8 bonusx; UINT8 bonusx;
UINT8 bonusy; UINT8 bonusy;
event_t *joyevents[MAXEVENTS];
UINT16 joyeventcount;
} snake_t; } snake_t;
static const char *bonuspatches[] = { static const char *bonuspatches[] = {
@ -113,6 +118,8 @@ static void Initialise(snake_t *snake)
snake->appley = M_RandomKey(NUM_BLOCKS_Y); snake->appley = M_RandomKey(NUM_BLOCKS_Y);
snake->bonustype = BONUS_NONE; snake->bonustype = BONUS_NONE;
snake->joyeventcount = 0;
} }
static UINT8 GetOppositeDir(UINT8 dir) static UINT8 GetOppositeDir(UINT8 dir)
@ -160,18 +167,19 @@ void Snake_Update(void *opaque)
UINT8 oldx, oldy; UINT8 oldx, oldy;
UINT16 i; UINT16 i;
UINT16 joystate = 0; UINT16 joystate = 0;
static INT32 pjoyx = 0, pjoyy = 0;
snake_t *snake = opaque; snake_t *snake = opaque;
// Handle retry // Handle retry
if (snake->gameover && (G_PlayerInputDown(0, GC_JUMP) || gamekeydown[KEY_ENTER])) if (snake->gameover && (PLAYER1INPUTDOWN(GC_JUMP) || gamekeydown[KEY_ENTER]))
{ {
Initialise(snake); Initialise(snake);
snake->pausepressed = true; // Avoid accidental pause on respawn snake->pausepressed = true; // Avoid accidental pause on respawn
} }
// Handle pause // Handle pause
if (G_PlayerInputDown(0, GC_PAUSE) || gamekeydown[KEY_ENTER]) if (PLAYER1INPUTDOWN(GC_PAUSE) || gamekeydown[KEY_ENTER])
{ {
if (!snake->pausepressed) if (!snake->pausepressed)
snake->paused = !snake->paused; snake->paused = !snake->paused;
@ -190,23 +198,58 @@ void Snake_Update(void *opaque)
oldx = snake->snakex[1]; oldx = snake->snakex[1];
oldy = snake->snakey[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 // Update direction
if (G_PlayerInputDown(0, GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3) if (PLAYER1INPUTDOWN(GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3)
{ {
if (snake->snakelength < 2 || x <= oldx) if (snake->snakelength < 2 || x <= oldx)
snake->snakedir[0] = 1; snake->snakedir[0] = 1;
} }
else if (G_PlayerInputDown(0, GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4) else if (PLAYER1INPUTDOWN(GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4)
{ {
if (snake->snakelength < 2 || x >= oldx) if (snake->snakelength < 2 || x >= oldx)
snake->snakedir[0] = 2; snake->snakedir[0] = 2;
} }
else if (G_PlayerInputDown(0, GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1) else if (PLAYER1INPUTDOWN(GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1)
{ {
if (snake->snakelength < 2 || y <= oldy) if (snake->snakelength < 2 || y <= oldy)
snake->snakedir[0] = 3; snake->snakedir[0] = 3;
} }
else if (G_PlayerInputDown(0, GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2) else if (PLAYER1INPUTDOWN(GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2)
{ {
if (snake->snakelength < 2 || y >= oldy) if (snake->snakelength < 2 || y >= oldy)
snake->snakedir[0] = 4; snake->snakedir[0] = 4;
@ -533,3 +576,18 @@ void Snake_Free(void **opaque)
*opaque = NULL; *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;
}

View file

@ -12,9 +12,12 @@
#ifndef __SNAKE__ #ifndef __SNAKE__
#define __SNAKE__ #define __SNAKE__
#include "d_event.h"
void Snake_Allocate(void **opaque); void Snake_Allocate(void **opaque);
void Snake_Update(void *opaque); void Snake_Update(void *opaque);
void Snake_Draw(void *opaque); void Snake_Draw(void *opaque);
void Snake_Free(void **opaque); void Snake_Free(void **opaque);
boolean Snake_JoyGrabber(void *opaque, event_t *ev);
#endif #endif