5d05b9d3e9
This ports id Software's Quake to run on the SDL plugin runtime. The source code originated from id under the GPLv2 license. I used https://github.com/ahefner/sdlquake as the base of my port. Performance is, unsurprisingly, not on par with what you're probably used to on PC. I average about 10FPS on ipod6g, but it's still playable. Sound works well enough, but in-game music is not supported. I've written ARM assembly routines for the inner sound loop. Make sure you turn the "brightness" all the way down, or colors will look funky. To run, extract Quake's data files to /.rockbox/quake. Have fun! Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
997 lines
19 KiB
C
997 lines
19 KiB
C
/*
|
|
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_vcr.h"
|
|
|
|
qsocket_t *net_activeSockets = NULL;
|
|
qsocket_t *net_freeSockets = NULL;
|
|
int net_numsockets = 0;
|
|
|
|
qboolean serialAvailable = false;
|
|
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];
|
|
|
|
void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
|
|
void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
|
|
void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
|
|
void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
|
|
|
|
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};
|
|
|
|
|
|
sizebuf_t net_message;
|
|
int net_activeconnections = 0;
|
|
|
|
int messagesSent = 0;
|
|
int messagesReceived = 0;
|
|
int unreliableMessagesSent = 0;
|
|
int unreliableMessagesReceived = 0;
|
|
|
|
cvar_t net_messagetimeout = {"net_messagetimeout","300"};
|
|
cvar_t hostname = {"hostname", "UNNAMED"};
|
|
|
|
qboolean configRestored = false;
|
|
cvar_t config_com_port = {"_config_com_port", "0x3f8", true};
|
|
cvar_t config_com_irq = {"_config_com_irq", "4", true};
|
|
cvar_t config_com_baud = {"_config_com_baud", "57600", true};
|
|
cvar_t config_com_modem = {"_config_com_modem", "1", true};
|
|
cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true};
|
|
cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true};
|
|
cvar_t config_modem_init = {"_config_modem_init", "", true};
|
|
cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true};
|
|
|
|
#ifdef IDGODS
|
|
cvar_t idgods = {"idgods", "0"};
|
|
#endif
|
|
|
|
int vcrFile = -1;
|
|
qboolean recording = 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;
|
|
|
|
|
|
double net_time;
|
|
|
|
double SetNetTime(void)
|
|
{
|
|
net_time = Sys_FloatTime();
|
|
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_freeSockets == NULL)
|
|
return NULL;
|
|
|
|
if (net_activeconnections >= svs.maxclients)
|
|
return NULL;
|
|
|
|
// get one from free list
|
|
sock = net_freeSockets;
|
|
net_freeSockets = sock->next;
|
|
|
|
// add it to active list
|
|
sock->next = net_activeSockets;
|
|
net_activeSockets = sock;
|
|
|
|
sock->disconnected = false;
|
|
sock->connecttime = net_time;
|
|
Q_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");
|
|
}
|
|
|
|
// add it to free list
|
|
sock->next = net_freeSockets;
|
|
net_freeSockets = sock;
|
|
sock->disconnected = true;
|
|
}
|
|
|
|
|
|
static void NET_Listen_f (void)
|
|
{
|
|
if (Cmd_Argc () != 2)
|
|
{
|
|
Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
|
|
return;
|
|
}
|
|
|
|
listening = Q_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 = Q_atoi(Cmd_Argv(1));
|
|
if (n < 1)
|
|
n = 1;
|
|
if (n > svs.maxclientslimit)
|
|
{
|
|
n = svs.maxclientslimit;
|
|
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");
|
|
|
|
svs.maxclients = n;
|
|
if (n == 1)
|
|
Cvar_Set ("deathmatch", "0");
|
|
else
|
|
Cvar_Set ("deathmatch", "1");
|
|
}
|
|
|
|
|
|
static void NET_Port_f (void)
|
|
{
|
|
int n;
|
|
|
|
if (Cmd_Argc () != 2)
|
|
{
|
|
Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
|
|
return;
|
|
}
|
|
|
|
n = Q_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 PrintSlistHeader(void)
|
|
{
|
|
Con_Printf("Server Map Users\n");
|
|
Con_Printf("--------------- --------------- -----\n");
|
|
slistLastShown = 0;
|
|
}
|
|
|
|
|
|
static void PrintSlist(void)
|
|
{
|
|
int n;
|
|
|
|
for (n = slistLastShown; n < hostCacheCount; n++)
|
|
{
|
|
if (hostcache[n].maxusers)
|
|
Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
|
|
else
|
|
Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
|
|
}
|
|
slistLastShown = n;
|
|
}
|
|
|
|
|
|
static void PrintSlistTrailer(void)
|
|
{
|
|
if (hostCacheCount)
|
|
Con_Printf("== end list ==\n\n");
|
|
else
|
|
Con_Printf("No Quake servers found.\n\n");
|
|
}
|
|
|
|
|
|
void NET_Slist_f (void)
|
|
{
|
|
if (slistInProgress)
|
|
return;
|
|
|
|
if (! slistSilent)
|
|
{
|
|
Con_Printf("Looking for Quake servers...\n");
|
|
PrintSlistHeader();
|
|
}
|
|
|
|
slistInProgress = true;
|
|
slistStartTime = Sys_FloatTime();
|
|
|
|
SchedulePollProcedure(&slistSendProcedure, 0.0);
|
|
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
|
|
|
hostCacheCount = 0;
|
|
}
|
|
|
|
|
|
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_FloatTime() - 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_FloatTime() - slistStartTime) < 1.5)
|
|
{
|
|
SchedulePollProcedure(&slistPollProcedure, 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;
|
|
int n;
|
|
int numdrivers = net_numdrivers;
|
|
|
|
SetNetTime();
|
|
|
|
if (host && *host == 0)
|
|
host = NULL;
|
|
|
|
if (host)
|
|
{
|
|
if (Q_strcasecmp (host, "local") == 0)
|
|
{
|
|
numdrivers = 1;
|
|
goto JustDoIt;
|
|
}
|
|
|
|
if (hostCacheCount)
|
|
{
|
|
for (n = 0; n < hostCacheCount; n++)
|
|
if (Q_strcasecmp (host, hostcache[n].name) == 0)
|
|
{
|
|
host = hostcache[n].cname;
|
|
break;
|
|
}
|
|
if (n < hostCacheCount)
|
|
goto JustDoIt;
|
|
}
|
|
}
|
|
|
|
slistSilent = host ? true : false;
|
|
NET_Slist_f ();
|
|
|
|
while(slistInProgress)
|
|
NET_Poll();
|
|
|
|
if (host == NULL)
|
|
{
|
|
if (hostCacheCount != 1)
|
|
return NULL;
|
|
host = hostcache[0].cname;
|
|
Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
|
|
}
|
|
|
|
if (hostCacheCount)
|
|
for (n = 0; n < hostCacheCount; n++)
|
|
if (Q_strcasecmp (host, hostcache[n].name) == 0)
|
|
{
|
|
host = hostcache[n].cname;
|
|
break;
|
|
}
|
|
|
|
JustDoIt:
|
|
for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
|
|
{
|
|
if (net_drivers[net_driverlevel].initialized == false)
|
|
continue;
|
|
ret = dfunc.Connect (host);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (host)
|
|
{
|
|
Con_Printf("\n");
|
|
PrintSlistHeader();
|
|
PrintSlist();
|
|
PrintSlistTrailer();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
NET_CheckNewConnections
|
|
===================
|
|
*/
|
|
|
|
struct
|
|
{
|
|
double time;
|
|
int op;
|
|
long session;
|
|
} vcrConnect;
|
|
|
|
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)
|
|
{
|
|
if (recording)
|
|
{
|
|
vcrConnect.time = host_time;
|
|
vcrConnect.op = VCR_OP_CONNECT;
|
|
vcrConnect.session = (long)ret;
|
|
Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
|
|
Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (recording)
|
|
{
|
|
vcrConnect.time = host_time;
|
|
vcrConnect.op = VCR_OP_CONNECT;
|
|
vcrConnect.session = 0;
|
|
Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
|
|
}
|
|
|
|
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
|
|
=================
|
|
*/
|
|
|
|
struct
|
|
{
|
|
double time;
|
|
int op;
|
|
long session;
|
|
int ret;
|
|
int len;
|
|
} vcrGetMessage;
|
|
|
|
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++;
|
|
}
|
|
|
|
if (recording)
|
|
{
|
|
vcrGetMessage.time = host_time;
|
|
vcrGetMessage.op = VCR_OP_GETMESSAGE;
|
|
vcrGetMessage.session = (long)sock;
|
|
vcrGetMessage.ret = ret;
|
|
vcrGetMessage.len = net_message.cursize;
|
|
Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
|
|
Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (recording)
|
|
{
|
|
vcrGetMessage.time = host_time;
|
|
vcrGetMessage.op = VCR_OP_GETMESSAGE;
|
|
vcrGetMessage.session = (long)sock;
|
|
vcrGetMessage.ret = ret;
|
|
Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
|
|
}
|
|
}
|
|
|
|
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
|
|
==================
|
|
*/
|
|
struct
|
|
{
|
|
double time;
|
|
int op;
|
|
long session;
|
|
int r;
|
|
} vcrSendMessage;
|
|
|
|
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++;
|
|
|
|
if (recording)
|
|
{
|
|
vcrSendMessage.time = host_time;
|
|
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
|
|
vcrSendMessage.session = (long)sock;
|
|
vcrSendMessage.r = r;
|
|
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
|
|
}
|
|
|
|
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++;
|
|
|
|
if (recording)
|
|
{
|
|
vcrSendMessage.time = host_time;
|
|
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
|
|
vcrSendMessage.session = (long)sock;
|
|
vcrSendMessage.r = r;
|
|
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
|
|
}
|
|
|
|
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);
|
|
|
|
if (recording)
|
|
{
|
|
vcrSendMessage.time = host_time;
|
|
vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
|
|
vcrSendMessage.session = (long)sock;
|
|
vcrSendMessage.r = r;
|
|
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
int NET_SendToAll(sizebuf_t *data, int blocktime)
|
|
{
|
|
double start;
|
|
int i;
|
|
int count = 0;
|
|
qboolean state1 [MAX_SCOREBOARD];
|
|
qboolean state2 [MAX_SCOREBOARD];
|
|
|
|
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
|
{
|
|
if (!host_client->netconnection)
|
|
continue;
|
|
if (host_client->active)
|
|
{
|
|
if (host_client->netconnection->driver == 0)
|
|
{
|
|
NET_SendMessage(host_client->netconnection, data);
|
|
state1[i] = true;
|
|
state2[i] = true;
|
|
continue;
|
|
}
|
|
count++;
|
|
state1[i] = false;
|
|
state2[i] = false;
|
|
}
|
|
else
|
|
{
|
|
state1[i] = true;
|
|
state2[i] = true;
|
|
}
|
|
}
|
|
|
|
start = Sys_FloatTime();
|
|
while (count)
|
|
{
|
|
count = 0;
|
|
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
|
{
|
|
if (! state1[i])
|
|
{
|
|
if (NET_CanSendMessage (host_client->netconnection))
|
|
{
|
|
state1[i] = true;
|
|
NET_SendMessage(host_client->netconnection, data);
|
|
}
|
|
else
|
|
{
|
|
NET_GetMessage (host_client->netconnection);
|
|
}
|
|
count++;
|
|
continue;
|
|
}
|
|
|
|
if (! state2[i])
|
|
{
|
|
if (NET_CanSendMessage (host_client->netconnection))
|
|
{
|
|
state2[i] = true;
|
|
}
|
|
else
|
|
{
|
|
NET_GetMessage (host_client->netconnection);
|
|
}
|
|
count++;
|
|
continue;
|
|
}
|
|
}
|
|
if ((Sys_FloatTime() - start) > blocktime)
|
|
break;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
|
|
/*
|
|
====================
|
|
NET_Init
|
|
====================
|
|
*/
|
|
|
|
void NET_Init (void)
|
|
{
|
|
int i;
|
|
int controlSocket;
|
|
qsocket_t *s;
|
|
|
|
if (COM_CheckParm("-playback"))
|
|
{
|
|
net_numdrivers = 1;
|
|
net_drivers[0].Init = VCR_Init;
|
|
}
|
|
|
|
if (COM_CheckParm("-record"))
|
|
recording = true;
|
|
|
|
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 = Q_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)
|
|
listening = true;
|
|
net_numsockets = svs.maxclientslimit;
|
|
if (cls.state != ca_dedicated)
|
|
net_numsockets++;
|
|
|
|
SetNetTime();
|
|
|
|
for (i = 0; i < net_numsockets; i++)
|
|
{
|
|
s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
|
|
s->next = net_freeSockets;
|
|
net_freeSockets = s;
|
|
s->disconnected = true;
|
|
}
|
|
|
|
// allocate space for network message buffer
|
|
SZ_Alloc (&net_message, NET_MAXMESSAGE);
|
|
|
|
Cvar_RegisterVariable (&net_messagetimeout);
|
|
Cvar_RegisterVariable (&hostname);
|
|
Cvar_RegisterVariable (&config_com_port);
|
|
Cvar_RegisterVariable (&config_com_irq);
|
|
Cvar_RegisterVariable (&config_com_baud);
|
|
Cvar_RegisterVariable (&config_com_modem);
|
|
Cvar_RegisterVariable (&config_modem_dialtype);
|
|
Cvar_RegisterVariable (&config_modem_clear);
|
|
Cvar_RegisterVariable (&config_modem_init);
|
|
Cvar_RegisterVariable (&config_modem_hangup);
|
|
#ifdef IDGODS
|
|
Cvar_RegisterVariable (&idgods);
|
|
#endif
|
|
|
|
Cmd_AddCommand ("slist", NET_Slist_f);
|
|
Cmd_AddCommand ("listen", NET_Listen_f);
|
|
Cmd_AddCommand ("maxplayers", MaxPlayers_f);
|
|
Cmd_AddCommand ("port", NET_Port_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);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
NET_Shutdown
|
|
====================
|
|
*/
|
|
|
|
void NET_Shutdown (void)
|
|
{
|
|
qsocket_t *sock;
|
|
|
|
SetNetTime();
|
|
|
|
for (sock = net_activeSockets; sock; sock = sock->next)
|
|
NET_Close(sock);
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
if (vcrFile != -1)
|
|
{
|
|
Con_Printf ("Closing vcrfile.\n");
|
|
Sys_FileClose(vcrFile);
|
|
}
|
|
}
|
|
|
|
|
|
static PollProcedure *pollProcedureList = NULL;
|
|
|
|
void NET_Poll(void)
|
|
{
|
|
PollProcedure *pp;
|
|
qboolean useModem;
|
|
|
|
if (!configRestored)
|
|
{
|
|
if (serialAvailable)
|
|
{
|
|
if (config_com_modem.value == 1.0)
|
|
useModem = true;
|
|
else
|
|
useModem = false;
|
|
SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
|
|
SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
|
|
}
|
|
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_FloatTime() + 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;
|
|
}
|
|
|
|
|
|
#ifdef IDGODS
|
|
#define IDNET 0xc0f62800
|
|
|
|
qboolean IsID(struct qsockaddr *addr)
|
|
{
|
|
if (idgods.value == 0.0)
|
|
return false;
|
|
|
|
if (addr->sa_family != 2)
|
|
return false;
|
|
|
|
if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
|
|
return true;
|
|
return false;
|
|
}
|
|
#endif
|