]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - fs.c
physics: fix and refactor unsticking
[xonotic/darkplaces.git] / fs.c
diff --git a/fs.c b/fs.c
index ad69946f961894f4e474cab6b918beac2f8ef02e..e2afcf052ca4b89b8227b7fd1f4a30b277aefea3 100644 (file)
--- a/fs.c
+++ b/fs.c
@@ -171,7 +171,7 @@ static fs_offset_t WriteAll(const filedesc_t fd, const void *const buf, const si
 
 /** \page fs File System
 
-All of Quake's data access is through a hierchal file system, but the contents
+All of Quake's data access is through a hierarchical file system, the contents
 of the file system can be transparently merged from several sources.
 
 The "base directory" is the path to the directory holding the quake.exe and
@@ -183,9 +183,8 @@ directory is only used during filesystem initialization.
 The "game directory" is the first tree on the search path and directory that
 all generated files (savegames, screenshots, demos, config files) will be
 saved to.  This can be overridden with the "-game" command line parameter.
-The game directory can never be changed while quake is executing.  This is a
-precaution against having a malicious server instruct clients to write files
-over areas they shouldn't.
+If multiple "-game <gamedir>" args are passed the last one is the "primary"
+and files will be saved there, the rest are read-only.
 
 */
 
@@ -382,7 +381,7 @@ typedef struct pack_s
        char filename [MAX_OSPATH];
        char shortname [MAX_QPATH];
        filedesc_t handle;
-       int ignorecase;  ///< PK3 ignores case
+       qbool ignorecase;  ///< PK3 ignores case
        int numfiles;
        qbool vpack;
        qbool dlcache;
@@ -412,7 +411,7 @@ void FS_Dir_f(cmd_state_t *cmd);
 void FS_Ls_f(cmd_state_t *cmd);
 void FS_Which_f(cmd_state_t *cmd);
 
-static searchpath_t *FS_FindFile (const char *name, int* index, qbool quiet);
+static searchpath_t *FS_FindFile (const char *name, int *index, const char **canonicalname, qbool quiet);
 static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack,
                                                                        fs_offset_t offset, fs_offset_t packsize,
                                                                        fs_offset_t realsize, int flags);
@@ -1324,7 +1323,7 @@ qbool FS_AddPack(const char *pakfile, qbool *already_loaded, qbool keep_plain_di
                *already_loaded = false;
 
        // then find the real name...
-       search = FS_FindFile(pakfile, &index, true);
+       search = FS_FindFile(pakfile, &index, NULL, true);
        if(!search || search->pack)
        {
                Con_Printf("could not find pak \"%s\"\n", pakfile);
@@ -1345,14 +1344,13 @@ Sets fs_gamedir, adds the directory to the head of the path,
 then loads and adds pak1.pak pak2.pak ...
 ================
 */
-static void FS_AddGameDirectory (const char *dir, qbool set_fs_gamedir)
+static void FS_AddGameDirectory (const char *dir)
 {
        int i;
        stringlist_t list;
        searchpath_t *search;
 
-       if (set_fs_gamedir)
-               dp_strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
+       dp_strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
 
        stringlistinit(&list);
        listdirectory(&list, "", dir);
@@ -1393,14 +1391,14 @@ static void FS_AddGameDirectory (const char *dir, qbool set_fs_gamedir)
 FS_AddGameHierarchy
 ================
 */
-static void FS_AddGameHierarchy (const char *dir, qbool set_fs_gamedir)
+static void FS_AddGameHierarchy (const char *dir)
 {
        char vabuf[1024];
        // Add the common game directory
-       FS_AddGameDirectory (va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, dir), set_fs_gamedir);
+       FS_AddGameDirectory (va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, dir));
 
        if (*fs_userdir)
-               FS_AddGameDirectory(va(vabuf, sizeof(vabuf), "%s%s/", fs_userdir, dir), set_fs_gamedir);
+               FS_AddGameDirectory(va(vabuf, sizeof(vabuf), "%s%s/", fs_userdir, dir));
 }
 
 
@@ -1561,32 +1559,30 @@ void FS_Rescan (void)
 
        // add the game-specific paths
        // gamedirname1 (typically id1)
-       FS_AddGameHierarchy (gamedirname1, true);
+       FS_AddGameHierarchy (gamedirname1);
        // update the com_modname (used for server info)
        if (gamedirname2 && gamedirname2[0])
                dp_strlcpy(com_modname, gamedirname2, sizeof(com_modname));
        else
                dp_strlcpy(com_modname, gamedirname1, sizeof(com_modname));
 
-       // add the secondary game-specific path, if any
+       // add the game-specific path, if any
        // (only used for mission packs and the like, which should set fs_modified)
        if (gamedirname2 && gamedirname2[0])
        {
                fs_modified = true;
-               FS_AddGameHierarchy (gamedirname2, true);
+               FS_AddGameHierarchy (gamedirname2);
        }
 
        // -game <gamedir>
        // Adds basedir/gamedir as an override game
        // LadyHavoc: now supports multiple -game directories
        // set the com_modname (reported in server info)
-       // bones_was_here: does NOT set fs_gamedir in FS_AddGameHierarchy()
-       // so that we still save files in the right place.
        *gamedirbuf = 0;
        for (i = 0;i < fs_numgamedirs;i++)
        {
                fs_modified = true;
-               FS_AddGameHierarchy (fs_gamedirs[i], false);
+               FS_AddGameHierarchy (fs_gamedirs[i]);
                // update the com_modname (used server info)
                dp_strlcpy (com_modname, fs_gamedirs[i], sizeof (com_modname));
                if(i)
@@ -2103,7 +2099,7 @@ void FS_Init_Commands(void)
        Cvar_RegisterVariable (&fs_unload_dlcache);
        Cvar_RegisterVariable (&cvar_fs_gamedir);
 
-       Cmd_AddCommand(CF_SHARED, "gamedir", FS_GameDir_f, "changes active gamedir list (can take multiple arguments), not including base directory (example usage: gamedir ctf)");
+       Cmd_AddCommand(CF_SHARED, "gamedir", FS_GameDir_f, "changes active gamedir list, can take multiple arguments which shouldn't include the base directory, the last gamedir is the \"primary\" and files will be saved there (example usage: gamedir ctf id1)");
        Cmd_AddCommand(CF_SHARED, "fs_rescan", FS_Rescan_f, "rescans filesystem for new pack archives and any other changes");
        Cmd_AddCommand(CF_SHARED, "path", FS_Path_f, "print searchpath (game directories and archives)");
        Cmd_AddCommand(CF_SHARED, "dir", FS_Dir_f, "list files in searchpath matching an * filename pattern, one per line");
@@ -2167,6 +2163,9 @@ static void FS_Init_Dir (void)
                                }
                        }
                }
