/* Relay -- a tool to record and play Quake2 demos Copyright (C) 2000 Conor Davis 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. Conor Davis cedavis@planetquake.com */ #include #include #include "shared.h" #include "proxy.h" #ifdef _WIN32 #define GAME_MODULE "gamex86.dll" #else #include #define GAME_MODULE "gamei386.so" #endif typedef game_export_t *(*GetGameAPI_t) (game_import_t *); // // UnloadGameModule // Calls the os-specific function to unload the given // proxy module and clears the handle. // void UnloadGameModule(proxy_t *proxydata) { if (!proxydata->hModule) return; #ifdef _WIN32 FreeLibrary(proxydata->hModule); #else dlclose(proxydata->hModule); #endif proxydata->hModule = NULL; } // // LoadGameModule // Calls the os-specific function to load the given file // as a proxy module. // qboolean LoadGameModule(proxy_t *proxydata, char *path, game_import_t *import) { #ifdef _WIN32 proxydata->hModule = LoadLibrary(path); #else proxydata->hModule = dlopen(path, RTLD_LAZY); #endif proxydata->ge = NULL; if (!proxydata->hModule) return false; return true; } // // LoadNextModule // Called by game module to search for the next module to // load and try to load it. // void LoadNextModule(proxy_t *proxydata, game_import_t *import) { cvar_t *basedir; cvar_t *game; cvar_t *proxy; cvar_t *nextproxy; cvar_t *modulename; char buf[1024], path[MAX_OSPATH]; char *gamedir, *current, *next; GetGameAPI_t GetGameAPI_f; basedir = import->cvar("basedir", ".", CVAR_NOSET); game = import->cvar("game", "", CVAR_SERVERINFO | CVAR_LATCH); proxy = import->cvar("proxy", "", CVAR_SERVERINFO | CVAR_LATCH); nextproxy = import->cvar("nextproxy", "", CVAR_NOSET); modulename = import->cvar("module", "", CVAR_LATCH); if (proxy->string[0] && !nextproxy->string[0]) import->cvar_forceset("nextproxy", proxy->string); strncpy(buf, nextproxy->string, sizeof(buf)-1); buf[sizeof(buf)-1] = 0; if (game->string[0]) gamedir = game->string; else gamedir = "baseq2"; if (strcmp(buf, ":")) { // find the next proxy in the chain, cycle until we can successfully load one for (current = buf; current; current = next) { next = strchr(current, ':'); if (next) { *next = 0; // replace colon with NUL character next++; import->cvar_forceset("nextproxy", next); } else import->cvar_forceset("nextproxy", ":"); if (current[0] && current[0] != ':') { sprintf(path, "%s/proxy/%s/" GAME_MODULE, basedir->string, current); import->dprintf("...loading proxy module \"%s\": ", path); if (LoadGameModule(proxydata, path, import)) { import->dprintf("ok\n"); break; } else import->dprintf("failed\n"); } } } // load the default game module if we haven't already loaded a proxy module if (!proxydata->hModule) { // allow user to override the module filename if (modulename->string[0]) sprintf(path, "%s/%s/%s", basedir->string, gamedir, modulename->string); else { #ifdef _WIN32 sprintf(path, "%s/%s/" GAME_MODULE, basedir->string, gamedir); #else // linux version will not work without 'module' variable set, // because it would try to load itself over and over indefinitely import->error("Must set 'module' console variable\ne.g.: set module mygame.so\n"); #endif } import->dprintf("...loading game module \"%s\": ", path); if (!LoadGameModule(proxydata, path, import)) { import->dprintf("failed\n"); // try to load the vanilla quake2 game module in baseq2 if (modulename->string[0]) { sprintf(path, "%s/baseq2/%s", basedir->string, modulename->string); } else { #ifdef _WIN32 sprintf(path, "%s/baseq2/" GAME_MODULE, basedir->string); #else import->error("Must set 'module' console variable\ne.g.: set module mygame.so\n"); #endif } import->dprintf("...loading default game module \"%s\": ", path); if (LoadGameModule(proxydata, path, import)) import->dprintf("ok\n"); else import->dprintf("failed\n"); } else import->dprintf("ok\n"); } if (!proxydata->hModule) return; #ifdef _WIN32 GetGameAPI_f = (GetGameAPI_t)GetProcAddress(proxydata->hModule, "GetGameAPI"); #else GetGameAPI_f = (GetGameAPI_t)dlsym(proxydata->hModule, "GetGameAPI"); #endif if (!GetGameAPI_f || !(proxydata->ge = GetGameAPI_f(import))) { UnloadGameModule(proxydata); proxydata->ge = NULL; return; } }