From 425decdf7e9284d15aa726e3ae96b9942fb0e3ea Mon Sep 17 00:00:00 2001 From: IronClawTrem Date: Sun, 16 Feb 2020 03:40:06 +0000 Subject: create tremded branch --- src/client/cl_ui.cpp | 1269 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1269 insertions(+) create mode 100644 src/client/cl_ui.cpp (limited to 'src/client/cl_ui.cpp') diff --git a/src/client/cl_ui.cpp b/src/client/cl_ui.cpp new file mode 100644 index 0000000..4052fe6 --- /dev/null +++ b/src/client/cl_ui.cpp @@ -0,0 +1,1269 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2000-2013 Darklegion Development +Copyright (C) 2015-2019 GrangerHub + +This file is part of Tremulous. + +Tremulous 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 3 of the License, +or (at your option) any later version. + +Tremulous 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 Tremulous; if not, see + +=========================================================================== +*/ + +#include "client.h" + +#include "cl_updates.h" + +/* +==================== +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 = (clc.netchan.alternateProtocol == 2 ? cl.snap.alternatePs.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) +{ + fileHandle_t fileOut = FS_SV_FOpenFileWrite("servercache.dat"); + FS_Write(&cls.numglobalservers, sizeof(int), fileOut); + FS_Write(&cls.numfavoriteservers, sizeof(int), fileOut); + + int 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); +} + +/* +==================== +GetNews +==================== +*/ +static bool GetNews(bool begin) +{ + bool finished = false; + fileHandle_t fileIn; + int readSize; + + if (begin) + { // if not already using curl, start the download + if (!clc.downloadCURLM) + { + if (!CL_cURL_Init()) + { + Cvar_Set("cl_newsString", "^1Error: Could not load cURL library"); + return true; + } + clc.activeCURLNotGameRelated = true; + CL_cURL_BeginDownload("news.dat", "http://grangerhub.com/wp-content/uploads/clientnews.txt"); + return false; + } + } + + if (!clc.downloadCURLM && FS_SV_FOpenFileRead("news.dat", &fileIn)) + { + readSize = FS_Read(clc.newsString, sizeof(clc.newsString), fileIn); + FS_FCloseFile(fileIn); + clc.newsString[readSize] = '\0'; + if (readSize > 0) + { + finished = true; + clc.cURLUsed = false; + CL_cURL_Shutdown(); + clc.activeCURLNotGameRelated = false; + } + } + if (!finished) strcpy(clc.newsString, "Retrieving..."); + Cvar_Set("cl_newsString", clc.newsString); + return finished; + Cvar_Set("cl_newsString", "^1You must compile your client with CURL support to use this feature"); + return true; +} + +/* +==================== +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 = true; + (*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) + { + ::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); + if (cls.localServers[n].adr.alternateProtocol != 0) + Q_strncpyz(buf + (int)strlen(buf), (cls.localServers[n].adr.alternateProtocol == 1 ? " -g" : " -1"), + buflen - (int)strlen(buf)); + 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); + if (cls.globalServers[n].adr.alternateProtocol != 0) + Q_strncpyz(buf + (int)strlen(buf), + (cls.globalServers[n].adr.alternateProtocol == 1 ? " -g" : " -1"), buflen - (int)strlen(buf)); + return; + } + break; + case AS_FAVORITES: + if (n >= 0 && n < MAX_OTHER_SERVERS) + { + Q_strncpyz(buf, NET_AdrToStringwPort(cls.favoriteServers[n].adr), buflen); + if (cls.favoriteServers[n].adr.alternateProtocol != 0) + Q_strncpyz(buf + (int)strlen(buf), + (cls.favoriteServers[n].adr.alternateProtocol == 1 ? " -g" : " -1"), buflen - (int)strlen(buf)); + 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'; + if (server->adr.alternateProtocol != 0) + { + char hn[MAX_HOSTNAME_LENGTH]; + Q_strncpyz(hn, server->hostName, sizeof(hn)); + Q_strcat( + hn, sizeof(hn), (server->adr.alternateProtocol == 1 ? S_COLOR_WHITE " [GPP]" : S_COLOR_WHITE " [1.1]")); + Info_SetValueForKey(info, "hostname", hn); + } + else + { + Info_SetValueForKey(info, "hostname", server->hostName); + } + Info_SetValueForKey(info, "mapname", server->mapName); + Info_SetValueForKey(info, "label", server->label); + 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)); + 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; +} + +#define FEATURED_MAXPING 200 +/* +==================== +LAN_CompareServers +==================== +*/ +static int LAN_CompareServers(int source, int sortKey, int sortDir, int s1, int s2) +{ + int res; + serverInfo_t *server1, *server2; + + server1 = LAN_GetServerPtr(source, s1); + server2 = LAN_GetServerPtr(source, s2); + if (!server1 || !server2) + { + return 0; + } + + // featured servers on top + if ((server1->label[0] && server1->ping <= FEATURED_MAXPING) || + (server2->label[0] && server2->ping <= FEATURED_MAXPING)) + { + res = Q_stricmpn(server1->label, server2->label, MAX_FEATLABEL_CHARS); + if (res) return -res; + } + + res = 0; + switch (sortKey) + { + case SORT_HOST: + { + char hostName1[MAX_HOSTNAME_LENGTH]; + char hostName2[MAX_HOSTNAME_LENGTH]; + char *p; + int i; + + for (p = server1->hostName, i = 0; *p != '\0'; p++) + { + if (Q_isalpha(*p)) hostName1[i++] = *p; + } + hostName1[i] = '\0'; + + for (p = server2->hostName, i = 0; *p != '\0'; p++) + { + if (Q_isalpha(*p)) hostName2[i++] = *p; + } + hostName2[i] = '\0'; + + res = Q_stricmp(hostName1, hostName2); + } + break; + + case SORT_GAME: + res = Q_stricmp(server1->game, server2->game); + break; + case SORT_MAP: + res = Q_stricmp(server1->mapName, server2->mapName); + break; + case SORT_CLIENTS: + if (server1->clients < server2->clients) + { + res = -1; + } + else if (server1->clients > server2->clients) + { + 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, bool 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 bool 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 false; +} + +/* +======================= +LAN_UpdateVisiblePings +======================= +*/ +static bool LAN_UpdateVisiblePings(int source) { return CL_UpdateVisiblePings_f(source); } +/* +==================== +LAN_GetServerStatus +==================== +*/ +static bool 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; } +/* +==================== +GetConfigString +==================== +*/ +static bool GetConfigString(int i, char *buf, int size) +{ + int offset; + + if (i < 0 || i >= MAX_CONFIGSTRINGS) return false; + + offset = cl.gameState.stringOffsets[i]; + if (!offset) + { + if (size) buf[0] = '\0'; + return false; + } + + Q_strncpyz(buf, cl.gameState.stringData + offset, size); + + return true; +} + +/* +==================== +FloatAsInt +==================== +*/ +static int FloatAsInt(float f) +{ + floatint_t fi; + fi.f = f; + return fi.i; +} + +static bool probingUI = false; + +/* +==================== +CL_UISystemCalls + +The ui module is making a system call +==================== +*/ +intptr_t CL_UISystemCalls(intptr_t *args) +{ + if (cls.uiInterface == 2) + { + if (args[0] >= UI_R_SETCLIPREGION && args[0] < UI_MEMSET) + { + if (args[0] < UI_S_STOPBACKGROUNDTRACK - 1) + { + args[0] += 1; + } + else if (args[0] < UI_S_STOPBACKGROUNDTRACK + 4) + { + args[0] += UI_PARSE_ADD_GLOBAL_DEFINE - UI_S_STOPBACKGROUNDTRACK + 1; + } + else if (args[0] >= UI_PARSE_ADD_GLOBAL_DEFINE + 4) + { + args[0] += UI_GETNEWS - UI_PARSE_ADD_GLOBAL_DEFINE - 5; + if (args[0] == UI_PARSE_SOURCE_FILE_AND_LINE || args[0] == UI_GETNEWS) + args[0] = UI_PARSE_SOURCE_FILE_AND_LINE - 1337 - args[0]; + } + else + { + args[0] -= 4; + } + } + + switch (args[0]) + { + case UI_LAN_GETSERVERCOUNT: + case UI_LAN_GETSERVERADDRESSSTRING: + case UI_LAN_GETSERVERINFO: + case UI_LAN_MARKSERVERVISIBLE: + case UI_LAN_UPDATEVISIBLEPINGS: + case UI_LAN_RESETPINGS: + case UI_LAN_ADDSERVER: + case UI_LAN_REMOVESERVER: + case UI_LAN_GETSERVERPING: + case UI_LAN_SERVERISVISIBLE: + case UI_LAN_COMPARESERVERS: + if (args[1] == AS_GLOBAL) + { + args[1] = AS_LOCAL; + } + else if (args[1] == AS_LOCAL) + { + args[1] = AS_GLOBAL; + } + } + } + + switch (args[0]) + { + case UI_ERROR: + if (probingUI) + { + cls.uiInterface = 2; + return 0; + } + 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((vmCvar_t *)VMA(1), (const char *)VMA(2), (const char *)VMA(3), args[4]); + return 0; + + case UI_CVAR_UPDATE: + Cvar_Update((vmCvar_t *)VMA(1)); + return 0; + + case UI_CVAR_SET: + Cvar_SetSafe((const char *)VMA(1), (const char *)VMA(2)); + return 0; + + case UI_CVAR_VARIABLEVALUE: + return FloatAsInt(Cvar_VariableValue((const char *)VMA(1))); + + case UI_CVAR_VARIABLESTRINGBUFFER: + Cvar_VariableStringBuffer((const char *)VMA(1), (char *)VMA(2), args[3]); + return 0; + + case UI_CVAR_SETVALUE: + Cvar_SetValueSafe((const char *)VMA(1), VMF(2)); + return 0; + + case UI_CVAR_RESET: + Cvar_Reset((const char *)VMA(1)); + return 0; + + case UI_CVAR_CREATE: + Cvar_Register(NULL, (const char *)VMA(1), (const char *)VMA(2), args[3]); + return 0; + + case UI_CVAR_INFOSTRINGBUFFER: + Cvar_InfoStringBuffer(args[1], (char *)VMA(2), args[3]); + return 0; + + case UI_ARGC: + return Cmd_Argc(); + + case UI_ARGV: + Cmd_ArgvBuffer(args[1], (char *)VMA(2), args[3]); + return 0; + + case UI_CMD_EXECUTETEXT: + if (args[1] == EXEC_NOW) + { + if (!strncmp((const char *)VMA(2), "snd_restart", 11) + || !strncmp((const char *)VMA(2), "vid_restart", 11) + || !strncmp((const char *)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; + } + } + + // TODO: Do this better + if (!strncmp((const char *)VMA(2), "checkForUpdate", 14)) + { + CL_GetLatestRelease(); + return 0; + } + + Cbuf_ExecuteText(args[1], (const char *)VMA(2)); + return 0; + + case UI_FS_FOPENFILE: + return FS_FOpenFileByMode((const char *)VMA(1), (fileHandle_t *)VMA(2), (FS_Mode)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((const char *)VMA(1), (const char *)VMA(2), (char *)VMA(3), args[4]); + + case UI_FS_SEEK: + return FS_Seek((fileHandle_t)args[1], args[2], (FS_Origin)args[3]); + + case UI_R_REGISTERMODEL: + return re.RegisterModel((const char *)VMA(1)); + + case UI_R_REGISTERSKIN: + return re.RegisterSkin((const char *)VMA(1)); + + case UI_R_REGISTERSHADERNOMIP: + return re.RegisterShaderNoMip((const char *)VMA(1)); + + case UI_R_CLEARSCENE: + re.ClearScene(); + return 0; + + case UI_R_ADDREFENTITYTOSCENE: + re.AddRefEntityToScene((const refEntity_t *)VMA(1)); + return 0; + + case UI_R_ADDPOLYTOSCENE: + re.AddPolyToScene(args[1], args[2], (const polyVert_t *)VMA(3), 1); + return 0; + + case UI_R_ADDLIGHTTOSCENE: + re.AddLightToScene((const float *)VMA(1), VMF(2), VMF(3), VMF(4), VMF(5)); + return 0; + + case UI_R_RENDERSCENE: + re.RenderScene((const refdef_t *)VMA(1)); + return 0; + + case UI_R_SETCOLOR: + re.SetColor((const float *)VMA(1)); + return 0; + + case UI_R_SETCLIPREGION: + re.SetClipRegion((const float *)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], (float *)VMA(2), (float *)VMA(3)); + return 0; + + case UI_UPDATESCREEN: + SCR_UpdateScreen(); + return 0; + + case UI_CM_LERPTAG: + re.LerpTag((orientation_t *)VMA(1), args[2], args[3], args[4], VMF(5), (const char *)VMA(6)); + return 0; + + case UI_S_REGISTERSOUND: + return S_RegisterSound((const char *)VMA(1), (bool)args[2]); + + case UI_S_STARTLOCALSOUND: + S_StartLocalSound(args[1], args[2]); + return 0; + + case UI_KEY_KEYNUMTOSTRINGBUF: + Key_KeynumToStringBuf(args[1], (char *)VMA(2), args[3]); + return 0; + + case UI_KEY_GETBINDINGBUF: + Key_GetBindingBuf(args[1], (char *)VMA(2), args[3]); + return 0; + + case UI_KEY_SETBINDING: + Key_SetBinding(args[1], (const char *)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((bool)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 toggle the console + Key_SetCatcher((args[1] & ~KEYCATCH_CONSOLE) | (Key_GetCatcher() & KEYCATCH_CONSOLE)); + return 0; + + case UI_GETCLIPBOARDDATA: + ((char *)VMA(1))[0] = '\0'; + return 0; + + case UI_GETCLIENTSTATE: + GetClientState((uiClientState_t *)VMA(1)); + return 0; + + case UI_GETGLCONFIG: + CL_GetGlconfig((glconfig_t *)VMA(1)); + return 0; + + case UI_GETCONFIGSTRING: + return GetConfigString(args[1], (char *)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], (const char *)VMA(2), (const char *)VMA(3)); + + case UI_LAN_REMOVESERVER: + LAN_RemoveServer(args[1], (const char *)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], (char *)VMA(2), args[3], (int *)VMA(4)); + return 0; + + case UI_LAN_GETPINGINFO: + LAN_GetPingInfo(args[1], (char *)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], (char *)VMA(3), args[4]); + return 0; + + case UI_LAN_GETSERVERINFO: + LAN_GetServerInfo(args[1], args[2], (char *)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], (bool)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((char *)VMA(1), (char *)VMA(2), args[3]); + + case UI_GETNEWS: + return GetNews((bool)args[1]); + + 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_SET_PBCLSTATUS: + return 0; + + case UI_R_REGISTERFONT: + re.RegisterFont((const char *)VMA(1), args[2], (fontInfo_t *)VMA(3)); + return 0; + + case UI_MEMSET: + ::memset(VMA(1), args[2], args[3]); + return 0; + + case UI_MEMCPY: + ::memcpy(VMA(1), VMA(2), args[3]); + return 0; + + case UI_STRNCPY: + strncpy((char *)VMA(1), (const char *)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_PARSE_ADD_GLOBAL_DEFINE: + return Parse_AddGlobalDefine((char *)VMA(1)); + case UI_PARSE_LOAD_SOURCE: + return Parse_LoadSourceHandle((char *)VMA(1)); + case UI_PARSE_FREE_SOURCE: + return Parse_FreeSourceHandle(args[1]); + case UI_PARSE_READ_TOKEN: + return Parse_ReadTokenHandle(args[1], (pc_token_t *)VMA(2)); + case UI_PARSE_SOURCE_FILE_AND_LINE: + return Parse_SourceFileAndLine(args[1], (char *)VMA(2), (int *)VMA(3)); + + case UI_S_STOPBACKGROUNDTRACK: + S_StopBackgroundTrack(); + return 0; + case UI_S_STARTBACKGROUNDTRACK: + S_StartBackgroundTrack((const char *)VMA(1), (const char *)VMA(2)); + return 0; + + case UI_REAL_TIME: + return Com_RealTime((qtime_t *)VMA(1)); + + case UI_CIN_PLAYCINEMATIC: + return CIN_PlayCinematic((const char *)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((const char *)VMA(1), (const char *)VMA(2), (const char *)VMA(3)); + return 0; + + 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 = false; + if (!cls.ui) + { + return; + } + VM_Call(cls.ui, UI_SHUTDOWN); + VM_Free(cls.ui); + cls.ui = NULL; +} + +/* +==================== +CL_InitUI +==================== +*/ +void CL_InitUI(void) +{ + // load the dll or bytecode + vmInterpret_t interpret = (vmInterpret_t)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; + } + + cls.ui = VM_Create("ui", CL_UISystemCalls, interpret); + if (!cls.ui) + { + Com_Printf("Failed to find a valid UI vm. The following paths were searched:\n"); + Cmd_ExecuteString("path /\n"); + Com_Error(ERR_RECONNECT, "VM_Create on UI failed"); + } + + // sanity check + int v = VM_Call(cls.ui, UI_GETAPIVERSION); + if (v != UI_API_VERSION) + { + // Free cls.ui now, so UI_SHUTDOWN doesn't get called later. + VM_Free(cls.ui); + cls.ui = NULL; + + cls.uiStarted = false; + Com_Error(ERR_DROP, "User Interface is version %d, expected %d", v, UI_API_VERSION); + } + + // Probe UI interface + // Calls the GPP UI_CONSOLE_COMMAND (10), if GPP will return false 0. If a 1.1.0 qvm, will hit the error handler. + Cmd_TokenizeString(""); + cls.uiInterface = 0; + probingUI = true; + if ( VM_Call(cls.ui, UI_CONSOLE_COMMAND, 0) < 0 ) + cls.uiInterface = 2; + + probingUI = false; + + if (clc.state >= CA_CONNECTED && clc.state <= CA_ACTIVE && + (clc.netchan.alternateProtocol == 2) != (cls.uiInterface == 2)) + { + Com_Printf(S_COLOR_YELLOW "WARNING: %s protocol %i, but a ui module using the %s interface was found\n", + (clc.demoplaying ? "Demo was recorded using" : "Server uses"), + (clc.netchan.alternateProtocol == 0 ? PROTOCOL_VERSION : clc.netchan.alternateProtocol == 1 ? 70 : 69), + (cls.uiInterface == 2 ? "1.1" : "non-1.1")); + } + + // init for this gamestate + VM_Call(cls.ui, UI_INIT, (clc.state >= CA_AUTHORIZING && clc.state < CA_ACTIVE)); + + // show where the ui folder was loaded from + Cmd_ExecuteString("which ui/\n"); + + clc.newsString[0] = '\0'; +} + +/* +==================== +UI_GameCommand + +See if the current console command is claimed by the ui +==================== +*/ +bool UI_GameCommand(void) +{ + if (!cls.ui) return false; + + return (bool)VM_Call(cls.ui, UI_CONSOLE_COMMAND - (cls.uiInterface == 2 ? 2 : 0), cls.realtime); +} -- cgit