+#else
+               // use the working directory
+               getcwd(fs_basedir, sizeof(fs_basedir));
 #endif
        }
 
@@ -2672,7 +2671,7 @@ Return the searchpath where the file was found (or NULL)
 and the file index in the package if relevant
 ====================
 */
-static searchpath_t *FS_FindFile (const char *name, int* index, qbool quiet)
+static searchpath_t *FS_FindFile (const char *name, int *index, const char **canonicalname, qbool quiet)
 {
        searchpath_t *search;
        pack_t *pak;
@@ -2710,15 +2709,18 @@ static searchpath_t *FS_FindFile (const char *name, int* index, qbool quiet)
 
                                                if (index != NULL)
                                                        *index = -1;
+                                               if (canonicalname)
+                                                       *canonicalname = NULL;
                                                return NULL;
                                        }
 
                                        if (!quiet && developer_extra.integer)
-                                               Con_DPrintf("FS_FindFile: %s in %s\n",
-                                                                       pak->files[middle].name, pak->filename);
+                                               Con_DPrintf("FS_FindFile: %s in %s\n", pak->files[middle].name, pak->filename);
 
                                        if (index != NULL)
                                                *index = middle;
+                                       if (canonicalname)
+                                               *canonicalname = pak->files[middle].name;
                                        return search;
                                }
 
@@ -2740,6 +2742,8 @@ static searchpath_t *FS_FindFile (const char *name, int* index, qbool quiet)
 
                                if (index != NULL)
                                        *index = -1;
+                               if (canonicalname)
+                                       *canonicalname = name;
                                return search;
                        }
                }
@@ -2750,6 +2754,8 @@ static searchpath_t *FS_FindFile (const char *name, int* index, qbool quiet)
 
        if (index != NULL)
                *index = -1;
+       if (canonicalname)
+               *canonicalname = NULL;
        return NULL;
 }
 
@@ -2766,7 +2772,7 @@ static qfile_t *FS_OpenReadFile (const char *filename, qbool quiet, qbool nonblo
        searchpath_t *search;
        int pack_ind;
 
-       search = FS_FindFile (filename, &pack_ind, quiet);
+       search = FS_FindFile (filename, &pack_ind, NULL, quiet);
 
        // Not found?
        if (search == NULL)
@@ -3647,7 +3653,7 @@ int FS_FileType (const char *filename)
        searchpath_t *search;
        char fullpath[MAX_OSPATH];
 
-       search = FS_FindFile (filename, NULL, true);
+       search = FS_FindFile (filename, NULL, NULL, true);
        if(!search)
                return FS_FILETYPE_NONE;
 
@@ -3664,11 +3670,15 @@ int FS_FileType (const char *filename)
 FS_FileExists
 
 Look for a file in the packages and in the filesystem
+Returns its canonical name (VFS path with correct capitalisation) if found, else NULL.
+If the file is found outside a pak, this will be the same pointer as passed in.
 ==================
 */
-qbool FS_FileExists (const char *filename)
+const char *FS_FileExists (const char *filename)
 {
-       return (FS_FindFile (filename, NULL, true) != NULL);
+       const char *canonicalname;
+
+       return FS_FindFile(filename, NULL, &canonicalname, true) ? canonicalname : NULL;
 }
 
 
@@ -4044,7 +4054,7 @@ void FS_Which_f(cmd_state_t *cmd)
                return;
        }
        filename = Cmd_Argv(cmd, 1);
-       sp = FS_FindFile(filename, &index, true);
+       sp = FS_FindFile(filename, &index, NULL, true);
        if (!sp) {
                Con_Printf("%s isn't anywhere\n", filename);
                return;
@@ -4064,7 +4074,7 @@ void FS_Which_f(cmd_state_t *cmd)
 const char *FS_WhichPack(const char *filename)
 {
        int index;
-       searchpath_t *sp = FS_FindFile(filename, &index, true);
+       searchpath_t *sp = FS_FindFile(filename, &index, NULL, true);
        if(sp && sp->pack)
                return sp->pack->shortname;
        else if(sp)