DEMO CODE
-When a demo is playing back, all NET_SendMessages are skipped, and
-NET_GetMessages are read from the demo file.
+When a demo is playing back, all outgoing network messages are skipped, and
+incoming messages are read from the demo file.
Whenever cl.time gets past the last received message, another message is
read from the demo file.
/*
====================
-CL_GetMessage
+CL_ReadDemoMessage
-Handles recording and playback of demos, on top of NET_ code
+Handles playback of demos
====================
*/
-int CL_GetMessage (void)
+void CL_ReadDemoMessage(void)
{
- int r, i;
- float f;
+ int r, i;
+ float f;
- if (cls.demoplayback)
- {
- if (cls.demopaused) // LordHavoc: pausedemo
- return 0;
+ if (!cls.demoplayback)
+ return;
+
+ // LordHavoc: pausedemo
+ if (cls.demopaused)
+ return;
// decide if it is time to grab the next message
- if (cls.signon == SIGNONS) // always grab until fully connected
+ // always grab until fully connected
+ if (cls.signon == SIGNONS)
+ {
+ if (cls.timedemo)
{
- if (cls.timedemo)
+ if (host_framecount == cls.td_lastframe)
{
- if (host_framecount == cls.td_lastframe)
- return 0; // already read this frame's message
- cls.td_lastframe = host_framecount;
+ // already read this frame's message
+ return;
+ }
+ cls.td_lastframe = host_framecount;
// if this is the second frame, grab the real td_starttime
// so the bogus time on the first frame doesn't count
- if (host_framecount == cls.td_startframe + 1)
- cls.td_starttime = realtime;
- }
- else if (cl.time <= cl.mtime[0])
- {
- return 0; // don't need another message yet
- }
- }
-
- // get the next message
- FS_Read (cls.demofile, &net_message.cursize, 4);
- VectorCopy (cl.mviewangles[0], cl.mviewangles[1]);
- for (i=0 ; i<3 ; i++)
- {
- r = FS_Read (cls.demofile, &f, 4);
- cl.mviewangles[0][i] = LittleFloat (f);
+ if (host_framecount == cls.td_startframe + 1)
+ cls.td_starttime = realtime;
}
-
- net_message.cursize = LittleLong (net_message.cursize);
- if (net_message.cursize > MAX_DATAGRAM)
- Host_Error ("Demo message > MAX_DATAGRAM");
- r = FS_Read (cls.demofile, net_message.data, net_message.cursize);
- if (r != net_message.cursize)
+ else if (cl.time <= cl.mtime[0])
{
- CL_Disconnect ();
- return 0;
+ // don't need another message yet
+ return;
}
-
- return 1;
}
- while (1)
+ // get the next message
+ FS_Read(cls.demofile, &net_message.cursize, 4);
+ net_message.cursize = LittleLong(net_message.cursize);
+ VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
+ for (i = 0;i < 3;i++)
{
- r = NET_GetMessage (cls.netcon);
-
- if (r != 1 && r != 2)
- return r;
-
- // discard nop keepalive message
- if (net_message.cursize == 1 && net_message.data[0] == svc_nop)
- Con_Printf ("<-- server to client keepalive\n");
- else
- break;
+ r = FS_Read(cls.demofile, &f, 4);
+ cl.mviewangles[0][i] = LittleFloat(f);
}
- if (cls.demorecording)
- CL_WriteDemoMessage ();
-
- return r;
+ if (net_message.cursize > NET_MAXMESSAGE)
+ Host_Error("Demo message > NET_MAXMESSAGE");
+ if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == (size_t)net_message.cursize)
+ {
+ MSG_BeginReading();
+ CL_ParseServerMessage();
+ }
+ else
+ CL_Disconnect();
}
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
{
float val;
qboolean impulsedown, impulseup, down;
-
+
impulsedown = key->state & 2;
impulseup = key->state & 4;
down = key->state & 1;
val = 0;
-
+
if (impulsedown && !impulseup)
{
if (down)
}
key->state &= 1; // clear impulses
-
+
return val;
}
================
*/
void CL_BaseMove (usercmd_t *cmd)
-{
+{
if (cls.signon != SIGNONS)
return;
-
+
CL_AdjustAngles ();
-
+
memset (cmd, 0, sizeof(*cmd));
-
+
if (in_strafe.state & 1)
{
cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
if (! (in_klook.state & 1) )
- {
+ {
cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
- }
+ }
//
// adjust for speed key
CL_SendMove
==============
*/
-void CL_SendMove (usercmd_t *cmd)
+void CL_SendMove(usercmd_t *cmd)
{
- int i;
- int bits;
- sizebuf_t buf;
- qbyte data[128];
+ int i;
+ int bits;
+ sizebuf_t buf;
+ qbyte data[128];
static double lastmovetime;
static float forwardmove, sidemove, upmove, total; // accumulation
cl.cmd = *cmd;
-//
-// send the movement message
-//
- MSG_WriteByte (&buf, clc_move);
+ // send the movement message
+ MSG_WriteByte (&buf, clc_move);
MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
MSG_WriteAngle (&buf, cl.viewangles[i]);
}
- MSG_WriteShort (&buf, forwardmove);
- MSG_WriteShort (&buf, sidemove);
- MSG_WriteShort (&buf, upmove);
+ MSG_WriteShort (&buf, forwardmove);
+ MSG_WriteShort (&buf, sidemove);
+ MSG_WriteShort (&buf, upmove);
forwardmove = sidemove = upmove = 0;
-//
-// send button bits
-//
+ // send button bits
bits = 0;
if ( in_attack.state & 3 )
if (in_button7.state & 3) bits |= 64;in_button7.state &= ~2;
if (in_button8.state & 3) bits |= 128;in_button8.state &= ~2;
- MSG_WriteByte (&buf, bits);
+ MSG_WriteByte (&buf, bits);
- MSG_WriteByte (&buf, in_impulse);
+ MSG_WriteByte (&buf, in_impulse);
in_impulse = 0;
// LordHavoc: should we ack this on receipt instead? would waste net bandwidth though
i = EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase);
if (i > 0)
{
- MSG_WriteByte (&buf, clc_ackentities);
- MSG_WriteLong (&buf, i);
+ MSG_WriteByte(&buf, clc_ackentities);
+ MSG_WriteLong(&buf, i);
}
-//
-// deliver the message
-//
+ // deliver the message
if (cls.demoplayback)
return;
-//
-// always dump the first two messages, because they may contain leftover inputs from the last level
-//
+ // always dump the first two messages, because they may contain leftover inputs from the last level
if (++cl.movemessages <= 2)
return;
- if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
+ if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
{
- Con_Printf ("CL_SendMove: lost server connection\n");
- CL_Disconnect ();
+ Con_Printf("CL_SendMove: lost server connection\n");
+ CL_Disconnect();
}
}
// we need to declare some mouse variables here, because the menu system
// references them even when on a unix system.
-// these two are not intended to be set directly
-cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player"};
-cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
-cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
-
cvar_t cl_shownet = {0, "cl_shownet","0"};
cvar_t cl_nolerp = {0, "cl_nolerp", "0"};
cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0"};
-mempool_t *cl_scores_mempool;
mempool_t *cl_refdef_mempool;
mempool_t *cl_entities_mempool;
if (!sv.active)
Host_ClearMemory ();
- Mem_EmptyPool(cl_scores_mempool);
Mem_EmptyPool(cl_entities_mempool);
// wipe the entire cl structure
This is also called on Host_Error, so it shouldn't cause any errors
=====================
*/
-void CL_Disconnect (void)
+void CL_Disconnect(void)
{
if (cls.state == ca_dedicated)
return;
cl.worldmodel = NULL;
if (cls.demoplayback)
- CL_StopPlayback ();
- else if (cls.state == ca_connected)
+ CL_StopPlayback();
+ else if (cls.netcon)
{
if (cls.demorecording)
- CL_Stop_f ();
-
- Con_DPrintf ("Sending clc_disconnect\n");
- SZ_Clear (&cls.message);
- MSG_WriteByte (&cls.message, clc_disconnect);
- NET_SendUnreliableMessage (cls.netcon, &cls.message);
- SZ_Clear (&cls.message);
- NET_Close (cls.netcon);
- cls.state = ca_disconnected; // prevent this code from executing again during Host_ShutdownServer
+ CL_Stop_f();
+
+ Con_DPrintf("Sending clc_disconnect\n");
+ SZ_Clear(&cls.message);
+ MSG_WriteByte(&cls.message, clc_disconnect);
+ NetConn_SendUnreliableMessage(cls.netcon, &cls.message);
+ SZ_Clear(&cls.message);
+ NetConn_Close(cls.netcon);
+ cls.netcon = NULL;
// if running a local server, shut it down
if (sv.active)
+ {
+ // prevent this code from executing again during Host_ShutdownServer
+ cls.state = ca_disconnected;
Host_ShutdownServer(false);
+ }
}
cls.state = ca_disconnected;
=====================
CL_EstablishConnection
-Host should be either "local" or a net address to be passed on
+Host should be either "local" or a net address
=====================
*/
-void CL_EstablishConnection (char *host)
+void CL_EstablishConnection(const char *host)
{
if (cls.state == ca_dedicated)
return;
- if (cls.demoplayback)
- return;
-
- CL_Disconnect ();
-
- cls.netcon = NET_Connect (host);
- if (!cls.netcon)
- Host_Error ("CL_Connect: connect failed\n");
- Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
+ // clear menu's connect error message
+ m_return_reason[0] = 0;
- cls.demonum = -1; // not in the demo loop now
- cls.state = ca_connected;
- cls.signon = 0; // need all the signon messages before playing
+ // stop demo loop in case this fails
+ cls.demonum = -1;
+ CL_Disconnect();
- CL_ClearState ();
+ if (LHNETADDRESS_FromString(&cls.connect_address, host, 26000) && (cls.connect_mysocket = NetConn_ChooseClientSocketForAddress(&cls.connect_address)))
+ {
+ cls.connect_trying = true;
+ cls.connect_remainingtries = 3;
+ cls.connect_nextsendtime = 0;
+ if (sv.active)
+ {
+ NetConn_ClientFrame();
+ NetConn_ServerFrame();
+ NetConn_ClientFrame();
+ NetConn_ServerFrame();
+ NetConn_ClientFrame();
+ NetConn_ServerFrame();
+ NetConn_ClientFrame();
+ NetConn_ServerFrame();
+ }
+ }
}
/*
Read all incoming data from the server
===============
*/
-int CL_ReadFromServer (void)
+int CL_ReadFromServer(void)
{
- int ret, netshown;
-
- cl.oldtime = cl.time;
- cl.time += cl.frametime;
-
- netshown = false;
- do
- {
- ret = CL_GetMessage ();
- if (ret == -1)
- Host_Error ("CL_ReadFromServer: lost server connection");
- if (!ret)
- break;
-
- cl.last_received_message = realtime;
-
- if (cl_shownet.integer)
- netshown = true;
-
- CL_ParseServerMessage ();
- }
- while (ret && cls.state == ca_connected);
-
- if (netshown)
- Con_Printf ("\n");
+ CL_ReadDemoMessage();
r_refdef.numentities = 0;
cl_num_entities = 0;
if (cls.state == ca_connected && cls.signon == SIGNONS)
{
- CL_RelinkEntities ();
+ CL_RelinkEntities();
// run cgame code (which can add more entities)
CL_CGVM_Frame();
}
-//
-// bring the links up to date
-//
return 0;
}
CL_SendCmd
=================
*/
-void CL_SendCmd (void)
+void CL_SendCmd(void)
{
- usercmd_t cmd;
-
- if (cls.state != ca_connected)
- return;
+ usercmd_t cmd;
if (cls.signon == SIGNONS)
{
- // get basic movement from keyboard
- CL_BaseMove (&cmd);
+ // get basic movement from keyboard
+ CL_BaseMove(&cmd);
- IN_PreMove(); // OS independent code
+ // OS independent code
+ IN_PreMove();
- // allow mice or other external controllers to add to the move
- IN_Move (&cmd);
+ // allow mice or other external controllers to add to the move
+ IN_Move(&cmd);
- IN_PostMove(); // OS independent code
+ // OS independent code
+ IN_PostMove();
- // send the unreliable message
- CL_SendMove (&cmd);
- }
- else if (cls.signon == 0 && !cls.demoplayback)
- {
- // LordHavoc: fix for NAT routing of netquake:
- // bounce back a clc_nop message to the newly allocated server port,
- // to establish a routing connection for incoming frames,
- // the server waits for this before sending anything
- if (realtime > cl.sendnoptime)
- {
- cl.sendnoptime = realtime + 3;
- Con_DPrintf("sending clc_nop to get server's attention\n");
- {
- sizebuf_t buf;
- qbyte data[128];
- buf.maxsize = 128;
- buf.cursize = 0;
- buf.data = data;
- MSG_WriteByte(&buf, clc_nop);
- if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
- {
- Con_Printf ("CL_SendCmd: lost server connection\n");
- CL_Disconnect ();
- }
- }
- }
+ // send the unreliable message
+ CL_SendMove(&cmd);
}
if (cls.demoplayback)
{
- SZ_Clear (&cls.message);
+ SZ_Clear(&cls.message);
return;
}
-// send the reliable message
- if (!cls.message.cursize)
- return; // no message at all
-
- if (!NET_CanSendMessage (cls.netcon))
+ // send the reliable message (forwarded commands) if there is one
+ if (cls.message.cursize && NetConn_CanSendMessage(cls.netcon))
{
- Con_DPrintf ("CL_WriteToServer: can't send\n");
if (developer.integer)
+ {
+ Con_Printf("CL_SendCmd: sending reliable message:\n");
SZ_HexDumpToConsole(&cls.message);
- return;
+ }
+ if (NetConn_SendReliableMessage(cls.netcon, &cls.message) == -1)
+ Host_Error("CL_WriteToServer: lost server connection");
+ SZ_Clear(&cls.message);
}
-
- if (NET_SendMessage (cls.netcon, &cls.message) == -1)
- Host_Error ("CL_WriteToServer: lost server connection");
-
- SZ_Clear (&cls.message);
}
// LordHavoc: pausedemo command
Con_Printf("Demo unpaused\n");
}
-/*
-======================
-CL_PModel_f
-LordHavoc: Intended for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
-======================
-*/
-static void CL_PModel_f (void)
-{
- int i;
- eval_t *val;
-
- if (Cmd_Argc () == 1)
- {
- Con_Printf ("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
- return;
- }
- i = atoi(Cmd_Argv(1));
-
- if (cmd_source == src_command)
- {
- if (cl_pmodel.integer == i)
- return;
- Cvar_SetValue ("_cl_pmodel", i);
- if (cls.state == ca_connected)
- Cmd_ForwardToServer ();
- return;
- }
-
- host_client->pmodel = i;
- if ((val = GETEDICTFIELDVALUE(sv_player, eval_pmodel)))
- val->_float = i;
-}
-
/*
======================
CL_Fog_f
*/
void CL_Init (void)
{
- cl_scores_mempool = Mem_AllocPool("client player info");
cl_entities_mempool = Mem_AllocPool("client entities");
cl_refdef_mempool = Mem_AllocPool("refdef");
//
// register our commands
//
- Cvar_RegisterVariable (&cl_name);
- Cvar_RegisterVariable (&cl_color);
- if (gamemode == GAME_NEHAHRA)
- Cvar_RegisterVariable (&cl_pmodel);
Cvar_RegisterVariable (&cl_upspeed);
Cvar_RegisterVariable (&cl_forwardspeed);
Cvar_RegisterVariable (&cl_backspeed);
// LordHavoc: added pausedemo
Cmd_AddCommand ("pausedemo", CL_PauseDemo_f);
- if (gamemode == GAME_NEHAHRA)
- Cmd_AddCommand ("pmodel", CL_PModel_f);
Cvar_RegisterVariable(&r_draweffects);
Cvar_RegisterVariable(&cl_explosions);
qboolean Nehahrademcompatibility; // LordHavoc: to allow playback of the early Nehahra movie segments
int dpprotocol; // LordHavoc: version of network protocol, or 0 if not DarkPlaces
+mempool_t *cl_scores_mempool;
+
/*
==================
CL_ParseStartSoundPacket
so the server doesn't disconnect.
==================
*/
+
+static qbyte olddata[NET_MAXMESSAGE];
void CL_KeepaliveMessage (void)
{
- float time;
+ float time;
static float lastmsg;
- int ret;
- int c;
- sizebuf_t old;
- qbyte olddata[8192];
-
- if (sv.active)
- return; // no need if server is local
- if (cls.demoplayback)
+ int oldreadcount;
+ qboolean oldbadread;
+ sizebuf_t old;
+
+ // no need if server is local and definitely not if this is a demo
+ if (sv.active || cls.demoplayback)
return;
// read messages from server, should just be nops
+ oldreadcount = msg_readcount;
+ oldbadread = msg_badread;
old = net_message;
- memcpy (olddata, net_message.data, net_message.cursize);
+ memcpy(olddata, net_message.data, net_message.cursize);
- do
- {
- ret = CL_GetMessage ();
- switch (ret)
- {
- default:
- Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
- case 0:
- break; // nothing waiting
- case 1:
- Host_Error ("CL_KeepaliveMessage: received a message");
- break;
- case 2:
- c = MSG_ReadByte();
- if (c != svc_nop)
- Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
- break;
- }
- } while (ret);
+ NetConn_ClientFrame();
+ msg_readcount = oldreadcount;
+ msg_badread = oldbadread;
net_message = old;
- memcpy (net_message.data, olddata, net_message.cursize);
-
-// check time
- time = Sys_DoubleTime ();
- if (time - lastmsg < 5)
- return;
- lastmsg = time;
-
-// write out a nop
- Con_Printf ("--> client to server keepalive\n");
+ memcpy(net_message.data, olddata, net_message.cursize);
- MSG_WriteByte (&cls.message, clc_nop);
- NET_SendMessage (cls.netcon, &cls.message);
- SZ_Clear (&cls.message);
+ if (cls.netcon && NetConn_CanSendMessage(cls.netcon) && (time = Sys_DoubleTime()) - lastmsg >= 5)
+ {
+ lastmsg = time;
+ // write out a nop
+ Con_Printf("--> client to server keepalive\n");
+ MSG_WriteByte(&cls.message, clc_nop);
+ NetConn_SendReliableMessage(cls.netcon, &cls.message);
+ SZ_Clear(&cls.message);
+ // try not to utterly crush the computer with work, that's just rude
+ Sys_Sleep();
+ }
}
void CL_ParseEntityLump(char *entdata)
Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
return;
}
+ Mem_EmptyPool(cl_scores_mempool);
cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
// parse gametype
=====================
*/
int parsingerror = false;
-void CL_ParseServerMessage (void)
+void CL_ParseServerMessage(void)
{
int cmd;
int i, entitiesupdated;
char *cmdlogname[32], *temp;
int cmdindex, cmdcount = 0;
+ if (cls.demorecording)
+ CL_WriteDemoMessage ();
+
+ cl.last_received_message = realtime;
+
//
// if recording demos, copy the message out
//
if (cl_shownet.integer == 1)
- Con_Printf ("%i ",net_message.cursize);
+ Con_Printf ("%f %i\n", realtime, net_message.cursize);
else if (cl_shownet.integer == 2)
Con_Printf ("------------------\n");
//
// parse the message
//
- MSG_BeginReading ();
+ //MSG_BeginReading ();
entitiesupdated = false;
break;
case svc_nop:
+ if (cls.signon < SIGNONS)
+ Con_Printf("<-- server to client keepalive\n");
break;
case svc_time:
void CL_Parse_Init(void)
{
// LordHavoc: added demo_nehahra cvar
+ cl_scores_mempool = Mem_AllocPool("client player info");
Cvar_RegisterVariable (&demo_nehahra);
if (gamemode == GAME_NEHAHRA)
Cvar_SetValue("demo_nehahra", 1);
if (count < 3)
return;
- DrawQ_Pic (0, 0, "turtle", 0, 0, 1, 1, 1, 1, 0);
+ DrawQ_Pic (0, 0, "gfx/turtle.lmp", 0, 0, 1, 1, 1, 1, 0);
}
/*
if (cls.demoplayback)
return;
- DrawQ_Pic (64, 0, "net", 0, 0, 1, 1, 1, 1, 0);
+ DrawQ_Pic (64, 0, "gfx/net.lmp", 0, 0, 1, 1, 1, 1, 0);
}
/*
// LordHavoc: pausedemo
qboolean demopaused;
+ qboolean connect_trying;
+ int connect_remainingtries;
+ double connect_nextsendtime;
+ lhnetsocket_t *connect_mysocket;
+ lhnetaddress_t connect_address;
// connection information
// 0 to SIGNONS
int signon;
- // network socket
- struct qsocket_s *netcon;
+ // network connection
+ netconn_t *netcon;
// writing buffer to send to server
sizebuf_t message;
}
void CL_Init (void);
-void CL_EstablishConnection (char *host);
+void CL_EstablishConnection(const char *host);
void CL_Disconnect (void);
void CL_Disconnect_f (void);
//
// cl_demo.c
//
-void CL_StopPlayback (void);
-int CL_GetMessage (void);
-
-void CL_NextDemo (void);
-void CL_Stop_f (void);
-void CL_Record_f (void);
-void CL_PlayDemo_f (void);
-void CL_TimeDemo_f (void);
+void CL_StopPlayback(void);
+void CL_ReadDemoMessage(void);
+void CL_WriteDemoMessage(void);
+
+void CL_NextDemo(void);
+void CL_Stop_f(void);
+void CL_Record_f(void);
+void CL_PlayDemo_f(void);
+void CL_TimeDemo_f(void);
//
// cl_parse.c
return false;
return true;
}
+
+// written by Elric, thanks Elric!
+char *SearchInfostring(const char *infostring, const char *key)
+{
+ static char value [256];
+ char crt_key [256];
+ size_t value_ind, key_ind;
+ char c;
+
+ if (*infostring++ != '\\')
+ return NULL;
+
+ value_ind = 0;
+ for (;;)
+ {
+ key_ind = 0;
+
+ // Get the key name
+ for (;;)
+ {
+ c = *infostring++;
+
+ if (c == '\0')
+ return NULL;
+ if (c == '\\')
+ {
+ crt_key[key_ind] = '\0';
+ break;
+ }
+
+ crt_key[key_ind++] = c;
+ }
+
+ // If it's the key we are looking for, save it in "value"
+ if (!strcmp(crt_key, key))
+ {
+ for (;;)
+ {
+ c = *infostring++;
+
+ if (c == '\0' || c == '\\')
+ {
+ value[value_ind] = '\0';
+ return value;
+ }
+
+ value[value_ind++] = c;
+ }
+ }
+
+ // Else, skip the value
+ for (;;)
+ {
+ c = *infostring++;
+
+ if (c == '\0')
+ return NULL;
+ if (c == '\\')
+ break;
+ }
+ }
+}
+
stringlist_t *listdirectory(char *path);
void freedirectory(stringlist_t *list);
+char *SearchInfostring(const char *infostring, const char *key);
+
#endif
CL_Disconnect ();
cls.demonum = -1;
- // unload any partially loaded models
- Mod_ClearErrorModels();
-
hosterror = false;
longjmp (host_abortserver, 1);
FIXME: make this just a stuffed echo?
=================
*/
-void SV_ClientPrintf (const char *fmt, ...)
+void SV_ClientPrintf(const char *fmt, ...)
{
va_list argptr;
char string[1024];
Sends text to all active clients
=================
*/
-void SV_BroadcastPrintf (const char *fmt, ...)
+void SV_BroadcastPrintf(const char *fmt, ...)
{
va_list argptr;
char string[1024];
int i;
- va_start (argptr,fmt);
- vsprintf (string, fmt,argptr);
- va_end (argptr);
+ va_start(argptr,fmt);
+ vsprintf(string, fmt,argptr);
+ va_end(argptr);
for (i=0 ; i<svs.maxclients ; i++)
if (svs.clients[i].active && svs.clients[i].spawned)
{
- MSG_WriteByte (&svs.clients[i].message, svc_print);
- MSG_WriteString (&svs.clients[i].message, string);
+ MSG_WriteByte(&svs.clients[i].message, svc_print);
+ MSG_WriteString(&svs.clients[i].message, string);
}
if (sv_echobprint.integer && cls.state == ca_dedicated)
- Sys_Printf ("%s", string);
+ Sys_Printf("%s", string);
}
/*
Send text over to the client to be executed
=================
*/
-void Host_ClientCommands (const char *fmt, ...)
+void Host_ClientCommands(const char *fmt, ...)
{
va_list argptr;
char string[1024];
- va_start (argptr,fmt);
- vsprintf (string, fmt,argptr);
- va_end (argptr);
+ va_start(argptr,fmt);
+ vsprintf(string, fmt,argptr);
+ va_end(argptr);
- MSG_WriteByte (&host_client->message, svc_stufftext);
- MSG_WriteString (&host_client->message, string);
+ MSG_WriteByte(&host_client->message, svc_stufftext);
+ MSG_WriteString(&host_client->message, string);
}
/*
if (crash = true), don't bother sending signofs
=====================
*/
-void SV_DropClient (qboolean crash)
+void SV_DropClient(qboolean crash)
{
int saveSelf;
int i;
client_t *client;
- Con_Printf ("Client \"%s\" dropped\n", host_client->name);
+ Con_Printf("Client \"%s\" dropped\n", host_client->name);
- if (!crash)
+ // send any final messages (don't check for errors)
+ if (host_client->netconnection)
{
- // send any final messages (don't check for errors)
- if (host_client->netconnection && !host_client->netconnection->disconnected)
+ // free the client (the body stays around)
+ host_client->active = false;
+
+ if (!crash)
{
-#if 1
- // LordHavoc: no opportunity for resending, so reliable is silly
- MSG_WriteByte (&host_client->message, svc_disconnect);
- NET_SendUnreliableMessage (host_client->netconnection, &host_client->message);
-#else
- if (NET_CanSendMessage (host_client->netconnection))
- {
- MSG_WriteByte (&host_client->message, svc_disconnect);
- NET_SendMessage (host_client->netconnection, &host_client->message);
- }
-#endif
+ // LordHavoc: no opportunity for resending, so use unreliable
+ MSG_WriteByte(&host_client->message, svc_disconnect);
+ NetConn_SendUnreliableMessage(host_client->netconnection, &host_client->message);
}
- }
-// break the net connection
- NET_Close (host_client->netconnection);
- host_client->netconnection = NULL;
+ // break the net connection
+ NetConn_Close(host_client->netconnection);
+ host_client->netconnection = NULL;
-// free the client (the body stays around)
- host_client->active = false;
- // note: don't clear name yet
- net_activeconnections--;
-
- if (sv.active && host_client->edict && host_client->spawned) // LordHavoc: don't call QC if server is dead (avoids recursive Host_Error in some mods when they run out of edicts)
- {
- // call the prog function for removing a client
- // this will set the body to a dead frame, among other things
- saveSelf = pr_global_struct->self;
- pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
- PR_ExecuteProgram (pr_global_struct->ClientDisconnect, "QC function ClientDisconnect is missing");
- pr_global_struct->self = saveSelf;
+ // LordHavoc: don't call QC if server is dead (avoids recursive
+ // Host_Error in some mods when they run out of edicts)
+ if (sv.active && host_client->edict && host_client->spawned)
+ {
+ // call the prog function for removing a client
+ // this will set the body to a dead frame, among other things
+ saveSelf = pr_global_struct->self;
+ pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
+ PR_ExecuteProgram(pr_global_struct->ClientDisconnect, "QC function ClientDisconnect is missing");
+ pr_global_struct->self = saveSelf;
+ }
}
// now clear name (after ClientDisconnect was called)
host_client->old_frags = -999999;
// send notification to all clients
- for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
+ for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
{
if (!client->active)
continue;
- MSG_WriteByte (&client->message, svc_updatename);
- MSG_WriteByte (&client->message, host_client - svs.clients);
- MSG_WriteString (&client->message, "");
- MSG_WriteByte (&client->message, svc_updatefrags);
- MSG_WriteByte (&client->message, host_client - svs.clients);
- MSG_WriteShort (&client->message, 0);
- MSG_WriteByte (&client->message, svc_updatecolors);
- MSG_WriteByte (&client->message, host_client - svs.clients);
- MSG_WriteByte (&client->message, 0);
+ MSG_WriteByte(&client->message, svc_updatename);
+ MSG_WriteByte(&client->message, host_client - svs.clients);
+ MSG_WriteString(&client->message, "");
+ MSG_WriteByte(&client->message, svc_updatefrags);
+ MSG_WriteByte(&client->message, host_client - svs.clients);
+ MSG_WriteShort(&client->message, 0);
+ MSG_WriteByte(&client->message, svc_updatecolors);
+ MSG_WriteByte(&client->message, host_client - svs.clients);
+ MSG_WriteByte(&client->message, 0);
}
- NET_Heartbeat (1);
+ NetConn_Heartbeat(1);
}
/*
sv.active = false;
// stop all client sounds immediately
- CL_Disconnect ();
+ CL_Disconnect();
- NET_Heartbeat (2);
- NET_Heartbeat (2);
+ NetConn_Heartbeat(2);
+ NetConn_Heartbeat(2);
// flush any pending messages - like the score!!!
start = Sys_DoubleTime();
do
{
count = 0;
+ NetConn_ClientFrame();
+ NetConn_ServerFrame();
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
{
if (host_client->active && host_client->message.cursize)
{
- if (NET_CanSendMessage (host_client->netconnection))
+ if (NetConn_CanSendMessage(host_client->netconnection))
{
- NET_SendMessage(host_client->netconnection, &host_client->message);
- SZ_Clear (&host_client->message);
+ NetConn_SendReliableMessage(host_client->netconnection, &host_client->message);
+ SZ_Clear(&host_client->message);
}
else
- {
- NET_GetMessage(host_client->netconnection);
count++;
- }
}
}
if ((Sys_DoubleTime() - start) > 3.0)
break;
}
- while (count);
+ while(count);
// make sure all the clients know we're disconnecting
buf.data = message;
buf.maxsize = 4;
buf.cursize = 0;
MSG_WriteByte(&buf, svc_disconnect);
- count = NET_SendToAll(&buf, 5);
+ count = NetConn_SendToAll(&buf, 5);
if (count)
- Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count);
+ Con_Printf("Host_ShutdownServer: NetConn_SendToAll failed for %u clients\n", count);
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
if (host_client->active)
SV_DropClient(crash); // server shutdown
+ NetConn_CloseServerPorts();
+
//
// clear structures
//
- memset (&sv, 0, sizeof(sv));
- memset (svs.clients, 0, svs.maxclients * sizeof(client_t));
+ memset(&sv, 0, sizeof(sv));
+ memset(svs.clients, 0, svs.maxclients * sizeof(client_t));
}
// LordHavoc: cap server at sys_ticrate in listen games
if (cls.state != ca_dedicated && svs.maxclients > 1 && ((realtime - lastservertime) < sys_ticrate.value))
return;
+
+ NetConn_ServerFrame();
+
// run the world state
if (!sv.paused && (svs.maxclients > 1 || (key_dest == key_game && !key_consoleactive)))
sv.frametime = pr_global_struct->frametime = frametimetotal;
lastservertime = realtime;
// set the time and clear the general datagram
- SV_ClearDatagram ();
-
-// check for new clients
- SV_CheckForNewClients ();
+ SV_ClearDatagram();
// read client messages
- SV_RunClients ();
+ SV_RunClients();
// move things around and think
// always pause in single player if in console or menus
if (sv.frametime)
- SV_Physics ();
+ SV_Physics();
// send all messages to the clients
- SV_SendClientMessages ();
+ SV_SendClientMessages();
// send an heartbeat if enough time has passed since the last one
- NET_Heartbeat (0);
+ NetConn_Heartbeat(0);
}
static double time3 = 0;
int pass1, pass2, pass3;
- if (setjmp (host_abortserver) )
+ if (setjmp(host_abortserver))
return; // something bad happened, or the server disconnected
-// keep the random time dependent
- rand ();
+ // keep the random time dependent
+ rand();
-// decide the simulation time
- if (!Host_FilterTime (time))
+ // decide the simulation time
+ if (!Host_FilterTime(time))
{
// if time was rejected, don't totally hog the CPU
Sys_Sleep();
return;
}
-// get new key events
- Sys_SendKeyEvents ();
+ // get new key events
+ Sys_SendKeyEvents();
-// allow mice or other external controllers to add commands
- IN_Commands ();
+ // allow mice or other external controllers to add commands
+ IN_Commands();
-// process console commands
- Cbuf_Execute ();
+ // process console commands
+ Cbuf_Execute();
// LordHavoc: map and load are delayed until video is initialized
Host_PerformSpawnServerAndLoadGame();
- NET_Poll();
-
-// if running the server locally, make intentions now
- if (sv.active)
- CL_SendCmd ();
+ // if running the server locally, make intentions now
+ if (cls.state == ca_connected && sv.active)
+ CL_SendCmd();
//-------------------
//
//
//-------------------
-// check for commands typed to the host
- Host_GetConsoleCommands ();
+ // check for commands typed to the host
+ Host_GetConsoleCommands();
if (sv.active)
- Host_ServerFrame ();
+ Host_ServerFrame();
//-------------------
//
//
//-------------------
-// if running the server remotely, send intentions now after
-// the incoming messages have been read
- if (!sv.active)
- CL_SendCmd ();
+ cl.oldtime = cl.time;
+ cl.time += cl.frametime;
+
+ NetConn_ClientFrame();
-// fetch results from server
if (cls.state == ca_connected)
- CL_ReadFromServer ();
+ {
+ // if running the server remotely, send intentions now after
+ // the incoming messages have been read
+ if (!sv.active)
+ CL_SendCmd();
+ CL_ReadFromServer();
+ }
ui_update();
CL_VideoFrame();
-// update video
+ // update video
if (host_speeds.integer)
- time1 = Sys_DoubleTime ();
+ time1 = Sys_DoubleTime();
- CL_UpdateScreen ();
+ CL_UpdateScreen();
if (host_speeds.integer)
- time2 = Sys_DoubleTime ();
+ time2 = Sys_DoubleTime();
-// update audio
+ // update audio
if (cls.signon == SIGNONS)
{
// LordHavoc: this used to use renderer variables (eww)
vec3_t forward, right, up;
AngleVectors(cl.viewangles, forward, right, up);
- S_Update (cl_entities[cl.viewentity].render.origin, forward, right, up);
+ S_Update(cl_entities[cl.viewentity].render.origin, forward, right, up);
}
else
- S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
+ S_Update(vec3_origin, vec3_origin, vec3_origin, vec3_origin);
CDAudio_Update();
if (host_speeds.integer)
{
pass1 = (time1 - time3)*1000000;
- time3 = Sys_DoubleTime ();
+ time3 = Sys_DoubleTime();
pass2 = (time2 - time1)*1000000;
pass3 = (time3 - time2)*1000000;
- Con_Printf ("%6ius total %6ius server %6ius gfx %6ius snd\n",
+ Con_Printf("%6ius total %6ius server %6ius gfx %6ius snd\n",
pass1+pass2+pass3, pass1, pass2, pass3);
}
developer.value = 1;
}
- Cmd_Init ();
+ Cmd_Init();
Memory_Init_Commands();
R_Modules_Init();
- Cbuf_Init ();
- V_Init ();
- COM_Init ();
- Host_InitLocal ();
- W_LoadWadFile ("gfx.wad");
- Key_Init ();
- Con_Init ();
- Chase_Init ();
- M_Init ();
- PR_Init ();
- Mod_Init ();
- NET_Init ();
- SV_Init ();
+ Cbuf_Init();
+ V_Init();
+ COM_Init();
+ Host_InitLocal();
+ W_LoadWadFile("gfx.wad");
+ Key_Init();
+ Con_Init();
+ Chase_Init();
+ M_Init();
+ PR_Init();
+ Mod_Init();
+ NetConn_Init();
+ SV_Init();
Con_Printf ("Builddate: %s\n", buildstring);
VID_Init();
Render_Init();
- S_Init ();
- CDAudio_Init ();
- CL_Init ();
+ S_Init();
+ CDAudio_Init();
+ CL_Init();
}
Cbuf_InsertText ("exec quake.rc\n");
- Cbuf_Execute ();
- Cbuf_Execute ();
- Cbuf_Execute ();
- Cbuf_Execute ();
+ Cbuf_Execute();
+ Cbuf_Execute();
+ Cbuf_Execute();
+ Cbuf_Execute();
host_initialized = true;
Host_WriteConfiguration ();
CDAudio_Shutdown ();
- NET_Shutdown ();
+ NetConn_Shutdown ();
S_Shutdown();
if (cls.state != ca_dedicated)
void Host_Status_f (void)
{
client_t *client;
- int seconds, minutes, hours = 0, j;
+ int seconds, minutes, hours = 0, j, players;
void (*print) (const char *fmt, ...);
if (cmd_source == src_command)
else
print = SV_ClientPrintf;
+ for (players = 0, j = 0;j < svs.maxclients;j++)
+ if (svs.clients[j].active)
+ players++;
print ("host: %s\n", Cvar_VariableString ("hostname"));
print ("version: %s build %s\n", gamename, buildstring);
- if (tcpipAvailable)
- print ("tcp/ip: %s\n", my_tcpip_address);
- if (ipxAvailable)
- print ("ipx: %s\n", my_ipx_address);
print ("map: %s\n", sv.name);
- print ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients);
+ print ("players: %i active (%i max)\n\n", players, svs.maxclients);
for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
{
if (!client->active)
continue;
- seconds = (int)(net_time - client->netconnection->connecttime);
+ seconds = (int)(realtime - client->netconnection->connecttime);
minutes = seconds / 60;
if (minutes)
{
*/
void Host_Reconnect_f (void)
{
- SCR_BeginLoadingPlaque ();
+ SCR_BeginLoadingPlaque();
cls.signon = 0; // need new connection messages
}
*/
void Host_Connect_f (void)
{
- char name[MAX_QPATH];
-
- cls.demonum = -1; // stop demo loop in case this fails
- if (cls.demoplayback)
- CL_Disconnect ();
- strcpy (name, Cmd_Argv(1));
- CL_EstablishConnection (name);
- Host_Reconnect_f ();
+ CL_EstablishConnection(Cmd_Argv(1));
}
str = FS_Getline (f);
sscanf (str, "%f\n",&time);
- CL_Disconnect_f ();
-
SV_SpawnServer (mapname);
if (!sv.active)
{
for (i = 0;i < NUM_SPAWN_PARMS;i++)
svs.clients->spawn_parms[i] = spawn_parms[i];
- if (cls.state != ca_dedicated)
- {
- CL_EstablishConnection ("local");
- Host_Reconnect_f ();
- }
+ // make sure we're connected to loopback
+ if (cls.state == ca_disconnected || !(cls.state == ca_connected && cls.netcon != NULL && LHNETADDRESS_GetAddressType(&cls.netcon->peeraddress) == LHNETADDRESSTYPE_LOOP))
+ CL_EstablishConnection("local");
}
//============================================================================
Host_Name_f
======================
*/
+cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player"};
void Host_Name_f (void)
{
- char newName[64];
+ char newName[sizeof(host_client->name)];
if (Cmd_Argc () == 1)
{
}
if (Cmd_Argc () == 2)
- strncpy(newName, Cmd_Argv(1), 15);
+ strncpy(newName, Cmd_Argv(1), sizeof(host_client->name) - 1);
else
- strncpy(newName, Cmd_Args(), 15);
- newName[15] = 0;
+ strncpy(newName, Cmd_Args(), sizeof(host_client->name) - 1);
+ newName[sizeof(host_client->name) - 1] = 0;
if (cmd_source == src_command)
{
if (strcmp(host_client->name, newName) != 0)
Con_Printf ("%s renamed to %s\n", host_client->name, newName);
strcpy (host_client->name, newName);
+ strcpy (host_client->old_name, newName);
sv_player->v->netname = PR_SetString(host_client->name);
// send notification to all clients
Host_Color_f
==================
*/
+cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"};
void Host_Color_f(void)
{
int top, bottom;
}
else
{
+ eval_t *val;
+ if ((val = GETEDICTFIELDVALUE(sv_player, eval_clientcolors)))
+ val->_float = playercolor;
host_client->colors = playercolor;
+ host_client->old_colors = playercolor;
sv_player->v->team = bottom + 1;
// send notification to all clients
}
}
+/*
+======================
+Host_PModel_f
+LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
+======================
+*/
+cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"};
+static void Host_PModel_f (void)
+{
+ int i;
+ eval_t *val;
+
+ if (Cmd_Argc () == 1)
+ {
+ Con_Printf ("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
+ return;
+ }
+ i = atoi(Cmd_Argv(1));
+
+ if (cmd_source == src_command)
+ {
+ if (cl_pmodel.integer == i)
+ return;
+ Cvar_SetValue ("_cl_pmodel", i);
+ if (cls.state == ca_connected)
+ Cmd_ForwardToServer ();
+ return;
+ }
+
+ host_client->pmodel = i;
+ if ((val = GETEDICTFIELDVALUE(sv_player, eval_pmodel)))
+ val->_float = i;
+}
+
//===========================================================================
*/
void Host_Spawn_f (void)
{
- int i;
- client_t *client;
- edict_t *ent;
+ int i;
+ client_t *client;
+ edict_t *ent;
func_t RestoreGame;
mfunction_t *f;
}
// LordHavoc: moved this above the QC calls at FrikaC's request
-// send all current names, colors, and frag counts
+ // send all current names, colors, and frag counts
SZ_Clear (&host_client->message);
ent = sv_player;
-// run the entrance script
+ // run the entrance script
if (sv.loadgame)
{
// loaded games are fully initialized already
}
else
{
- eval_t *val;
- // set up the edict
- ED_ClearEdict(ent);
- ent->v->colormap = NUM_FOR_EDICT(ent);
- ent->v->team = (host_client->colors & 15) + 1;
- ent->v->netname = PR_SetString(host_client->name);
- if ((val = GETEDICTFIELDVALUE(ent, eval_pmodel)))
- val->_float = host_client->pmodel;
-
// copy spawn parms out of the client_t
-
for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
// call the spawn function
-
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(sv_player);
PR_ExecuteProgram (pr_global_struct->ClientConnect, "QC function ClientConnect is missing");
}
-// send time of update
+ // send time of update
MSG_WriteByte (&host_client->message, svc_time);
MSG_WriteFloat (&host_client->message, sv.time);
{
MSG_WriteByte (&host_client->message, svc_updatename);
MSG_WriteByte (&host_client->message, i);
- MSG_WriteString (&host_client->message, client->name);
+ MSG_WriteString (&host_client->message, client->old_name);
MSG_WriteByte (&host_client->message, svc_updatefrags);
MSG_WriteByte (&host_client->message, i);
MSG_WriteShort (&host_client->message, client->old_frags);
MSG_WriteByte (&host_client->message, svc_updatecolors);
MSG_WriteByte (&host_client->message, i);
- MSG_WriteByte (&host_client->message, client->colors);
+ MSG_WriteByte (&host_client->message, client->old_colors);
}
-// send all current light styles
+ // send all current light styles
for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
{
MSG_WriteByte (&host_client->message, svc_lightstyle);
MSG_WriteString (&host_client->message, sv.lightstyles[i]);
}
-//
-// send some stats
-//
+ // send some stats
MSG_WriteByte (&host_client->message, svc_updatestat);
MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
MSG_WriteLong (&host_client->message, pr_global_struct->total_secrets);
MSG_WriteByte (&host_client->message, STAT_MONSTERS);
MSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters);
-// send a fixangle
-// Never send a roll angle, because savegames can catch the server
-// in a state where it is expecting the client to correct the angle
-// and it won't happen if the game was just loaded, so you wind up
-// with a permanent head tilt
+ // send a fixangle
+ // Never send a roll angle, because savegames can catch the server
+ // in a state where it is expecting the client to correct the angle
+ // and it won't happen if the game was just loaded, so you wind up
+ // with a permanent head tilt
MSG_WriteByte (&host_client->message, svc_setangle);
for (i=0 ; i < 2 ; i++)
MSG_WriteAngle (&host_client->message, ent->v->angles[i] );
Host_PerformLoadGame(sv_loadgame);
else if (sv_spawnmap[0])
SV_SpawnServer(sv_spawnmap);
- if (sv.active && cls.state == ca_disconnected)
- Cmd_ExecuteString ("connect local", src_command);
sv_loadgame[0] = 0;
sv_spawnmap[0] = 0;
+ if (sv.active && cls.state == ca_disconnected)
+ Cmd_ExecuteString ("connect local", src_command);
}
//=============================================================================
Cmd_AddCommand ("changelevel", Host_Changelevel_f);
Cmd_AddCommand ("connect", Host_Connect_f);
Cmd_AddCommand ("reconnect", Host_Reconnect_f);
- Cmd_AddCommand ("name", Host_Name_f);
Cmd_AddCommand ("version", Host_Version_f);
Cmd_AddCommand ("say", Host_Say_f);
Cmd_AddCommand ("say_team", Host_Say_Team_f);
Cmd_AddCommand ("tell", Host_Tell_f);
- Cmd_AddCommand ("color", Host_Color_f);
Cmd_AddCommand ("kill", Host_Kill_f);
Cmd_AddCommand ("pause", Host_Pause_f);
- Cmd_AddCommand ("spawn", Host_Spawn_f);
- Cmd_AddCommand ("begin", Host_Begin_f);
- Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
Cmd_AddCommand ("kick", Host_Kick_f);
Cmd_AddCommand ("ping", Host_Ping_f);
Cmd_AddCommand ("load", Host_Loadgame_f);
Cmd_AddCommand ("viewframe", Host_Viewframe_f);
Cmd_AddCommand ("viewnext", Host_Viewnext_f);
Cmd_AddCommand ("viewprev", Host_Viewprev_f);
+
+ Cvar_RegisterVariable (&cl_name);
+ Cmd_AddCommand ("name", Host_Name_f);
+ Cvar_RegisterVariable (&cl_color);
+ Cmd_AddCommand ("color", Host_Color_f);
+ if (gamemode == GAME_NEHAHRA)
+ {
+ Cvar_RegisterVariable (&cl_pmodel);
+ Cmd_AddCommand ("pmodel", Host_PModel_f);
+ }
+ Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
+ Cmd_AddCommand ("spawn", Host_Spawn_f);
+ Cmd_AddCommand ("begin", Host_Begin_f);
}
SHAREDOBJECTS= cmd.o collision.o common.o crc.o cvar.o \
filematch.o host.o host_cmd.o image.o mathlib.o matrixlib.o \
model_alias.o model_brush.o model_shared.o model_sprite.o \
- net_bsd.o net_dgrm.o net_loop.o net_main.o net_master.o \
- net_udp.o palette.o portals.o protocol.o fs.o \
+ netconn.o lhnet.o palette.o portals.o protocol.o fs.o \
sys_shared.o world.o wad.o zone.o
COMMONOBJECTS= $(CLIENTOBJECTS) $(SERVEROBJECTS) $(SHAREDOBJECTS)
void M_Menu_Save_f (void);
void M_Menu_MultiPlayer_f (void);
void M_Menu_Setup_f (void);
- void M_Menu_Net_f (void);
void M_Menu_Options_f (void);
void M_Menu_Options_Effects_f (void);
void M_Menu_Options_ColorControl_f (void);
void M_Menu_Quit_f (void);
void M_Menu_LanConfig_f (void);
void M_Menu_GameOptions_f (void);
-void M_Menu_Search_f (void);
-void M_Menu_InetSearch_f (void);
void M_Menu_ServerList_f (void);
void M_Main_Draw (void);
void M_Save_Draw (void);
void M_MultiPlayer_Draw (void);
void M_Setup_Draw (void);
- void M_Net_Draw (void);
void M_Options_Draw (void);
void M_Options_Effects_Draw (void);
void M_Options_ColorControl_Draw (void);
void M_Quit_Draw (void);
void M_LanConfig_Draw (void);
void M_GameOptions_Draw (void);
-void M_Search_Draw (void);
-void M_InetSearch_Draw (void);
void M_ServerList_Draw (void);
void M_Main_Key (int key);
void M_Save_Key (int key);
void M_MultiPlayer_Key (int key);
void M_Setup_Key (int key);
- void M_Net_Key (int key);
void M_Options_Key (int key);
void M_Options_Effects_Key (int key);
void M_Options_ColorControl_Key (int key);
void M_Quit_Key (int key);
void M_LanConfig_Key (int key);
void M_GameOptions_Key (int key);
-void M_Search_Key (int key);
-void M_InetSearch_Key (int key);
void M_ServerList_Key (int key);
qboolean m_entersound; // play after drawing a frame, so caching
// won't disrupt the sound
-int m_return_state;
-qboolean m_return_onerror;
char m_return_reason [32];
#define StartingGame (m_multiplayer_cursor == 1)
#define JoiningGame (m_multiplayer_cursor == 0)
-#define IPXConfig (m_net_cursor == 0)
-#define TCPIPConfig (m_net_cursor == 1)
-
-void M_ConfigureNetSubsystem(void);
// Nehahra
#define NumberOfNehahraDemos 34
float menu_x, menu_y, menu_width, menu_height;
-void M_DrawBackground(void)
+void M_Background(int width, int height)
{
- menu_width = 320;
- menu_height = 200;
+ menu_width = width;
+ menu_height = height;
menu_x = (vid.conwidth - menu_width) * 0.5;
menu_y = (vid.conheight - menu_height) * 0.5;
- DrawQ_Fill(0, 0, vid.conwidth, vid.conheight, 0, 0, 0, 0.5, 0);
+ DrawQ_Fill(menu_x, menu_y, menu_width, menu_height, 0, 0, 0, 0.5, 0);
+ //DrawQ_Fill(0, 0, vid.conwidth, vid.conheight, 0, 0, 0, 0.5, 0);
}
/*
{
m_entersound = true;
- if (key_dest == key_menu)
+ if (key_dest != key_menu || m_state != m_main)
+ M_Menu_Main_f ();
+ else
{
- if (m_state != m_main)
- {
- M_Menu_Main_f ();
- return;
- }
key_dest = key_game;
m_state = m_none;
- return;
}
- //if (key_dest == key_console)
- // Con_ToggleConsole_f ();
- //else
- M_Menu_Main_f ();
}
{
int i;
+ M_Background(320, 200);
+
for (i = 0;i < NumberOfNehahraDemos;i++)
M_Print (16, 16 + 8*i, NehahraDemos[i].desc);
int f;
cachepic_t *p;
+ M_Background(320, 200);
+
M_DrawPic (16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic ("gfx/ttl_main.lmp");
M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_main.lmp");
{
cachepic_t *p;
+ M_Background(320, 200);
+
M_DrawPic (16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic ("gfx/ttl_sgl.lmp");
int i;
cachepic_t *p;
+ M_Background(320, 200);
+
p = Draw_CachePic ("gfx/p_load.lmp");
M_DrawPic ( (320-p->width)/2, 4, "gfx/p_load.lmp");
int i;
cachepic_t *p;
+ M_Background(320, 200);
+
p = Draw_CachePic ("gfx/p_save.lmp");
M_DrawPic ( (320-p->width)/2, 4, "gfx/p_save.lmp");
int f;
cachepic_t *p;
+ M_Background(320, 200);
+
M_DrawPic (16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic ("gfx/p_multi.lmp");
M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi.lmp");
f = (int)(realtime * 10)%6;
M_DrawPic (54, 32 + m_multiplayer_cursor * 20, va("gfx/menudot%i.lmp", f+1));
-
- if (ipxAvailable || tcpipAvailable)
- return;
- M_PrintWhite ((320/2) - ((27*8)/2), 168, "No Communications Available");
}
switch (m_multiplayer_cursor)
{
case 0:
- if (ipxAvailable || tcpipAvailable)
- M_Menu_Net_f ();
- break;
-
case 1:
- if (ipxAvailable || tcpipAvailable)
- M_Menu_Net_f ();
+ M_Menu_LanConfig_f ();
break;
case 2:
{
cachepic_t *p;
+ M_Background(320, 200);
+
M_DrawPic (16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic ("gfx/p_multi.lmp");
M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi.lmp");
setup_bottom = 15;
}
-//=============================================================================
-/* NET MENU */
-
-int m_net_cursor;
-int m_net_items;
-int m_net_saveHeight;
-
-char *net_helpMessage [] =
-{
-/* .........1.........2.... */
- " Novell network LANs ",
- " or Windows 95 DOS-box. ",
- " ",
- "(LAN=Local Area Network)",
-
- " Commonly used to play ",
- " over the Internet, but ",
- " also used on a Local ",
- " Area Network. "
-};
-
-void M_Menu_Net_f (void)
-{
- key_dest = key_menu;
- m_state = m_net;
- m_entersound = true;
- m_net_items = 2;
-
- if (m_net_cursor >= m_net_items)
- m_net_cursor = 0;
- m_net_cursor--;
- M_Net_Key (K_DOWNARROW);
-}
-
-
-void M_Net_Draw (void)
-{
- int f;
- cachepic_t *p;
-
- M_DrawPic (16, 4, "gfx/qplaque.lmp");
- p = Draw_CachePic ("gfx/p_multi.lmp");
- M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi.lmp");
-
- f = 32;
-
- if (ipxAvailable)
- M_DrawPic (72, f, "gfx/netmen3.lmp");
- else
- M_DrawPic (72, f, "gfx/dim_ipx.lmp");
-
- f += 19;
- if (tcpipAvailable)
- M_DrawPic (72, f, "gfx/netmen4.lmp");
- else
- M_DrawPic (72, f, "gfx/dim_tcp.lmp");
-
- if (m_net_items == 5) // JDC, could just be removed
- {
- f += 19;
- M_DrawPic (72, f, "gfx/netmen5.lmp");
- }
-
- f = (320-26*8)/2;
- M_DrawTextBox (f, 134, 24, 4);
- f += 8;
- M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]);
- M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]);
-
- f = (int)(realtime * 10)%6;
- M_DrawPic (54, 32 + m_net_cursor * 20, va("gfx/menudot%i.lmp", f+1));
-}
-
-
-void M_Net_Key (int k)
-{
-again:
- switch (k)
- {
- case K_ESCAPE:
- M_Menu_MultiPlayer_f ();
- break;
-
- case K_DOWNARROW:
- S_LocalSound ("misc/menu1.wav");
- if (++m_net_cursor >= m_net_items)
- m_net_cursor = 0;
- break;
-
- case K_UPARROW:
- S_LocalSound ("misc/menu1.wav");
- if (--m_net_cursor < 0)
- m_net_cursor = m_net_items - 1;
- break;
-
- case K_ENTER:
- m_entersound = true;
-
- switch (m_net_cursor)
- {
- case 0:
- M_Menu_LanConfig_f ();
- break;
-
- case 1:
- M_Menu_LanConfig_f ();
- break;
-
- case 2:
-// multiprotocol
- break;
- }
- }
-
- if (m_net_cursor == 0 && !ipxAvailable)
- goto again;
- if (m_net_cursor == 1 && !tcpipAvailable)
- goto again;
-}
-
//=============================================================================
/* OPTIONS MENU */
float y;
cachepic_t *p;
+ M_Background(320, 240);
+
M_DrawPic(16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic("gfx/p_option.lmp");
M_DrawPic((320-p->width)/2, 4, "gfx/p_option.lmp");
float y;
cachepic_t *p;
+ M_Background(320, 200);
+
M_DrawPic(16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic("gfx/p_option.lmp");
M_DrawPic((320-p->width)/2, 4, "gfx/p_option.lmp");
float x, y, c, s, t, u, v;
cachepic_t *p;
+ M_Background(320, 256);
+
M_DrawPic(16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic("gfx/p_option.lmp");
M_DrawPic((320-p->width)/2, 4, "gfx/p_option.lmp");
cachepic_t *p;
char keystring[1024];
+ M_Background(320, 200);
+
p = Draw_CachePic ("gfx/ttl_cstm.lmp");
M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_cstm.lmp");
cachepic_t *p;
const char* string;
+ M_Background(320, 200);
+
M_DrawPic(16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic("gfx/vidmodes.lmp");
M_DrawPic((320-p->width)/2, 4, "gfx/vidmodes.lmp");
void M_Help_Draw (void)
{
+ M_Background(320, 200);
M_DrawPic (0, 0, va("gfx/help%i.lmp", help_page));
}
void M_Quit_Draw (void)
{
- M_DrawTextBox (56, 76, 24, 4);
- M_Print (64, 84, quitMessage[msgNumber*4+0]);
- M_Print (64, 92, quitMessage[msgNumber*4+1]);
- M_Print (64, 100, quitMessage[msgNumber*4+2]);
- M_Print (64, 108, quitMessage[msgNumber*4+3]);
+ M_Background(208, 48);
+ M_DrawTextBox(0, 0, 24, 4);
+ M_Print(8, 8, quitMessage[msgNumber*4+0]);
+ M_Print(8, 16, quitMessage[msgNumber*4+1]);
+ M_Print(8, 24, quitMessage[msgNumber*4+2]);
+ M_Print(8, 32, quitMessage[msgNumber*4+3]);
}
//=============================================================================
/* LAN CONFIG MENU */
int lanConfig_cursor = -1;
-int lanConfig_cursor_table [] = {72, 92, 112, 144};
-#define NUM_LANCONFIG_CMDS 4
+int lanConfig_cursor_table [] = {56, 76, 112};
+#define NUM_LANCONFIG_CMDS 3
int lanConfig_port;
char lanConfig_portname[6];
m_entersound = true;
if (lanConfig_cursor == -1)
{
- if (JoiningGame && TCPIPConfig)
- lanConfig_cursor = 2;
- else
+ if (JoiningGame)
lanConfig_cursor = 1;
}
- if (StartingGame && lanConfig_cursor == 2)
+ if (StartingGame)
lanConfig_cursor = 1;
- lanConfig_port = DEFAULTnet_hostport;
+ lanConfig_port = 26000;
sprintf(lanConfig_portname, "%u", lanConfig_port);
- m_return_onerror = false;
m_return_reason[0] = 0;
}
char *startJoin;
char *protocol;
+ M_Background(320, 200);
+
M_DrawPic (16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic ("gfx/p_multi.lmp");
basex = (320-p->width)/2;
startJoin = "New Game";
else
startJoin = "Join Game";
- if (IPXConfig)
- protocol = "IPX";
- else
- protocol = "TCP/IP";
+ protocol = "TCP/IP";
M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
basex += 8;
- M_Print (basex, 52, "Address:");
- if (IPXConfig)
- M_Print (basex+9*8, 52, my_ipx_address);
- else
- M_Print (basex+9*8, 52, my_tcpip_address);
-
M_Print (basex, lanConfig_cursor_table[0], "Port");
M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);
if (JoiningGame)
{
- M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
- M_Print (basex, lanConfig_cursor_table[2], "Search for internet games...");
- M_Print (basex, 128, "Join game at:");
- M_DrawTextBox (basex+8, lanConfig_cursor_table[3]-8, 22, 1);
- M_Print (basex+16, lanConfig_cursor_table[3], lanConfig_joinname);
+ M_Print (basex, lanConfig_cursor_table[1], "Search for games...");
+ M_Print (basex, lanConfig_cursor_table[2]-16, "Join game at:");
+ M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
+ M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
}
else
{
if (lanConfig_cursor == 0)
M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
- if (lanConfig_cursor == 3)
- M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [3], 10+((int)(realtime*4)&1));
+ if (lanConfig_cursor == 2)
+ M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
if (*m_return_reason)
M_PrintWhite (basex, 168, m_return_reason);
switch (key)
{
case K_ESCAPE:
- M_Menu_Net_f ();
+ M_Menu_MultiPlayer_f ();
break;
case K_UPARROW:
m_entersound = true;
- M_ConfigureNetSubsystem ();
+ Cbuf_AddText ("stopdemo\n");
+
+ Cvar_SetValue("port", lanConfig_port);
- if (lanConfig_cursor == 1 || lanConfig_cursor == 2)
+ if (lanConfig_cursor == 1)
{
if (StartingGame)
{
M_Menu_GameOptions_f ();
break;
}
- if (lanConfig_cursor == 1)
- M_Menu_Search_f();
- else
- M_Menu_InetSearch_f();
+ M_Menu_ServerList_f();
break;
}
- if (lanConfig_cursor == 3)
- {
- m_return_state = m_state;
- m_return_onerror = true;
- key_dest = key_game;
- m_state = m_none;
+ if (lanConfig_cursor == 2)
Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
- break;
- }
-
break;
case K_BACKSPACE:
lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
}
- if (lanConfig_cursor == 3)
+ if (lanConfig_cursor == 2)
{
if (strlen(lanConfig_joinname))
lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
if (key < 32 || key > 127)
break;
- if (lanConfig_cursor == 3)
+ if (lanConfig_cursor == 2)
{
l = strlen(lanConfig_joinname);
if (l < 21)
}
}
- if (StartingGame && lanConfig_cursor == 3)
+ if (StartingGame && lanConfig_cursor == 2)
{
if (key == K_UPARROW)
lanConfig_cursor = 1;
}
l = atoi(lanConfig_portname);
- if (l > 65535)
- l = lanConfig_port;
- else
+ if (l <= 65535)
lanConfig_port = l;
sprintf(lanConfig_portname, "%u", lanConfig_port);
}
int x;
gamelevels_t *g;
+ M_Background(320, 200);
+
M_DrawPic (16, 4, "gfx/qplaque.lmp");
p = Draw_CachePic ("gfx/p_multi.lmp");
M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi.lmp");
switch (key)
{
case K_ESCAPE:
- M_Menu_Net_f ();
+ M_Menu_MultiPlayer_f ();
break;
case K_UPARROW:
{
if (sv.active)
Cbuf_AddText ("disconnect\n");
- Cbuf_AddText ("listen 0\n"); // so host_netport will be re-examined
Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
g = lookupgameinfo();
}
}
-//=============================================================================
-/* SEARCH MENU */
-
-qboolean searchComplete = false;
-double searchCompleteTime;
-
-void M_Menu_Search_f (void)
-{
- key_dest = key_menu;
- m_state = m_search;
- m_entersound = false;
- slistSilent = true;
- slistLocal = false;
- searchComplete = false;
- NET_Slist_f();
-
-}
-
-
-void M_Search_Draw (void)
-{
- cachepic_t *p;
- int x;
-
- p = Draw_CachePic ("gfx/p_multi.lmp");
- M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi.lmp");
- x = (320/2) - ((12*8)/2) + 4;
- M_DrawTextBox (x-8, 32, 12, 1);
- M_Print (x, 40, "Searching...");
-
- if(slistInProgress)
- {
- NET_Poll();
- return;
- }
-
- if (! searchComplete)
- {
- searchComplete = true;
- searchCompleteTime = realtime;
- }
-
- if (hostCacheCount)
- {
- M_Menu_ServerList_f ();
- return;
- }
-
- M_PrintWhite ((320/2) - ((22*8)/2), 64, va("No %s servers found", gamename));
- if ((realtime - searchCompleteTime) < 3.0)
- return;
-
- M_Menu_LanConfig_f ();
-}
-
-
-void M_Search_Key (int key)
-{
-}
-
-//=============================================================================
-/* INTERNET SEARCH MENU */
-
-void M_Menu_InetSearch_f (void)
-{
- key_dest = key_menu;
- m_state = m_search;
- m_entersound = false;
- slistSilent = true;
- slistLocal = false;
- searchComplete = false;
- NET_InetSlist_f();
-
-}
-
-
-void M_InetSearch_Draw (void)
-{
- M_Search_Draw (); // it's the same one, so why bother?
-}
-
-
-void M_InetSearch_Key (int key)
-{
-}
-
//=============================================================================
/* SLIST MENU */
-int slist_cursor;
-qboolean slist_sorted;
+int slist_cursor;
void M_Menu_ServerList_f (void)
{
m_state = m_slist;
m_entersound = true;
slist_cursor = 0;
- m_return_onerror = false;
m_return_reason[0] = 0;
- slist_sorted = false;
+ Net_Slist_f();
}
void M_ServerList_Draw (void)
{
- int n;
- char string [64];
- cachepic_t *p;
+ int n, y, visible, start, end;
+ cachepic_t *p;
- if (!slist_sorted)
- {
- if (hostCacheCount > 1)
- {
- int i,j;
- hostcache_t temp;
- for (i = 0; i < hostCacheCount; i++)
- for (j = i+1; j < hostCacheCount; j++)
- if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
- {
- memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
- memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
- memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
- }
- }
- slist_sorted = true;
- }
+ // use as much vertical space as available
+ M_Background(640, vid.conheight);
+ // scroll the list as the cursor moves
+ visible = (vid.conheight - 16 - 32) / 8;
+ start = bound(0, slist_cursor - (visible >> 1), hostCacheCount - visible);
+ end = min(start + visible, hostCacheCount);
- p = Draw_CachePic ("gfx/p_multi.lmp");
- M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi.lmp");
- for (n = 0; n < hostCacheCount; n++)
+ p = Draw_CachePic("gfx/p_multi.lmp");
+ M_DrawPic((640 - p->width) / 2, 4, "gfx/p_multi.lmp");
+ y = 32;
+ for (n = start;n < end;n++)
{
- if (hostcache[n].maxusers)
- sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
- else
- sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
- M_Print (16, 32 + 8*n, string);
+ M_Print(0, y, hostcache[n].line1);y += 8;
+ M_Print(0, y, hostcache[n].line2);y += 8;
}
- M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
+ M_DrawCharacter(0, 32 + (slist_cursor - start) * 16, 12+((int)(realtime*4)&1));
if (*m_return_reason)
- M_PrintWhite (16, 168, m_return_reason);
+ M_PrintWhite(16, vid.conheight - 8, m_return_reason);
}
-void M_ServerList_Key (int k)
+void M_ServerList_Key(int k)
{
switch (k)
{
case K_ESCAPE:
- M_Menu_LanConfig_f ();
+ M_Menu_LanConfig_f();
break;
case K_SPACE:
- M_Menu_Search_f ();
+ Net_Slist_f();
break;
case K_UPARROW:
case K_LEFTARROW:
- S_LocalSound ("misc/menu1.wav");
+ S_LocalSound("misc/menu1.wav");
slist_cursor--;
if (slist_cursor < 0)
slist_cursor = hostCacheCount - 1;
case K_DOWNARROW:
case K_RIGHTARROW:
- S_LocalSound ("misc/menu1.wav");
+ S_LocalSound("misc/menu1.wav");
slist_cursor++;
if (slist_cursor >= hostCacheCount)
slist_cursor = 0;
break;
case K_ENTER:
- S_LocalSound ("misc/menu2.wav");
- m_return_state = m_state;
- m_return_onerror = true;
- slist_sorted = false;
- key_dest = key_game;
- m_state = m_none;
- Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
+ S_LocalSound("misc/menu2.wav");
+ Cbuf_AddText(va("connect \"%s\"\n", hostcache[slist_cursor].cname));
break;
default:
void M_Draw (void)
{
- if (m_state == m_none || key_dest != key_menu)
+ if (key_dest != key_menu)
+ m_state = m_none;
+ if (m_state == m_none)
return;
- M_DrawBackground();
-
switch (m_state)
{
case m_none:
M_Setup_Draw ();
break;
- case m_net:
- M_Net_Draw ();
- break;
-
case m_options:
M_Options_Draw ();
break;
M_GameOptions_Draw ();
break;
- case m_search:
- M_Search_Draw ();
- break;
-
case m_slist:
M_ServerList_Draw ();
break;
M_Setup_Key (key);
return;
- case m_net:
- M_Net_Key (key);
- return;
-
case m_options:
M_Options_Key (key);
return;
M_GameOptions_Key (key);
return;
- case m_search:
- M_Search_Key (key);
- break;
-
case m_slist:
M_ServerList_Key (key);
return;
}
}
-
-void M_ConfigureNetSubsystem(void)
-{
-// enable/disable net systems to match desired config
-
- Cbuf_AddText ("stopdemo\n");
-
- if (IPXConfig || TCPIPConfig)
- net_hostport = lanConfig_port;
-}
-
#ifndef MENU_H
#define MENU_H
-//
-// the net drivers should just set the apropriate bits in m_activenet,
-// instead of having the menu code look through their internal tables
-//
-#define MNET_IPX 1
-#define MNET_TCP 2
-
enum m_state_e {
m_none,
m_main,
m_save,
m_multiplayer,
m_setup,
- m_net,
m_options,
m_video,
m_keys,
m_quit,
m_lanconfig,
m_gameoptions,
- m_search,
m_slist,
m_options_effects,
m_options_colorcontrol
};
-extern int m_activenet;
-extern int m_return_state;
extern enum m_state_e m_state;
-extern qboolean m_return_onerror;
extern char m_return_reason[32];
//
// LordHavoc: unload the existing model in this slot (if there is one)
Mod_UnloadModel(mod);
mod->isworldmodel = isworldmodel;
- mod->needload = false;
mod->used = true;
mod->crc = crc;
- // errors can prevent the corresponding mod->error = false;
- mod->error = true;
+ // errors can prevent the corresponding mod->needload = false;
+ mod->needload = true;
// all models use memory, so allocate a memory pool
mod->mempool = Mem_AllocPool(mod->name);
Mem_Free(buf);
// no errors occurred
- mod->error = false;
+ mod->needload = false;
return mod;
}
{
}
-void Mod_ClearErrorModels (void)
-{
- int i;
- model_t *mod;
-
- for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
- if (mod->error)
- Mod_FreeModel(mod);
-}
-
void Mod_ClearUsed(void)
{
int i;
qboolean isworldmodel;
// true if this model is a HalfLife .bsp file
qboolean ishlbsp;
- // true if this model was not successfully loaded and should be purged
- qboolean error;
// mod_brush, mod_alias, mod_sprite
modtype_t type;
void Mod_Init (void);
void Mod_CheckLoaded (model_t *mod);
void Mod_ClearAll (void);
-void Mod_ClearErrorModels (void);
model_t *Mod_FindName (const char *name);
model_t *Mod_ForName (const char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel);
void Mod_TouchModel (const char *name);
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net.h -- quake's interface to the networking layer
-
-#ifndef NET_H
-#define NET_H
-
-struct qsockaddr
-{
- short sa_family;
- unsigned char sa_data[14];
-};
-
-
-#define NET_NAMELEN 64
-
-#define NET_MAXMESSAGE (MAX_DATAGRAM + 64)
-#define NET_HEADERSIZE (2 * sizeof(unsigned int))
-#define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE)
-
-// NetHeader flags
-#define NETFLAG_LENGTH_MASK 0x0000ffff
-#define NETFLAG_DATA 0x00010000
-#define NETFLAG_ACK 0x00020000
-#define NETFLAG_NAK 0x00040000
-#define NETFLAG_EOM 0x00080000
-#define NETFLAG_UNRELIABLE 0x00100000
-#define NETFLAG_CTL 0x80000000
-
-
-#define NET_PROTOCOL_VERSION 3
-
-// This is the network info/connection protocol. It is used to find Quake
-// servers, get info about them, and connect to them. Once connected, the
-// Quake game protocol (documented elsewhere) is used.
-//
-//
-// General notes:
-// game_name is currently always "QUAKE", but is there so this same protocol
-// can be used for future games as well; can you say Quake2?
-//
-// CCREQ_CONNECT
-// string game_name "QUAKE"
-// byte net_protocol_version NET_PROTOCOL_VERSION
-//
-// CCREQ_SERVER_INFO
-// string game_name "QUAKE"
-// byte net_protocol_version NET_PROTOCOL_VERSION
-//
-// CCREQ_PLAYER_INFO
-// byte player_number
-//
-// CCREQ_RULE_INFO
-// string rule
-//
-//
-//
-// CCREP_ACCEPT
-// long port
-//
-// CCREP_REJECT
-// string reason
-//
-// CCREP_SERVER_INFO
-// string server_address
-// string host_name
-// string level_name
-// byte current_players
-// byte max_players
-// byte protocol_version NET_PROTOCOL_VERSION
-//
-// CCREP_PLAYER_INFO
-// byte player_number
-// string name
-// long colors
-// long frags
-// long connect_time
-// string address
-//
-// CCREP_RULE_INFO
-// string rule
-// string value
-
-// note:
-// There are two address forms used above. The short form is just a
-// port number. The address that goes along with the port is defined as
-// "whatever address you receive this reponse from". This lets us use
-// the host OS to solve the problem of multiple host addresses (possibly
-// with no routing between them); the host will use the right address
-// when we reply to the inbound connection request. The long from is
-// a full address and port in a string. It is used for returning the
-// address of a server that is not running locally.
-
-#define CCREQ_CONNECT 0x01
-#define CCREQ_SERVER_INFO 0x02
-#define CCREQ_PLAYER_INFO 0x03
-#define CCREQ_RULE_INFO 0x04
-
-#define CCREP_ACCEPT 0x81
-#define CCREP_REJECT 0x82
-#define CCREP_SERVER_INFO 0x83
-#define CCREP_PLAYER_INFO 0x84
-#define CCREP_RULE_INFO 0x85
-
-typedef struct qsocket_s
-{
- struct qsocket_s *next;
- double connecttime;
- double lastMessageTime;
- double lastSendTime;
-
- qboolean disconnected;
- qboolean canSend;
- qboolean sendNext;
-
- int driver;
- int landriver;
- int socket;
- void *driverdata;
-
- unsigned int ackSequence;
- unsigned int sendSequence;
- unsigned int unreliableSendSequence;
- int sendMessageLength;
- qbyte sendMessage [NET_MAXMESSAGE];
-
- unsigned int receiveSequence;
- unsigned int unreliableReceiveSequence;
- int receiveMessageLength;
- qbyte receiveMessage [NET_MAXMESSAGE];
-
- struct qsockaddr addr;
- char address[NET_NAMELEN];
-} qsocket_t;
-
-extern qsocket_t *net_activeSockets;
-extern mempool_t *net_mempool;
-
-typedef struct
-{
- char *name;
- qboolean initialized;
- int controlSock;
- int (*Init) (void);
- void (*Shutdown) (void);
- void (*Listen) (qboolean state);
- int (*OpenSocket) (int port);
- int (*CloseSocket) (int socket);
- int (*Connect) (int socket, struct qsockaddr *addr);
- int (*CheckNewConnections) (void);
- int (*Recv) (qbyte *buf, int len, struct qsockaddr *addr);
- int (*Send) (qbyte *buf, int len, struct qsockaddr *addr);
- int (*Read) (int socket, qbyte *buf, int len, struct qsockaddr *addr);
- int (*Write) (int socket, qbyte *buf, int len, struct qsockaddr *addr);
- int (*Broadcast) (int socket, qbyte *buf, int len);
- char * (*AddrToString) (const struct qsockaddr *addr);
- int (*StringToAddr) (const char *string, struct qsockaddr *addr);
- int (*GetSocketAddr) (int socket, struct qsockaddr *addr);
- int (*GetNameFromAddr) (const struct qsockaddr *addr, char *name);
- int (*GetAddrFromName) (const char *name, struct qsockaddr *addr);
- int (*AddrCompare) (const struct qsockaddr *addr1, const struct qsockaddr *addr2);
- int (*GetSocketPort) (struct qsockaddr *addr);
- int (*SetSocketPort) (struct qsockaddr *addr, int port);
-} net_landriver_t;
-
-#define MAX_NET_DRIVERS 8
-extern int net_numlandrivers;
-extern net_landriver_t net_landrivers[MAX_NET_DRIVERS];
-
-typedef struct
-{
- char *name;
- qboolean initialized;
- int (*Init) (void);
- void (*Listen) (qboolean state);
- void (*SearchForHosts) (qboolean xmit);
- qboolean (*SearchForInetHosts) (const char *master);
- qsocket_t *(*Connect) (const char *host);
- qsocket_t *(*CheckNewConnections) (void);
- int (*QGetMessage) (qsocket_t *sock);
- int (*QSendMessage) (qsocket_t *sock, sizebuf_t *data);
- int (*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data);
- qboolean (*CanSendMessage) (qsocket_t *sock);
- qboolean (*CanSendUnreliableMessage) (qsocket_t *sock);
- void (*Close) (qsocket_t *sock);
- void (*Shutdown) (void);
- void (*Heartbeat) (const char *host);
- int controlSock;
-} net_driver_t;
-
-extern int net_numdrivers;
-extern net_driver_t net_drivers[MAX_NET_DRIVERS];
-
-extern int DEFAULTnet_hostport;
-extern int net_hostport;
-
-extern int net_driverlevel;
-extern cvar_t hostname;
-extern cvar_t developer_networking;
-extern char playername[];
-extern int playercolor;
-
-extern int messagesSent;
-extern int messagesReceived;
-extern int unreliableMessagesSent;
-extern int unreliableMessagesReceived;
-
-qsocket_t *NET_NewQSocket (void);
-void NET_FreeQSocket(qsocket_t *);
-double SetNetTime(void);
-
-
-#define HOSTCACHESIZE 128
-
-typedef struct
-{
- char name[64];
- char map[64];
- char cname[64];
- int users;
- int maxusers;
- //int driver;
- //int ldriver;
- //struct qsockaddr addr;
-} hostcache_t;
-
-extern int hostCacheCount;
-extern hostcache_t hostcache[HOSTCACHESIZE];
-
-#if !defined(_WIN32 ) && !defined (__linux__) && !defined (__sun__)
-#ifndef htonl
-extern unsigned long htonl (unsigned long hostlong);
-#endif
-#ifndef htons
-extern unsigned short htons (unsigned short hostshort);
-#endif
-#ifndef ntohl
-extern unsigned long ntohl (unsigned long netlong);
-#endif
-#ifndef ntohs
-extern unsigned short ntohs (unsigned short netshort);
-#endif
-#endif
-
-//============================================================================
-//
-// public network functions
-//
-//============================================================================
-
-extern double net_time;
-extern sizebuf_t net_message;
-extern int net_activeconnections;
-
-void NET_Init (void);
-void NET_Shutdown (void);
-
-struct qsocket_s *NET_CheckNewConnections (void);
-// returns a new connection number if there is one pending, else -1
-
-struct qsocket_s *NET_Connect (char *host);
-// called by client to connect to a host. Returns -1 if not able to
-
-void NET_Heartbeat (int priority);
-// Send an heartbeat to the master server(s). priority: 0 = lowest, 1 = state change, 2 = force
-
-qboolean NET_CanSendMessage (qsocket_t *sock);
-// Returns true or false if the given qsocket can currently accept a
-// message to be transmitted.
-
-int NET_GetMessage (struct qsocket_s *sock);
-// returns data in net_message sizebuf
-// returns 0 if no data is waiting
-// returns 1 if a message was received
-// returns 2 if an unreliable message was received
-// returns -1 if the connection died
-
-int NET_SendMessage (struct qsocket_s *sock, sizebuf_t *data);
-int NET_SendUnreliableMessage (struct qsocket_s *sock, sizebuf_t *data);
-// returns 0 if the message connot be delivered reliably, but the connection
-// is still considered valid
-// returns 1 if the message was sent properly
-// returns -1 if the connection died
-
-int NET_SendToAll(sizebuf_t *data, int blocktime);
-// This is a reliable *blocking* send to all attached clients.
-
-
-void NET_Close (struct qsocket_s *sock);
-// if a dead connection is returned by a get or send function, this function
-// should be called when it is convenient
-
-// Server calls when a client is kicked off for a game related misbehavior
-// like an illegal protocal conversation. Client calls when disconnecting
-// from a server.
-// A netcon_t number will not be reused until this function is called for it
-
-void NET_Poll(void);
-
-
-typedef struct _PollProcedure
-{
- struct _PollProcedure *next;
- double nextTime;
- void (*procedure)();
- void *arg;
-} PollProcedure;
-
-void SchedulePollProcedure(PollProcedure *pp, double timeOffset);
-
-extern qboolean ipxAvailable;
-extern qboolean tcpipAvailable;
-extern char my_ipx_address[NET_NAMELEN];
-extern char my_tcpip_address[NET_NAMELEN];
-
-extern qboolean slistInProgress;
-extern qboolean slistSilent;
-extern qboolean slistLocal;
-
-void NET_Slist_f (void);
-void NET_InetSlist_f (void);
-
-#endif
-
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-#include "quakedef.h"
-
-#include "net_loop.h"
-#include "net_dgrm.h"
-
-net_driver_t net_drivers[MAX_NET_DRIVERS] =
-{
- {
- "Loopback",
- false,
- Loop_Init,
- Loop_Listen,
- Loop_SearchForHosts,
- Loop_SearchForInetHosts,
- Loop_Connect,
- Loop_CheckNewConnections,
- Loop_GetMessage,
- Loop_SendMessage,
- Loop_SendUnreliableMessage,
- Loop_CanSendMessage,
- Loop_CanSendUnreliableMessage,
- Loop_Close,
- Loop_Shutdown,
- Loop_Heartbeat
- }
- ,
- {
- "Datagram",
- false,
- Datagram_Init,
- Datagram_Listen,
- Datagram_SearchForHosts,
- Datagram_SearchForInetHosts,
- Datagram_Connect,
- Datagram_CheckNewConnections,
- Datagram_GetMessage,
- Datagram_SendMessage,
- Datagram_SendUnreliableMessage,
- Datagram_CanSendMessage,
- Datagram_CanSendUnreliableMessage,
- Datagram_Close,
- Datagram_Shutdown,
- Datagram_Heartbeat
- }
-};
-
-int net_numdrivers = 2;
-
-#include "net_udp.h"
-
-net_landriver_t net_landrivers[MAX_NET_DRIVERS] =
-{
- {
- "UDP",
- false,
- 0,
- UDP_Init,
- UDP_Shutdown,
- UDP_Listen,
- UDP_OpenSocket,
- UDP_CloseSocket,
- UDP_Connect,
- UDP_CheckNewConnections,
- UDP_Recv,
- UDP_Send,
- UDP_Read,
- UDP_Write,
- UDP_Broadcast,
- UDP_AddrToString,
- UDP_StringToAddr,
- UDP_GetSocketAddr,
- UDP_GetNameFromAddr,
- UDP_GetAddrFromName,
- UDP_AddrCompare,
- UDP_GetSocketPort,
- UDP_SetSocketPort
- }
-};
-
-int net_numlandrivers = 1;
-
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net_dgrm.c
-
-// This is enables a simple IP banning mechanism
-#define BAN_TEST
-
-#ifdef BAN_TEST
-#if defined(_WIN32)
-#include <windows.h>
-#elif defined (NeXT)
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#else
-#define AF_INET 2 /* internet */
-struct in_addr
-{
- union
- {
- struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;
- struct { unsigned short s_w1,s_w2; } S_un_w;
- unsigned long S_addr;
- } S_un;
-};
-#define s_addr S_un.S_addr /* can be used for most tcp & ip code */
-struct sockaddr_in
-{
- short sin_family;
- unsigned short sin_port;
- struct in_addr sin_addr;
- char sin_zero[8];
-};
-char *inet_ntoa(struct in_addr in);
-unsigned long inet_addr(const char *cp);
-#endif
-#endif // BAN_TEST
-
-#include "quakedef.h"
-#include "net_dgrm.h"
-#include "net_master.h"
-
-cvar_t cl_port = {CVAR_SAVE, "cl_port", "0"};
-
-// these two macros are to make the code more readable
-#define sfunc net_landrivers[sock->landriver]
-#define dfunc net_landrivers[net_landriverlevel]
-
-static int net_landriverlevel;
-
-/* statistic counters */
-int packetsSent = 0;
-int packetsReSent = 0;
-int packetsReceived = 0;
-int receivedDuplicateCount = 0;
-int shortPacketCount = 0;
-int droppedDatagrams;
-
-static int myDriverLevel;
-
-struct
-{
- unsigned int length;
- unsigned int sequence;
- qbyte data[MAX_DATAGRAM];
-} packetBuffer;
-
-/*
-#ifdef DEBUG
-char *StrAddr (struct qsockaddr *addr)
-{
- static char buf[34];
- qbyte *p = (qbyte *)addr;
- int n;
-
- for (n = 0; n < 16; n++)
- sprintf (buf + n * 2, "%02x", *p++);
- return buf;
-}
-#endif
-*/
-
-
-#ifdef BAN_TEST
-unsigned long banAddr = 0x00000000;
-unsigned long banMask = 0xffffffff;
-
-void NET_Ban_f (void)
-{
- char addrStr [32];
- char maskStr [32];
- void (*print) (const char *fmt, ...);
-
- if (cmd_source == src_command)
- {
- if (!sv.active)
- {
- Cmd_ForwardToServer ();
- return;
- }
- print = Con_Printf;
- }
- else
- {
- if (pr_global_struct->deathmatch)
- return;
- print = SV_ClientPrintf;
- }
-
- switch (Cmd_Argc ())
- {
- case 1:
- if (((struct in_addr *)&banAddr)->s_addr)
- {
- strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr));
- strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask));
- print("Banning %s [%s]\n", addrStr, maskStr);
- }
- else
- print("Banning not active\n");
- break;
-
- case 2:
- if (strcasecmp(Cmd_Argv(1), "off") == 0)
- banAddr = 0x00000000;
- else
- banAddr = inet_addr(Cmd_Argv(1));
- banMask = 0xffffffff;
- break;
-
- case 3:
- banAddr = inet_addr(Cmd_Argv(1));
- banMask = inet_addr(Cmd_Argv(2));
- break;
-
- default:
- print("BAN ip_address [mask]\n");
- break;
- }
-}
-#endif
-
-
-int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)
-{
- unsigned int packetLen;
- unsigned int dataLen;
- unsigned int eom;
-
-#ifdef DEBUG
- if (data->cursize == 0)
- Sys_Error("Datagram_SendMessage: zero length message\n");
-
- if (data->cursize > NET_MAXMESSAGE)
- Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize);
-
- if (sock->canSend == false)
- Sys_Error("SendMessage: called with canSend == false\n");
-#endif
-
- memcpy(sock->sendMessage, data->data, data->cursize);
- sock->sendMessageLength = data->cursize;
-
- if (data->cursize <= MAX_DATAGRAM)
- {
- dataLen = data->cursize;
- eom = NETFLAG_EOM;
- }
- else
- {
- dataLen = MAX_DATAGRAM;
- eom = 0;
- }
- packetLen = NET_HEADERSIZE + dataLen;
-
- packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
- packetBuffer.sequence = BigLong(sock->sendSequence++);
- memcpy (packetBuffer.data, sock->sendMessage, dataLen);
-
- sock->canSend = false;
-
- if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
- return -1;
-
- sock->lastSendTime = net_time;
- packetsSent++;
- return 1;
-}
-
-
-int SendMessageNext (qsocket_t *sock)
-{
- unsigned int packetLen;
- unsigned int dataLen;
- unsigned int eom;
-
- if (sock->sendMessageLength <= MAX_DATAGRAM)
- {
- dataLen = sock->sendMessageLength;
- eom = NETFLAG_EOM;
- }
- else
- {
- dataLen = MAX_DATAGRAM;
- eom = 0;
- }
- packetLen = NET_HEADERSIZE + dataLen;
-
- packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
- packetBuffer.sequence = BigLong(sock->sendSequence++);
- memcpy (packetBuffer.data, sock->sendMessage, dataLen);
-
- sock->sendNext = false;
-
- if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
- return -1;
-
- sock->lastSendTime = net_time;
- packetsSent++;
- return 1;
-}
-
-
-int ReSendMessage (qsocket_t *sock)
-{
- unsigned int packetLen;
- unsigned int dataLen;
- unsigned int eom;
-
- if (sock->sendMessageLength <= MAX_DATAGRAM)
- {
- dataLen = sock->sendMessageLength;
- eom = NETFLAG_EOM;
- }
- else
- {
- dataLen = MAX_DATAGRAM;
- eom = 0;
- }
- packetLen = NET_HEADERSIZE + dataLen;
-
- packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
- packetBuffer.sequence = BigLong(sock->sendSequence - 1);
- memcpy (packetBuffer.data, sock->sendMessage, dataLen);
-
- sock->sendNext = false;
-
- if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
- return -1;
-
- sock->lastSendTime = net_time;
- packetsReSent++;
- return 1;
-}
-
-
-qboolean Datagram_CanSendMessage (qsocket_t *sock)
-{
- if (sock->sendNext)
- SendMessageNext (sock);
-
- return sock->canSend;
-}
-
-
-qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock)
-{
- return true;
-}
-
-
-int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
-{
- int packetLen;
-
-#ifdef DEBUG
- if (data->cursize == 0)
- Sys_Error("Datagram_SendUnreliableMessage: zero length message\n");
-
- if (data->cursize > MAX_DATAGRAM)
- Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);
-#endif
-
- packetLen = NET_HEADERSIZE + data->cursize;
-
- packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);
- packetBuffer.sequence = BigLong(sock->unreliableSendSequence++);
- memcpy (packetBuffer.data, data->data, data->cursize);
-
- if (sfunc.Write (sock->socket, (qbyte *)&packetBuffer, packetLen, &sock->addr) == -1)
- return -1;
-
- packetsSent++;
- return 1;
-}
-
-
-int Datagram_GetMessage (qsocket_t *sock)
-{
- unsigned int length;
- unsigned int flags;
- int ret = 0;
- struct qsockaddr readaddr;
- unsigned int sequence;
- unsigned int count;
- int temp;
-
- if (!sock->canSend)
- if ((net_time - sock->lastSendTime) > 1.0)
- ReSendMessage (sock);
-
- while(1)
- {
- length = sfunc.Read (sock->socket, (qbyte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);
-
- if (length == 0)
- break;
-
- if ((int)length == -1)
- {
- Con_Printf("Read error\n");
- return -1;
- }
-
- if ((temp = sfunc.AddrCompare(&readaddr, &sock->addr)) != 0)
- {
- char tempaddress1[64], tempaddress2[64];
- if (temp == 1)
- {
- if (developer_networking.integer)
- {
- dfunc.GetNameFromAddr (&sock->addr, tempaddress1);
- dfunc.GetNameFromAddr (&readaddr, tempaddress2);
- Con_Printf("Packet from wrong port received but accepted (Expected: %s Received: %s)\n", tempaddress1, tempaddress2);
- }
- }
- else
- {
- dfunc.GetNameFromAddr (&sock->addr, tempaddress1);
- dfunc.GetNameFromAddr (&readaddr, tempaddress2);
- Con_Printf("Forged packet received (Expected: %s Received: %s)\n", tempaddress1, tempaddress2);
- continue;
- }
- }
-
- if (length < NET_HEADERSIZE)
- {
- shortPacketCount++;
- continue;
- }
-
- length = BigLong(packetBuffer.length);
- flags = length & (~NETFLAG_LENGTH_MASK);
- length &= NETFLAG_LENGTH_MASK;
-
- if (flags & NETFLAG_CTL)
- continue;
-
- sequence = BigLong(packetBuffer.sequence);
- packetsReceived++;
-
- if (flags & NETFLAG_UNRELIABLE)
- {
- if (sequence < sock->unreliableReceiveSequence)
- {
- Con_DPrintf("Got a stale datagram\n");
- ret = 0;
- break;
- }
- if (sequence != sock->unreliableReceiveSequence)
- {
- count = sequence - sock->unreliableReceiveSequence;
- droppedDatagrams += count;
- Con_DPrintf("Dropped %u datagram(s)\n", count);
- }
- sock->unreliableReceiveSequence = sequence + 1;
-
- length -= NET_HEADERSIZE;
-
- SZ_Clear (&net_message);
- SZ_Write (&net_message, packetBuffer.data, length);
-
- ret = 2;
- break;
- }
-
- if (flags & NETFLAG_ACK)
- {
- if (sequence != (sock->sendSequence - 1))
- {
- Con_DPrintf("Stale ACK received\n");
- continue;
- }
- if (sequence == sock->ackSequence)
- {
- sock->ackSequence++;
- if (sock->ackSequence != sock->sendSequence)
- Con_DPrintf("ack sequencing error\n");
- }
- else
- {
- Con_DPrintf("Duplicate ACK received\n");
- continue;
- }
- sock->sendMessageLength -= MAX_DATAGRAM;
- if (sock->sendMessageLength > 0)
- {
- memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
- sock->sendNext = true;
- }
- else
- {
- sock->sendMessageLength = 0;
- sock->canSend = true;
- }
- continue;
- }
-
- if (flags & NETFLAG_DATA)
- {
- packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
- packetBuffer.sequence = BigLong(sequence);
- sfunc.Write (sock->socket, (qbyte *)&packetBuffer, NET_HEADERSIZE, &readaddr);
-
- if (sequence != sock->receiveSequence)
- {
- receivedDuplicateCount++;
- continue;
- }
- sock->receiveSequence++;
-
- length -= NET_HEADERSIZE;
-
- if (flags & NETFLAG_EOM)
- {
- SZ_Clear(&net_message);
- SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
- SZ_Write(&net_message, packetBuffer.data, length);
- sock->receiveMessageLength = 0;
-
- ret = 1;
- break;
- }
-
- memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
- sock->receiveMessageLength += length;
- continue;
- }
- }
-
- if (sock->sendNext)
- SendMessageNext (sock);
-
- return ret;
-}
-
-
-void PrintStats(qsocket_t *s)
-{
- Con_Printf("canSend = %4u \n", s->canSend);
- Con_Printf("sendSeq = %4u ", s->sendSequence);
- Con_Printf("recvSeq = %4u \n", s->receiveSequence);
- Con_Printf("\n");
-}
-
-void NET_Stats_f (void)
-{
- qsocket_t *s;
-
- if (Cmd_Argc () == 1)
- {
- Con_Printf("unreliable messages sent = %i\n", unreliableMessagesSent);
- Con_Printf("unreliable messages recv = %i\n", unreliableMessagesReceived);
- Con_Printf("reliable messages sent = %i\n", messagesSent);
- Con_Printf("reliable messages received = %i\n", messagesReceived);
- Con_Printf("packetsSent = %i\n", packetsSent);
- Con_Printf("packetsReSent = %i\n", packetsReSent);
- Con_Printf("packetsReceived = %i\n", packetsReceived);
- Con_Printf("receivedDuplicateCount = %i\n", receivedDuplicateCount);
- Con_Printf("shortPacketCount = %i\n", shortPacketCount);
- Con_Printf("droppedDatagrams = %i\n", droppedDatagrams);
- }
- else if (strcmp(Cmd_Argv(1), "*") == 0)
- {
- for (s = net_activeSockets; s; s = s->next)
- PrintStats(s);
- }
- else
- {
- for (s = net_activeSockets; s; s = s->next)
- if (strcasecmp(Cmd_Argv(1), s->address) == 0)
- break;
- if (s == NULL)
- return;
- PrintStats(s);
- }
-}
-
-/*
-static qboolean testInProgress = false;
-static int testPollCount;
-static int testDriver;
-static int testSocket;
-
-static void Test_Poll(void);
-PollProcedure testPollProcedure = {NULL, 0.0, Test_Poll};
-
-static void Test_Poll(void)
-{
- struct qsockaddr clientaddr;
- int control;
- int len;
- char name[32];
- char address[64];
- int colors;
- int frags;
- int connectTime;
- qbyte playerNumber;
- int c;
-
- net_landriverlevel = testDriver;
-
- while (1)
- {
- len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);
- if (len < (int)sizeof(int))
- break;
-
- net_message.cursize = len;
-
- MSG_BeginReading ();
- control = BigLong(*((int *)net_message.data));
- MSG_ReadLong();
- if (control == -1)
- break;
- if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
- break;
- if ((control & NETFLAG_LENGTH_MASK) != len)
- break;
-
- c = MSG_ReadByte();
- if (c != CCREP_PLAYER_INFO)
- Sys_Error("Unexpected repsonse to Player Info request\n");
-
- playerNumber = MSG_ReadByte();
- strcpy(name, MSG_ReadString());
- colors = MSG_ReadLong();
- frags = MSG_ReadLong();
- connectTime = MSG_ReadLong();
- strcpy(address, MSG_ReadString());
-
- Con_Printf("%s\n frags:%3i colors:%u %u time:%u\n %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);
- }
-
- testPollCount--;
- if (testPollCount)
- {
- SchedulePollProcedure(&testPollProcedure, 0.1);
- }
- else
- {
- dfunc.CloseSocket(testSocket);
- testInProgress = false;
- }
-}
-
-static void Test_f (void)
-{
- const char *host;
- int n, max = MAX_SCOREBOARD;
- struct qsockaddr sendaddr;
-
- if (testInProgress)
- return;
-
- host = Cmd_Argv (1);
-
- if (host && hostCacheCount)
- {
- for (n = 0; n < hostCacheCount; n++)
- if (strcasecmp (host, hostcache[n].name) == 0)
- {
- if (hostcache[n].driver != myDriverLevel)
- continue;
- net_landriverlevel = hostcache[n].ldriver;
- max = hostcache[n].maxusers;
- memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
- break;
- }
- if (n < hostCacheCount)
- goto JustDoIt;
- }
-
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- {
- if (!net_landrivers[net_landriverlevel].initialized)
- continue;
-
- // see if we can resolve the host name
- if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
- break;
- }
- if (net_landriverlevel == net_numlandrivers)
- return;
-
-JustDoIt:
- testSocket = dfunc.OpenSocket(0);
- if (testSocket == -1)
- return;
-
- testInProgress = true;
- testPollCount = 20;
- testDriver = net_landriverlevel;
-
- for (n = 0; n < max; n++)
- {
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);
- MSG_WriteByte(&net_message, n);
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);
- }
- SZ_Clear(&net_message);
- SchedulePollProcedure(&testPollProcedure, 0.1);
-}
-
-
-static qboolean test2InProgress = false;
-static int test2Driver;
-static int test2Socket;
-
-static void Test2_Poll(void);
-PollProcedure test2PollProcedure = {NULL, 0.0, Test2_Poll};
-
-static void Test2_Poll(void)
-{
- struct qsockaddr clientaddr;
- int control;
- int len;
- int c;
- char name[256];
- char value[256];
-
- net_landriverlevel = test2Driver;
- name[0] = 0;
-
- len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);
- if (len < (int)sizeof(int))
- goto Reschedule;
-
- net_message.cursize = len;
-
- MSG_BeginReading ();
- control = BigLong(*((int *)net_message.data));
- MSG_ReadLong();
- if (control == -1)
- goto Error;
- if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
- goto Error;
- if ((control & NETFLAG_LENGTH_MASK) != len)
- goto Error;
-
- c = MSG_ReadByte();
- if (c != CCREP_RULE_INFO)
- goto Error;
-
- strcpy(name, MSG_ReadString());
- if (name[0] == 0)
- goto Done;
- strcpy(value, MSG_ReadString());
-
- Con_Printf("%-16.16s %-16.16s\n", name, value);
-
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
- MSG_WriteString(&net_message, name);
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
-
-Reschedule:
- SchedulePollProcedure(&test2PollProcedure, 0.05);
- return;
-
-Error:
- Con_Printf("Unexpected repsonse to Rule Info request\n");
-Done:
- dfunc.CloseSocket(test2Socket);
- test2InProgress = false;
- return;
-}
-
-static void Test2_f (void)
-{
- const char *host;
- int n;
- struct qsockaddr sendaddr;
-
- if (test2InProgress)
- return;
-
- host = Cmd_Argv (1);
-
- if (host && hostCacheCount)
- {
- for (n = 0; n < hostCacheCount; n++)
- if (strcasecmp (host, hostcache[n].name) == 0)
- {
- if (hostcache[n].driver != myDriverLevel)
- continue;
- net_landriverlevel = hostcache[n].ldriver;
- memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
- break;
- }
- if (n < hostCacheCount)
- goto JustDoIt;
- }
-
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- {
- if (!net_landrivers[net_landriverlevel].initialized)
- continue;
-
- // see if we can resolve the host name
- if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
- break;
- }
- if (net_landriverlevel == net_numlandrivers)
- return;
-
-JustDoIt:
- test2Socket = dfunc.OpenSocket(0);
- if (test2Socket == -1)
- return;
-
- test2InProgress = true;
- test2Driver = net_landriverlevel;
-
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
- MSG_WriteString(&net_message, "");
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);
- SZ_Clear(&net_message);
- SchedulePollProcedure(&test2PollProcedure, 0.05);
-}
-*/
-
-int Datagram_Init (void)
-{
- int i;
- int csock;
-
- myDriverLevel = net_driverlevel;
- Cmd_AddCommand ("net_stats", NET_Stats_f);
- Cvar_RegisterVariable (&cl_port);
-
- if (COM_CheckParm("-nolan"))
- return -1;
-
- for (i = 0; i < net_numlandrivers; i++)
- {
- csock = net_landrivers[i].Init ();
- if (csock == -1)
- continue;
- net_landrivers[i].initialized = true;
- net_landrivers[i].controlSock = csock;
- }
-
-#ifdef BAN_TEST
- Cmd_AddCommand ("ban", NET_Ban_f);
-#endif
- //Cmd_AddCommand ("test", Test_f);
- //Cmd_AddCommand ("test2", Test2_f);
-
- return 0;
-}
-
-
-void Datagram_Shutdown (void)
-{
- int i;
-
-//
-// shutdown the lan drivers
-//
- for (i = 0; i < net_numlandrivers; i++)
- {
- if (net_landrivers[i].initialized)
- {
- net_landrivers[i].Shutdown ();
- net_landrivers[i].initialized = false;
- }
- }
-}
-
-
-void Datagram_Close (qsocket_t *sock)
-{
- sfunc.CloseSocket(sock->socket);
-}
-
-
-void Datagram_Listen (qboolean state)
-{
- int i;
-
- for (i = 0; i < net_numlandrivers; i++)
- if (net_landrivers[i].initialized)
- net_landrivers[i].Listen (state);
-}
-
-
-static qsocket_t *_Datagram_CheckNewConnections (void)
-{
- struct qsockaddr clientaddr;
- struct qsockaddr newaddr;
- int newsock;
- int acceptsock;
- qsocket_t *sock;
- qsocket_t *s;
- int len;
- int command;
- int control;
- int ret;
- int c;
-
- acceptsock = dfunc.CheckNewConnections();
- if (acceptsock == -1)
- return NULL;
-
- SZ_Clear(&net_message);
-
- len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
- if (len < (int)sizeof(int))
- return NULL;
- net_message.cursize = len;
-
- MSG_BeginReading ();
- control = BigLong(*((int *)net_message.data));
- MSG_ReadLong();
-
- // Messages starting by 0xFFFFFFFF are master server messages
- if ((unsigned int)control == 0xFFFFFFFF)
- {
- int responsesize = Master_HandleMessage();
- if (responsesize > 0)
- {
- dfunc.Write(acceptsock, net_message.data, responsesize, &clientaddr);
- SZ_Clear(&net_message);
- }
- return NULL;
- }
- if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
- return NULL;
- if ((control & NETFLAG_LENGTH_MASK) != len)
- return NULL;
-
- command = MSG_ReadByte();
- if (command == CCREQ_SERVER_INFO)
- {
- if (strcmp(MSG_ReadString(), "QUAKE") != 0)
- return NULL;
-
- Con_DPrintf("Datagram_CheckNewConnections: received CCREQ_SERVERINFO, replying.\n");
-
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
- dfunc.GetSocketAddr(acceptsock, &newaddr);
- MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
- MSG_WriteString(&net_message, hostname.string);
- MSG_WriteString(&net_message, sv.name);
- MSG_WriteByte(&net_message, net_activeconnections);
- MSG_WriteByte(&net_message, svs.maxclients);
- MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- return NULL;
- }
-
- if (command == CCREQ_PLAYER_INFO)
- {
- int playerNumber;
- int activeNumber;
- int clientNumber;
- client_t *client;
-
- playerNumber = MSG_ReadByte();
- activeNumber = -1;
- for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
- {
- if (client->active)
- {
- activeNumber++;
- if (activeNumber == playerNumber)
- break;
- }
- }
- if (clientNumber == svs.maxclients)
- return NULL;
-
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
- MSG_WriteByte(&net_message, playerNumber);
- MSG_WriteString(&net_message, client->name);
- MSG_WriteLong(&net_message, client->colors);
- MSG_WriteLong(&net_message, (int)client->edict->v->frags);
- MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
- MSG_WriteString(&net_message, client->netconnection->address);
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
-
- return NULL;
- }
-
- if (command == CCREQ_RULE_INFO)
- {
- char *prevCvarName;
- cvar_t *var;
-
- // find the search start location
- prevCvarName = MSG_ReadString();
- var = Cvar_FindVarAfter(prevCvarName, CVAR_NOTIFY);
-
- // send the response
-
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREP_RULE_INFO);
- if (var)
- {
- MSG_WriteString(&net_message, var->name);
- MSG_WriteString(&net_message, var->string);
- }
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
-
- return NULL;
- }
-
- if (command != CCREQ_CONNECT)
- return NULL;
-
- if (strcmp(MSG_ReadString(), "QUAKE") != 0)
- return NULL;
-
- c = MSG_ReadByte();
- if (c != NET_PROTOCOL_VERSION)
- {
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREP_REJECT);
- MSG_WriteString(&net_message, "Incompatible version.\n");
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- return NULL;
- }
-
-#ifdef BAN_TEST
- // check for a ban
- if (clientaddr.sa_family == AF_INET)
- {
- unsigned long testAddr;
- testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;
- if ((testAddr & banMask) == banAddr)
- {
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREP_REJECT);
- MSG_WriteString(&net_message, "You have been banned.\n");
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- return NULL;
- }
- }
-#endif
-
- // see if this guy is already connected
- for (s = net_activeSockets; s; s = s->next)
- {
- if (s->driver != net_driverlevel)
- continue;
- ret = dfunc.AddrCompare(&clientaddr, &s->addr);
- if (ret >= 0)
- {
- // is this a duplicate connection request?
- if (ret == 0 && net_time - s->connecttime < 2.0)
- {
- // yes, so send a duplicate reply
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREP_ACCEPT);
- dfunc.GetSocketAddr(s->socket, &newaddr);
- MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- // LordHavoc: send from s->socket instead of acceptsock, this
- // way routers usually identify the connection correctly
- // (thanks to faded for provoking me to recite a lengthy
- // explanation of NAT nightmares, and realize this easy
- // workaround for quake)
- dfunc.Write (s->socket, net_message.data, net_message.cursize, &clientaddr);
- // LordHavoc: also send from acceptsock, for good measure
- dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- return NULL;
- }
- // it's somebody coming back in from a crash/disconnect
- // so close the old qsocket and let their retry get them back in
- NET_Close(s);
- return NULL;
- }
- }
-
- // allocate a QSocket
- sock = NET_NewQSocket ();
- if (sock == NULL)
- {
- // no room; try to let him know
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREP_REJECT);
- MSG_WriteString(&net_message, "Server is full.\n");
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
- return NULL;
- }
-
- // allocate a network socket
- newsock = dfunc.OpenSocket(0);
- if (newsock == -1)
- {
- NET_FreeQSocket(sock);
- return NULL;
- }
-
- // connect to the client
- if (dfunc.Connect (newsock, &clientaddr) == -1)
- {
- dfunc.CloseSocket(newsock);
- NET_FreeQSocket(sock);
- return NULL;
- }
-
- // everything is allocated, just fill in the details
- sock->socket = newsock;
- sock->landriver = net_landriverlevel;
- sock->addr = clientaddr;
- strcpy(sock->address, dfunc.AddrToString(&clientaddr));
-
- // send him back the info about the server connection he has been allocated
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREP_ACCEPT);
- dfunc.GetSocketAddr(newsock, &newaddr);
- MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- // LordHavoc: send from sock->socket instead of acceptsock, this way routers
- // usually identify the connection correctly (thanks to faded for provoking
- // me to recite a lengthy explanation of NAT nightmares, and realize this
- // easy workaround for quake)
- dfunc.Write (sock->socket, net_message.data, net_message.cursize, &clientaddr);
- // LordHavoc: also send from acceptsock, for good measure
- dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
- SZ_Clear(&net_message);
-
- return sock;
-}
-
-qsocket_t *Datagram_CheckNewConnections (void)
-{
- qsocket_t *ret = NULL;
-
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- if (net_landrivers[net_landriverlevel].initialized)
- if ((ret = _Datagram_CheckNewConnections ()) != NULL)
- break;
- return ret;
-}
-
-
-static qboolean Datagram_HandleServerInfo (struct qsockaddr *readaddr)
-{
- //struct qsockaddr myaddr;
- int control;
- int c, n;
- char cname[256];
-
- if (net_message.cursize < (int)sizeof(int))
- return false;
-
- // don't answer our own query
- //dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
- //if (dfunc.AddrCompare(readaddr, &myaddr) >= 0)
- // return false;
-
- // is the cache full?
- if (hostCacheCount == HOSTCACHESIZE)
- return false;
-
- MSG_BeginReading ();
- control = BigLong(*((int *)net_message.data));
- MSG_ReadLong();
- if (control == -1)
- return false;
- if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
- return false;
- if ((control & NETFLAG_LENGTH_MASK) != net_message.cursize)
- return false;
-
- c = MSG_ReadByte();
- if (c != CCREP_SERVER_INFO)
- return false;
-
- // LordHavoc: because the UDP driver reports 0.0.0.0:26000 as the address
- // string we just ignore it and keep the real address
- MSG_ReadString();
- // hostcache only uses text addresses
- strcpy(cname, dfunc.AddrToString(readaddr));
- // search the cache for this server
- for (n = 0; n < hostCacheCount; n++)
- //if (dfunc.AddrCompare(readaddr, &hostcache[n].addr) == 0)
- if (!strcmp(cname, hostcache[n].cname))
- return false;
-
- // add it
- hostCacheCount++;
- strcpy(hostcache[n].name, MSG_ReadString());
- strcpy(hostcache[n].map, MSG_ReadString());
- hostcache[n].users = MSG_ReadByte();
- hostcache[n].maxusers = MSG_ReadByte();
- c = MSG_ReadByte();
- if (c != NET_PROTOCOL_VERSION)
- {
- strncpy(hostcache[n].cname, hostcache[n].name, sizeof(hostcache[n].cname) - 1);
- hostcache[n].cname[sizeof(hostcache[n].cname) - 1] = 0;
- strcpy(hostcache[n].name, "*");
- strncat(hostcache[n].name, hostcache[n].cname, sizeof(hostcache[n].name) - 1);
- hostcache[n].name[sizeof(hostcache[n].name) - 1] = 0;
- }
- strcpy(hostcache[n].cname, cname);
- //memcpy(&hostcache[n].addr, readaddr, sizeof(struct qsockaddr));
- //hostcache[n].driver = net_driverlevel;
- //hostcache[n].ldriver = net_landriverlevel;
-
- /*
- // check for a name conflict
- for (i = 0; i < hostCacheCount; i++)
- {
- if (i == n)
- continue;
- if (strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
- {
- i = strlen(hostcache[n].name);
- if (i < 15 && hostcache[n].name[i-1] > '8')
- {
- hostcache[n].name[i] = '0';
- hostcache[n].name[i+1] = 0;
- }
- else
- hostcache[n].name[i-1]++;
- i = -1;
- }
- }
- */
-
- return true;
-}
-
-
-static void _Datagram_SearchForHosts (qboolean xmit)
-{
- int ret;
- struct qsockaddr readaddr;
-
- if (xmit)
- {
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
- MSG_WriteString(&net_message, "QUAKE");
- MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
- SZ_Clear(&net_message);
- }
-
- while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
- {
- net_message.cursize = ret;
- Datagram_HandleServerInfo (&readaddr);
- }
-}
-
-void Datagram_SearchForHosts (qboolean xmit)
-{
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- {
- if (hostCacheCount == HOSTCACHESIZE)
- break;
- if (net_landrivers[net_landriverlevel].initialized)
- _Datagram_SearchForHosts (xmit);
- }
-}
-
-
-static qboolean _Datagram_SearchForInetHosts (const char *master)
-{
- qboolean result = false;
- struct qsockaddr masteraddr;
- struct qsockaddr readaddr;
- int ret;
-
- if (master)
- {
- if (dfunc.GetAddrFromName(master, &masteraddr) != -1)
- {
- int portnum = 0;
- const char* port = strrchr (master, ':');
- if (port)
- portnum = atoi (port + 1);
- if (!portnum)
- portnum = MASTER_PORT;
- Con_DPrintf("Datagram_SearchForInetHosts: sending %d byte message to master %s port %i\n", net_message.cursize, master, portnum);
- dfunc.SetSocketPort (&masteraddr, portnum);
- dfunc.Write (dfunc.controlSock, net_message.data, net_message.cursize, &masteraddr);
- }
- }
-
- while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
- {
- net_message.cursize = ret;
- Con_DPrintf("Datagram_SearchForInetHosts: Read received %d byte message\n", net_message.cursize);
- if (Datagram_HandleServerInfo (&readaddr))
- result = true;
- else
- Master_ParseServerList (&dfunc);
- }
-
- return result;
-}
-
-
-qboolean Datagram_SearchForInetHosts (const char *master)
-{
- qboolean result = false;
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- {
- if (hostCacheCount == HOSTCACHESIZE)
- break;
- if (net_landrivers[net_landriverlevel].initialized)
- if (_Datagram_SearchForInetHosts (master))
- result = true;
- }
-
- return result;
-}
-
-
-static qsocket_t *_Datagram_Connect (const char *host)
-{
- struct qsockaddr sendaddr;
- struct qsockaddr readaddr;
- qsocket_t *sock;
- int newsock;
- int ret;
- int reps;
- double start_time;
- int control;
- char *reason;
-
- // see if we can resolve the host name
- if (dfunc.GetAddrFromName(host, &sendaddr) == -1)
- return NULL;
-
- newsock = dfunc.OpenSocket (cl_port.integer);
- if (newsock == -1)
- return NULL;
-
- sock = NET_NewQSocket ();
- if (sock == NULL)
- goto ErrorReturn2;
- sock->socket = newsock;
- sock->landriver = net_landriverlevel;
-
- // connect to the host
- if (dfunc.Connect (newsock, &sendaddr) == -1)
- goto ErrorReturn;
-
- // send the connection request
- Con_Printf("trying...\n");CL_UpdateScreen();CL_UpdateScreen();
- start_time = net_time;
-
- for (reps = 0; reps < 3; reps++)
- {
- SZ_Clear(&net_message);
- // save space for the header, filled in later
- MSG_WriteLong(&net_message, 0);
- MSG_WriteByte(&net_message, CCREQ_CONNECT);
- MSG_WriteString(&net_message, "QUAKE");
- MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);
- SZ_Clear(&net_message);
- do
- {
- ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);
- // if we got something, validate it
- if (ret > 0)
- {
- // is it from the right place?
- // we don't care if the port matches (this adds support for
- // the NAT fix in the server inspired by faded)
- if (sfunc.AddrCompare(&readaddr, &sendaddr) < 0)
- {
- char tempaddress1[64], tempaddress2[64];
- dfunc.GetNameFromAddr (&sendaddr, tempaddress1);
- dfunc.GetNameFromAddr (&readaddr, tempaddress2);
- Con_Printf("wrong reply address (Expected: %s Received: %s)\n", tempaddress1, tempaddress2);
- CL_UpdateScreen ();
- CL_UpdateScreen ();
- ret = 0;
- continue;
- }
-
- if (ret < (int)sizeof(int))
- {
- ret = 0;
- continue;
- }
-
- net_message.cursize = ret;
- MSG_BeginReading ();
-
- control = BigLong(*((int *)net_message.data));
- MSG_ReadLong();
- if (control == -1)
- {
- ret = 0;
- continue;
- }
- if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
- {
- ret = 0;
- continue;
- }
- if ((control & NETFLAG_LENGTH_MASK) != ret)
- {
- ret = 0;
- continue;
- }
- }
- }
- while (ret == 0 && (SetNetTime() - start_time) < 2.5);
- if (ret)
- break;
- Con_Printf("still trying...\n");CL_UpdateScreen();CL_UpdateScreen();
- start_time = SetNetTime();
- }
-
- if (ret == 0)
- {
- reason = "No Response";
- Con_Printf("%s\n", reason);
- strcpy(m_return_reason, reason);
- goto ErrorReturn;
- }
-
- if (ret == -1)
- {
- reason = "Network Error";
- Con_Printf("%s\n", reason);
- strcpy(m_return_reason, reason);
- goto ErrorReturn;
- }
-
- ret = MSG_ReadByte();
- if (ret == CCREP_REJECT)
- {
- reason = MSG_ReadString();
- Con_Printf("%s", reason);
- strncpy(m_return_reason, reason, 31);
- goto ErrorReturn;
- }
-
- if (ret == CCREP_ACCEPT)
- {
- memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));
- dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
- }
- else
- {
- reason = "Bad Response";
- Con_Printf("%s\n", reason);
- strcpy(m_return_reason, reason);
- goto ErrorReturn;
- }
-
- dfunc.GetNameFromAddr (&sendaddr, sock->address);
-
- Con_Printf ("Connection accepted to %s\n", sock->address);
- sock->lastMessageTime = SetNetTime();
-
- // switch the connection to the specified address
- if (dfunc.Connect (newsock, &sock->addr) == -1)
- {
- reason = "Connect to Game failed";
- Con_Printf("%s\n", reason);
- strcpy(m_return_reason, reason);
- goto ErrorReturn;
- }
-
- m_return_onerror = false;
- return sock;
-
-ErrorReturn:
- NET_FreeQSocket(sock);
-ErrorReturn2:
- dfunc.CloseSocket(newsock);
- if (m_return_onerror)
- {
- key_dest = key_menu;
- m_state = m_return_state;
- m_return_onerror = false;
- }
- return NULL;
-}
-
-qsocket_t *Datagram_Connect (const char *host)
-{
- qsocket_t *ret = NULL;
-
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- if (net_landrivers[net_landriverlevel].initialized)
- if ((ret = _Datagram_Connect (host)) != NULL)
- break;
- return ret;
-}
-
-static void _Datagram_Heartbeat (const char *master)
-{
- struct qsockaddr masteraddr;
- int portnum;
- const char* port;
-
- if (dfunc.GetAddrFromName(master, &masteraddr) == -1)
- return;
-
- portnum = 0;
- port = strrchr (master, ':');
- if (port)
- portnum = atoi (port + 1);
- if (!portnum)
- portnum = MASTER_PORT;
- dfunc.SetSocketPort (&masteraddr, portnum);
-
- // FIXME: this is the only use of UDP_Send in the entire engine, add a dfunc.acceptSock to get rid of this function!
- dfunc.Send (net_message.data, net_message.cursize, &masteraddr);
-}
-
-void Datagram_Heartbeat (const char *master)
-{
- for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
- if (net_landrivers[net_landriverlevel].initialized)
- _Datagram_Heartbeat (master);
-}
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net_dgrm.h
-
-#ifndef NET_DGRM_H
-#define NET_DGRM_H
-
-int Datagram_Init (void);
-void Datagram_Listen (qboolean state);
-void Datagram_SearchForHosts (qboolean xmit);
-qboolean Datagram_SearchForInetHosts (const char *master);
-qsocket_t *Datagram_Connect (const char *host);
-qsocket_t *Datagram_CheckNewConnections (void);
-int Datagram_GetMessage (qsocket_t *sock);
-int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data);
-int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
-qboolean Datagram_CanSendMessage (qsocket_t *sock);
-qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock);
-void Datagram_Close (qsocket_t *sock);
-void Datagram_Shutdown (void);
-void Datagram_Heartbeat (const char *master);
-
-#endif
-
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net_loop.c
-
-#include "quakedef.h"
-#include "net_loop.h"
-
-qboolean localconnectpending = false;
-qsocket_t *loop_client = NULL;
-qsocket_t *loop_server = NULL;
-
-int Loop_Init (void)
-{
- if (cls.state == ca_dedicated)
- return -1;
- return 0;
-}
-
-
-void Loop_Shutdown (void)
-{
-}
-
-
-void Loop_Heartbeat (const char *master)
-{
-}
-
-
-void Loop_Listen (qboolean state)
-{
-}
-
-
-void Loop_SearchForHosts (qboolean xmit)
-{
- if (!sv.active)
- return;
-
- hostCacheCount = 1;
- if (strcmp(hostname.string, "UNNAMED") == 0)
- strcpy(hostcache[0].name, "local");
- else
- strcpy(hostcache[0].name, hostname.string);
- strcpy(hostcache[0].map, sv.name);
- hostcache[0].users = net_activeconnections;
- hostcache[0].maxusers = svs.maxclients;
- //hostcache[0].driver = net_driverlevel;
- strcpy(hostcache[0].cname, "local");
-}
-
-
-qboolean Loop_SearchForInetHosts (const char *master)
-{
- return false;
-}
-
-
-qsocket_t *Loop_Connect (const char *host)
-{
- if (strcmp(host,"local") != 0)
- return NULL;
-
- localconnectpending = true;
-
- if (!loop_client)
- {
- if ((loop_client = NET_NewQSocket ()) == NULL)
- {
- Con_Printf("Loop_Connect: no qsocket available\n");
- return NULL;
- }
- strcpy (loop_client->address, "localhost");
- }
- loop_client->receiveMessageLength = 0;
- loop_client->sendMessageLength = 0;
- loop_client->canSend = true;
-
- if (!loop_server)
- {
- if ((loop_server = NET_NewQSocket ()) == NULL)
- {
- Con_Printf("Loop_Connect: no qsocket available\n");
- return NULL;
- }
- strcpy (loop_server->address, "LOCAL");
- }
- loop_server->receiveMessageLength = 0;
- loop_server->sendMessageLength = 0;
- loop_server->canSend = true;
-
- loop_client->driverdata = (void *)loop_server;
- loop_server->driverdata = (void *)loop_client;
-
- return loop_client;
-}
-
-
-qsocket_t *Loop_CheckNewConnections (void)
-{
- if (!localconnectpending)
- return NULL;
-
- localconnectpending = false;
- loop_server->sendMessageLength = 0;
- loop_server->receiveMessageLength = 0;
- loop_server->canSend = true;
- loop_client->sendMessageLength = 0;
- loop_client->receiveMessageLength = 0;
- loop_client->canSend = true;
- return loop_server;
-}
-
-
-static int IntAlign(int value)
-{
- return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));
-}
-
-
-int Loop_GetMessage (qsocket_t *sock)
-{
- int ret;
- int length;
-
- if (sock->receiveMessageLength == 0)
- return 0;
-
- ret = sock->receiveMessage[0];
- length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);
- // alignment byte skipped here
- SZ_Clear (&net_message);
- SZ_Write (&net_message, &sock->receiveMessage[4], length);
-
- length = IntAlign(length + 4);
- sock->receiveMessageLength -= length;
-
- if (sock->receiveMessageLength)
- memcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength);
-
- if (sock->driverdata && ret == 1)
- ((qsocket_t *)sock->driverdata)->canSend = true;
-
- return ret;
-}
-
-
-int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data)
-{
- qbyte *buffer;
- int *bufferLength;
-
- if (!sock->driverdata)
- return -1;
-
- bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;
-
- if ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE)
- Host_Error("Loop_SendMessage: overflow\n");
-
- buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;
-
- // message type
- *buffer++ = 1;
-
- // length
- *buffer++ = data->cursize & 0xff;
- *buffer++ = data->cursize >> 8;
-
- // align
- buffer++;
-
- // message
- memcpy(buffer, data->data, data->cursize);
- *bufferLength = IntAlign(*bufferLength + data->cursize + 4);
-
- sock->canSend = false;
- return 1;
-}
-
-
-int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
-{
- qbyte *buffer;
- int *bufferLength;
-
- if (!sock->driverdata)
- return -1;
-
- bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;
-
- // LordHavoc: added an extra sizeof(qbyte) to account for alignment
- if ((*bufferLength + data->cursize + sizeof(qbyte) + sizeof(short) + sizeof(qbyte)) > NET_MAXMESSAGE)
- return 0;
-
- buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;
-
- // message type
- *buffer++ = 2;
-
- // length
- *buffer++ = data->cursize & 0xff;
- *buffer++ = data->cursize >> 8;
-
- // align
- buffer++;
-
- // message
- memcpy(buffer, data->data, data->cursize);
- *bufferLength = IntAlign(*bufferLength + data->cursize + 4);
- return 1;
-}
-
-
-qboolean Loop_CanSendMessage (qsocket_t *sock)
-{
- if (!sock->driverdata)
- return false;
- return sock->canSend;
-}
-
-
-qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock)
-{
- return true;
-}
-
-
-void Loop_Close (qsocket_t *sock)
-{
- if (sock->driverdata)
- ((qsocket_t *)sock->driverdata)->driverdata = NULL;
- sock->receiveMessageLength = 0;
- sock->sendMessageLength = 0;
- sock->canSend = true;
- if (sock == loop_client)
- loop_client = NULL;
- else
- loop_server = NULL;
-}
-
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net_loop.h
-
-#ifndef NET_LOOP_H
-#define NET_LOOP_H
-
-int Loop_Init (void);
-void Loop_Listen (qboolean state);
-void Loop_SearchForHosts (qboolean xmit);
-qboolean Loop_SearchForInetHosts (const char *master);
-qsocket_t *Loop_Connect (const char *host);
-qsocket_t *Loop_CheckNewConnections (void);
-int Loop_GetMessage (qsocket_t *sock);
-int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data);
-int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
-qboolean Loop_CanSendMessage (qsocket_t *sock);
-qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock);
-void Loop_Close (qsocket_t *sock);
-void Loop_Shutdown (void);
-void Loop_Heartbeat (const char *master);
-
-#endif
-
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net_main.c
-
-#include "quakedef.h"
-#include "net_master.h"
-
-qsocket_t *net_activeSockets = NULL;
-mempool_t *net_mempool;
-
-qboolean ipxAvailable = false;
-qboolean tcpipAvailable = false;
-
-int net_hostport;
-int DEFAULTnet_hostport = 26000;
-
-char my_ipx_address[NET_NAMELEN];
-char my_tcpip_address[NET_NAMELEN];
-
-static qboolean listening = false;
-
-qboolean slistInProgress = false;
-qboolean slistSilent = false;
-qboolean slistLocal = true;
-static double slistStartTime;
-static int slistLastShown;
-
-static void Slist_Send(void);
-static void Slist_Poll(void);
-PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
-PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
-
-static void InetSlist_Send(void);
-static void InetSlist_Poll(void);
-PollProcedure inetSlistSendProcedure = {NULL, 0.0, InetSlist_Send};
-PollProcedure inetSlistPollProcedure = {NULL, 0.0, InetSlist_Poll};
-
-
-sizebuf_t net_message;
-int net_activeconnections = 0;
-
-int messagesSent = 0;
-int messagesReceived = 0;
-int unreliableMessagesSent = 0;
-int unreliableMessagesReceived = 0;
-
-cvar_t net_messagetimeout = {0, "net_messagetimeout","300"};
-cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED"};
-cvar_t developer_networking = {0, "developer_networking", "0"};
-
-qboolean configRestored = false;
-
-// these two macros are to make the code more readable
-#define sfunc net_drivers[sock->driver]
-#define dfunc net_drivers[net_driverlevel]
-
-int net_driverlevel;
-
-/*
-#define SLSERVERS 1024
-#define SLNAME 40
-#define SLMAPNAME 16
-#define SLMODNAME 16
-typedef struct slserver_s
-{
- unsigned int ipaddr;
- unsigned short port;
- unsigned short ping;
- char name[SLNAME];
- char mapname[SLMAPNAME];
- char modname[SLMODNAME];
-}
-slserver_t;
-
-slserver_t sl_server[SLSERVERS];
-int sl_numservers = 0;
-
-void SL_ClearServers(void)
-{
- sl_numservers = 0;
-}
-
-slserver_t *SL_FindServer(unsigned int ipaddr, unsigned short port)
-{
- int i;
- slserver_t *sl;
- for (i = 0, sl = sl_server;i < sl_numservers;i++, sl++)
- if (sl->ipaddr == ipaddr && sl->port == port)
- return;
-}
-
-void SL_AddServer(unsigned int ipaddr, unsigned short port)
-{
- if (SL_FindServer(ipaddr, port))
- return;
- memset(sl_server + sl_numservers, 0, sizeof(slserver_t));
- sl_server[sl_numservers].ipaddr = ipaddr;
- sl_server[sl_numservers].port = port;
- sl_server[sl_numservers].ping = 0xFFFF;
- sl_numservers++;
-}
-
-void SL_UpdateServerName(unsigned int ipaddr, unsigned short port, const char *name);
-{
- int namelen;
- slserver_t *sl;
- sl = SL_FindServer(ipaddr, port);
- if (sl == NULL)
- return;
- memset(sl->name, 0, sizeof(sl->name));
- namelen = strlen(name);
- if (namelen > sizeof(sl->name) - 1)
- namelen = sizeof(sl->name) - 1;
- if (namelen)
- memcpy(sl->name, name, namelen);
-}
-
-void SL_UpdateServerModName(unsigned int ipaddr, unsigned short port, const char *name);
-{
- int namelen;
- slserver_t *sl;
- sl = SL_FindServer(ipaddr, port);
- if (sl == NULL)
- return;
- memset(sl->modname, 0, sizeof(sl->modname));
- namelen = strlen(name);
- if (namelen > sizeof(sl->modname) - 1)
- namelen = sizeof(sl->modname) - 1;
- if (namelen)
- memcpy(sl->modname, name, namelen);
-}
-
-void SL_UpdateServerMapName(unsigned int ipaddr, unsigned short port, const char *name);
-{
- int namelen;
- slserver_t *sl;
- sl = SL_FindServer(ipaddr, port);
- if (sl == NULL)
- return;
- memset(sl->mapname, 0, sizeof(sl->mapname));
- namelen = strlen(name);
- if (namelen > sizeof(sl->mapname) - 1)
- namelen = sizeof(sl->mapname) - 1;
- if (namelen)
- memcpy(sl->mapname, name, namelen);
-}
-
-void SL_UpdateServerPing(unsigned int ipaddr, unsigned short port, float ping);
-{
- int i;
- slserver_t *sl;
- sl = SL_FindServer(ipaddr, port);
- if (sl == NULL)
- return;
- i = ping * 1000.0;
- sl->ping = bound(0, i, 9999);
-}
-*/
-
-
-double net_time;
-
-double SetNetTime(void)
-{
- net_time = Sys_DoubleTime();
- return net_time;
-}
-
-
-/*
-===================
-NET_NewQSocket
-
-Called by drivers when a new communications endpoint is required
-The sequence and buffer fields will be filled in properly
-===================
-*/
-qsocket_t *NET_NewQSocket (void)
-{
- qsocket_t *sock;
-
- if (net_activeconnections >= svs.maxclients)
- return NULL;
-
- sock = Mem_Alloc(net_mempool, sizeof(qsocket_t));
-
- // add it to active list
- sock->next = net_activeSockets;
- net_activeSockets = sock;
-
- sock->disconnected = false;
- sock->connecttime = net_time;
- strcpy (sock->address,"UNSET ADDRESS");
- sock->driver = net_driverlevel;
- sock->socket = 0;
- sock->driverdata = NULL;
- sock->canSend = true;
- sock->sendNext = false;
- sock->lastMessageTime = net_time;
- sock->ackSequence = 0;
- sock->sendSequence = 0;
- sock->unreliableSendSequence = 0;
- sock->sendMessageLength = 0;
- sock->receiveSequence = 0;
- sock->unreliableReceiveSequence = 0;
- sock->receiveMessageLength = 0;
-
- return sock;
-}
-
-
-void NET_FreeQSocket(qsocket_t *sock)
-{
- qsocket_t *s;
-
- // remove it from active list
- if (sock == net_activeSockets)
- net_activeSockets = net_activeSockets->next;
- else
- {
- for (s = net_activeSockets; s; s = s->next)
- if (s->next == sock)
- {
- s->next = sock->next;
- break;
- }
- if (!s)
- Sys_Error ("NET_FreeQSocket: not active\n");
- }
-
- Mem_Free(sock);
-}
-
-
-static void NET_Listen_f (void)
-{
- if (Cmd_Argc () != 2)
- {
- Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
- return;
- }
-
- listening = atoi(Cmd_Argv(1)) ? true : false;
-
- for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
- {
- if (net_drivers[net_driverlevel].initialized == false)
- continue;
- dfunc.Listen (listening);
- }
-}
-
-
-static void MaxPlayers_f (void)
-{
- int n;
-
- if (Cmd_Argc () != 2)
- {
- Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
- return;
- }
-
- if (sv.active)
- {
- Con_Printf ("maxplayers can not be changed while a server is running.\n");
- return;
- }
-
- n = atoi(Cmd_Argv(1));
- n = bound(1, n, MAX_SCOREBOARD);
- if (svs.maxclients != n)
- Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
-
- if ((n == 1) && listening)
- Cbuf_AddText ("listen 0\n");
-
- if ((n > 1) && (!listening))
- Cbuf_AddText ("listen 1\n");
-
- SV_SetMaxClients(n);
-}
-
-
-static void NET_Port_f (void)
-{
- int n;
-
- if (Cmd_Argc () != 2)
- {
- Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
- return;
- }
-
- n = atoi(Cmd_Argv(1));
- if (n < 1 || n > 65534)
- {
- Con_Printf ("Bad value, must be between 1 and 65534\n");
- return;
- }
-
- DEFAULTnet_hostport = n;
- net_hostport = n;
-
- if (listening)
- {
- // force a change to the new port
- Cbuf_AddText ("listen 0\n");
- Cbuf_AddText ("listen 1\n");
- }
-}
-
-
-static void NET_Heartbeat_f (void)
-{
- NET_Heartbeat (2);
-}
-
-
-static void PrintSlistHeader(void)
-{
- Con_Printf("Server Address Name/Description Map Users\n");
- Con_Printf("--------------------- ---------------------------------- --------------- -----\n");
- slistLastShown = 0;
-}
-
-
-static void PrintSlist(void)
-{
- int n;
- for (n = slistLastShown; n < hostCacheCount; n++)
- Con_Printf("%-21.21s %-34.34s %-15.15s %2u/%2u\n", hostcache[n].cname, hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
- slistLastShown = n;
-}
-
-
-static void PrintSlistTrailer(void)
-{
- if (hostCacheCount)
- Con_Printf("== end list ==\n\n");
- else
- Con_Printf("No %s servers found.\n\n", gamename);
-}
-
-
-void NET_SlistCommon (PollProcedure *sendProcedure, PollProcedure *pollProcedure)
-{
- if (slistInProgress)
- return;
-
- if (! slistSilent)
- {
- Con_Printf("Looking for %s servers...\n", gamename);
- PrintSlistHeader();
- }
-
- slistInProgress = true;
- slistStartTime = Sys_DoubleTime();
-
- SchedulePollProcedure(sendProcedure, 0.0);
- SchedulePollProcedure(pollProcedure, 0.1);
-
- hostCacheCount = 0;
-}
-
-
-void NET_Slist_f (void)
-{
- NET_SlistCommon (&slistSendProcedure, &slistPollProcedure);
-}
-
-
-void NET_InetSlist_f (void)
-{
- NET_SlistCommon (&inetSlistSendProcedure, &inetSlistPollProcedure);
-}
-
-
-static void Slist_Send(void)
-{
- for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
- {
- if (!slistLocal && net_driverlevel == 0)
- continue;
- if (net_drivers[net_driverlevel].initialized == false)
- continue;
- dfunc.SearchForHosts (true);
- }
-
- if ((Sys_DoubleTime() - slistStartTime) < 0.5)
- SchedulePollProcedure(&slistSendProcedure, 0.75);
-}
-
-
-static void Slist_Poll(void)
-{
- for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
- {
- if (!slistLocal && net_driverlevel == 0)
- continue;
- if (net_drivers[net_driverlevel].initialized == false)
- continue;
- dfunc.SearchForHosts (false);
- }
-
- if (! slistSilent)
- PrintSlist();
-
- if ((Sys_DoubleTime() - slistStartTime) < 1.5)
- {
- SchedulePollProcedure(&slistPollProcedure, 0.1);
- return;
- }
-
- if (! slistSilent)
- PrintSlistTrailer();
- slistInProgress = false;
- slistSilent = false;
- slistLocal = true;
-}
-
-
-static void InetSlist_Send(void)
-{
- const char* host;
-
- if (!slistInProgress)
- return;
-
- while ((host = Master_BuildGetServers ()) != NULL)
- {
- for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
- {
- if (!slistLocal && net_driverlevel == 0)
- continue;
- if (net_drivers[net_driverlevel].initialized == false)
- continue;
- dfunc.SearchForInetHosts (host);
- }
- }
-
- if ((Sys_DoubleTime() - slistStartTime) < 3.5)
- SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
-}
-
-
-static void InetSlist_Poll(void)
-{
- for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
- {
- if (!slistLocal && net_driverlevel == 0)
- continue;
- if (net_drivers[net_driverlevel].initialized == false)
- continue;
- // We stop as soon as we have one answer (FIXME: bad...)
- if (dfunc.SearchForInetHosts (NULL))
- slistInProgress = false;
- }
-
- if (! slistSilent)
- PrintSlist();
-
- if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
- {
- SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
- return;
- }
-
- if (! slistSilent)
- PrintSlistTrailer();
- slistInProgress = false;
- slistSilent = false;
- slistLocal = true;
-}
-
-
-/*
-===================
-NET_Connect
-===================
-*/
-
-int hostCacheCount = 0;
-hostcache_t hostcache[HOSTCACHESIZE];
-
-qsocket_t *NET_Connect (char *host)
-{
- qsocket_t *ret;
-
- if (host == NULL || *host == 0)
- return NULL;
-
- SetNetTime();
-
- if (host && strcasecmp (host, "local") == 0)
- {
- net_driverlevel = 0;
- return dfunc.Connect (host);
- }
-
- for (net_driverlevel = 0;net_driverlevel < net_numdrivers;net_driverlevel++)
- {
- if (net_drivers[net_driverlevel].initialized == false)
- continue;
- ret = dfunc.Connect (host);
- if (ret)
- return ret;
- }
-
- return NULL;
-}
-
-
-/*
-===================
-NET_CheckNewConnections
-===================
-*/
-
-qsocket_t *NET_CheckNewConnections (void)
-{
- qsocket_t *ret;
-
- SetNetTime();
-
- for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
- {
- if (net_drivers[net_driverlevel].initialized == false)
- continue;
- if (net_driverlevel && listening == false)
- continue;
- ret = dfunc.CheckNewConnections ();
- if (ret)
- return ret;
- }
-
- return NULL;
-}
-
-/*
-===================
-NET_Close
-===================
-*/
-void NET_Close (qsocket_t *sock)
-{
- if (!sock)
- return;
-
- if (sock->disconnected)
- return;
-
- SetNetTime();
-
- // call the driver_Close function
- sfunc.Close (sock);
-
- NET_FreeQSocket(sock);
-}
-
-
-/*
-=================
-NET_GetMessage
-
-If there is a complete message, return it in net_message
-
-returns 0 if no data is waiting
-returns 1 if a message was received
-returns -1 if connection is invalid
-=================
-*/
-
-extern void PrintStats(qsocket_t *s);
-
-int NET_GetMessage (qsocket_t *sock)
-{
- int ret;
-
- if (!sock)
- return -1;
-
- if (sock->disconnected)
- {
- Con_Printf("NET_GetMessage: disconnected socket\n");
- return -1;
- }
-
- SetNetTime();
-
- ret = sfunc.QGetMessage(sock);
-
- // see if this connection has timed out
- if (ret == 0 && sock->driver)
- {
- if (net_time - sock->lastMessageTime > net_messagetimeout.value)
- {
- NET_Close(sock);
- return -1;
- }
- }
-
-
- if (ret > 0)
- {
- if (sock->driver)
- {
- sock->lastMessageTime = net_time;
- if (ret == 1)
- messagesReceived++;
- else if (ret == 2)
- unreliableMessagesReceived++;
- }
- }
-
- return ret;
-}
-
-
-/*
-==================
-NET_SendMessage
-
-Try to send a complete length+message unit over the reliable stream.
-returns 0 if the message cannot be delivered reliably, but the connection
- is still considered valid
-returns 1 if the message was sent properly
-returns -1 if the connection died
-==================
-*/
-int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
-{
- int r;
-
- if (!sock)
- return -1;
-
- if (sock->disconnected)
- {
- Con_Printf("NET_SendMessage: disconnected socket\n");
- return -1;
- }
-
- SetNetTime();
- r = sfunc.QSendMessage(sock, data);
- if (r == 1 && sock->driver)
- messagesSent++;
-
- return r;
-}
-
-
-int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
-{
- int r;
-
- if (!sock)
- return -1;
-
- if (sock->disconnected)
- {
- Con_Printf("NET_SendMessage: disconnected socket\n");
- return -1;
- }
-
- SetNetTime();
- r = sfunc.SendUnreliableMessage(sock, data);
- if (r == 1 && sock->driver)
- unreliableMessagesSent++;
-
- return r;
-}
-
-
-/*
-==================
-NET_CanSendMessage
-
-Returns true or false if the given qsocket can currently accept a
-message to be transmitted.
-==================
-*/
-qboolean NET_CanSendMessage (qsocket_t *sock)
-{
- int r;
-
- if (!sock)
- return false;
-
- if (sock->disconnected)
- return false;
-
- SetNetTime();
-
- r = sfunc.CanSendMessage(sock);
-
- return r;
-}
-
-
-/*
-====================
-NET_Heartbeat
-
-Send an heartbeat to the master server(s)
-====================
-*/
-void NET_Heartbeat (int priority)
-{
- const char* host;
-
- if (! Master_AllowHeartbeat (priority))
- return;
-
- while ((host = Master_BuildHeartbeat ()) != NULL)
- {
- for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
- {
- if (net_drivers[net_driverlevel].initialized == false)
- continue;
- if (net_driverlevel && listening == false)
- continue;
- dfunc.Heartbeat (host);
- }
- }
-}
-
-
-int NET_SendToAll(sizebuf_t *data, int blocktime)
-{
- double start;
- int i;
- int count = 0;
- qbyte state [MAX_SCOREBOARD];
-
- for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
- {
- state[i] = 2;
- if (host_client->netconnection && host_client->active)
- {
- if (host_client->netconnection->driver == 0)
- NET_SendMessage(host_client->netconnection, data);
- else
- state[i] = 0;
- }
- }
-
- // for every player (simultaneously) wait for the first CanSendMessage
- // and send the message, then wait for a second CanSendMessage (verifying
- // it was received)
- start = Sys_DoubleTime();
- do
- {
- count = 0;
- for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
- {
- if (state[i] < 2)
- {
- count++;
- // need to send to this one
- if (NET_CanSendMessage (host_client->netconnection))
- {
- if (state[i] == 0 && NET_SendMessage (host_client->netconnection, data) == -1)
- state[i] = 2; // connection lost
- state[i]++;
- }
- else
- NET_GetMessage (host_client->netconnection);
- }
- }
- }
- while (count && (Sys_DoubleTime() - start) < blocktime);
- return count;
-}
-
-
-//=============================================================================
-
-/*
-====================
-NET_Init
-====================
-*/
-
-void NET_Init (void)
-{
- int i;
- int controlSocket;
-
- i = COM_CheckParm ("-port");
- if (!i)
- i = COM_CheckParm ("-udpport");
- if (!i)
- i = COM_CheckParm ("-ipxport");
-
- if (i)
- {
- if (i < com_argc-1)
- DEFAULTnet_hostport = atoi (com_argv[i+1]);
- else
- Sys_Error ("NET_Init: you must specify a number after -port");
- }
- net_hostport = DEFAULTnet_hostport;
-
- if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
- listening = true;
-
- SetNetTime();
-
- net_mempool = Mem_AllocPool("qsocket");
-
- // allocate space for network message buffer
- SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
-
- Cvar_RegisterVariable (&net_messagetimeout);
- Cvar_RegisterVariable (&hostname);
- Cvar_RegisterVariable (&developer_networking);
-
- Cmd_AddCommand ("net_slist", NET_Slist_f);
- Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
- Cmd_AddCommand ("listen", NET_Listen_f);
- Cmd_AddCommand ("maxplayers", MaxPlayers_f);
- Cmd_AddCommand ("port", NET_Port_f);
- Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
-
- // initialize all the drivers
- for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
- {
- controlSocket = net_drivers[net_driverlevel].Init();
- if (controlSocket == -1)
- continue;
- net_drivers[net_driverlevel].initialized = true;
- net_drivers[net_driverlevel].controlSock = controlSocket;
- if (listening)
- net_drivers[net_driverlevel].Listen (true);
- }
-
- if (*my_ipx_address)
- Con_DPrintf("IPX address %s\n", my_ipx_address);
- if (*my_tcpip_address)
- Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
-
- Master_Init ();
-}
-
-/*
-====================
-NET_Shutdown
-====================
-*/
-
-void NET_Shutdown (void)
-{
- SetNetTime();
-
- while (net_activeSockets)
- NET_Close(net_activeSockets);
-
-//
-// shutdown the drivers
-//
- for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
- {
- if (net_drivers[net_driverlevel].initialized == true)
- {
- net_drivers[net_driverlevel].Shutdown ();
- net_drivers[net_driverlevel].initialized = false;
- }
- }
-
- Mem_FreePool(&net_mempool);
-}
-
-
-static PollProcedure *pollProcedureList = NULL;
-
-void NET_Poll(void)
-{
- PollProcedure *pp;
-
- if (!configRestored)
- configRestored = true;
-
- SetNetTime();
-
- for (pp = pollProcedureList; pp; pp = pp->next)
- {
- if (pp->nextTime > net_time)
- break;
- pollProcedureList = pp->next;
- pp->procedure(pp->arg);
- }
-}
-
-
-void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
-{
- PollProcedure *pp, *prev;
-
- proc->nextTime = Sys_DoubleTime() + timeOffset;
- for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
- {
- if (pp->nextTime >= proc->nextTime)
- break;
- prev = pp;
- }
-
- if (prev == NULL)
- {
- proc->next = pollProcedureList;
- pollProcedureList = proc;
- return;
- }
-
- proc->next = pp;
- prev->next = proc;
-}
-
+++ /dev/null
-/*
-Copyright (C) 2002 Mathieu Olivier
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net_master.c
-
-#include "quakedef.h"
-
-
-cvar_t sv_public = {0, "sv_public", "0"};
-cvar_t sv_heartbeatperiod = {CVAR_SAVE, "sv_heartbeatperiod", "180"};
-
-cvar_t sv_masters [] =
-{
- {CVAR_SAVE, "sv_master1", ""},
- {CVAR_SAVE, "sv_master2", ""},
- {CVAR_SAVE, "sv_master3", ""},
- {CVAR_SAVE, "sv_master4", ""},
- {0, "sv_masterextra1", "198.88.152.4"},
- {0, "sv_masterextra2", "68.102.242.12"}
-};
-
-static double nextheartbeattime = 0;
-
-
-/*
-====================
-Master_AllowHeartbeat
-
-Allow (or not) NET_Heartbeat to proceed depending on various factors
-====================
-*/
-qboolean Master_AllowHeartbeat (int priority)
-{
- // LordHavoc: make advertising optional
- if (!sv_public.integer)
- return false;
- // LordHavoc: don't advertise singleplayer games
- if (svs.maxclients < 2)
- return false;
- // if it's a state change (client connected), limit next heartbeat to no
- // more than 30 sec in the future
- if (priority == 1 && nextheartbeattime > realtime + 30.0)
- nextheartbeattime = realtime + 30.0;
- if (priority <= 1 && realtime < nextheartbeattime)
- return false;
- // limit heartbeatperiod to 30 to 270 second range,
- // lower limit is to avoid abusing master servers with excess traffic,
- // upper limit is to avoid timing out on the master server (which uses
- // 300 sec timeout)
- if (sv_heartbeatperiod.value < 30)
- Cvar_SetValueQuick(&sv_heartbeatperiod, 30);
- if (sv_heartbeatperiod.value > 270)
- Cvar_SetValueQuick(&sv_heartbeatperiod, 270);
- // send a heartbeat as often as the admin wants
- nextheartbeattime = realtime + sv_heartbeatperiod.value;
- return true;
-}
-
-
-/*
-====================
-Master_BuildGetServers
-
-Build a getservers request for a master server
-====================
-*/
-const char* Master_BuildGetServers (void)
-{
- static int nextmaster = 0;
- cvar_t* sv_master;
- char request [256];
-
- if (nextmaster >= (int)(sizeof (sv_masters) / sizeof (sv_masters[0])))
- {
- nextmaster = 0;
- return NULL;
- }
-
- // find a non-empty master server address in the list
- for(;;)
- {
- sv_master = &sv_masters[nextmaster++];
- if (sv_master->string[0])
- break;
- if (nextmaster >= (int)(sizeof (sv_masters) / sizeof (sv_masters[0])))
- {
- nextmaster = 0;
- return NULL;
- }
- }
-
- // Build the heartbeat
- snprintf (request, sizeof (request), "getservers %s %u empty full\x0A", gamename, NET_PROTOCOL_VERSION);
- SZ_Clear (&net_message);
- MSG_WriteLong (&net_message, -1);
- MSG_WriteString (&net_message, request);
-
- net_message.cursize--; // we don't send the trailing '\0'
-
- return sv_master->string;
-}
-
-
-/*
-====================
-Master_BuildHeartbeat
-
-Build an heartbeat for a master server
-====================
-*/
-const char* Master_BuildHeartbeat (void)
-{
- static int nextmaster = 0;
- cvar_t* sv_master;
-
- if (nextmaster >= (int)(sizeof (sv_masters) / sizeof (sv_masters[0])))
- {
- nextmaster = 0;
- return NULL;
- }
-
- // find a non-empty master server address in the list
- for(;;)
- {
- sv_master = &sv_masters[nextmaster++];
- if (sv_master->string[0])
- break;
- if (nextmaster >= (int)(sizeof (sv_masters) / sizeof (sv_masters[0])))
- {
- nextmaster = 0;
- return NULL;
- }
- }
-
- // Build the heartbeat
- SZ_Clear (&net_message);
- MSG_WriteLong (&net_message, -1);
- MSG_WriteString (&net_message, "heartbeat DarkPlaces\x0A");
-
- net_message.cursize--; // we don't send the trailing '\0'
-
- return sv_master->string;
-}
-
-
-/*
-====================
-Master_HandleMessage
-
-Handle the master server messages
-====================
-*/
-int Master_HandleMessage (void)
-{
- const char* string = MSG_ReadString ();
-
- // If it's a "getinfo" request
- if (!strncmp (string, "getinfo", 7))
- {
- char response [512];
- size_t length;
-
- length = snprintf (response, sizeof (response), "infoResponse\x0A"
- "\\gamename\\%s\\modname\\%s\\sv_maxclients\\%d"
- "\\clients\\%d\\mapname\\%s\\hostname\\%s\\protocol\\%d",
- gamename, com_modname, svs.maxclients, net_activeconnections,
- sv.name, hostname.string, NET_PROTOCOL_VERSION);
-
- // Too long to fit into the buffer?
- if (length >= sizeof (response))
- return -1;
-
- // If there was a challenge in the getinfo message
- if (string[7] == ' ')
- {
- string += 8; // skip the header and the space
-
- // If the challenge wouldn't fit into the buffer
- if (length + 11 + strlen (string) >= sizeof (response))
- return -1;
-
- sprintf (response + length, "\\challenge\\%s", string);
- }
-
- SZ_Clear (&net_message);
- MSG_WriteLong (&net_message, -1);
- MSG_WriteString (&net_message, response);
-
- return net_message.cursize - 1;
- }
-
- return 0;
-}
-
-
-/*
-====================
-Master_Init
-
-Initialize the code that handles master server requests and reponses
-====================
-*/
-void Master_Init (void)
-{
- unsigned int ind;
- Cvar_RegisterVariable (&sv_public);
- Cvar_RegisterVariable (&sv_heartbeatperiod);
- for (ind = 0; ind < sizeof (sv_masters) / sizeof (sv_masters[0]); ind++)
- Cvar_RegisterVariable (&sv_masters[ind]);
-}
-
-
-/*
-====================
-Master_ParseServerList
-
-Parse getserverResponse messages
-Returns true if it was a valid getserversResponse
-====================
-*/
-int Master_ParseServerList (net_landriver_t* dfunc)
-{
- int servercount = 0;
- int control;
- qbyte* servers;
- qbyte* crtserver;
- struct qsockaddr svaddr;
- char ipstring [32];
- char string[32];
-
- if (developer.integer)
- {
- Con_Printf("Master_ParseServerList: packet received:\n");
- SZ_HexDumpToConsole(&net_message);
- }
-
- if (net_message.cursize < 23)
- return 0;
-
- // is the cache full?
- if (hostCacheCount == HOSTCACHESIZE)
- return 0;
-
- MSG_BeginReading ();
- control = MSG_ReadBigLong();
- if (control != -1)
- return 0;
-
- if (MSG_ReadBytes(19, string) < 19 || memcmp(string, "getserversResponse\\", 19))
- return 0;
-
- crtserver = servers = Z_Malloc (net_message.cursize - 23);
- memcpy (servers , net_message.data + 23, net_message.cursize - 23);
-
- // Extract the IP addresses
- while ((crtserver[0] != 0xFF || crtserver[1] != 0xFF || crtserver[2] != 0xFF || crtserver[3] != 0xFF) && (crtserver[4] != 0 || crtserver[5] != 0))
- {
- // LordHavoc: FIXME: this could be much faster than converting to a string and back
- // LordHavoc: FIXME: this code is very UDP specific, perhaps it should be part of net_udp?
- sprintf (ipstring, "%u.%u.%u.%u:%u", crtserver[0], crtserver[1], crtserver[2], crtserver[3], (crtserver[4] << 8) | crtserver[5]);
- dfunc->GetAddrFromName (ipstring, &svaddr);
- Con_DPrintf("Requesting info from server %s\n", ipstring);
-
- // Send a request at this address
- SZ_Clear(&net_message);
- MSG_WriteLong(&net_message, 0); // save space for the header, filled in later
- MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
- MSG_WriteString(&net_message, "QUAKE");
- MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
- *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
- dfunc->Write(dfunc->controlSock, net_message.data, net_message.cursize, &svaddr);
- SZ_Clear(&net_message);
-
- servercount++;
-
- if (crtserver[6] != '\\')
- break;
- crtserver += 7;
- }
-
- Z_Free (servers);
-
- return servercount;
-}
+++ /dev/null
-/*
-Copyright (C) 2002 Mathieu Olivier
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net_master.h
-
-#ifndef NET_MASTER_H
-#define NET_MASTER_H
-
-#define MASTER_PORT 27950
-
-qboolean Master_AllowHeartbeat (int priority);
-const char* Master_BuildGetServers (void);
-const char* Master_BuildHeartbeat (void);
-int Master_HandleMessage (void);
-void Master_Init (void);
-int Master_ParseServerList (net_landriver_t* dfunc);
-
-#endif
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-#include "quakedef.h"
-#include "net_udp.h"
-#ifdef WIN32
-#include "winquake.h"
-#define MAXHOSTNAMELEN 256
-#else
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#ifdef __sun__
-#include <sys/filio.h>
-#endif
-
-#ifdef NeXT
-#include <libc.h>
-#endif
-#endif
-
-static int net_acceptsocket = -1; // socket for fielding new connections
-static int net_controlsocket;
-static int net_broadcastsocket = 0;
-static struct qsockaddr broadcastaddr;
-
-static union {unsigned int i;unsigned char d[4];} myAddr;
-
-//=============================================================================
-
-#ifdef WIN32
-WSADATA winsockdata;
-#endif
-
-int UDP_Init (void)
-{
- int i, j;
- struct hostent *local;
- char buff[MAXHOSTNAMELEN];
-
- if (COM_CheckParm ("-noudp"))
- return -1;
-
-#ifdef WIN32
- if (WSAStartup (MAKEWORD(1, 1), &winsockdata))
- {
- Con_SafePrintf ("Winsock initialization failed.\n");
- return -1;
- }
-#endif
-
- // loopback as a worst case fallback
- myAddr.i = htonl(INADDR_ANY);
-
- net_controlsocket = -1;
- for (j = 0;net_controlsocket == -1;j++)
- {
- switch(j)
- {
- case 0:
- if ((i = COM_CheckParm("-ip")) != 0 && i < com_argc)
- myAddr.i = inet_addr(com_argv[i+1]);
- break;
- case 1:
- myAddr.i = htonl(INADDR_ANY);
- break;
- case 2:
- if (gethostname(buff, MAXHOSTNAMELEN) != -1)
- {
- buff[MAXHOSTNAMELEN - 1] = 0;
- local = gethostbyname(buff);
- if (local != NULL)
- myAddr.i = *((int *)local->h_addr_list[0]);
- else
- continue;
- }
- else
- continue;
- break;
- default:
- Con_Printf("UDP_Init: Giving up, UDP networking support disabled.\n");
-#ifdef WIN32
- WSACleanup ();
-#endif
- return -1;
- }
-
- if (myAddr.i == htonl(INADDR_LOOPBACK))
- sprintf(my_tcpip_address, "INADDR_LOOPBACK");
- else if (myAddr.i == htonl(INADDR_ANY))
- sprintf(my_tcpip_address, "INADDR_ANY");
- else if (myAddr.i == htonl(INADDR_NONE))
- sprintf(my_tcpip_address, "INADDR_NONE");
- else
- sprintf(my_tcpip_address, "%d.%d.%d.%d", myAddr.d[0], myAddr.d[1], myAddr.d[2], myAddr.d[3]);
- Con_Printf("UDP_Init: Binding to IP Interface Address of %s... ", my_tcpip_address);
- if ((net_controlsocket = UDP_OpenSocket (0)) == -1)
- Con_Printf("failed\n");
- else
- Con_Printf("succeeded\n");
- }
-
- ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
- ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = htonl(INADDR_BROADCAST);
- ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((unsigned short)net_hostport);
-
- Con_Printf("UDP Initialized\n");
- tcpipAvailable = true;
-
- return net_controlsocket;
-}
-
-//=============================================================================
-
-void UDP_Shutdown (void)
-{
- UDP_Listen (false);
- UDP_CloseSocket (net_controlsocket);
-#ifdef WIN32
- WSACleanup ();
-#endif
-}
-
-//=============================================================================
-
-void UDP_Listen (qboolean state)
-{
- // enable listening
- if (state)
- {
- if (net_acceptsocket != -1)
- return;
- if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == -1)
- Sys_Error ("UDP_Listen: Unable to open accept socket\n");
- return;
- }
-
- // disable listening
- if (net_acceptsocket == -1)
- return;
- UDP_CloseSocket (net_acceptsocket);
- net_acceptsocket = -1;
-}
-
-//=============================================================================
-
-int UDP_OpenSocket (int port)
-{
- int newsocket;
- struct sockaddr_in address;
-
- if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
- return -1;
-
- {
-#ifdef WIN32
- u_long _true = 1;
- if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
- {
- closesocket (newsocket);
-#else
- char _true = 1;
- if (ioctl (newsocket, FIONBIO, &_true) == -1)
- {
- close (newsocket);
-#endif
- Sys_Error("UDP_OpenSocket: unable to do a ioctl FIONBIO on the socket\n");
- }
- }
-
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = myAddr.i;
- address.sin_port = htons((unsigned short)port);
- if (bind(newsocket, (void *)&address, sizeof(address)) == -1)
- {
-#ifdef WIN32
- closesocket(newsocket);
-#else
- close(newsocket);
-#endif
- Sys_Error ("UDP_OpenSocket: Unable to bind to %s", UDP_AddrToString((struct qsockaddr *)&address));
- }
-
- return newsocket;
-}
-
-//=============================================================================
-
-int UDP_CloseSocket (int socket)
-{
- if (net_broadcastsocket == socket)
- net_broadcastsocket = 0;
-#ifdef WIN32
- return closesocket (socket);
-#else
- return close (socket);
-#endif
-}
-
-//=============================================================================
-
-int UDP_Connect (int socket, struct qsockaddr *addr)
-{
- return 0;
-}
-
-//=============================================================================
-
-int UDP_CheckNewConnections (void)
-{
- char buf[4096];
-#ifndef WIN32
- unsigned long available;
- struct sockaddr_in from;
- socklen_t fromlen;
-#endif
-
- if (net_acceptsocket == -1)
- return -1;
-
-#ifdef WIN32
- if (recvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) >= 0)
- return net_acceptsocket;
-#else
- if (ioctl (net_acceptsocket, FIONREAD, &available) == -1)
- Sys_Error ("UDP: ioctlsocket (FIONREAD) failed\n");
- if (available)
- return net_acceptsocket;
- recvfrom (net_acceptsocket, buf, 0, 0, (struct sockaddr *) &from, &fromlen);
-#endif
- return -1;
-}
-
-//=============================================================================
-
-int UDP_Recv (qbyte *buf, int len, struct qsockaddr *addr)
-{
- return UDP_Read (net_acceptsocket, buf, len, addr);
-}
-
-//=============================================================================
-
-int UDP_Send (qbyte *buf, int len, struct qsockaddr *addr)
-{
- return UDP_Write (net_acceptsocket, buf, len, addr);
-}
-
-//=============================================================================
-
-int UDP_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr)
-{
- int addrlen = sizeof (struct qsockaddr);
- int ret;
-
- ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
- if (ret == -1)
- {
-#ifdef WIN32
- int e = WSAGetLastError();
- if (e == WSAEWOULDBLOCK || e == WSAECONNREFUSED)
- return 0;
- Con_Printf("UDP_Read(%i, %p, %i, <%s>): WSAGetLastError == %i\n", socket, buf, len, UDP_AddrToString(addr), e);
-#else
- if (errno == EWOULDBLOCK || errno == ECONNREFUSED)
- return 0;
- Con_Printf("UDP_Read(%i, %p, %i, <%s>): errno == %i (%s)\n", socket, buf, len, UDP_AddrToString(addr), errno, strerror(errno));
-#endif
- }
- else if (developer_networking.integer)
- {
- Con_Printf("UDP_Read(%i, %p, %i, <%s>) = %i\n", socket, buf, len, UDP_AddrToString(addr), ret);
- Com_HexDumpToConsole(buf, ret);
- }
-
- return ret;
-}
-
-//=============================================================================
-
-int UDP_MakeSocketBroadcastCapable (int socket)
-{
- int i = 1;
-
- // make this socket broadcast capable
- if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
- return -1;
- net_broadcastsocket = socket;
-
- return 0;
-}
-
-//=============================================================================
-
-int UDP_Broadcast (int socket, qbyte *buf, int len)
-{
- int ret;
-
- if (socket != net_broadcastsocket)
- {
- if (net_broadcastsocket != 0)
- Sys_Error("Attempted to use multiple broadcasts sockets\n");
- ret = UDP_MakeSocketBroadcastCapable (socket);
- if (ret == -1)
- {
- Con_Printf("Unable to make socket broadcast capable\n");
- return ret;
- }
- }
-
- return UDP_Write (socket, buf, len, &broadcastaddr);
-}
-
-//=============================================================================
-
-int UDP_Write (int socket, qbyte *buf, int len, struct qsockaddr *addr)
-{
- int ret;
-
- if (developer_networking.integer)
- {
- Con_Printf("UDP_Write(%i, %p, %i, <%s>)\n", socket, buf, len, UDP_AddrToString(addr));
- Com_HexDumpToConsole(buf, len);
- }
-
- ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
- if (ret == -1)
- {
-#ifdef WIN32
- int e = WSAGetLastError();
- if (e == WSAEWOULDBLOCK)
- return 0;
- Con_Printf("UDP_Write(%i, %p, %i, <%s>): WSAGetLastError == %i\n", socket, buf, len, UDP_AddrToString(addr), e);
-#else
- if (errno == EWOULDBLOCK)
- return 0;
- Con_Printf("UDP_Write(%i, %p, %i, <%s>): errno == %i (%s)\n", socket, buf, len, UDP_AddrToString(addr), errno, strerror(errno));
-#endif
- }
- return ret;
-}
-
-//=============================================================================
-
-char *UDP_AddrToString (const struct qsockaddr *addr)
-{
- static char buffer[22]; // only 22 needed (3 + 1 + 3 + 1 + 3 + 1 + 3 + 1 + 5 + null)
- unsigned char *ip = (char *)(&((struct sockaddr_in *)addr)->sin_addr.s_addr);
- sprintf(buffer, "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], ntohs(((struct sockaddr_in *)addr)->sin_port));
- return buffer;
-}
-
-//=============================================================================
-
-int UDP_StringToAddr (const char *string, struct qsockaddr *addr)
-{
- int ha[4], hp, ipaddr, j, numbers;
- const char *colon;
-
- hp = net_hostport;
- colon = strrchr(string, ':');
- if (colon)
- {
- hp = atoi(colon + 1);
- if (hp == 0)
- hp = net_hostport;
- }
- numbers = sscanf(string, "%d.%d.%d.%d", &ha[0], &ha[1], &ha[2], &ha[3]);
- for (ipaddr = 0, j = 0;j < numbers;j++)
- ipaddr = (ipaddr << 8) | ha[j];
- // if the address is incomplete take most important numbers from myAddr
- if (numbers < 4)
- ipaddr |= ntohl(myAddr.i) & (-1 << (numbers * 8));
-
- addr->sa_family = AF_INET;
- ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
- ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp);
- if (ipaddr == INADDR_ANY)
- return -1;
- else
- return 0;
-}
-
-//=============================================================================
-
-int UDP_GetSocketAddr (int socket, struct qsockaddr *addr)
-{
- int ret;
- int addrlen = sizeof(struct qsockaddr);
- memset(addr, 0, sizeof(struct qsockaddr));
- ret = getsockname(socket, (struct sockaddr *)addr, &addrlen);
- if (ret == -1)
- {
-#ifdef WIN32
- int e = WSAGetLastError();
- Con_Printf("UDP_GetSocketAddr: WASGetLastError == %i\n", e);
-#else
- Con_Printf("UDP_GetSocketAddr: errno == %i (%s)\n", errno, strerror(errno));
-#endif
- }
- return ret;
-}
-
-//=============================================================================
-
-int UDP_GetNameFromAddr (const struct qsockaddr *addr, char *name)
-{
- struct hostent *hostentry;
-
- hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
- if (hostentry)
- {
- strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
- return 0;
- }
-
- strcpy (name, UDP_AddrToString (addr));
- return 0;
-}
-
-//=============================================================================
-
-int UDP_GetAddrFromName(const char *name, struct qsockaddr *addr)
-{
- struct hostent *hostentry;
-
- if (name[0] >= '0' && name[0] <= '9')
- return UDP_StringToAddr (name, addr);
-
- hostentry = gethostbyname (name);
- if (!hostentry)
- return -1;
-
- addr->sa_family = AF_INET;
- ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);
- ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
-
- return 0;
-}
-
-//=============================================================================
-
-int UDP_AddrCompare (const struct qsockaddr *addr1, const struct qsockaddr *addr2)
-{
- if (addr1->sa_family != addr2->sa_family)
- return -1;
-
- if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
- return -1;
-
- if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
- return 1;
-
- return 0;
-}
-
-//=============================================================================
-
-int UDP_GetSocketPort (struct qsockaddr *addr)
-{
- return ntohs(((struct sockaddr_in *)addr)->sin_port);
-}
-
-
-int UDP_SetSocketPort (struct qsockaddr *addr, int port)
-{
- ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
- return 0;
-}
-
+++ /dev/null
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// net_udp.h
-
-#ifndef NET_UDP_H
-#define NET_UDP_H
-
-int UDP_Init (void);
-void UDP_Shutdown (void);
-void UDP_Listen (qboolean state);
-int UDP_OpenSocket (int port);
-int UDP_CloseSocket (int socket);
-int UDP_Connect (int socket, struct qsockaddr *addr);
-int UDP_CheckNewConnections (void);
-int UDP_Recv (qbyte *buf, int len, struct qsockaddr *addr);
-int UDP_Send (qbyte *buf, int len, struct qsockaddr *addr);
-int UDP_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr);
-int UDP_Write (int socket, qbyte *buf, int len, struct qsockaddr *addr);
-int UDP_Broadcast (int socket, qbyte *buf, int len);
-char *UDP_AddrToString (const struct qsockaddr *addr);
-int UDP_StringToAddr (const char *string, struct qsockaddr *addr);
-int UDP_GetSocketAddr (int socket, struct qsockaddr *addr);
-int UDP_GetNameFromAddr (const struct qsockaddr *addr, char *name);
-int UDP_GetAddrFromName (const char *name, struct qsockaddr *addr);
-int UDP_AddrCompare (const struct qsockaddr *addr1, const struct qsockaddr *addr2);
-int UDP_GetSocketPort (struct qsockaddr *addr);
-int UDP_SetSocketPort (struct qsockaddr *addr, int port);
-
-#endif
-
*/
void PF_setcolor (void)
{
- client_t *client;
- int entnum, i;
+ client_t *client;
+ int entnum, i;
+ eval_t *val;
entnum = G_EDICTNUM(OFS_PARM0);
i = G_FLOAT(OFS_PARM1);
}
client = &svs.clients[entnum-1];
+ if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
+ val->_float = i;
client->colors = i;
+ client->old_colors = i;
client->edict->v->team = (i & 15) + 1;
MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
int eval_pmodel;
int eval_punchvector;
int eval_viewzoom;
+int eval_clientcolors;
mfunction_t *SV_PlayerPhysicsQC;
mfunction_t *EndFrameQC;
eval_pmodel = FindFieldOffset("pmodel");
eval_punchvector = FindFieldOffset("punchvector");
eval_viewzoom = FindFieldOffset("viewzoom");
+ eval_clientcolors = FindFieldOffset("clientcolors");
// LordHavoc: allowing QuakeC to override the player movement code
SV_PlayerPhysicsQC = ED_FindFunction ("SV_PlayerPhysics");
{ev_float, "ping"},
{ev_vector, "movement"},
{ev_float, "pmodel"},
- {ev_vector, "punchvector"}
+ {ev_vector, "punchvector"},
+ {ev_float, "clientcolors"}
};
/*
extern int eval_pmodel;
extern int eval_punchvector;
extern int eval_viewzoom;
+extern int eval_clientcolors;
#define GETEDICTFIELDVALUE(ed, fieldoffset) (fieldoffset ? (eval_t *)((qbyte *)ed->v + fieldoffset) : NULL)
// LordHavoc: increased player limit from 16 to 64
#define MAX_SCOREBOARD 64
-#define MAX_SCOREBOARDNAME 32
+// LordHavoc: increased name limit from 32 to 64 characters
+#define MAX_SCOREBOARDNAME 64
#define SOUND_CHANNELS 8
#include "wad.h"
#include "draw.h"
#include "screen.h"
-#include "net.h"
+#include "netconn.h"
#include "protocol.h"
#include "cmd.h"
#include "sbar.h"
// not bounded in any way, changed at start of every frame, never reset
extern double realtime;
-void Host_ClearMemory (void);
-void Host_ServerFrame (void);
-void Host_InitCommands (void);
-void Host_Init (void);
+void Host_ClearMemory(void);
+void Host_InitCommands(void);
+void Host_Init(void);
void Host_Shutdown(void);
-void Host_Error (const char *error, ...);
-void Host_EndGame (const char *message, ...);
-void Host_Frame (float time);
-void Host_Quit_f (void);
-void Host_ClientCommands (const char *fmt, ...);
-void Host_ShutdownServer (qboolean crash);
+void Host_Error(const char *error, ...);
+void Host_EndGame(const char *message, ...);
+void Host_Frame(float time);
+void Host_Quit_f(void);
+void Host_ClientCommands(const char *fmt, ...);
+void Host_ShutdownServer(qboolean crash);
+void Host_Reconnect_f(void);
// skill level for currently loaded level (in case the user changes the cvar while the level is running, this reflects the level actually in use)
extern int current_skill;
qboolean dropasap;
// only valid before spawned
qboolean sendsignon;
+ // remove this client immediately
+ qboolean deadsocket;
// reliable messages must be sent periodically
double last_message;
// communications handle
- struct qsocket_s *netconnection;
+ netconn_t *netconnection;
// movement
usercmd_t cmd;
qbyte msgbuf[MAX_DATAGRAM];
// EDICT_NUM(clientnum+1)
edict_t *edict;
- // for printing to other people
- char name[32];
- int colors;
float ping_times[NUM_PING_TIMES];
// ping_times[num_pings%NUM_PING_TIMES]
// spawn parms are carried from level to level
float spawn_parms[NUM_SPAWN_PARMS];
-// client known data for deltas
- int old_frags;
+ // properties that are sent across the network only when changed
+ char name[64], old_name[64];
+ int colors, old_colors;
+ int frags, old_frags;
+ // other properties not sent across the network
int pmodel;
+ // visibility state
+ float visibletime[MAX_EDICTS];
#ifdef QUAKEENTITIES
// delta compression state
float nextfullupdate[MAX_EDICTS];
-#endif
- // visibility state
- float visibletime[MAX_EDICTS];
-
-#ifndef QUAKEENTITIES
+#else
entity_database_t entitydatabase;
int entityframenumber; // incremented each time an entity frame is sent
#endif
void SV_SendClientMessages (void);
void SV_ClearDatagram (void);
+void SV_ReadClientMessage(void);
+
int SV_ModelIndex (const char *name);
void SV_SetIdealPitch (void);
void SV_AddUpdates (void);
void SV_ClientThink (void);
-void SV_AddClientToServer (struct qsocket_s *ret);
void SV_ClientPrintf (const char *fmt, ...);
void SV_BroadcastPrintf (const char *fmt, ...);
void SV_MoveToGoal (void);
-void SV_CheckForNewClients (void);
void SV_RunClients (void);
void SV_SaveSpawnparms (void);
void SV_SpawnServer (const char *server);
once for a player each game, not once for each level change.
================
*/
-void SV_ConnectClient (int clientnum)
+void SV_ConnectClient (int clientnum, netconn_t *netconnection)
{
client_t *client;
- struct qsocket_s *netconnection;
int i;
float spawn_parms[NUM_SPAWN_PARMS];
client = svs.clients + clientnum;
- Con_DPrintf ("Client %s connected\n", client->netconnection->address);
-
// set up the client_t
- netconnection = client->netconnection;
-
if (sv.loadgame)
memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
memset (client, 0, sizeof(*client));
client->netconnection = netconnection;
+ Con_DPrintf ("Client %s connected\n", client->netconnection->address);
+
strcpy (client->name, "unconnected");
client->active = true;
client->spawned = false;
memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
else
{
- // call the progs to get default spawn parms for the new client
+ // call the progs to get default spawn parms for the new client
PR_ExecuteProgram (pr_global_struct->SetNewParms, "QC function SetNewParms is missing");
for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
client->spawn_parms[i] = (&pr_global_struct->parm1)[i];
+ // set up the edict a bit
+ ED_ClearEdict(client->edict);
+ client->edict->v->colormap = NUM_FOR_EDICT(client->edict);
+ client->edict->v->netname = PR_SetString(client->name);
}
SV_SendServerinfo (client);
}
-/*
-===================
-SV_CheckForNewClients
-
-===================
-*/
-void SV_CheckForNewClients (void)
-{
- struct qsocket_s *ret;
- int i;
-
-//
-// check for new connections
-//
- while (1)
- {
- ret = NET_CheckNewConnections ();
- if (!ret)
- break;
-
- //
- // init a new client structure
- //
- for (i=0 ; i<svs.maxclients ; i++)
- if (!svs.clients[i].active)
- break;
- if (i == svs.maxclients)
- Sys_Error ("Host_CheckForNewClients: no free clients");
-
- svs.clients[i].netconnection = ret;
- SV_ConnectClient (i);
-
- net_activeconnections++;
- NET_Heartbeat (1);
- }
-}
-
-
-
/*
===============================================================================
SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
// send the datagram
- if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)
+ if (NetConn_SendUnreliableMessage (client->netconnection, &msg) == -1)
{
SV_DropClient (true);// if the message couldn't send, kick off
return false;
{
int i, j;
client_t *client;
+ eval_t *val;
+ char *s;
// check for changes to be sent over the reliable streams
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
{
+ // update the host_client fields we care about according to the entity fields
sv_player = host_client->edict;
- if (host_client->old_frags != sv_player->v->frags)
+ s = PR_GetString(sv_player->v->netname);
+ if (s != host_client->name)
+ {
+ if (s == NULL)
+ s = "";
+ // point the string back at host_client->name to keep it safe
+ strncpy(host_client->name, s, sizeof(host_client->name) - 1);
+ sv_player->v->netname = PR_SetString(host_client->name);
+ }
+ if ((val = GETEDICTFIELDVALUE(sv_player, eval_clientcolors)) && host_client->colors != val->_float)
+ host_client->colors = val->_float;
+ host_client->frags = sv_player->v->frags;
+ if (gamemode == GAME_NEHAHRA)
+ if ((val = GETEDICTFIELDVALUE(sv_player, eval_pmodel)) && host_client->pmodel != val->_float)
+ host_client->pmodel = val->_float;
+
+ // if the fields changed, send messages about the changes
+ if (strcmp(host_client->old_name, host_client->name))
+ {
+ strcpy(host_client->old_name, host_client->name);
+ for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
+ {
+ if (!client->active || !client->spawned)
+ continue;
+ MSG_WriteByte (&client->message, svc_updatename);
+ MSG_WriteByte (&client->message, i);
+ MSG_WriteString (&client->message, host_client->name);
+ }
+ }
+ if (host_client->old_colors != host_client->colors)
+ {
+ host_client->old_colors = host_client->colors;
+ for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
+ {
+ if (!client->active || !client->spawned)
+ continue;
+ MSG_WriteByte (&client->message, svc_updatecolors);
+ MSG_WriteByte (&client->message, i);
+ MSG_WriteByte (&client->message, host_client->colors);
+ }
+ }
+ if (host_client->old_frags != host_client->frags)
{
+ host_client->old_frags = host_client->frags;
for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
{
if (!client->active || !client->spawned)
continue;
MSG_WriteByte (&client->message, svc_updatefrags);
MSG_WriteByte (&client->message, i);
- MSG_WriteShort (&client->message, sv_player->v->frags);
+ MSG_WriteShort (&client->message, host_client->frags);
}
-
- host_client->old_frags = sv_player->v->frags;
}
}
- for (j=0, host_client = svs.clients ; j<svs.maxclients ; j++, host_client++)
+ for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
{
- if (!host_client->active)
+ if (!client->active)
continue;
- SZ_Write (&host_client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
+ SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
}
SZ_Clear (&sv.reliable_datagram);
MSG_WriteChar (&msg, svc_nop);
- if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)
+ if (NetConn_SendUnreliableMessage (client->netconnection, &msg) == -1)
SV_DropClient (true); // if the message couldn't send, kick off
client->last_message = realtime;
}
if (!host_client->active)
continue;
+ if (host_client->deadsocket)
+ {
+ SV_DropClient (true); // if the message couldn't send, kick off
+ continue;
+ }
+
if (host_client->spawned)
{
if (!SV_SendClientDatagram (host_client))
if (host_client->message.cursize || host_client->dropasap)
{
- if (!NET_CanSendMessage (host_client->netconnection))
+ if (!NetConn_CanSendMessage (host_client->netconnection))
continue;
if (host_client->dropasap)
SV_DropClient (false); // went to another level
else
{
- if (NET_SendMessage (host_client->netconnection, &host_client->message) == -1)
+ if (NetConn_SendReliableMessage (host_client->netconnection, &host_client->message) == -1)
SV_DropClient (true); // if the message couldn't send, kick off
SZ_Clear (&host_client->message);
host_client->last_message = realtime;
MSG_WriteChar (&msg, svc_stufftext);
MSG_WriteString (&msg, "reconnect\n");
- NET_SendToAll (&msg, 5);
+ NetConn_SendToAll (&msg, 5);
if (cls.state != ca_dedicated)
Cmd_ExecuteString ("reconnect\n", src_command);
//
if (sv.active)
SV_SendReconnect ();
+ else
+ NetConn_OpenServerPorts(svs.maxclients > 1);
//
// make cvars consistant
SV_SendServerinfo (host_client);
Con_DPrintf ("Server spawned.\n");
- NET_Heartbeat (2);
+ NetConn_Heartbeat (2);
}
/*
===================
SV_ReadClientMessage
-
-Returns false if the client should be killed
===================
*/
-extern void SV_SendServerinfo (client_t *client);
-qboolean SV_ReadClientMessage (void)
+extern void SV_SendServerinfo(client_t *client);
+void SV_ReadClientMessage(void)
{
- int ret;
- int cmd;
- char *s;
+ int cmd;
+ char *s;
+
+ //MSG_BeginReading ();
- for (;;)
+ for(;;)
{
-nextmsg:
- ret = NET_GetMessage (host_client->netconnection);
- if (ret == -1)
+ if (!host_client->active)
{
- Con_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");
- return false;
+ // a command caused an error
+ SV_DropClient (false);
+ return;
}
- if (!ret)
- return true;
- MSG_BeginReading ();
+ if (msg_badread)
+ {
+ Con_Printf ("SV_ReadClientMessage: badread\n");
+ SV_DropClient (false);
+ return;
+ }
- for(;;)
+ cmd = MSG_ReadChar ();
+ if (cmd == -1)
{
- if (!host_client->active)
- // a command caused an error
- return false;
+ // end of message
+ break;
+ }
- if (msg_badread)
- {
- Con_Printf ("SV_ReadClientMessage: badread\n");
- return false;
- }
+ switch (cmd)
+ {
+ default:
+ Con_Printf ("SV_ReadClientMessage: unknown command char %i\n", cmd);
+ SV_DropClient (false);
+ return;
- cmd = MSG_ReadChar ();
+ case clc_nop:
+ break;
- switch (cmd)
+ case clc_stringcmd:
+ s = MSG_ReadString ();
+ if (strncasecmp(s, "spawn", 5) == 0
+ || strncasecmp(s, "begin", 5) == 0
+ || strncasecmp(s, "prespawn", 8) == 0)
+ Cmd_ExecuteString (s, src_client);
+ else if (SV_ParseClientCommandQC)
{
- case -1:
- // end of message
- goto nextmsg;
-
- default:
- Con_Printf ("SV_ReadClientMessage: unknown command char %i\n", cmd);
- return false;
-
- case clc_nop:
- break;
-
- case clc_stringcmd:
- s = MSG_ReadString ();
- if (strncasecmp(s, "spawn", 5) == 0
- || strncasecmp(s, "begin", 5) == 0
- || strncasecmp(s, "prespawn", 8) == 0)
- Cmd_ExecuteString (s, src_client);
- else if (SV_ParseClientCommandQC)
- {
- G_INT(OFS_PARM0) = PR_SetString(s);
- pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
- PR_ExecuteProgram ((func_t)(SV_ParseClientCommandQC - pr_functions), "");
- }
- else if (strncasecmp(s, "status", 6) == 0
- || strncasecmp(s, "name", 4) == 0
- || strncasecmp(s, "say", 3) == 0
- || strncasecmp(s, "say_team", 8) == 0
- || strncasecmp(s, "tell", 4) == 0
- || strncasecmp(s, "color", 5) == 0
- || strncasecmp(s, "kill", 4) == 0
- || strncasecmp(s, "pause", 5) == 0
- || strncasecmp(s, "kick", 4) == 0
- || strncasecmp(s, "ping", 4) == 0
- || strncasecmp(s, "ban", 3) == 0
- || strncasecmp(s, "pmodel", 6) == 0
- || (gamemode == GAME_NEHAHRA && (strncasecmp(s, "max", 3) == 0 || strncasecmp(s, "monster", 7) == 0 || strncasecmp(s, "scrag", 5) == 0 || strncasecmp(s, "gimme", 5) == 0 || strncasecmp(s, "wraith", 6) == 0))
- || (gamemode != GAME_NEHAHRA && (strncasecmp(s, "god", 3) == 0 || strncasecmp(s, "notarget", 8) == 0 || strncasecmp(s, "fly", 3) == 0 || strncasecmp(s, "give", 4) == 0 || strncasecmp(s, "noclip", 6) == 0)))
- Cmd_ExecuteString (s, src_client);
- else
- Con_Printf("%s tried to %s\n", host_client->name, s);
- break;
-
- case clc_disconnect:
- return false;
-
- case clc_move:
- SV_ReadClientMove (&host_client->cmd);
- break;
-
- case clc_ackentities:
- EntityFrame_AckFrame(&host_client->entitydatabase, MSG_ReadLong());
- break;
+ G_INT(OFS_PARM0) = PR_SetString(s);
+ pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
+ PR_ExecuteProgram ((func_t)(SV_ParseClientCommandQC - pr_functions), "");
}
+ else if (strncasecmp(s, "status", 6) == 0
+ || strncasecmp(s, "name", 4) == 0
+ || strncasecmp(s, "say", 3) == 0
+ || strncasecmp(s, "say_team", 8) == 0
+ || strncasecmp(s, "tell", 4) == 0
+ || strncasecmp(s, "color", 5) == 0
+ || strncasecmp(s, "kill", 4) == 0
+ || strncasecmp(s, "pause", 5) == 0
+ || strncasecmp(s, "kick", 4) == 0
+ || strncasecmp(s, "ping", 4) == 0
+ || strncasecmp(s, "ban", 3) == 0
+ || strncasecmp(s, "pmodel", 6) == 0
+ || (gamemode == GAME_NEHAHRA && (strncasecmp(s, "max", 3) == 0 || strncasecmp(s, "monster", 7) == 0 || strncasecmp(s, "scrag", 5) == 0 || strncasecmp(s, "gimme", 5) == 0 || strncasecmp(s, "wraith", 6) == 0))
+ || (gamemode != GAME_NEHAHRA && (strncasecmp(s, "god", 3) == 0 || strncasecmp(s, "notarget", 8) == 0 || strncasecmp(s, "fly", 3) == 0 || strncasecmp(s, "give", 4) == 0 || strncasecmp(s, "noclip", 6) == 0)))
+ Cmd_ExecuteString (s, src_client);
+ else
+ Con_Printf("%s tried to %s\n", host_client->name, s);
+ break;
+
+ case clc_disconnect:
+ SV_DropClient (false); // client wants to disconnect
+ return;
+
+ case clc_move:
+ SV_ReadClientMove (&host_client->cmd);
+ break;
+
+ case clc_ackentities:
+ EntityFrame_AckFrame(&host_client->entitydatabase, MSG_ReadLong());
+ break;
}
}
- return true;
}
-
/*
==================
SV_RunClients
sv_player = host_client->edict;
- if (!SV_ReadClientMessage ())
- {
- SV_DropClient (false); // client misbehaved...
- continue;
- }
-
if (!host_client->spawned)
{
// clear client movement until a new packet is received