mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-01-21 00:41:05 +00:00
Merge branch 'searchpath'
This commit is contained in:
commit
11b3a0515a
12 changed files with 471 additions and 383 deletions
|
@ -162,10 +162,8 @@ is searched at:
|
||||||
- The directory given with the *+set basedir /path/to/quake2_installation/*
|
- The directory given with the *+set basedir /path/to/quake2_installation/*
|
||||||
commandline argument.
|
commandline argument.
|
||||||
|
|
||||||
Yamagi Quake II has support for an alternative startup config. It may be a good
|
If you're a package maintainer, please look at our documentation at
|
||||||
idea to install it, since it sets some global options to sane defaults. Copy
|
[stuff/packaging.md](stuff/packaging.md).
|
||||||
yq2.cfg to the baseq2/ subdirectory in your gamedata directory. Usually yq2.cfg
|
|
||||||
can be found somewhere in /usr/share or /usr/local/share.
|
|
||||||
|
|
||||||
|
|
||||||
### Compiling from source
|
### Compiling from source
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
#if defined(__linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
#if defined(__linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||||
#include <unistd.h> // readlink(), amongst others
|
#include <unistd.h> // readlink(), amongst others
|
||||||
|
#include "../../common/header/shared.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
|
@ -64,11 +66,12 @@ static void SetExecutablePath(char* exePath)
|
||||||
exePath[0] = '\0';
|
exePath[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__linux) || defined(__NetBSD__) || defined(__OpenBSD__)
|
#elif defined(__linux) || defined(__NetBSD__)
|
||||||
|
|
||||||
// all the platforms that have /proc/$pid/exe or similar that symlink the
|
// all the platforms that have /proc/$pid/exe or similar that symlink the
|
||||||
// real executable - basiscally Linux and the BSDs except for FreeBSD which
|
// real executable - basiscally Linux and the BSDs except for FreeBSD which
|
||||||
// doesn't enable proc by default and has a sysctl() for this
|
// doesn't enable proc by default and has a sysctl() for this. OpenBSD once
|
||||||
|
// had /proc but removed it for security reasons.
|
||||||
char buf[PATH_MAX] = {0};
|
char buf[PATH_MAX] = {0};
|
||||||
#ifdef __linux
|
#ifdef __linux
|
||||||
snprintf(buf, sizeof(buf), "/proc/%d/exe", getpid());
|
snprintf(buf, sizeof(buf), "/proc/%d/exe", getpid());
|
||||||
|
@ -115,7 +118,13 @@ static void SetExecutablePath(char* exePath)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#error "Unsupported Platform!" // feel free to add implementation for your platform and send me a patch
|
// Several platforms (for example OpenBSD) donn't provide a
|
||||||
|
// reliable way to determine the executable path. Just return
|
||||||
|
// an empty string.
|
||||||
|
exePath[0] = '\0';
|
||||||
|
|
||||||
|
// feel free to add implementation for your platform and send a pull request.
|
||||||
|
#warning "SetExecutablePath() is unimplemented on this platform"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -124,18 +133,25 @@ const char *Sys_GetBinaryDir(void)
|
||||||
{
|
{
|
||||||
static char exeDir[PATH_MAX] = {0};
|
static char exeDir[PATH_MAX] = {0};
|
||||||
|
|
||||||
if(exeDir[0] != '\0') return exeDir;
|
if(exeDir[0] != '\0') {
|
||||||
|
return exeDir;
|
||||||
|
}
|
||||||
|
|
||||||
SetExecutablePath(exeDir);
|
SetExecutablePath(exeDir);
|
||||||
|
|
||||||
// cut off executable name
|
if (exeDir[0] == '\0') {
|
||||||
char* lastSlash = strrchr(exeDir, '/');
|
Com_Printf("Couldn't determine executable path. Using ./ instead.\n");
|
||||||
|
Q_strlcpy(exeDir, "./", sizeof(exeDir));
|
||||||
|
} else {
|
||||||
|
// cut off executable name
|
||||||
|
char *lastSlash = strrchr(exeDir, '/');
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
char* lastBackSlash = strrchr(exeDir, '\\');
|
char* lastBackSlash = strrchr(exeDir, '\\');
|
||||||
if(lastSlash == NULL || lastBackSlash > lastSlash) lastSlash = lastBackSlash;
|
if(lastSlash == NULL || lastBackSlash > lastSlash) lastSlash = lastBackSlash;
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
if(lastSlash != NULL) lastSlash[1] = '\0'; // cut off after last (back)slash
|
if (lastSlash != NULL) lastSlash[1] = '\0'; // cut off after last (back)slash
|
||||||
|
}
|
||||||
|
|
||||||
return exeDir;
|
return exeDir;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include "../../common/header/common.h"
|
#include "../../common/header/common.h"
|
||||||
#include "header/unix.h"
|
#include "header/unix.h"
|
||||||
|
|
||||||
|
qboolean is_portable;
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -47,6 +49,13 @@ main(int argc, char **argv)
|
||||||
/* register signal handler */
|
/* register signal handler */
|
||||||
registerHandler();
|
registerHandler();
|
||||||
|
|
||||||
|
/* Are we portable? */
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "-portable") == 0) {
|
||||||
|
is_portable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Prevent running Quake II as root. Only very mad
|
/* Prevent running Quake II as root. Only very mad
|
||||||
minded or stupid people even think about it. :) */
|
minded or stupid people even think about it. :) */
|
||||||
if (getuid() == 0)
|
if (getuid() == 0)
|
||||||
|
|
|
@ -65,6 +65,8 @@ int findhandle;
|
||||||
int argc;
|
int argc;
|
||||||
char *argv[MAX_NUM_ARGVS];
|
char *argv[MAX_NUM_ARGVS];
|
||||||
|
|
||||||
|
qboolean is_portable;
|
||||||
|
|
||||||
/* ================================================================ */
|
/* ================================================================ */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -647,31 +649,33 @@ void
|
||||||
Sys_RedirectStdout(void)
|
Sys_RedirectStdout(void)
|
||||||
{
|
{
|
||||||
char *cur;
|
char *cur;
|
||||||
char *home;
|
|
||||||
char *old;
|
char *old;
|
||||||
|
char dir[MAX_OSPATH];
|
||||||
char path_stdout[MAX_OSPATH];
|
char path_stdout[MAX_OSPATH];
|
||||||
char path_stderr[MAX_OSPATH];
|
char path_stderr[MAX_OSPATH];
|
||||||
|
const char *tmp;
|
||||||
|
|
||||||
if (portable->value)
|
if (is_portable) {
|
||||||
|
tmp = Sys_GetBinaryDir();
|
||||||
|
Q_strlcpy(dir, tmp, sizeof(dir));
|
||||||
|
} else {
|
||||||
|
tmp = Sys_GetHomeDir();
|
||||||
|
Q_strlcpy(dir, tmp, sizeof(dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
home = Sys_GetHomeDir();
|
cur = old = dir;
|
||||||
|
|
||||||
if (home == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur = old = home;
|
|
||||||
|
|
||||||
while (cur != NULL)
|
while (cur != NULL)
|
||||||
{
|
{
|
||||||
if ((cur - old) > 1)
|
if ((cur - old) > 1)
|
||||||
{
|
{
|
||||||
*cur = '\0';
|
*cur = '\0';
|
||||||
Sys_Mkdir(home);
|
Sys_Mkdir(dir);
|
||||||
*cur = '/';
|
*cur = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,8 +683,8 @@ Sys_RedirectStdout(void)
|
||||||
cur = strchr(old + 1, '/');
|
cur = strchr(old + 1, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(path_stdout, sizeof(path_stdout), "%s/%s", home, "stdout.txt");
|
snprintf(path_stdout, sizeof(path_stdout), "%s/%s", dir, "stdout.txt");
|
||||||
snprintf(path_stderr, sizeof(path_stderr), "%s/%s", home, "stderr.txt");
|
snprintf(path_stderr, sizeof(path_stderr), "%s/%s", dir, "stderr.txt");
|
||||||
|
|
||||||
freopen(path_stdout, "w", stdout);
|
freopen(path_stdout, "w", stdout);
|
||||||
freopen(path_stderr, "w", stderr);
|
freopen(path_stderr, "w", stderr);
|
||||||
|
@ -755,7 +759,21 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||||
/* Force DPI awareness */
|
/* Force DPI awareness */
|
||||||
Sys_SetHighDPIMode();
|
Sys_SetHighDPIMode();
|
||||||
|
|
||||||
/* FIXME: No one can see this! */
|
/* Parse the command line arguments */
|
||||||
|
ParseCommandLine(lpCmdLine);
|
||||||
|
|
||||||
|
/* Are we portable? */
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "-portable") == 0) {
|
||||||
|
is_portable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to redirect stdout before anything happens. */
|
||||||
|
#ifndef DEDICATED_ONLY
|
||||||
|
Sys_RedirectStdout();
|
||||||
|
#endif
|
||||||
|
|
||||||
printf("Yamagi Quake II v%s\n", YQ2VERSION);
|
printf("Yamagi Quake II v%s\n", YQ2VERSION);
|
||||||
printf("=====================\n\n");
|
printf("=====================\n\n");
|
||||||
|
|
||||||
|
@ -791,12 +809,10 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||||
printf("Platform: %s\n", YQ2OSTYPE);
|
printf("Platform: %s\n", YQ2OSTYPE);
|
||||||
printf("Architecture: %s\n", YQ2ARCH);
|
printf("Architecture: %s\n", YQ2ARCH);
|
||||||
|
|
||||||
|
|
||||||
/* Seed PRNG */
|
/* Seed PRNG */
|
||||||
randk_seed();
|
randk_seed();
|
||||||
|
|
||||||
/* Parse the command line arguments */
|
|
||||||
ParseCommandLine(lpCmdLine);
|
|
||||||
|
|
||||||
/* Call the initialization code */
|
/* Call the initialization code */
|
||||||
Qcommon_Init(argc, argv);
|
Qcommon_Init(argc, argv);
|
||||||
|
|
||||||
|
|
|
@ -785,7 +785,7 @@ Key_WriteConsoleHistory()
|
||||||
int i;
|
int i;
|
||||||
char path[MAX_OSPATH];
|
char path[MAX_OSPATH];
|
||||||
|
|
||||||
if (portable->value)
|
if (is_portable)
|
||||||
{
|
{
|
||||||
Com_sprintf(path, sizeof(path), "%sconsole_history.txt", Sys_GetBinaryDir());
|
Com_sprintf(path, sizeof(path), "%sconsole_history.txt", Sys_GetBinaryDir());
|
||||||
}
|
}
|
||||||
|
@ -832,7 +832,7 @@ Key_ReadConsoleHistory()
|
||||||
|
|
||||||
char path[MAX_OSPATH];
|
char path[MAX_OSPATH];
|
||||||
|
|
||||||
if (portable->value)
|
if (is_portable)
|
||||||
{
|
{
|
||||||
Com_sprintf(path, sizeof(path), "%sconsole_history.txt", Sys_GetBinaryDir());
|
Com_sprintf(path, sizeof(path), "%sconsole_history.txt", Sys_GetBinaryDir());
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ Com_VPrintf(int print_level, const char *fmt, va_list argptr)
|
||||||
/* logfile */
|
/* logfile */
|
||||||
if (logfile_active && logfile_active->value)
|
if (logfile_active && logfile_active->value)
|
||||||
{
|
{
|
||||||
char name[MAX_QPATH];
|
char name[MAX_OSPATH];
|
||||||
|
|
||||||
if (!logfile)
|
if (!logfile)
|
||||||
{
|
{
|
||||||
|
|
|
@ -252,7 +252,7 @@ Cvar_Set2(char *var_name, char *value, qboolean force)
|
||||||
|
|
||||||
if (!strcmp(var->name, "game"))
|
if (!strcmp(var->name, "game"))
|
||||||
{
|
{
|
||||||
FS_SetGamedir(var->string);
|
FS_BuildGameSpecificSearchPath(var->string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ Cvar_GetLatchedVars(void)
|
||||||
|
|
||||||
if (!strcmp(var->name, "game"))
|
if (!strcmp(var->name, "game"))
|
||||||
{
|
{
|
||||||
FS_SetGamedir(var->string);
|
FS_BuildGameSpecificSearchPath(var->string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,26 +114,28 @@ fsPackTypes_t fs_packtypes[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
char fs_gamedir[MAX_OSPATH];
|
char fs_gamedir[MAX_OSPATH];
|
||||||
static char fs_currentGame[MAX_QPATH];
|
qboolean file_from_pak;
|
||||||
|
|
||||||
static char fs_fileInPath[MAX_OSPATH];
|
|
||||||
static qboolean fs_fileInPack;
|
|
||||||
|
|
||||||
/* Set by FS_FOpenFile. */
|
|
||||||
int file_from_pak = 0;
|
|
||||||
#ifdef ZIP
|
|
||||||
int file_from_pk3 = 0;
|
|
||||||
char file_from_pk3_name[MAX_QPATH];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cvar_t *fs_homepath;
|
|
||||||
cvar_t *fs_basedir;
|
cvar_t *fs_basedir;
|
||||||
cvar_t *fs_cddir;
|
cvar_t *fs_cddir;
|
||||||
cvar_t *fs_gamedirvar;
|
cvar_t *fs_gamedirvar;
|
||||||
cvar_t *fs_debug;
|
cvar_t *fs_debug;
|
||||||
|
|
||||||
fsHandle_t *FS_GetFileByHandle(fileHandle_t f);
|
fsHandle_t *FS_GetFileByHandle(fileHandle_t f);
|
||||||
char *Sys_GetCurrentDirectory(void);
|
|
||||||
|
// --------
|
||||||
|
|
||||||
|
// Raw search path, the actual search
|
||||||
|
// bath is build from this one.
|
||||||
|
typedef struct fsRawPath_s {
|
||||||
|
char path[MAX_OSPATH];
|
||||||
|
qboolean create;
|
||||||
|
struct fsRawPath_s *next;
|
||||||
|
} fsRawPath_t;
|
||||||
|
|
||||||
|
fsRawPath_t *fs_rawPath;
|
||||||
|
|
||||||
|
// --------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All of Quake's data access is through a hierchal file system, but the
|
* All of Quake's data access is through a hierchal file system, but the
|
||||||
|
@ -343,11 +345,7 @@ FS_FOpenFile(const char *name, fileHandle_t *f, qboolean gamedir_only)
|
||||||
fsSearchPath_t *search;
|
fsSearchPath_t *search;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
file_from_pak = 0;
|
file_from_pak = false;
|
||||||
#ifdef ZIP
|
|
||||||
file_from_pk3 = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
handle = FS_HandleForFile(name, f);
|
handle = FS_HandleForFile(name, f);
|
||||||
Q_strlcpy(handle->name, name, sizeof(handle->name));
|
Q_strlcpy(handle->name, name, sizeof(handle->name));
|
||||||
handle->mode = FS_READ;
|
handle->mode = FS_READ;
|
||||||
|
@ -381,19 +379,16 @@ FS_FOpenFile(const char *name, fileHandle_t *f, qboolean gamedir_only)
|
||||||
if (Q_stricmp(pack->files[i].name, handle->name) == 0)
|
if (Q_stricmp(pack->files[i].name, handle->name) == 0)
|
||||||
{
|
{
|
||||||
/* Found it! */
|
/* Found it! */
|
||||||
Com_FilePath(pack->name, fs_fileInPath, sizeof(fs_fileInPath));
|
|
||||||
fs_fileInPack = true;
|
|
||||||
|
|
||||||
if (fs_debug->value)
|
if (fs_debug->value)
|
||||||
{
|
{
|
||||||
Com_Printf("FS_FOpenFile: '%s' (found in '%s').\n",
|
Com_Printf("FS_FOpenFile: '%s' (found in '%s').\n",
|
||||||
handle->name, pack->name);
|
handle->name, pack->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pack->pak)
|
if (pack->pak)
|
||||||
{
|
{
|
||||||
/* PAK */
|
/* PAK */
|
||||||
file_from_pak = 1;
|
file_from_pak = true;
|
||||||
handle->file = fopen(pack->name, "rb");
|
handle->file = fopen(pack->name, "rb");
|
||||||
|
|
||||||
if (handle->file)
|
if (handle->file)
|
||||||
|
@ -406,8 +401,7 @@ FS_FOpenFile(const char *name, fileHandle_t *f, qboolean gamedir_only)
|
||||||
else if (pack->pk3)
|
else if (pack->pk3)
|
||||||
{
|
{
|
||||||
/* PK3 */
|
/* PK3 */
|
||||||
file_from_pk3 = 1;
|
file_from_pak = true;
|
||||||
Q_strlcpy(file_from_pk3_name, strrchr(pack->name, '/') + 1, sizeof(file_from_pk3_name));
|
|
||||||
handle->zip = unzOpen(pack->name);
|
handle->zip = unzOpen(pack->name);
|
||||||
|
|
||||||
if (handle->zip)
|
if (handle->zip)
|
||||||
|
@ -449,10 +443,6 @@ FS_FOpenFile(const char *name, fileHandle_t *f, qboolean gamedir_only)
|
||||||
|
|
||||||
if (handle->file)
|
if (handle->file)
|
||||||
{
|
{
|
||||||
/* Found it! */
|
|
||||||
Q_strlcpy(fs_fileInPath, search->path, sizeof(fs_fileInPath));
|
|
||||||
fs_fileInPack = false;
|
|
||||||
|
|
||||||
if (fs_debug->value)
|
if (fs_debug->value)
|
||||||
{
|
{
|
||||||
Com_Printf("FS_FOpenFile: '%s' (found in '%s').\n",
|
Com_Printf("FS_FOpenFile: '%s' (found in '%s').\n",
|
||||||
|
@ -463,11 +453,6 @@ FS_FOpenFile(const char *name, fileHandle_t *f, qboolean gamedir_only)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not found! */
|
|
||||||
fs_fileInPath[0] = 0;
|
|
||||||
fs_fileInPack = false;
|
|
||||||
|
|
||||||
if (fs_debug->value)
|
if (fs_debug->value)
|
||||||
{
|
{
|
||||||
Com_Printf("FS_FOpenFile: couldn't find '%s'.\n", handle->name);
|
Com_Printf("FS_FOpenFile: couldn't find '%s'.\n", handle->name);
|
||||||
|
@ -809,171 +794,6 @@ FS_LoadPK3(const char *packPath)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Adds the directory to the head of the path, then loads and adds pak1.pak
|
|
||||||
* pak2.pak ...
|
|
||||||
*
|
|
||||||
* Extended all functionality to include Quake III .pk3
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
FS_AddGameDirectory(const char *dir)
|
|
||||||
{
|
|
||||||
char **list; /* File list. */
|
|
||||||
char path[MAX_OSPATH]; /* Path to PAK / PK3. */
|
|
||||||
int i, j; /* Loop counters. */
|
|
||||||
int nfiles; /* Number of files in list. */
|
|
||||||
fsSearchPath_t *search; /* Search path. */
|
|
||||||
fsPack_t *pack; /* PAK / PK3 file. */
|
|
||||||
|
|
||||||
pack = NULL;
|
|
||||||
|
|
||||||
/* Set game directory. */
|
|
||||||
Q_strlcpy(fs_gamedir, dir, sizeof(fs_gamedir));
|
|
||||||
|
|
||||||
/* Create directory if it does not exist. */
|
|
||||||
FS_CreatePath(fs_gamedir);
|
|
||||||
|
|
||||||
/* Add the directory to the search path. */
|
|
||||||
search = Z_Malloc(sizeof(fsSearchPath_t));
|
|
||||||
Q_strlcpy(search->path, dir, sizeof(search->path));
|
|
||||||
search->next = fs_searchPaths;
|
|
||||||
fs_searchPaths = search;
|
|
||||||
|
|
||||||
/* Add numbered pack files in sequence. */
|
|
||||||
for (i = 0; i < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); i++)
|
|
||||||
{
|
|
||||||
for (j = 0; j < MAX_PAKS; j++)
|
|
||||||
{
|
|
||||||
Com_sprintf(path, sizeof(path), "%s/pak%d.%s",
|
|
||||||
dir, j, fs_packtypes[i].suffix);
|
|
||||||
|
|
||||||
switch (fs_packtypes[i].format)
|
|
||||||
{
|
|
||||||
case PAK:
|
|
||||||
pack = FS_LoadPAK(path);
|
|
||||||
break;
|
|
||||||
#ifdef ZIP
|
|
||||||
case PK3:
|
|
||||||
pack = FS_LoadPK3(path);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pack == NULL)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
search = Z_Malloc(sizeof(fsSearchPath_t));
|
|
||||||
search->pack = pack;
|
|
||||||
search->next = fs_searchPaths;
|
|
||||||
fs_searchPaths = search;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add not numbered pack files. */
|
|
||||||
for (i = 0; i < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); i++)
|
|
||||||
{
|
|
||||||
Com_sprintf(path, sizeof(path), "%s/*.%s", dir, fs_packtypes[i].suffix);
|
|
||||||
|
|
||||||
if ((list = FS_ListFiles(path, &nfiles, 0, SFF_SUBDIR)) == NULL)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Com_sprintf(path, sizeof(path), "%s/pak*.%s",
|
|
||||||
dir, fs_packtypes[i].suffix);
|
|
||||||
|
|
||||||
for (j = 0; j < nfiles - 1; j++)
|
|
||||||
{
|
|
||||||
/* Skip all packs starting with "pak" */
|
|
||||||
if (glob_match(path, list[j]))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fs_packtypes[i].format)
|
|
||||||
{
|
|
||||||
case PAK:
|
|
||||||
pack = FS_LoadPAK(list[j]);
|
|
||||||
break;
|
|
||||||
#ifdef ZIP
|
|
||||||
case PK3:
|
|
||||||
pack = FS_LoadPK3(list[j]);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pack == NULL)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
search = Z_Malloc(sizeof(fsSearchPath_t));
|
|
||||||
search->pack = pack;
|
|
||||||
search->next = fs_searchPaths;
|
|
||||||
fs_searchPaths = search;
|
|
||||||
}
|
|
||||||
|
|
||||||
FS_FreeList(list, nfiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use ~/.quake2/dir as fs_gamedir.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
FS_AddHomeAsGameDirectory(char *dir)
|
|
||||||
{
|
|
||||||
char *home;
|
|
||||||
char gdir[MAX_OSPATH];
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (portable->value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
home = Sys_GetHomeDir();
|
|
||||||
|
|
||||||
if (home == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = snprintf(gdir, sizeof(gdir), "%s%s/", home, dir);
|
|
||||||
FS_CreatePath(gdir);
|
|
||||||
|
|
||||||
if ((len > 0) && (len < sizeof(gdir)) && (gdir[len - 1] == '/'))
|
|
||||||
{
|
|
||||||
gdir[len - 1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_strlcpy(fs_gamedir, gdir, sizeof(fs_gamedir));
|
|
||||||
|
|
||||||
FS_AddGameDirectory(gdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FS_AddBinaryDirAsGameDirectory(const char* dir)
|
|
||||||
{
|
|
||||||
char gdir[MAX_OSPATH];
|
|
||||||
const char *datadir = Sys_GetBinaryDir();
|
|
||||||
if(datadir[0] == '\0')
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int len = snprintf(gdir, sizeof(gdir), "%s%s/", datadir, dir);
|
|
||||||
|
|
||||||
printf("Using binary dir %s to fetch paks\n", gdir);
|
|
||||||
|
|
||||||
if ((len > 0) && (len < sizeof(gdir)) && (gdir[len - 1] == '/'))
|
|
||||||
{
|
|
||||||
gdir[len - 1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FS_AddGameDirectory(gdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allows enumerating all of the directories in the search path.
|
* Allows enumerating all of the directories in the search path.
|
||||||
*/
|
*/
|
||||||
|
@ -1060,97 +880,6 @@ FS_Path_f(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Sets the gamedir and path to a different directory.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
FS_SetGamedir(char *dir)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
fsSearchPath_t *next;
|
|
||||||
|
|
||||||
if (!*dir || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/"))
|
|
||||||
{
|
|
||||||
Com_Printf("Gamedir should be a single filename, not a path.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not set BASEDIR as gamedir. It was already set by FS_InitFilesystem()
|
|
||||||
* and setting it again f*cks the search pathes up. Yes, this a hack. */
|
|
||||||
if(!Q_stricmp(dir, BASEDIRNAME))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free up any current game dir info. */
|
|
||||||
while (fs_searchPaths != fs_baseSearchPaths)
|
|
||||||
{
|
|
||||||
if (fs_searchPaths->pack)
|
|
||||||
{
|
|
||||||
if (fs_searchPaths->pack->pak)
|
|
||||||
{
|
|
||||||
fclose(fs_searchPaths->pack->pak);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ZIP
|
|
||||||
if (fs_searchPaths->pack->pk3)
|
|
||||||
{
|
|
||||||
unzClose(fs_searchPaths->pack->pk3);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Z_Free(fs_searchPaths->pack->files);
|
|
||||||
Z_Free(fs_searchPaths->pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
next = fs_searchPaths->next;
|
|
||||||
Z_Free(fs_searchPaths);
|
|
||||||
fs_searchPaths = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close open files for game dir. */
|
|
||||||
for (i = 0; i < MAX_HANDLES; i++)
|
|
||||||
{
|
|
||||||
if (strstr(fs_handles[i].name, dir) &&
|
|
||||||
((fs_handles[i].file != NULL)
|
|
||||||
#ifdef ZIP
|
|
||||||
|| (fs_handles[i].zip != NULL)
|
|
||||||
#endif
|
|
||||||
))
|
|
||||||
{
|
|
||||||
FS_FCloseFile(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flush all data, so it will be forced to reload. */
|
|
||||||
if ((dedicated != NULL) && (dedicated->value != 1))
|
|
||||||
{
|
|
||||||
Cbuf_AddText("vid_restart\nsnd_restart\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
Com_sprintf(fs_gamedir, sizeof(fs_gamedir), "%s/%s",
|
|
||||||
fs_basedir->string, dir);
|
|
||||||
|
|
||||||
if ((strcmp(dir, BASEDIRNAME) == 0) || (*dir == 0))
|
|
||||||
{
|
|
||||||
Cvar_FullSet("gamedir", "", CVAR_SERVERINFO | CVAR_NOSET);
|
|
||||||
Cvar_FullSet("game", "", CVAR_LATCH | CVAR_SERVERINFO);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Cvar_FullSet("gamedir", dir, CVAR_SERVERINFO | CVAR_NOSET);
|
|
||||||
|
|
||||||
if (fs_cddir->string[0] == '\0')
|
|
||||||
{
|
|
||||||
FS_AddGameDirectory(va("%s/%s", fs_cddir->string, dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
FS_AddGameDirectory(va("%s/%s", fs_basedir->string, dir));
|
|
||||||
FS_AddBinaryDirAsGameDirectory(dir);
|
|
||||||
FS_AddHomeAsGameDirectory(dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a filelink_t.
|
* Creates a filelink_t.
|
||||||
*/
|
*/
|
||||||
|
@ -1523,67 +1252,327 @@ FS_Dir_f(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------
|
||||||
|
|
||||||
|
void
|
||||||
|
FS_AddDirToSearchPath(char *dir, qboolean create) {
|
||||||
|
char **list;
|
||||||
|
char path[MAX_OSPATH];
|
||||||
|
int i, j;
|
||||||
|
int nfiles;
|
||||||
|
fsPack_t *pack = NULL;
|
||||||
|
fsSearchPath_t *search;
|
||||||
|
size_t len = strlen(dir);
|
||||||
|
|
||||||
|
// The directory must not end with an /. It would
|
||||||
|
// f*ck up the logic in other parts of the game...
|
||||||
|
if (dir[len - 1] == '/')
|
||||||
|
{
|
||||||
|
dir[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
else if (dir[len - 1] == '\\') {
|
||||||
|
dir[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current directory as game directory. This
|
||||||
|
// is somewhat fragile since the game directory MUST
|
||||||
|
// be the last directory added to the search path.
|
||||||
|
Q_strlcpy(fs_gamedir, dir, sizeof(fs_gamedir));
|
||||||
|
|
||||||
|
if (create) {
|
||||||
|
FS_CreatePath(fs_gamedir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the directory itself.
|
||||||
|
search = Z_Malloc(sizeof(fsSearchPath_t));
|
||||||
|
Q_strlcpy(search->path, dir, sizeof(search->path));
|
||||||
|
search->next = fs_searchPaths;
|
||||||
|
fs_searchPaths = search;
|
||||||
|
|
||||||
|
// We need to add numbered paks in te directory in
|
||||||
|
// sequence and all other paks after them. Otherwise
|
||||||
|
// the gamedata may break.
|
||||||
|
for (i = 0; i < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); i++) {
|
||||||
|
for (j = 0; j < MAX_PAKS; j++) {
|
||||||
|
Com_sprintf(path, sizeof(path), "%s/pak%d.%s", dir, j, fs_packtypes[i].suffix);
|
||||||
|
|
||||||
|
switch (fs_packtypes[i].format)
|
||||||
|
{
|
||||||
|
case PAK:
|
||||||
|
pack = FS_LoadPAK(path);
|
||||||
|
break;
|
||||||
|
#ifdef ZIP
|
||||||
|
case PK3:
|
||||||
|
pack = FS_LoadPK3(path);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pack == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
search = Z_Malloc(sizeof(fsSearchPath_t));
|
||||||
|
search->pack = pack;
|
||||||
|
search->next = fs_searchPaths;
|
||||||
|
fs_searchPaths = search;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// And as said above all other pak files.
|
||||||
|
for (i = 0; i < sizeof(fs_packtypes) / sizeof(fs_packtypes[0]); i++) {
|
||||||
|
Com_sprintf(path, sizeof(path), "%s/*.%s", dir, fs_packtypes[i].suffix);
|
||||||
|
|
||||||
|
// Nothing here, next pak type please.
|
||||||
|
if ((list = FS_ListFiles(path, &nfiles, 0, SFF_SUBDIR)) == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Com_sprintf(path, sizeof(path), "%s/pak*.%s", dir, fs_packtypes[i].suffix);
|
||||||
|
|
||||||
|
for (j = 0; j < nfiles - 1; j++)
|
||||||
|
{
|
||||||
|
// If the pak starts with the string 'pak' it's ignored.
|
||||||
|
// This is somewhat stupid, it would be better to ignore
|
||||||
|
// just pak%d...
|
||||||
|
if (glob_match(path, list[j]))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fs_packtypes[i].format)
|
||||||
|
{
|
||||||
|
case PAK:
|
||||||
|
pack = FS_LoadPAK(list[j]);
|
||||||
|
break;
|
||||||
|
#ifdef ZIP
|
||||||
|
case PK3:
|
||||||
|
pack = FS_LoadPK3(list[j]);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pack == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
search = Z_Malloc(sizeof(fsSearchPath_t));
|
||||||
|
search->pack = pack;
|
||||||
|
search->next = fs_searchPaths;
|
||||||
|
fs_searchPaths = search;
|
||||||
|
}
|
||||||
|
|
||||||
|
FS_FreeList(list, nfiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FS_BuildGenericSearchPath(void) {
|
||||||
|
// We may not use the va() function from shared.c
|
||||||
|
// since it's buffersize is 1024 while most OS have
|
||||||
|
// a maximum path size of 4096...
|
||||||
|
char path[MAX_OSPATH];
|
||||||
|
|
||||||
|
fsRawPath_t *search = fs_rawPath;
|
||||||
|
|
||||||
|
while (search != NULL) {
|
||||||
|
Com_sprintf(path, sizeof(path), "%s/%s", search->path, BASEDIRNAME);
|
||||||
|
FS_AddDirToSearchPath(path, search->create);
|
||||||
|
|
||||||
|
search = search->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Until here we've added the generic directories to the
|
||||||
|
// search path. Save the current head node so we can
|
||||||
|
// distinguish generic and specialized directories.
|
||||||
|
fs_baseSearchPaths = fs_searchPaths;
|
||||||
|
|
||||||
|
// We need to create the screenshot directory since the
|
||||||
|
// render dll doesn't link the filesystem stuff.
|
||||||
|
Com_sprintf(path, sizeof(path), "%s/scrnshot", fs_gamedir);
|
||||||
|
Sys_Mkdir(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FS_BuildGameSpecificSearchPath(char *dir)
|
||||||
|
{
|
||||||
|
// We may not use the va() function from shared.c
|
||||||
|
// since it's buffersize is 1024 while most OS have
|
||||||
|
// a maximum path size of 4096...
|
||||||
|
char path[MAX_OSPATH];
|
||||||
|
int i;
|
||||||
|
fsRawPath_t *search;
|
||||||
|
fsSearchPath_t *next;
|
||||||
|
|
||||||
|
// This is against PEBCAK. The user may give us paths like
|
||||||
|
// xatrix/ or even /home/stupid/quake2/xatrix.
|
||||||
|
if (!*dir || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/") || strstr(dir, "\\"))
|
||||||
|
{
|
||||||
|
Com_Printf("Gamedir should be a single filename, not a path.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BASEDIR is already added as a generic directory. Adding it
|
||||||
|
// again as a specialised directory breaks the logic in other
|
||||||
|
// parts of the code. This may happen if the user does something
|
||||||
|
// like ./quake2 +set game baseq2
|
||||||
|
if(!Q_stricmp(dir, BASEDIRNAME))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We may already have specialised directories in our search
|
||||||
|
// path. This can happen if the server changes the mod. Let's
|
||||||
|
// remove them.
|
||||||
|
while (fs_searchPaths != fs_baseSearchPaths)
|
||||||
|
{
|
||||||
|
if (fs_searchPaths->pack)
|
||||||
|
{
|
||||||
|
if (fs_searchPaths->pack->pak)
|
||||||
|
{
|
||||||
|
fclose(fs_searchPaths->pack->pak);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ZIP
|
||||||
|
if (fs_searchPaths->pack->pk3)
|
||||||
|
{
|
||||||
|
unzClose(fs_searchPaths->pack->pk3);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Z_Free(fs_searchPaths->pack->files);
|
||||||
|
Z_Free(fs_searchPaths->pack);
|
||||||
|
}
|
||||||
|
|
||||||
|
next = fs_searchPaths->next;
|
||||||
|
Z_Free(fs_searchPaths);
|
||||||
|
fs_searchPaths = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close open files for game dir. */
|
||||||
|
for (i = 0; i < MAX_HANDLES; i++)
|
||||||
|
{
|
||||||
|
if (strstr(fs_handles[i].name, dir) &&
|
||||||
|
((fs_handles[i].file != NULL)
|
||||||
|
#ifdef ZIP
|
||||||
|
|| (fs_handles[i].zip != NULL)
|
||||||
|
#endif
|
||||||
|
))
|
||||||
|
{
|
||||||
|
FS_FCloseFile(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce a renderer and sound backend restart to
|
||||||
|
// purge all internal caches. This is rather hacky
|
||||||
|
// but Quake II doesn't have a better mechanism...
|
||||||
|
if ((dedicated != NULL) && (dedicated->value != 1))
|
||||||
|
{
|
||||||
|
Cbuf_AddText("vid_restart\nsnd_restart\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The game was reset to baseq2. Nothing to do here.
|
||||||
|
if ((Q_stricmp(dir, BASEDIRNAME) == 0) || (*dir == 0)) {
|
||||||
|
Cvar_FullSet("gamedir", "", CVAR_SERVERINFO | CVAR_NOSET);
|
||||||
|
Cvar_FullSet("game", "", CVAR_LATCH | CVAR_SERVERINFO);
|
||||||
|
|
||||||
|
// fs_gamedir must be reset to the last
|
||||||
|
// dir of the generic search path.
|
||||||
|
Q_strlcpy(fs_gamedir, fs_baseSearchPaths->path, sizeof(fs_gamedir));
|
||||||
|
} else {
|
||||||
|
Cvar_FullSet("gamedir", dir, CVAR_SERVERINFO | CVAR_NOSET);
|
||||||
|
search = fs_rawPath;
|
||||||
|
|
||||||
|
while (search != NULL) {
|
||||||
|
Com_sprintf(path, sizeof(path), "%s/%s", search->path, dir);
|
||||||
|
FS_AddDirToSearchPath(path, search->create);
|
||||||
|
|
||||||
|
search = search->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to create the screenshot directory since the
|
||||||
|
// render dll doesn't link the filesystem stuff.
|
||||||
|
Com_sprintf(path, sizeof(path), "%s/scrnshot", fs_gamedir);
|
||||||
|
Sys_Mkdir(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------
|
||||||
|
|
||||||
|
void FS_AddDirToRawPath (const char *dir, qboolean create) {
|
||||||
|
fsRawPath_t *search;
|
||||||
|
|
||||||
|
// Add the directory
|
||||||
|
search = Z_Malloc(sizeof(fsRawPath_t));
|
||||||
|
Q_strlcpy(search->path, dir, sizeof(search->path));
|
||||||
|
search->create = create;
|
||||||
|
search->next = fs_rawPath;
|
||||||
|
fs_rawPath = search;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FS_BuildRawPath(void) {
|
||||||
|
// Add $HOME/.yq2 (MUST be the last dir!)
|
||||||
|
if (!is_portable) {
|
||||||
|
const char *homedir = Sys_GetHomeDir();
|
||||||
|
|
||||||
|
if (homedir != NULL) {
|
||||||
|
FS_AddDirToRawPath(homedir, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add $binarydir
|
||||||
|
const char *binarydir = Sys_GetBinaryDir();
|
||||||
|
|
||||||
|
if(binarydir[0] != '\0')
|
||||||
|
{
|
||||||
|
FS_AddDirToRawPath(binarydir, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add $basedir/
|
||||||
|
FS_AddDirToRawPath(fs_basedir->string, false);
|
||||||
|
|
||||||
|
// Add SYSTEMDIR
|
||||||
|
#ifdef SYSTEMWIDE
|
||||||
|
FS_AddDirToRawPath(SYSTEMDIR, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The CD must be the last directory of the path,
|
||||||
|
// otherwise we cannot be sure that the game won't
|
||||||
|
// stream the videos from the CD.
|
||||||
|
if (fs_cddir->string[0] != '\0') {
|
||||||
|
FS_AddDirToRawPath(fs_cddir->string, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------
|
||||||
|
|
||||||
void
|
void
|
||||||
FS_InitFilesystem(void)
|
FS_InitFilesystem(void)
|
||||||
{
|
{
|
||||||
char scrnshotdir[MAX_OSPATH];
|
// Register FS commands.
|
||||||
|
|
||||||
/* Register FS commands. */
|
|
||||||
Cmd_AddCommand("path", FS_Path_f);
|
Cmd_AddCommand("path", FS_Path_f);
|
||||||
Cmd_AddCommand("link", FS_Link_f);
|
Cmd_AddCommand("link", FS_Link_f);
|
||||||
Cmd_AddCommand("dir", FS_Dir_f);
|
Cmd_AddCommand("dir", FS_Dir_f);
|
||||||
|
|
||||||
/* basedir <path> Allows the game to run from outside the data tree. */
|
// Register cvars
|
||||||
fs_basedir = Cvar_Get("basedir",
|
fs_basedir = Cvar_Get("basedir", ".", CVAR_NOSET);
|
||||||
#ifdef SYSTEMWIDE
|
|
||||||
SYSTEMDIR,
|
|
||||||
#else
|
|
||||||
".",
|
|
||||||
#endif
|
|
||||||
CVAR_NOSET);
|
|
||||||
|
|
||||||
/* cddir <path> Logically concatenates the cddir after the basedir to
|
|
||||||
allow the game to run from outside the data tree. */
|
|
||||||
fs_cddir = Cvar_Get("cddir", "", CVAR_NOSET);
|
fs_cddir = Cvar_Get("cddir", "", CVAR_NOSET);
|
||||||
|
fs_gamedirvar = Cvar_Get("game", "", CVAR_LATCH | CVAR_SERVERINFO);
|
||||||
if (fs_cddir->string[0] != '\0')
|
|
||||||
{
|
|
||||||
FS_AddGameDirectory(va("%s/" BASEDIRNAME, fs_cddir->string));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Debug flag. */
|
|
||||||
fs_debug = Cvar_Get("fs_debug", "0", 0);
|
fs_debug = Cvar_Get("fs_debug", "0", 0);
|
||||||
|
|
||||||
/* Game directory. */
|
// Build search path
|
||||||
fs_gamedirvar = Cvar_Get("game", "", CVAR_LATCH | CVAR_SERVERINFO);
|
FS_BuildRawPath();
|
||||||
|
FS_BuildGenericSearchPath();
|
||||||
|
|
||||||
/* Current directory. */
|
|
||||||
fs_homepath = Cvar_Get("homepath", Sys_GetCurrentDirectory(), CVAR_NOSET);
|
|
||||||
|
|
||||||
/* Add baseq2 to search path. */
|
|
||||||
FS_AddGameDirectory(va("%s/" BASEDIRNAME, fs_basedir->string));
|
|
||||||
FS_AddBinaryDirAsGameDirectory(BASEDIRNAME);
|
|
||||||
FS_AddHomeAsGameDirectory(BASEDIRNAME);
|
|
||||||
|
|
||||||
/* Any set gamedirs will be freed up to here. */
|
|
||||||
fs_baseSearchPaths = fs_searchPaths;
|
|
||||||
Q_strlcpy(fs_currentGame, BASEDIRNAME, sizeof(fs_currentGame));
|
|
||||||
|
|
||||||
/* Check for game override. */
|
|
||||||
if (fs_gamedirvar->string[0] != '\0')
|
if (fs_gamedirvar->string[0] != '\0')
|
||||||
{
|
{
|
||||||
FS_SetGamedir(fs_gamedirvar->string);
|
FS_BuildGameSpecificSearchPath(fs_gamedirvar->string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create directory if it does not exist. */
|
// Debug output
|
||||||
FS_CreatePath(fs_gamedir);
|
|
||||||
|
|
||||||
/* create the scrnshots directory if it doesn't exist
|
|
||||||
* (do it here instead of in ref_gl so ref_gl doesn't need mkdir)
|
|
||||||
*/
|
|
||||||
Com_sprintf(scrnshotdir, sizeof(scrnshotdir), "%s/scrnshot", FS_Gamedir());
|
|
||||||
Sys_Mkdir(scrnshotdir);
|
|
||||||
|
|
||||||
Com_Printf("Using '%s' for writing.\n", fs_gamedir);
|
Com_Printf("Using '%s' for writing.\n", fs_gamedir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -643,7 +643,7 @@ void Pmove(pmove_t *pmove);
|
||||||
|
|
||||||
#define SFF_INPACK 0x20
|
#define SFF_INPACK 0x20
|
||||||
|
|
||||||
extern int file_from_pak;
|
extern qboolean file_from_pak;
|
||||||
|
|
||||||
typedef int fileHandle_t;
|
typedef int fileHandle_t;
|
||||||
|
|
||||||
|
@ -680,7 +680,7 @@ char **FS_ListFiles2(char *findname, int *numfiles,
|
||||||
void FS_FreeList(char **list, int nfiles);
|
void FS_FreeList(char **list, int nfiles);
|
||||||
|
|
||||||
void FS_InitFilesystem(void);
|
void FS_InitFilesystem(void);
|
||||||
void FS_SetGamedir(char *dir);
|
void FS_BuildGameSpecificSearchPath(char *dir);
|
||||||
char *FS_Gamedir(void);
|
char *FS_Gamedir(void);
|
||||||
char *FS_NextPath(char *prevpath);
|
char *FS_NextPath(char *prevpath);
|
||||||
int FS_LoadFile(char *path, void **buffer);
|
int FS_LoadFile(char *path, void **buffer);
|
||||||
|
@ -726,7 +726,9 @@ extern cvar_t *modder;
|
||||||
extern cvar_t *dedicated;
|
extern cvar_t *dedicated;
|
||||||
extern cvar_t *host_speeds;
|
extern cvar_t *host_speeds;
|
||||||
extern cvar_t *log_stats;
|
extern cvar_t *log_stats;
|
||||||
extern cvar_t *portable;
|
|
||||||
|
/* Hack for portable client */
|
||||||
|
extern qboolean is_portable;
|
||||||
|
|
||||||
extern FILE *log_stats_file;
|
extern FILE *log_stats_file;
|
||||||
|
|
||||||
|
|
|
@ -213,14 +213,6 @@ Qcommon_Init(int argc, char **argv)
|
||||||
Cbuf_AddEarlyCommands(false);
|
Cbuf_AddEarlyCommands(false);
|
||||||
Cbuf_Execute();
|
Cbuf_Execute();
|
||||||
|
|
||||||
/* Be portable, don't add HOME to the search path
|
|
||||||
* This is needed by Sys_RedirectStdout() on Windows*/
|
|
||||||
portable = Cvar_Get("portable", "0", 0);
|
|
||||||
|
|
||||||
#ifndef DEDICATED_ONLY
|
|
||||||
Sys_RedirectStdout();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FS_InitFilesystem();
|
FS_InitFilesystem();
|
||||||
|
|
||||||
Cbuf_AddText("exec default.cfg\n");
|
Cbuf_AddText("exec default.cfg\n");
|
||||||
|
|
|
@ -296,7 +296,7 @@ SV_BeginDownload_f(void)
|
||||||
extern cvar_t *allow_download_models;
|
extern cvar_t *allow_download_models;
|
||||||
extern cvar_t *allow_download_sounds;
|
extern cvar_t *allow_download_sounds;
|
||||||
extern cvar_t *allow_download_maps;
|
extern cvar_t *allow_download_maps;
|
||||||
extern int file_from_pak;
|
extern qboolean file_from_pak;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
name = Cmd_Argv(1);
|
name = Cmd_Argv(1);
|
||||||
|
|
66
stuff/packaging.md
Normal file
66
stuff/packaging.md
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
# Notes for Package Maintainers
|
||||||
|
|
||||||
|
Our 7.00 release caused some trouble for package maintainers
|
||||||
|
(see https://github.com/yquake2/yquake2/issues/214), so we decided to finally
|
||||||
|
properly document how we think it should be done and what assumptions
|
||||||
|
Yamagi Quake II makes regarding binary locations etc.
|
||||||
|
|
||||||
|
## Where you should put the executables
|
||||||
|
|
||||||
|
Yamagi Quake II expects all binaries (executables and libs) to be in the same directory
|
||||||
|
(or, in the case of game.so/.dll/dylib, in the mod-specific subdirectory).
|
||||||
|
|
||||||
|
So the binary directory should look somehow like this *(on Unix-like systems;
|
||||||
|
on Windows and OSX it's very similar but with different extensions: .dll or
|
||||||
|
.dylib instead of .so, and the executables have .exe file extension on Windows of course)*:
|
||||||
|
|
||||||
|
* /path/to/yamagi-quake2/
|
||||||
|
- quake2
|
||||||
|
- q2ded
|
||||||
|
- ref_gl1.so
|
||||||
|
- ref_gl3.so
|
||||||
|
- baseq2/
|
||||||
|
* game.so
|
||||||
|
- xatrix/
|
||||||
|
* game.so
|
||||||
|
- ... *(the same for other addons/mods)*
|
||||||
|
|
||||||
|
Yamagi Quake2 will get the directory the `quake2` executable is in from the system
|
||||||
|
and then look in that directory (and nowhere else!) for `ref_*.so`.
|
||||||
|
It will look for `game.so` there first, but if it's not found in the binary directory,
|
||||||
|
it will look for it in all directories that are also searched for game
|
||||||
|
data (SYSTEMDIR, basedir, $HOME/.yq2/). This is for better compatibility with mods that
|
||||||
|
might ship their own game.so.
|
||||||
|
|
||||||
|
You can **just symlink the executables to a directory in your $PATH**, like /usr/bin/.
|
||||||
|
(*Except on OpenBSD, which does not provide a way to get the executable directory,
|
||||||
|
there you'll need a shellscript that first does a `cd /path/to/yamagi-quake2/` and
|
||||||
|
then executes `./quake2`*)
|
||||||
|
|
||||||
|
We want all binaries to be in the same directory to ensure that people don't accidentally
|
||||||
|
update only parts of their Yamagi Quake II installtion, so they'd end up with a new
|
||||||
|
quake2 executable and old render libraries (`ref_*.so`) and report weird bugs.
|
||||||
|
|
||||||
|
## The SYSTEMWIDE and SYSTEMDIR options
|
||||||
|
|
||||||
|
The Makefile allows you to enable the `SYSTEMWIDE` feature (`WITH_SYSTEMWIDE=yes`) and
|
||||||
|
lets you specify the directory that will be used (`SYSTEMDIR`, `WITH_SYSTEMDIR=/your/custom/path/`).
|
||||||
|
If you don't set SYSTEMDIR, it defaults to `/usr/share/games/quake2`, which is what debian uses.
|
||||||
|
|
||||||
|
The `SYSTEMDIR` was meant to contain just the game data, *not* the binaries, and allows
|
||||||
|
several Quake2 source ports to share the same game data.
|
||||||
|
Unfortunately, we didn't document this assumption, so some packages used it for both binaries
|
||||||
|
and data, just binaries or - which causes most trouble - only for the game libs, but not the
|
||||||
|
executables. The latter case doesn't work anymore since we (re)introduced the render libs,
|
||||||
|
as they need to be located next to the executable, and if the executable is in /usr/bin/ you
|
||||||
|
don't want to put libs next to it.
|
||||||
|
|
||||||
|
Anyway: If you use `SYSTEMWIDE`/`SYSTEMDIR`, please use it for game data.
|
||||||
|
You *can* also put the binaries in there, but in that case please put all of them
|
||||||
|
(including executables) in there, as explained above.
|
||||||
|
|
||||||
|
## Alternative startup config
|
||||||
|
|
||||||
|
Yamagi Quake II has support for an alternative startup config.
|
||||||
|
It may be a good idea to install it, since it sets some global options to sane defaults.
|
||||||
|
Copy yq2.cfg to the baseq2/ subdirectory in the gamedata (`SYSTEMDIR`) directory.
|
Loading…
Reference in a new issue