mirror of
https://github.com/Q3Rally-Team/q3rally.git
synced 2024-11-28 14:42:33 +00:00
0d5fb492cd
Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
1168 lines
25 KiB
C
1168 lines
25 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
Quake III Arena source code 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.
|
|
|
|
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "client.h"
|
|
|
|
#include "../botlib/botlib.h"
|
|
|
|
extern botlib_export_t *botlib_export;
|
|
|
|
vm_t *uivm;
|
|
|
|
/*
|
|
====================
|
|
GetClientState
|
|
====================
|
|
*/
|
|
static void GetClientState( uiClientState_t *state ) {
|
|
state->connectPacketCount = clc.connectPacketCount;
|
|
state->connState = clc.state;
|
|
Q_strncpyz( state->servername, clc.servername, sizeof( state->servername ) );
|
|
Q_strncpyz( state->updateInfoString, cls.updateInfoString, sizeof( state->updateInfoString ) );
|
|
Q_strncpyz( state->messageString, clc.serverMessage, sizeof( state->messageString ) );
|
|
state->clientNum = cl.snap.ps.clientNum;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_LoadCachedServers
|
|
====================
|
|
*/
|
|
void LAN_LoadCachedServers( void ) {
|
|
int size;
|
|
fileHandle_t fileIn;
|
|
cls.numglobalservers = cls.numfavoriteservers = 0;
|
|
cls.numGlobalServerAddresses = 0;
|
|
if (FS_SV_FOpenFileRead("servercache.dat", &fileIn)) {
|
|
FS_Read(&cls.numglobalservers, sizeof(int), fileIn);
|
|
FS_Read(&cls.numfavoriteservers, sizeof(int), fileIn);
|
|
FS_Read(&size, sizeof(int), fileIn);
|
|
if (size == sizeof(cls.globalServers) + sizeof(cls.favoriteServers)) {
|
|
FS_Read(&cls.globalServers, sizeof(cls.globalServers), fileIn);
|
|
FS_Read(&cls.favoriteServers, sizeof(cls.favoriteServers), fileIn);
|
|
} else {
|
|
cls.numglobalservers = cls.numfavoriteservers = 0;
|
|
cls.numGlobalServerAddresses = 0;
|
|
}
|
|
FS_FCloseFile(fileIn);
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_SaveServersToCache
|
|
====================
|
|
*/
|
|
void LAN_SaveServersToCache( void ) {
|
|
int size;
|
|
fileHandle_t fileOut = FS_SV_FOpenFileWrite("servercache.dat");
|
|
FS_Write(&cls.numglobalservers, sizeof(int), fileOut);
|
|
FS_Write(&cls.numfavoriteservers, sizeof(int), fileOut);
|
|
size = sizeof(cls.globalServers) + sizeof(cls.favoriteServers);
|
|
FS_Write(&size, sizeof(int), fileOut);
|
|
FS_Write(&cls.globalServers, sizeof(cls.globalServers), fileOut);
|
|
FS_Write(&cls.favoriteServers, sizeof(cls.favoriteServers), fileOut);
|
|
FS_FCloseFile(fileOut);
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
LAN_ResetPings
|
|
====================
|
|
*/
|
|
static void LAN_ResetPings(int source) {
|
|
int count,i;
|
|
serverInfo_t *servers = NULL;
|
|
count = 0;
|
|
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
servers = &cls.localServers[0];
|
|
count = MAX_OTHER_SERVERS;
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
servers = &cls.globalServers[0];
|
|
count = MAX_GLOBAL_SERVERS;
|
|
break;
|
|
case AS_FAVORITES :
|
|
servers = &cls.favoriteServers[0];
|
|
count = MAX_OTHER_SERVERS;
|
|
break;
|
|
}
|
|
if (servers) {
|
|
for (i = 0; i < count; i++) {
|
|
servers[i].ping = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_AddServer
|
|
====================
|
|
*/
|
|
static int LAN_AddServer(int source, const char *name, const char *address) {
|
|
int max, *count, i;
|
|
netadr_t adr;
|
|
serverInfo_t *servers = NULL;
|
|
max = MAX_OTHER_SERVERS;
|
|
count = NULL;
|
|
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
count = &cls.numlocalservers;
|
|
servers = &cls.localServers[0];
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
max = MAX_GLOBAL_SERVERS;
|
|
count = &cls.numglobalservers;
|
|
servers = &cls.globalServers[0];
|
|
break;
|
|
case AS_FAVORITES :
|
|
count = &cls.numfavoriteservers;
|
|
servers = &cls.favoriteServers[0];
|
|
break;
|
|
}
|
|
if (servers && *count < max) {
|
|
NET_StringToAdr( address, &adr, NA_UNSPEC );
|
|
for ( i = 0; i < *count; i++ ) {
|
|
if (NET_CompareAdr(servers[i].adr, adr)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i >= *count) {
|
|
servers[*count].adr = adr;
|
|
Q_strncpyz(servers[*count].hostName, name, sizeof(servers[*count].hostName));
|
|
servers[*count].visible = qtrue;
|
|
(*count)++;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_RemoveServer
|
|
====================
|
|
*/
|
|
static void LAN_RemoveServer(int source, const char *addr) {
|
|
int *count, i;
|
|
serverInfo_t *servers = NULL;
|
|
count = NULL;
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
count = &cls.numlocalservers;
|
|
servers = &cls.localServers[0];
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
count = &cls.numglobalservers;
|
|
servers = &cls.globalServers[0];
|
|
break;
|
|
case AS_FAVORITES :
|
|
count = &cls.numfavoriteservers;
|
|
servers = &cls.favoriteServers[0];
|
|
break;
|
|
}
|
|
if (servers) {
|
|
netadr_t comp;
|
|
NET_StringToAdr( addr, &comp, NA_UNSPEC );
|
|
for (i = 0; i < *count; i++) {
|
|
if (NET_CompareAdr( comp, servers[i].adr)) {
|
|
int j = i;
|
|
while (j < *count - 1) {
|
|
Com_Memcpy(&servers[j], &servers[j+1], sizeof(servers[j]));
|
|
j++;
|
|
}
|
|
(*count)--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
LAN_GetServerCount
|
|
====================
|
|
*/
|
|
static int LAN_GetServerCount( int source ) {
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
return cls.numlocalservers;
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
return cls.numglobalservers;
|
|
break;
|
|
case AS_FAVORITES :
|
|
return cls.numfavoriteservers;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_GetLocalServerAddressString
|
|
====================
|
|
*/
|
|
static void LAN_GetServerAddressString( int source, int n, char *buf, int buflen ) {
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
Q_strncpyz(buf, NET_AdrToStringwPort( cls.localServers[n].adr) , buflen );
|
|
return;
|
|
}
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
|
|
Q_strncpyz(buf, NET_AdrToStringwPort( cls.globalServers[n].adr) , buflen );
|
|
return;
|
|
}
|
|
break;
|
|
case AS_FAVORITES :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
Q_strncpyz(buf, NET_AdrToStringwPort( cls.favoriteServers[n].adr) , buflen );
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
buf[0] = '\0';
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_GetServerInfo
|
|
====================
|
|
*/
|
|
static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {
|
|
char info[MAX_STRING_CHARS];
|
|
serverInfo_t *server = NULL;
|
|
info[0] = '\0';
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
server = &cls.localServers[n];
|
|
}
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
|
|
server = &cls.globalServers[n];
|
|
}
|
|
break;
|
|
case AS_FAVORITES :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
server = &cls.favoriteServers[n];
|
|
}
|
|
break;
|
|
}
|
|
if (server && buf) {
|
|
buf[0] = '\0';
|
|
Info_SetValueForKey( info, "hostname", server->hostName);
|
|
Info_SetValueForKey( info, "mapname", server->mapName);
|
|
Info_SetValueForKey( info, "clients", va("%i",server->clients));
|
|
Info_SetValueForKey( info, "sv_maxclients", va("%i",server->maxClients));
|
|
Info_SetValueForKey( info, "ping", va("%i",server->ping));
|
|
Info_SetValueForKey( info, "minping", va("%i",server->minPing));
|
|
Info_SetValueForKey( info, "maxping", va("%i",server->maxPing));
|
|
Info_SetValueForKey( info, "game", server->game);
|
|
Info_SetValueForKey( info, "gametype", va("%i",server->gameType));
|
|
Info_SetValueForKey( info, "nettype", va("%i",server->netType));
|
|
Info_SetValueForKey( info, "addr", NET_AdrToStringwPort(server->adr));
|
|
Info_SetValueForKey( info, "punkbuster", va("%i", server->punkbuster));
|
|
Info_SetValueForKey( info, "g_needpass", va("%i", server->g_needpass));
|
|
Info_SetValueForKey( info, "g_humanplayers", va("%i", server->g_humanplayers));
|
|
Q_strncpyz(buf, info, buflen);
|
|
} else {
|
|
if (buf) {
|
|
buf[0] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_GetServerPing
|
|
====================
|
|
*/
|
|
static int LAN_GetServerPing( int source, int n ) {
|
|
serverInfo_t *server = NULL;
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
server = &cls.localServers[n];
|
|
}
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
|
|
server = &cls.globalServers[n];
|
|
}
|
|
break;
|
|
case AS_FAVORITES :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
server = &cls.favoriteServers[n];
|
|
}
|
|
break;
|
|
}
|
|
if (server) {
|
|
return server->ping;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_GetServerPtr
|
|
====================
|
|
*/
|
|
static serverInfo_t *LAN_GetServerPtr( int source, int n ) {
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
return &cls.localServers[n];
|
|
}
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
|
|
return &cls.globalServers[n];
|
|
}
|
|
break;
|
|
case AS_FAVORITES :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
return &cls.favoriteServers[n];
|
|
}
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_CompareServers
|
|
====================
|
|
*/
|
|
static int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ) {
|
|
int res;
|
|
serverInfo_t *server1, *server2;
|
|
int clients1, clients2;
|
|
|
|
server1 = LAN_GetServerPtr(source, s1);
|
|
server2 = LAN_GetServerPtr(source, s2);
|
|
if (!server1 || !server2) {
|
|
return 0;
|
|
}
|
|
|
|
res = 0;
|
|
switch( sortKey ) {
|
|
case SORT_HOST:
|
|
res = Q_stricmp( server1->hostName, server2->hostName );
|
|
break;
|
|
|
|
case SORT_MAP:
|
|
res = Q_stricmp( server1->mapName, server2->mapName );
|
|
break;
|
|
case SORT_CLIENTS:
|
|
// sub sort by max clients
|
|
if ( server1->clients == server2->clients ) {
|
|
clients1 = server1->maxClients;
|
|
clients2 = server2->maxClients;
|
|
} else {
|
|
clients1 = server1->clients;
|
|
clients2 = server2->clients;
|
|
}
|
|
|
|
if (clients1 < clients2) {
|
|
res = -1;
|
|
}
|
|
else if (clients1 > clients2) {
|
|
res = 1;
|
|
}
|
|
else {
|
|
res = 0;
|
|
}
|
|
break;
|
|
case SORT_GAME:
|
|
if (server1->gameType < server2->gameType) {
|
|
res = -1;
|
|
}
|
|
else if (server1->gameType > server2->gameType) {
|
|
res = 1;
|
|
}
|
|
else {
|
|
res = 0;
|
|
}
|
|
break;
|
|
case SORT_PING:
|
|
if (server1->ping < server2->ping) {
|
|
res = -1;
|
|
}
|
|
else if (server1->ping > server2->ping) {
|
|
res = 1;
|
|
}
|
|
else {
|
|
res = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (sortDir) {
|
|
if (res < 0)
|
|
return 1;
|
|
if (res > 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_GetPingQueueCount
|
|
====================
|
|
*/
|
|
static int LAN_GetPingQueueCount( void ) {
|
|
return (CL_GetPingQueueCount());
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_ClearPing
|
|
====================
|
|
*/
|
|
static void LAN_ClearPing( int n ) {
|
|
CL_ClearPing( n );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_GetPing
|
|
====================
|
|
*/
|
|
static void LAN_GetPing( int n, char *buf, int buflen, int *pingtime ) {
|
|
CL_GetPing( n, buf, buflen, pingtime );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_GetPingInfo
|
|
====================
|
|
*/
|
|
static void LAN_GetPingInfo( int n, char *buf, int buflen ) {
|
|
CL_GetPingInfo( n, buf, buflen );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_MarkServerVisible
|
|
====================
|
|
*/
|
|
static void LAN_MarkServerVisible(int source, int n, qboolean visible ) {
|
|
if (n == -1) {
|
|
int count = MAX_OTHER_SERVERS;
|
|
serverInfo_t *server = NULL;
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
server = &cls.localServers[0];
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
server = &cls.globalServers[0];
|
|
count = MAX_GLOBAL_SERVERS;
|
|
break;
|
|
case AS_FAVORITES :
|
|
server = &cls.favoriteServers[0];
|
|
break;
|
|
}
|
|
if (server) {
|
|
for (n = 0; n < count; n++) {
|
|
server[n].visible = visible;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
cls.localServers[n].visible = visible;
|
|
}
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
|
|
cls.globalServers[n].visible = visible;
|
|
}
|
|
break;
|
|
case AS_FAVORITES :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
cls.favoriteServers[n].visible = visible;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=======================
|
|
LAN_ServerIsVisible
|
|
=======================
|
|
*/
|
|
static int LAN_ServerIsVisible(int source, int n ) {
|
|
switch (source) {
|
|
case AS_LOCAL :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
return cls.localServers[n].visible;
|
|
}
|
|
break;
|
|
case AS_MPLAYER:
|
|
case AS_GLOBAL :
|
|
if (n >= 0 && n < MAX_GLOBAL_SERVERS) {
|
|
return cls.globalServers[n].visible;
|
|
}
|
|
break;
|
|
case AS_FAVORITES :
|
|
if (n >= 0 && n < MAX_OTHER_SERVERS) {
|
|
return cls.favoriteServers[n].visible;
|
|
}
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
/*
|
|
=======================
|
|
LAN_UpdateVisiblePings
|
|
=======================
|
|
*/
|
|
qboolean LAN_UpdateVisiblePings(int source ) {
|
|
return CL_UpdateVisiblePings_f(source);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LAN_GetServerStatus
|
|
====================
|
|
*/
|
|
int LAN_GetServerStatus( char *serverAddress, char *serverStatus, int maxLen ) {
|
|
return CL_ServerStatus( serverAddress, serverStatus, maxLen );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_GetGlConfig
|
|
====================
|
|
*/
|
|
static void CL_GetGlconfig( glconfig_t *config ) {
|
|
*config = cls.glconfig;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_GetClipboardData
|
|
====================
|
|
*/
|
|
static void CL_GetClipboardData( char *buf, int buflen ) {
|
|
char *cbd;
|
|
|
|
cbd = Sys_GetClipboardData();
|
|
|
|
if ( !cbd ) {
|
|
*buf = 0;
|
|
return;
|
|
}
|
|
|
|
Q_strncpyz( buf, cbd, buflen );
|
|
|
|
Z_Free( cbd );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
Key_KeynumToStringBuf
|
|
====================
|
|
*/
|
|
static void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {
|
|
Q_strncpyz( buf, Key_KeynumToString( keynum ), buflen );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
Key_GetBindingBuf
|
|
====================
|
|
*/
|
|
static void Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
|
|
char *value;
|
|
|
|
value = Key_GetBinding( keynum );
|
|
if ( value ) {
|
|
Q_strncpyz( buf, value, buflen );
|
|
}
|
|
else {
|
|
*buf = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CLUI_GetCDKey
|
|
====================
|
|
*/
|
|
static void CLUI_GetCDKey( char *buf, int buflen ) {
|
|
#ifndef STANDALONE
|
|
const char *gamedir;
|
|
gamedir = Cvar_VariableString( "fs_game" );
|
|
if (UI_usesUniqueCDKey() && gamedir[0] != 0) {
|
|
Com_Memcpy( buf, &cl_cdkey[16], 16);
|
|
buf[16] = 0;
|
|
} else {
|
|
Com_Memcpy( buf, cl_cdkey, 16);
|
|
buf[16] = 0;
|
|
}
|
|
#else
|
|
*buf = 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
CLUI_SetCDKey
|
|
====================
|
|
*/
|
|
#ifndef STANDALONE
|
|
static void CLUI_SetCDKey( char *buf ) {
|
|
const char *gamedir;
|
|
gamedir = Cvar_VariableString( "fs_game" );
|
|
if (UI_usesUniqueCDKey() && gamedir[0] != 0) {
|
|
Com_Memcpy( &cl_cdkey[16], buf, 16 );
|
|
cl_cdkey[32] = 0;
|
|
// set the flag so the fle will be written at the next opportunity
|
|
cvar_modifiedFlags |= CVAR_ARCHIVE;
|
|
} else {
|
|
Com_Memcpy( cl_cdkey, buf, 16 );
|
|
// set the flag so the fle will be written at the next opportunity
|
|
cvar_modifiedFlags |= CVAR_ARCHIVE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
====================
|
|
GetConfigString
|
|
====================
|
|
*/
|
|
static int GetConfigString(int index, char *buf, int size)
|
|
{
|
|
int offset;
|
|
|
|
if (index < 0 || index >= MAX_CONFIGSTRINGS)
|
|
return qfalse;
|
|
|
|
offset = cl.gameState.stringOffsets[index];
|
|
if (!offset) {
|
|
if( size ) {
|
|
buf[0] = 0;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
Q_strncpyz( buf, cl.gameState.stringData+offset, size);
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
FloatAsInt
|
|
====================
|
|
*/
|
|
static int FloatAsInt( float f ) {
|
|
floatint_t fi;
|
|
fi.f = f;
|
|
return fi.i;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_UISystemCalls
|
|
|
|
The ui module is making a system call
|
|
====================
|
|
*/
|
|
intptr_t CL_UISystemCalls( intptr_t *args ) {
|
|
switch( args[0] ) {
|
|
case UI_ERROR:
|
|
Com_Error( ERR_DROP, "%s", (const char*)VMA(1) );
|
|
return 0;
|
|
|
|
case UI_PRINT:
|
|
Com_Printf( "%s", (const char*)VMA(1) );
|
|
return 0;
|
|
|
|
case UI_MILLISECONDS:
|
|
return Sys_Milliseconds();
|
|
|
|
case UI_CVAR_REGISTER:
|
|
Cvar_Register( VMA(1), VMA(2), VMA(3), args[4] );
|
|
return 0;
|
|
|
|
case UI_CVAR_UPDATE:
|
|
Cvar_Update( VMA(1) );
|
|
return 0;
|
|
|
|
case UI_CVAR_SET:
|
|
Cvar_SetSafe( VMA(1), VMA(2) );
|
|
return 0;
|
|
|
|
case UI_CVAR_VARIABLEVALUE:
|
|
return FloatAsInt( Cvar_VariableValue( VMA(1) ) );
|
|
|
|
case UI_CVAR_VARIABLESTRINGBUFFER:
|
|
Cvar_VariableStringBuffer( VMA(1), VMA(2), args[3] );
|
|
return 0;
|
|
|
|
case UI_CVAR_SETVALUE:
|
|
Cvar_SetValueSafe( VMA(1), VMF(2) );
|
|
return 0;
|
|
|
|
case UI_CVAR_RESET:
|
|
Cvar_Reset( VMA(1) );
|
|
return 0;
|
|
|
|
case UI_CVAR_CREATE:
|
|
Cvar_Register( NULL, VMA(1), VMA(2), args[3] );
|
|
return 0;
|
|
|
|
case UI_CVAR_INFOSTRINGBUFFER:
|
|
Cvar_InfoStringBuffer( args[1], VMA(2), args[3] );
|
|
return 0;
|
|
|
|
case UI_ARGC:
|
|
return Cmd_Argc();
|
|
|
|
case UI_ARGV:
|
|
Cmd_ArgvBuffer( args[1], VMA(2), args[3] );
|
|
return 0;
|
|
|
|
case UI_CMD_EXECUTETEXT:
|
|
if(args[1] == EXEC_NOW
|
|
&& (!strncmp(VMA(2), "snd_restart", 11)
|
|
|| !strncmp(VMA(2), "vid_restart", 11)
|
|
|| !strncmp(VMA(2), "quit", 5)))
|
|
{
|
|
Com_Printf (S_COLOR_YELLOW "turning EXEC_NOW '%.11s' into EXEC_INSERT\n", (const char*)VMA(2));
|
|
args[1] = EXEC_INSERT;
|
|
}
|
|
Cbuf_ExecuteText( args[1], VMA(2) );
|
|
return 0;
|
|
|
|
case UI_FS_FOPENFILE:
|
|
return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] );
|
|
|
|
case UI_FS_READ:
|
|
FS_Read( VMA(1), args[2], args[3] );
|
|
return 0;
|
|
|
|
case UI_FS_WRITE:
|
|
FS_Write( VMA(1), args[2], args[3] );
|
|
return 0;
|
|
|
|
case UI_FS_FCLOSEFILE:
|
|
FS_FCloseFile( args[1] );
|
|
return 0;
|
|
|
|
case UI_FS_GETFILELIST:
|
|
return FS_GetFileList( VMA(1), VMA(2), VMA(3), args[4] );
|
|
|
|
case UI_FS_SEEK:
|
|
return FS_Seek( args[1], args[2], args[3] );
|
|
|
|
case UI_R_REGISTERMODEL:
|
|
return re.RegisterModel( VMA(1) );
|
|
|
|
case UI_R_REGISTERSKIN:
|
|
return re.RegisterSkin( VMA(1) );
|
|
|
|
case UI_R_REGISTERSHADERNOMIP:
|
|
return re.RegisterShaderNoMip( VMA(1) );
|
|
|
|
case UI_R_CLEARSCENE:
|
|
re.ClearScene();
|
|
return 0;
|
|
|
|
case UI_R_ADDREFENTITYTOSCENE:
|
|
re.AddRefEntityToScene( VMA(1) );
|
|
return 0;
|
|
|
|
case UI_R_ADDPOLYTOSCENE:
|
|
re.AddPolyToScene( args[1], args[2], VMA(3), 1 );
|
|
return 0;
|
|
|
|
case UI_R_ADDLIGHTTOSCENE:
|
|
re.AddLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
|
|
return 0;
|
|
|
|
case UI_R_RENDERSCENE:
|
|
re.RenderScene( VMA(1) );
|
|
return 0;
|
|
|
|
case UI_R_SETCOLOR:
|
|
re.SetColor( VMA(1) );
|
|
return 0;
|
|
|
|
case UI_R_DRAWSTRETCHPIC:
|
|
re.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] );
|
|
return 0;
|
|
|
|
case UI_R_MODELBOUNDS:
|
|
re.ModelBounds( args[1], VMA(2), VMA(3) );
|
|
return 0;
|
|
|
|
case UI_UPDATESCREEN:
|
|
SCR_UpdateScreen();
|
|
return 0;
|
|
|
|
case UI_CM_LERPTAG:
|
|
re.LerpTag( VMA(1), args[2], args[3], args[4], VMF(5), VMA(6) );
|
|
return 0;
|
|
|
|
case UI_S_REGISTERSOUND:
|
|
return S_RegisterSound( VMA(1), args[2] );
|
|
|
|
case UI_S_STARTLOCALSOUND:
|
|
S_StartLocalSound( args[1], args[2] );
|
|
return 0;
|
|
|
|
case UI_KEY_KEYNUMTOSTRINGBUF:
|
|
Key_KeynumToStringBuf( args[1], VMA(2), args[3] );
|
|
return 0;
|
|
|
|
case UI_KEY_GETBINDINGBUF:
|
|
Key_GetBindingBuf( args[1], VMA(2), args[3] );
|
|
return 0;
|
|
|
|
case UI_KEY_SETBINDING:
|
|
Key_SetBinding( args[1], VMA(2) );
|
|
return 0;
|
|
|
|
case UI_KEY_ISDOWN:
|
|
return Key_IsDown( args[1] );
|
|
|
|
case UI_KEY_GETOVERSTRIKEMODE:
|
|
return Key_GetOverstrikeMode();
|
|
|
|
case UI_KEY_SETOVERSTRIKEMODE:
|
|
Key_SetOverstrikeMode( args[1] );
|
|
return 0;
|
|
|
|
case UI_KEY_CLEARSTATES:
|
|
Key_ClearStates();
|
|
return 0;
|
|
|
|
case UI_KEY_GETCATCHER:
|
|
return Key_GetCatcher();
|
|
|
|
case UI_KEY_SETCATCHER:
|
|
// Don't allow the ui module to close the console
|
|
Key_SetCatcher( args[1] | ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) );
|
|
return 0;
|
|
|
|
case UI_GETCLIPBOARDDATA:
|
|
CL_GetClipboardData( VMA(1), args[2] );
|
|
return 0;
|
|
|
|
case UI_GETCLIENTSTATE:
|
|
GetClientState( VMA(1) );
|
|
return 0;
|
|
|
|
case UI_GETGLCONFIG:
|
|
CL_GetGlconfig( VMA(1) );
|
|
return 0;
|
|
|
|
case UI_GETCONFIGSTRING:
|
|
return GetConfigString( args[1], VMA(2), args[3] );
|
|
|
|
case UI_LAN_LOADCACHEDSERVERS:
|
|
LAN_LoadCachedServers();
|
|
return 0;
|
|
|
|
case UI_LAN_SAVECACHEDSERVERS:
|
|
LAN_SaveServersToCache();
|
|
return 0;
|
|
|
|
case UI_LAN_ADDSERVER:
|
|
return LAN_AddServer(args[1], VMA(2), VMA(3));
|
|
|
|
case UI_LAN_REMOVESERVER:
|
|
LAN_RemoveServer(args[1], VMA(2));
|
|
return 0;
|
|
|
|
case UI_LAN_GETPINGQUEUECOUNT:
|
|
return LAN_GetPingQueueCount();
|
|
|
|
case UI_LAN_CLEARPING:
|
|
LAN_ClearPing( args[1] );
|
|
return 0;
|
|
|
|
case UI_LAN_GETPING:
|
|
LAN_GetPing( args[1], VMA(2), args[3], VMA(4) );
|
|
return 0;
|
|
|
|
case UI_LAN_GETPINGINFO:
|
|
LAN_GetPingInfo( args[1], VMA(2), args[3] );
|
|
return 0;
|
|
|
|
case UI_LAN_GETSERVERCOUNT:
|
|
return LAN_GetServerCount(args[1]);
|
|
|
|
case UI_LAN_GETSERVERADDRESSSTRING:
|
|
LAN_GetServerAddressString( args[1], args[2], VMA(3), args[4] );
|
|
return 0;
|
|
|
|
case UI_LAN_GETSERVERINFO:
|
|
LAN_GetServerInfo( args[1], args[2], VMA(3), args[4] );
|
|
return 0;
|
|
|
|
case UI_LAN_GETSERVERPING:
|
|
return LAN_GetServerPing( args[1], args[2] );
|
|
|
|
case UI_LAN_MARKSERVERVISIBLE:
|
|
LAN_MarkServerVisible( args[1], args[2], args[3] );
|
|
return 0;
|
|
|
|
case UI_LAN_SERVERISVISIBLE:
|
|
return LAN_ServerIsVisible( args[1], args[2] );
|
|
|
|
case UI_LAN_UPDATEVISIBLEPINGS:
|
|
return LAN_UpdateVisiblePings( args[1] );
|
|
|
|
case UI_LAN_RESETPINGS:
|
|
LAN_ResetPings( args[1] );
|
|
return 0;
|
|
|
|
case UI_LAN_SERVERSTATUS:
|
|
return LAN_GetServerStatus( VMA(1), VMA(2), args[3] );
|
|
|
|
case UI_LAN_COMPARESERVERS:
|
|
return LAN_CompareServers( args[1], args[2], args[3], args[4], args[5] );
|
|
|
|
case UI_MEMORY_REMAINING:
|
|
return Hunk_MemoryRemaining();
|
|
|
|
case UI_GET_CDKEY:
|
|
CLUI_GetCDKey( VMA(1), args[2] );
|
|
return 0;
|
|
|
|
case UI_SET_CDKEY:
|
|
#ifndef STANDALONE
|
|
CLUI_SetCDKey( VMA(1) );
|
|
#endif
|
|
return 0;
|
|
|
|
case UI_SET_PBCLSTATUS:
|
|
return 0;
|
|
|
|
case UI_R_REGISTERFONT:
|
|
re.RegisterFont( VMA(1), args[2], VMA(3));
|
|
return 0;
|
|
|
|
case UI_MEMSET:
|
|
Com_Memset( VMA(1), args[2], args[3] );
|
|
return 0;
|
|
|
|
case UI_MEMCPY:
|
|
Com_Memcpy( VMA(1), VMA(2), args[3] );
|
|
return 0;
|
|
|
|
case UI_STRNCPY:
|
|
strncpy( VMA(1), VMA(2), args[3] );
|
|
return args[1];
|
|
|
|
case UI_SIN:
|
|
return FloatAsInt( sin( VMF(1) ) );
|
|
|
|
case UI_COS:
|
|
return FloatAsInt( cos( VMF(1) ) );
|
|
|
|
case UI_ATAN2:
|
|
return FloatAsInt( atan2( VMF(1), VMF(2) ) );
|
|
|
|
case UI_SQRT:
|
|
return FloatAsInt( sqrt( VMF(1) ) );
|
|
|
|
case UI_FLOOR:
|
|
return FloatAsInt( floor( VMF(1) ) );
|
|
|
|
case UI_CEIL:
|
|
return FloatAsInt( ceil( VMF(1) ) );
|
|
|
|
case UI_PC_ADD_GLOBAL_DEFINE:
|
|
return botlib_export->PC_AddGlobalDefine( VMA(1) );
|
|
case UI_PC_LOAD_SOURCE:
|
|
return botlib_export->PC_LoadSourceHandle( VMA(1) );
|
|
case UI_PC_FREE_SOURCE:
|
|
return botlib_export->PC_FreeSourceHandle( args[1] );
|
|
case UI_PC_READ_TOKEN:
|
|
return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) );
|
|
case UI_PC_SOURCE_FILE_AND_LINE:
|
|
return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) );
|
|
|
|
case UI_S_STOPBACKGROUNDTRACK:
|
|
S_StopBackgroundTrack();
|
|
return 0;
|
|
case UI_S_STARTBACKGROUNDTRACK:
|
|
S_StartBackgroundTrack( VMA(1), VMA(2));
|
|
return 0;
|
|
|
|
case UI_REAL_TIME:
|
|
return Com_RealTime( VMA(1) );
|
|
|
|
case UI_CIN_PLAYCINEMATIC:
|
|
Com_DPrintf("UI_CIN_PlayCinematic\n");
|
|
return CIN_PlayCinematic(VMA(1), args[2], args[3], args[4], args[5], args[6]);
|
|
|
|
case UI_CIN_STOPCINEMATIC:
|
|
return CIN_StopCinematic(args[1]);
|
|
|
|
case UI_CIN_RUNCINEMATIC:
|
|
return CIN_RunCinematic(args[1]);
|
|
|
|
case UI_CIN_DRAWCINEMATIC:
|
|
CIN_DrawCinematic(args[1]);
|
|
return 0;
|
|
|
|
case UI_CIN_SETEXTENTS:
|
|
CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);
|
|
return 0;
|
|
|
|
case UI_R_REMAP_SHADER:
|
|
re.RemapShader( VMA(1), VMA(2), VMA(3) );
|
|
return 0;
|
|
|
|
case UI_VERIFY_CDKEY:
|
|
return CL_CDKeyValidate(VMA(1), VMA(2));
|
|
|
|
default:
|
|
Com_Error( ERR_DROP, "Bad UI system trap: %ld", (long int) args[0] );
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_ShutdownUI
|
|
====================
|
|
*/
|
|
void CL_ShutdownUI( void ) {
|
|
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_UI );
|
|
cls.uiStarted = qfalse;
|
|
if ( !uivm ) {
|
|
return;
|
|
}
|
|
VM_Call( uivm, UI_SHUTDOWN );
|
|
VM_Free( uivm );
|
|
uivm = NULL;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
CL_InitUI
|
|
====================
|
|
*/
|
|
#define UI_OLD_API_VERSION 4
|
|
|
|
void CL_InitUI( void ) {
|
|
int v;
|
|
vmInterpret_t interpret;
|
|
|
|
// load the dll or bytecode
|
|
interpret = Cvar_VariableValue("vm_ui");
|
|
if(cl_connectedToPureServer)
|
|
{
|
|
// if sv_pure is set we only allow qvms to be loaded
|
|
if(interpret != VMI_COMPILED && interpret != VMI_BYTECODE)
|
|
interpret = VMI_COMPILED;
|
|
}
|
|
|
|
uivm = VM_Create( "ui", CL_UISystemCalls, interpret );
|
|
if ( !uivm ) {
|
|
Com_Error( ERR_FATAL, "VM_Create on UI failed" );
|
|
}
|
|
|
|
// sanity check
|
|
v = VM_Call( uivm, UI_GETAPIVERSION );
|
|
if (v == UI_OLD_API_VERSION) {
|
|
// Com_Printf(S_COLOR_YELLOW "WARNING: loading old Quake III Arena User Interface version %d\n", v );
|
|
// init for this gamestate
|
|
VM_Call( uivm, UI_INIT, (clc.state >= CA_AUTHORIZING && clc.state < CA_ACTIVE));
|
|
}
|
|
else if (v != UI_API_VERSION) {
|
|
// Free uivm now, so UI_SHUTDOWN doesn't get called later.
|
|
VM_Free( uivm );
|
|
uivm = NULL;
|
|
|
|
Com_Error( ERR_DROP, "User Interface is version %d, expected %d", v, UI_API_VERSION );
|
|
cls.uiStarted = qfalse;
|
|
}
|
|
else {
|
|
// init for this gamestate
|
|
VM_Call( uivm, UI_INIT, (clc.state >= CA_AUTHORIZING && clc.state < CA_ACTIVE) );
|
|
}
|
|
}
|
|
|
|
#ifndef STANDALONE
|
|
qboolean UI_usesUniqueCDKey( void ) {
|
|
if (uivm) {
|
|
return (VM_Call( uivm, UI_HASUNIQUECDKEY) == qtrue);
|
|
} else {
|
|
return qfalse;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
====================
|
|
UI_GameCommand
|
|
|
|
See if the current console command is claimed by the ui
|
|
====================
|
|
*/
|
|
qboolean UI_GameCommand( void ) {
|
|
if ( !uivm ) {
|
|
return qfalse;
|
|
}
|
|
|
|
return VM_Call( uivm, UI_CONSOLE_COMMAND, cls.realtime );
|
|
}
|