mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-14 16:31:38 +00:00
3da350a3ed
Added new project/target for easy integration into NQ engines - read nq_api.c for guidelines. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4024 fc73d0e0-1445-4013-8a0c-d673dee63da5
230 lines
6.8 KiB
C
230 lines
6.8 KiB
C
/*
|
|
This file is intended as a set of exports for an NQ-based engine.
|
|
This is supported _purely_ for clients, and will not work for servers.
|
|
|
|
|
|
|
|
[EndUser] how to use:
|
|
to join a qw server: connect "udp:127.0.0.1:27500"
|
|
to watch a qtv stream: connect "tcp:3@127.0.0.1:27599" (where '3' is the streamid)
|
|
to watch an mvd demo: connect "demo:blahblah.mvd" - the demo will be loaded from $WORKINGDIR/qw/demos/ - note that $WORKINGDIR is NOT always the same dir
|
|
as your engine is running from. The -basedir argument will break it, or engines that hunt down a 'proper' installation of quake instead.
|
|
|
|
|
|
[Developer] how to incorporate into an nq engine:
|
|
load up net_win.c
|
|
find the #include "net_wins.h" line.
|
|
dupe it, call it net_qtv.h
|
|
dupe the header itself too, changing all WINS_foo to QTV_foo.
|
|
find the net_landrivers array. Dupe the first block, then edit the first block to be all QTV_foo functions.
|
|
bump net_numlandrivers.
|
|
For non-window operating systems, you'll need to do the same, just figure out which net_win.c equivelent function it uses first. :P
|
|
certain engines may do weird things with the port. probably its best to just use Cmd_Args() for the connect command instead of Cmd_Argv(1), and to add
|
|
port parsing to XXXX_GetAddrFromName instead of messing around with port cvars etc and ruining server configs.
|
|
If your engine already has weird port behaviour, then its entirely your problem to fix. :P
|
|
You probably want to tweak your menus a little to clean up the nq/qw/qtv connection distinctions.
|
|
If you do want to make changes to libqtv, please consider joining the FTE team (or at least the irc channel) in order to contribute without forking.
|
|
|
|
[Developer] how to compile libqtv:
|
|
cflags MUST define 'LIBQTV' or it won't compile properly.
|
|
The relevent exports are all tagged as 'EXPORT void PUBLIC fname(...)' (dllexport+cdecl in windows), feel free to define those properly if you're making a linux shared object without exporting all (potentially conflicting) internals.
|
|
This means you can compile it as a dll without any issues, one with a standardized interface. Any libqtv-specific bugfixes can be released independantly from engine(s).
|
|
Compiling a dll with msvc will generally automatically produce a .lib which you can directly link against. Alternatively, include both projects in your workspace and set up dependancies properly and it'll be automatically imported.
|
|
|
|
[PowerUser] issues:
|
|
its a full qtv proxy, but you can't get admin/rcon access to it.
|
|
it doesn't read any configs, and has no console, thus you cannot set an rcon password/port.
|
|
without console/rcon, you cannot enable any listening ports for other users.
|
|
if you need a public qtv proxy, use a standalone version.
|
|
*/
|
|
|
|
|
|
|
|
#include "qtv.h"
|
|
int build_number(void);
|
|
|
|
static cluster_t *cluster;
|
|
|
|
//note that a qsockaddr is only 16 bytes.
|
|
//this is not enough for ipv6 etc.
|
|
struct qsockaddr
|
|
{
|
|
int ipid;
|
|
};
|
|
char resolvedadrstring[128];
|
|
int lastadrid;
|
|
|
|
#ifdef _WIN32
|
|
#define EXPORT __declspec(dllexport)
|
|
#define PUBLIC __cdecl
|
|
#endif
|
|
#ifndef EXPORT
|
|
#define EXPORT
|
|
#endif
|
|
#ifndef PUBLIC
|
|
#define PUBLIC
|
|
#endif
|
|
|
|
EXPORT int PUBLIC QTV_Init (void)
|
|
{
|
|
cluster = malloc(sizeof(*cluster));
|
|
if (cluster)
|
|
{
|
|
memset(cluster, 0, sizeof(*cluster));
|
|
|
|
cluster->qwdsocket[0] = INVALID_SOCKET;
|
|
cluster->qwdsocket[1] = INVALID_SOCKET;
|
|
cluster->tcpsocket[0] = INVALID_SOCKET;
|
|
cluster->tcpsocket[1] = INVALID_SOCKET;
|
|
cluster->anticheattime = 1*1000;
|
|
cluster->tooslowdelay = 100;
|
|
cluster->qwlistenportnum = 0;
|
|
cluster->allownqclients = true;
|
|
strcpy(cluster->hostname, DEFAULT_HOSTNAME);
|
|
cluster->buildnumber = build_number();
|
|
cluster->maxproxies = -1;
|
|
|
|
strcpy(cluster->demodir, "qw/demos/");
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
EXPORT void PUBLIC QTV_Shutdown (void)
|
|
{
|
|
}
|
|
EXPORT void PUBLIC QTV_Listen (qboolean state)
|
|
{
|
|
}
|
|
EXPORT int PUBLIC QTV_OpenSocket (int port)
|
|
{
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_CloseSocket (int socket)
|
|
{
|
|
//give it a chance to close any server connections from us disconnecting (should have already send disconnect message, but won't have run the server so not noticed the lack of viewers)
|
|
Cluster_Run(cluster, false);
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_Connect (int socket, struct qsockaddr *addr)
|
|
{
|
|
if (addr->ipid == lastadrid)
|
|
{
|
|
strlcpy(cluster->autojoinadr, resolvedadrstring, sizeof(cluster->autojoinadr));
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
cluster->autojoinadr[0] = 0;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_CheckNewConnections (void)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
static byte pendingbuf[8][1032];
|
|
static int pendinglen[8];
|
|
static unsigned int pendingin, pendingout;
|
|
void QTV_DoReceive(void *data, int length)
|
|
{
|
|
int idx;
|
|
if (length > sizeof(pendingbuf[0]))
|
|
return;
|
|
idx = pendingout++;
|
|
idx &= 7;
|
|
memcpy(pendingbuf[idx], data, length);
|
|
pendinglen[idx] = length;
|
|
}
|
|
EXPORT int PUBLIC QTV_Read (int socket, byte *buf, int len, struct qsockaddr *addr)
|
|
{
|
|
if (pendingout == pendingin)
|
|
{
|
|
Cluster_Run(cluster, false);
|
|
Cluster_Run(cluster, false);
|
|
}
|
|
|
|
while (pendingin != pendingout)
|
|
{
|
|
int idx = pendingin++;
|
|
idx &= 7;
|
|
if (pendinglen[idx] > len)
|
|
continue; //error
|
|
memcpy(buf, pendingbuf[idx], pendinglen[idx]);
|
|
return pendinglen[idx];
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_Write (int socket, byte *buf, int len, struct qsockaddr *addr)
|
|
{
|
|
netmsg_t m;
|
|
netadr_t from;
|
|
from.tcpcon = NULL;
|
|
((struct sockaddr*)from.sockaddr)->sa_family = AF_UNSPEC;
|
|
|
|
m.cursize = len;
|
|
m.data = buf;
|
|
m.readpos = 0;
|
|
|
|
QW_ProcessUDPPacket(cluster, &m, from);
|
|
|
|
if (pendingout == pendingin)
|
|
Cluster_Run(cluster, false);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_Broadcast (int socket, byte *buf, int len)
|
|
{
|
|
netmsg_t m;
|
|
netadr_t from;
|
|
from.tcpcon = NULL;
|
|
((struct sockaddr*)from.sockaddr)->sa_family = AF_UNSPEC;
|
|
|
|
m.cursize = len;
|
|
m.data = buf;
|
|
m.readpos = 0;
|
|
|
|
QW_ProcessUDPPacket(cluster, &m, from);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT char *PUBLIC QTV_AddrToString (struct qsockaddr *addr)
|
|
{
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_StringToAddr (char *string, struct qsockaddr *addr)
|
|
{
|
|
if (!strncmp(string, "udp:", 4) || !strncmp(string, "tcp:", 4) || !strncmp(string, "file:", 5))
|
|
{
|
|
snprintf(resolvedadrstring, sizeof(resolvedadrstring), "%s", string);
|
|
addr->ipid = ++lastadrid;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
EXPORT int PUBLIC QTV_GetSocketAddr (int socket, struct qsockaddr *addr)
|
|
{
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
|
{
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_GetAddrFromName (char *name, struct qsockaddr *addr)
|
|
{
|
|
return QTV_StringToAddr(name, addr);
|
|
}
|
|
EXPORT int PUBLIC QTV_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
|
|
{
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_GetSocketPort (struct qsockaddr *addr)
|
|
{
|
|
return 0;
|
|
}
|
|
EXPORT int PUBLIC QTV_SetSocketPort (struct qsockaddr *addr, int port)
|
|
{
|
|
return 0;
|
|
}
|