From acab8db4fc72cd553dd2d65b11d0b8512e242594 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 21 Mar 2019 13:49:44 +0300 Subject: [PATCH 1/3] UnpackTool --- src/main/java/lwjake2/UnpackTool.java | 103 ++++++++++++++++++ .../lwjake2/qcommon/BaseQ2FileSystem.java | 33 +++++- 2 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 src/main/java/lwjake2/UnpackTool.java diff --git a/src/main/java/lwjake2/UnpackTool.java b/src/main/java/lwjake2/UnpackTool.java new file mode 100644 index 0000000..8528d45 --- /dev/null +++ b/src/main/java/lwjake2/UnpackTool.java @@ -0,0 +1,103 @@ +package lwjake2; + +import lombok.Value; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.util.*; + +@Slf4j +@UtilityClass +public class UnpackTool { + + private static final String READ_ONLY = "r"; + private static Map listPakFiles = new HashMap<>(); + private static Map pakFiles = new HashMap<>(); + + private static RandomAccessFile getPak(String pakName) { + RandomAccessFile raf; + + if (!pakFiles.containsKey(pakName)) { + try { + raf = new RandomAccessFile(pakName, READ_ONLY); + } catch (FileNotFoundException e) { + log.error("Read file error: {}", e.getMessage()); + raf = null; + } + + pakFiles.put(pakName, raf); + } else { + raf = pakFiles.get(pakName); + } + + return raf; + } + + public static void add(Entry entry) { + listPakFiles.put(entry.getName(), entry); + } + + public static void printList() { + listPakFiles.values().stream() + .sorted((o1, o2) -> { + final int result = o1.getPakName().compareTo(o2.getPakName()); + if (result == 0) { + return o1.getName().compareTo(o2.getName()); + } else { + return result; + } + }) + .forEach(entry -> log.info("{}: {}", entry.getPakName(), entry.getName())); + } + + public static Collection list() { + return listPakFiles.values(); + } + + public static Entry get(String name) { + return listPakFiles.get(name); + } + + @Value + public static class Entry { + private String name; + private int pos; + private long size; + private String pakName; + + public Entry(String name, int pos, long size, String pakName) { + int idx; + if ((idx = name.indexOf('\0')) != -1) { + this.name = name.substring(0, idx); + } else { + this.name = name; + } + + this.pos = pos; + this.size = size; + this.pakName = pakName; + } + + public byte[] getBytes() throws IOException { + RandomAccessFile pak = UnpackTool.getPak(pakName); + if (pak == null) { + return null; + } + + pak.seek(pos); + + byte[] result = new byte[(int) size]; + if (result.length < size) { + log.error("Can't cast long to int: size too big for intValue"); + return null; + } + + pak.readFully(result); + return result; + } + } +} diff --git a/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java b/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java index 28150dc..41f64b8 100644 --- a/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java +++ b/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java @@ -22,12 +22,14 @@ import lombok.extern.slf4j.Slf4j; import lwjake2.Defines; import lwjake2.ErrorCode; import lwjake2.Globals; +import lwjake2.UnpackTool; import lwjake2.game.Cmd; import lwjake2.game.cvar_t; import lwjake2.sys.Sys; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; @@ -487,7 +489,7 @@ public class BaseQ2FileSystem implements FileSystem { * Takes an explicit (not game tree related) path to a pak file. * * Loads the header and directory, adding the files at the beginning of the - * list so they override previous pack files. + * printList so they override previous pack files. */ private pack_t loadPackFile(String packfile) { dpackheader_t header; @@ -538,6 +540,12 @@ public class BaseQ2FileSystem implements FileSystem { entry.filelen = packhandle.getInt(); newfiles.put(entry.name.toLowerCase(), entry); + UnpackTool.add(new UnpackTool.Entry( + entry.name, + entry.filepos, + entry.filelen, + packfile + )); } } catch (IOException e) { @@ -564,7 +572,6 @@ public class BaseQ2FileSystem implements FileSystem { */ private void addGameDirectory(String dir) { int i; - searchpath_t search; pack_t pak; String pakfile; @@ -573,7 +580,7 @@ public class BaseQ2FileSystem implements FileSystem { // // add the directory to the search path // ensure fs_userdir is first in searchpath - search = new searchpath_t(); + searchpath_t search = new searchpath_t(); search.filename = dir; if (fs_searchpaths != null) { search.next = fs_searchpaths.next; @@ -600,6 +607,26 @@ public class BaseQ2FileSystem implements FileSystem { search.next = fs_searchpaths; fs_searchpaths = search; } + + UnpackTool.printList(); + + final File baseq2UnpackDir = new File(dir, "_unpack"); + baseq2UnpackDir.mkdirs(); + + UnpackTool.list().forEach(entry -> { + File file = new File(baseq2UnpackDir, entry.getName()); + if (file.exists()) { + return; + } + + file.getParentFile().mkdirs(); + try (FileOutputStream fos = new FileOutputStream(file)) { + log.info("Write '{}'...", entry.getName()); + fos.write(entry.getBytes()); + } catch (IOException e) { + log.error("Can't write file '{}': {}", entry.getName(), e.getMessage()); + } + }); } /* From 980229bff9ed881bf87312cf59a704ec8d2841bf Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 21 Mar 2019 17:14:58 +0300 Subject: [PATCH 2/3] use unpack files --- src/main/java/lwjake2/UnpackLoader.java | 82 ++ src/main/java/lwjake2/client/CL.java | 15 +- src/main/java/lwjake2/client/CL_ents.java | 3 +- src/main/java/lwjake2/client/CL_parse.java | 26 +- src/main/java/lwjake2/client/Console.java | 4 +- src/main/java/lwjake2/client/Menu.java | 11 +- src/main/java/lwjake2/client/SCR.java | 7 +- src/main/java/lwjake2/game/Cmd.java | 5 +- .../lwjake2/qcommon/BaseQ2FileSystem.java | 967 ------------------ src/main/java/lwjake2/qcommon/CM.java | 5 +- src/main/java/lwjake2/qcommon/Cvar.java | 2 +- src/main/java/lwjake2/qcommon/Qcommon.java | 17 +- src/main/java/lwjake2/render/lwjgl/Image.java | 11 +- src/main/java/lwjake2/render/lwjgl/Misc.java | 6 +- src/main/java/lwjake2/render/lwjgl/Model.java | 6 +- src/main/java/lwjake2/server/SV_CCMDS.java | 52 +- src/main/java/lwjake2/server/SV_INIT.java | 6 +- src/main/java/lwjake2/server/SV_USER.java | 15 +- src/main/java/lwjake2/sound/WaveLoader.java | 7 +- .../lwjake2/sound/lwjgl/LWJGLSoundImpl.java | 6 +- src/main/java/lwjake2/util/Lib.java | 3 +- 21 files changed, 188 insertions(+), 1068 deletions(-) create mode 100644 src/main/java/lwjake2/UnpackLoader.java delete mode 100644 src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java diff --git a/src/main/java/lwjake2/UnpackLoader.java b/src/main/java/lwjake2/UnpackLoader.java new file mode 100644 index 0000000..40da0ee --- /dev/null +++ b/src/main/java/lwjake2/UnpackLoader.java @@ -0,0 +1,82 @@ +package lwjake2; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Paths; + +@Slf4j +@UtilityClass +public class UnpackLoader { + + @Getter + @Setter + private static String rootPath; + + private static File getFile(String path) { + File file = new File(rootPath, path); + if (!file.exists()) { + log.warn("File '{}' not exists", file.getPath()); + return null; + } + + return file; + } + + @Nullable + public static byte[] loadFile(String path) { + File file = getFile(path); + if (file == null) { + return null; + } + + byte[] result = new byte[(int) file.length()]; + if (result.length < file.length()) { + log.error("Can't cast long to int: {} < {}", result.length, file.length()); + return null; + } + + try (FileInputStream fis = new FileInputStream(file)) { + fis.read(result); + } catch (IOException e) { + log.error("Can't read file '{}': {}", file.getPath(), e.getMessage()); + return null; + } + + return result; + } + + @Nullable + public static ByteBuffer loadFileAsByteBuffer(String path) { + byte[] bytes = loadFile(path); + if (bytes == null) { + return null; + } + + return ByteBuffer.wrap(bytes); + } + + public static RandomAccessFile loadFileAsRAF(String path) { + File file = getFile(path); + if (file == null) { + return null; + } + + try { + return new RandomAccessFile(file, "r"); + } catch (FileNotFoundException e) { + log.error("Can't read file '{}': {}", file.getPath(), e.getMessage()); + return null; + } + } + + public static boolean exists(String path) { + return Files.exists(Paths.get(rootPath, path)); + } +} diff --git a/src/main/java/lwjake2/client/CL.java b/src/main/java/lwjake2/client/CL.java index d75f991..589b2be 100644 --- a/src/main/java/lwjake2/client/CL.java +++ b/src/main/java/lwjake2/client/CL.java @@ -31,8 +31,7 @@ import lwjake2.qcommon.CM; import lwjake2.qcommon.Cbuf; import lwjake2.qcommon.Com; import lwjake2.qcommon.Cvar; -import lwjake2.qcommon.FileSystem; -import lwjake2.qcommon.BaseQ2FileSystem; +import lwjake2.UnpackLoader; import lwjake2.qcommon.MSG; import lwjake2.qcommon.Netchan; import lwjake2.qcommon.SZ; @@ -58,7 +57,7 @@ import java.nio.ByteOrder; */ @Slf4j public final class CL { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = /*BaseQ2FileSystem.getInstance()*/null; static int precache_check; // for autodownload of precache items @@ -160,10 +159,10 @@ public final class CL { // // open the demo file // - name = fileSystem.getGamedir() + "/demos/" + Cmd.Argv(1) + ".dm2"; + name = Globals.BASEDIRNAME + "/demos/" + Cmd.Argv(1) + ".dm2"; log.info("recording to {}", name); - fileSystem.createPath(name); +// fileSystem.createPath(name); Globals.cls.demofile = new RandomAccessFile(name, "rw"); if (Globals.cls.demofile == null) { log.error("ERROR: couldn't open."); @@ -945,7 +944,7 @@ public final class CL { // checking for skins in the model if (CL.precache_model == null) { - CL.precache_model = fileSystem.loadFile(Globals.cl.configstrings[CL.precache_check]); + CL.precache_model = UnpackLoader.loadFile(Globals.cl.configstrings[CL.precache_check]); if (CL.precache_model == null) { CL.precache_model_skin = 0; CL.precache_check++; @@ -1376,7 +1375,7 @@ public final class CL { // if (Globals.cls.state == Defines.ca_uninitialized) // return; - path = fileSystem.getGamedir() + "/config.cfg"; + path = Globals.BASEDIRNAME + "/config.cfg"; f = Lib.fopen(path, "rw"); if (f == null) { log.warn("Couldn't write config.cfg."); @@ -1577,7 +1576,7 @@ public final class CL { InitLocal(); IN.Init(); - fileSystem.execAutoexec(); +// fileSystem.execAutoexec(); Cbuf.Execute(); } diff --git a/src/main/java/lwjake2/client/CL_ents.java b/src/main/java/lwjake2/client/CL_ents.java index 3a2fda7..ac305c3 100644 --- a/src/main/java/lwjake2/client/CL_ents.java +++ b/src/main/java/lwjake2/client/CL_ents.java @@ -26,7 +26,6 @@ import lwjake2.game.player_state_t; import lwjake2.game.pmove_t; import lwjake2.qcommon.Com; import lwjake2.qcommon.FileSystem; -import lwjake2.qcommon.BaseQ2FileSystem; import lwjake2.qcommon.MSG; import lwjake2.util.Math3D; @@ -42,7 +41,7 @@ import lwjake2.util.Math3D; * ========================================================================= */ public class CL_ents { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; static int bitcounts[] = new int[32]; /// just for protocol profiling diff --git a/src/main/java/lwjake2/client/CL_parse.java b/src/main/java/lwjake2/client/CL_parse.java index 97fcc32..560a0dd 100644 --- a/src/main/java/lwjake2/client/CL_parse.java +++ b/src/main/java/lwjake2/client/CL_parse.java @@ -23,13 +23,14 @@ import lwjake2.Defines; import lwjake2.ErrorCode; import lwjake2.Globals; import lwjake2.game.Cmd; +import lwjake2.game.cvar_t; import lwjake2.game.entity_state_t; import lwjake2.qcommon.CM; import lwjake2.qcommon.Cbuf; import lwjake2.qcommon.Com; import lwjake2.qcommon.Cvar; import lwjake2.qcommon.FileSystem; -import lwjake2.qcommon.BaseQ2FileSystem; +import lwjake2.UnpackLoader; import lwjake2.qcommon.MSG; import lwjake2.qcommon.SZ; import lwjake2.render.model_t; @@ -40,12 +41,15 @@ import lwjake2.util.Lib; import java.io.IOException; import java.io.RandomAccessFile; +import static lwjake2.Defines.CVAR_LATCH; +import static lwjake2.Defines.CVAR_SERVERINFO; + /** * CL_parse */ @Slf4j public class CL_parse { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; //// cl_parse.c -- parse a message received from the server @@ -60,7 +64,7 @@ public class CL_parse { // ============================================================================= public static String DownloadFileName(String fn) { - return fileSystem.getGamedir() + "/" + fn; + return Globals.BASEDIRNAME + "/" + fn; } /* @@ -78,7 +82,7 @@ public class CL_parse { return true; } - if (fileSystem.fileLength(filename) > 0) { // it exists, no need to download + if (UnpackLoader.exists(filename)) { // it exists, no need to download return true; } @@ -150,7 +154,7 @@ public class CL_parse { return; } - if (fileSystem.loadFile(filename) != null) { // it exists, no need to + if (UnpackLoader.loadFile(filename) != null) { // it exists, no need to // download Com.Printf("File already exists.\n"); return; @@ -223,7 +227,7 @@ public class CL_parse { if (Globals.cls.download == null) { String name = DownloadFileName(Globals.cls.downloadtempname).toLowerCase(); - fileSystem.createPath(name); +// fileSystem.createPath(name); Globals.cls.download = Lib.fopen(name, "rw"); if (Globals.cls.download == null) { @@ -321,12 +325,12 @@ public class CL_parse { Com.dprintln("gamedir=" + str); // set gamedir + cvar_t gamedirVar = Cvar.Get("game", "", CVAR_LATCH | CVAR_SERVERINFO); if (str.length() > 0 - && (fileSystem.getGamedirVar().string == null - || fileSystem.getGamedirVar().string.length() == 0 || fileSystem.getGamedirVar().string - .equals(str)) - || (str.length() == 0 && (fileSystem.getGamedirVar().string != null || fileSystem.getGamedirVar().string - .length() == 0))) + && (gamedirVar.string == null + || gamedirVar.string.length() == 0 + || gamedirVar.string.equals(str)) + || (str.length() == 0 && (gamedirVar.string != null || gamedirVar.string.length() == 0))) Cvar.Set("game", str); // parse player entity number diff --git a/src/main/java/lwjake2/client/Console.java b/src/main/java/lwjake2/client/Console.java index a8a66c5..32431ae 100644 --- a/src/main/java/lwjake2/client/Console.java +++ b/src/main/java/lwjake2/client/Console.java @@ -43,7 +43,7 @@ import static lwjake2.Globals.*; */ @Slf4j public final class Console { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; public static Runnable ToggleConsole_f = () -> { SCR.EndLoadingPlaque(); // get rid of loading plaque @@ -92,7 +92,7 @@ public final class Console { //Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), // Cmd_Argv(1)); - name = fileSystem.getGamedir() + "/" + Cmd.Argv(1) + ".txt"; + name = Globals.BASEDIRNAME + "/" + Cmd.Argv(1) + ".txt"; log.info("Dumped console text to {}", name); fileSystem.createPath(name); diff --git a/src/main/java/lwjake2/client/Menu.java b/src/main/java/lwjake2/client/Menu.java index af07396..a648eb1 100644 --- a/src/main/java/lwjake2/client/Menu.java +++ b/src/main/java/lwjake2/client/Menu.java @@ -19,6 +19,7 @@ package lwjake2.client; import lwjake2.Globals; +import lwjake2.UnpackLoader; import lwjake2.game.Cmd; import lwjake2.game.cvar_t; import lwjake2.qcommon.*; @@ -52,7 +53,7 @@ interface KeyCallback { } public final class Menu extends Key { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*(BaseQ2FileSystem.getInstance())*/; static int m_main_cursor; @@ -1621,7 +1622,7 @@ public final class Menu extends Key { int n; int isdeveloper; - byte b[] = fileSystem.loadFile("credits"); + byte b[] = UnpackLoader.loadFile("credits"); if (b != null) { creditsBuffer = new String(b); @@ -1835,7 +1836,7 @@ public final class Menu extends Key { for (i = 0; i < MAX_SAVEGAMES; i++) { m_savestrings[i] = ""; - name = fileSystem.getGamedir() + "/save/save" + i + "/server.ssv"; + name = Globals.BASEDIRNAME + "/save/save" + i + "/server.ssv"; try { f = new QuakeFile(name, "r"); @@ -2307,7 +2308,7 @@ public final class Menu extends Key { /* * * load the list of map names */ - mapsname = fileSystem.getGamedir() + "/maps.lst"; + mapsname = Globals.BASEDIRNAME + "/maps.lst"; // Check user dir first (default ~/.lwjake2) if ((fp = Lib.fopen(mapsname, "r")) == null) { @@ -2315,7 +2316,7 @@ public final class Menu extends Key { mapsname = fileSystem.getBaseGamedir() + "/maps.lst"; if ((fp = Lib.fopen(mapsname, "r")) == null) { // Open the pak's maplist - buffer = fileSystem.loadFile("maps.lst"); + buffer = UnpackLoader.loadFile("maps.lst"); if (buffer == null) Com.Error(ERR_DROP, "couldn't find maps.lst\n"); } else { diff --git a/src/main/java/lwjake2/client/SCR.java b/src/main/java/lwjake2/client/SCR.java index 4e876b7..46c7665 100644 --- a/src/main/java/lwjake2/client/SCR.java +++ b/src/main/java/lwjake2/client/SCR.java @@ -21,6 +21,7 @@ package lwjake2.client; import lombok.extern.slf4j.Slf4j; import lwjake2.Defines; import lwjake2.Globals; +import lwjake2.UnpackLoader; import lwjake2.game.Cmd; import lwjake2.game.cvar_t; import lwjake2.qcommon.*; @@ -43,7 +44,7 @@ import static lwjake2.Globals.*; */ @Slf4j public final class SCR { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc static String[][] sb_nums = { @@ -1368,7 +1369,7 @@ public final class SCR { qfiles.pcx_t pcx; // load the file - ByteBuffer raw = fileSystem.loadMappedFile(filename); + ByteBuffer raw = UnpackLoader.loadFileAsByteBuffer(filename); if (raw == null) { VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename @@ -1807,7 +1808,7 @@ public final class SCR { } String name = "video/" + arg; - cl.cinematic_file = fileSystem.loadMappedFile(name); + cl.cinematic_file = UnpackLoader.loadFileAsByteBuffer(name); if (cl.cinematic_file == null) { //Com.Error(ERR_DROP, "Cinematic " + name + " not found.\n"); FinishCinematic(); diff --git a/src/main/java/lwjake2/game/Cmd.java b/src/main/java/lwjake2/game/Cmd.java index e4e1344..a556cf8 100644 --- a/src/main/java/lwjake2/game/Cmd.java +++ b/src/main/java/lwjake2/game/Cmd.java @@ -21,6 +21,7 @@ package lwjake2.game; import lombok.extern.slf4j.Slf4j; import lwjake2.Defines; import lwjake2.Globals; +import lwjake2.UnpackLoader; import lwjake2.game.monsters.M_Player; import lwjake2.qcommon.*; import lwjake2.server.SV_GAME; @@ -35,7 +36,7 @@ import java.util.Vector; */ @Slf4j public final class Cmd { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; static Runnable List_f = () -> { cmd_function_t cmd = Cmd.cmd_functions; int i = 0; @@ -55,7 +56,7 @@ public final class Cmd { } byte[] f = null; - f = fileSystem.loadFile(Cmd.Argv(1)); + f = UnpackLoader.loadFile(Cmd.Argv(1)); if (f == null) { log.info("couldn't exec {}", Cmd.Argv(1)); return; diff --git a/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java b/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java deleted file mode 100644 index 41f64b8..0000000 --- a/src/main/java/lwjake2/qcommon/BaseQ2FileSystem.java +++ /dev/null @@ -1,967 +0,0 @@ -/* - * Copyright (C) 1997-2001 Id Software, Inc. - * - * 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. - */ - -package lwjake2.qcommon; - -import lombok.extern.slf4j.Slf4j; -import lwjake2.Defines; -import lwjake2.ErrorCode; -import lwjake2.Globals; -import lwjake2.UnpackTool; -import lwjake2.game.Cmd; -import lwjake2.game.cvar_t; -import lwjake2.sys.Sys; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import static lwjake2.Defines.*; - -/* - * ================================================== - * - * QUAKE FILESYSTEM - * - * @author cwei - * @author DmitriyMX - * @modify 2018-03-06 - * - * ================================================== - */ - -@Slf4j -public class BaseQ2FileSystem implements FileSystem { - private static final BaseQ2FileSystem instance = new BaseQ2FileSystem(); - private static final int IDPAKHEADER = (('K' << 24) + ('C' << 16) + ('A' << 8) + 'P'); - private static final int MAX_FILES_IN_PACK = 4096; - // read in blocks of 64k - private static final int MAX_READ = 0x10000; - - public static BaseQ2FileSystem getInstance() { - return instance; - } - - private BaseQ2FileSystem() {} - - private static class packfile_t { - static final int SIZE = 64; - static final int NAME_SIZE = 56; - String name; // char name[56] - int filepos, filelen; - public String toString() { - return name + " [ length: " + filelen + " pos: " + filepos + " ]"; - } - } - - private static class pack_t { - String filename; - RandomAccessFile handle; - ByteBuffer backbuffer; - int numfiles; - Hashtable files; // with packfile_t entries - } - - private String fs_gamedir; - - private String fs_userdir; - - private cvar_t fs_basedir; - - private cvar_t fs_cddir; - - private cvar_t fs_gamedirvar; - - private static class filelink_t { - String from; - int fromlength; - String to; - } - - // with filelink_t entries - private List fs_links = new LinkedList<>(); - - private static class searchpath_t { - String filename; - pack_t pack; // only one of filename or pack will be used - searchpath_t next; - } - - private searchpath_t fs_searchpaths; - - // without gamedirs - private searchpath_t fs_base_searchpaths; - - /* - * All of Quake's data access is through a hierchal file system, but 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 all game directories. The sys_* files pass this to host_init in - * quakeparms_t->basedir. This can be overridden with the "-basedir" command - * line parm to allow code debugging in a different directory. The base - * 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 precacution against having a malicious server - * instruct clients to write files over areas they shouldn't. - * - */ - - /* - * CreatePath - * - * Creates any directories needed to store the given filename. - */ - @Override - public void createPath(String path) { - int index = path.lastIndexOf('/'); - // -1 if not found and 0 means write to root - if (index > 0) { - File f = new File(path.substring(0, index)); - if (!f.mkdirs() && !f.isDirectory()) { - log.warn("can't create path \"{}\"", path); - } - } - } - - @Override - public int fileLength(String filename) { - searchpath_t search; - String netpath; - pack_t pak; - - file_from_pak = 0; - - // check for links first - for (filelink_t link : fs_links) { - if (filename.regionMatches(0, link.from, 0, link.fromlength)) { - netpath = link.to + filename.substring(link.fromlength); - File file = new File(netpath); - if (file.canRead()) { - Com.DPrintf("link file: " + netpath + '\n'); - return (int) file.length(); - } - return -1; - } - } - - // search through the path, one element at a time - - for (search = fs_searchpaths; search != null; search = search.next) { - // is the element a pak file? - if (search.pack != null) { - // look through all the pak file elements - pak = search.pack; - filename = filename.toLowerCase(); - packfile_t entry = pak.files.get(filename); - - if (entry != null) { - // found it! - file_from_pak = 1; - Com.DPrintf("PackFile: " + pak.filename + " : " + filename - + '\n'); - // open a new file on the pakfile - File file = new File(pak.filename); - if (!file.canRead()) { - Com.Error(ErrorCode.ERR_FATAL, "Couldn't reopen " - + pak.filename); - } - return entry.filelen; - } - } else { - // check a file in the directory tree - netpath = search.filename + '/' + filename; - - File file = new File(netpath); - if (!file.canRead()) - continue; - - Com.DPrintf("FindFile: " + netpath + '\n'); - - return (int) file.length(); - } - } - Com.DPrintf("FindFile: can't find " + filename + '\n'); - return -1; - } - - private int file_from_pak = 0; - - /* - * FOpenFile - * - * Finds the file in the search path. returns a RadomAccesFile. Used for - * streaming data out of either a pak file or a seperate file. - */ - @Override - public RandomAccessFile FOpenFile(String filename) throws IOException { - searchpath_t search; - String netpath; - pack_t pak; - File file; - - file_from_pak = 0; - - // check for links first - for (filelink_t link : fs_links) { - // if (!strncmp (filename, link->from, link->fromlength)) - if (filename.regionMatches(0, link.from, 0, link.fromlength)) { - netpath = link.to + filename.substring(link.fromlength); - file = new File(netpath); - if (file.canRead()) { - //Com.DPrintf ("link file: " + netpath +'\n'); - return new RandomAccessFile(file, "r"); - } - return null; - } - } - - // - // search through the path, one element at a time - // - for (search = fs_searchpaths; search != null; search = search.next) { - // is the element a pak file? - if (search.pack != null) { - // look through all the pak file elements - pak = search.pack; - filename = filename.toLowerCase(); - packfile_t entry = pak.files.get(filename); - - if (entry != null) { - // found it! - file_from_pak = 1; - //Com.DPrintf ("PackFile: " + pak.filename + " : " + - // filename + '\n'); - file = new File(pak.filename); - if (!file.canRead()) - Com.Error(ErrorCode.ERR_FATAL, "Couldn't reopen " - + pak.filename); - if (pak.handle == null || !pak.handle.getFD().valid()) { - // hold the pakfile handle open - pak.handle = new RandomAccessFile(pak.filename, "r"); - } - // open a new file on the pakfile - - RandomAccessFile raf = new RandomAccessFile(file, "r"); - raf.seek(entry.filepos); - - return raf; - } - } else { - // check a file in the directory tree - netpath = search.filename + '/' + filename; - - file = new File(netpath); - if (!file.canRead()) - continue; - - //Com.DPrintf("FindFile: " + netpath +'\n'); - - return new RandomAccessFile(file, "r"); - } - } - //Com.DPrintf ("FindFile: can't find " + filename + '\n'); - return null; - } - - /** - * Read - * - * Properly handles partial reads - */ - @Override - public void read(byte[] buffer, int len, RandomAccessFile file) { - int block, remaining; - int offset = 0; - int read; - - // read in chunks for progress bar - remaining = len; - - while (remaining != 0) { - block = Math.min(remaining, MAX_READ); - try { - read = file.read(buffer, offset, block); - } catch (IOException e) { - log.error(e.toString()); - throw new RuntimeException("Look log file"); - } - - if (read == 0) { - log.error("FS_Read: 0 bytes read"); - throw new RuntimeException("Look log file"); - } else if (read == -1) { - log.error("FS_Read: -1 bytes read"); - throw new RuntimeException("Look log file"); - } - // - // do some progress bar thing here... - // - remaining -= read; - offset += read; - } - } - - /* - * LoadFile - * - * Filename are reletive to the quake search path a null buffer will just - * return the file content as byte[] - */ - @Override - public byte[] loadFile(String path) { - RandomAccessFile file; - - byte[] buf = null; - int len; - - // TODO hack for bad strings (fuck \0) - int index = path.indexOf('\0'); - if (index != -1) - path = path.substring(0, index); - - // look for it in the filesystem or pack files - len = fileLength(path); - - if (len < 1) - return null; - - try { - file = FOpenFile(path); - //Read(buf = new byte[len], len, h); - buf = new byte[len]; - assert file != null; - file.readFully(buf); - file.close(); - } catch (IOException e) { - Com.Error(ErrorCode.ERR_FATAL, e.toString()); - } - return buf; - } - - /* - * LoadMappedFile - * - * Filename are reletive to the quake search path a null buffer will just - * return the file content as ByteBuffer (memory mapped) - */ - @Override - public ByteBuffer loadMappedFile(String filename) { - searchpath_t search; - String netpath; - pack_t pak; - File file; - - int fileLength; - FileChannel channel = null; - FileInputStream input = null; - ByteBuffer buffer; - - file_from_pak = 0; - - try { - // check for links first - for (filelink_t link : fs_links) { - if (filename.regionMatches(0, link.from, 0, link.fromlength)) { - netpath = link.to + filename.substring(link.fromlength); - file = new File(netpath); - if (file.canRead()) { - input = new FileInputStream(file); - channel = input.getChannel(); - fileLength = (int) channel.size(); - buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, - fileLength); - input.close(); - return buffer; - } - return null; - } - } - - // - // search through the path, one element at a time - // - for (search = fs_searchpaths; search != null; search = search.next) { - // is the element a pak file? - if (search.pack != null) { - // look through all the pak file elements - pak = search.pack; - filename = filename.toLowerCase(); - packfile_t entry = pak.files.get(filename); - - if (entry != null) { - // found it! - file_from_pak = 1; - //Com.DPrintf ("PackFile: " + pak.filename + " : " + - // filename + '\n'); - file = new File(pak.filename); - if (!file.canRead()) - Com.Error(ErrorCode.ERR_FATAL, "Couldn't reopen " - + pak.filename); - if (pak.handle == null || !pak.handle.getFD().valid()) { - // hold the pakfile handle open - pak.handle = new RandomAccessFile(pak.filename, "r"); - } - // open a new file on the pakfile - if (pak.backbuffer == null) { - channel = pak.handle.getChannel(); - pak.backbuffer = channel.map( - FileChannel.MapMode.READ_ONLY, 0, - pak.handle.length()); - channel.close(); - } - pak.backbuffer.position(entry.filepos); - buffer = pak.backbuffer.slice(); - buffer.limit(entry.filelen); - return buffer; - } - } else { - // check a file in the directory tree - netpath = search.filename + '/' + filename; - - file = new File(netpath); - if (!file.canRead()) - continue; - - //Com.DPrintf("FindFile: " + netpath +'\n'); - input = new FileInputStream(file); - channel = input.getChannel(); - fileLength = (int) channel.size(); - buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, - fileLength); - input.close(); - return buffer; - } - } - } catch (Exception ignored) { - } - try { - if (input != null) - input.close(); - else if (channel != null && channel.isOpen()) - channel.close(); - } catch (IOException ignored) { - } - return null; - } - - private static class dpackheader_t { - int ident; // IDPAKHEADER - int dirofs; - int dirlen; - } - - // buffer for C-Strings char[56] - private byte[] tmpText = new byte[packfile_t.NAME_SIZE]; - - /* - * LoadPackFile - * - * Takes an explicit (not game tree related) path to a pak file. - * - * Loads the header and directory, adding the files at the beginning of the - * printList so they override previous pack files. - */ - private pack_t loadPackFile(String packfile) { - dpackheader_t header; - Hashtable newfiles; - RandomAccessFile file; - int numpackfiles; - pack_t pack; - // unsigned checksum; - // - try { - file = new RandomAccessFile(packfile, "r"); - FileChannel fc = file.getChannel(); - ByteBuffer packhandle = fc.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); - packhandle.order(ByteOrder.LITTLE_ENDIAN); - - fc.close(); - - if (packhandle.limit() < 1) - return null; - // - header = new dpackheader_t(); - header.ident = packhandle.getInt(); - header.dirofs = packhandle.getInt(); - header.dirlen = packhandle.getInt(); - - if (header.ident != IDPAKHEADER) - Com.Error(ErrorCode.ERR_FATAL, packfile + " is not a packfile"); - - numpackfiles = header.dirlen / packfile_t.SIZE; - - if (numpackfiles > MAX_FILES_IN_PACK) - Com.Error(ErrorCode.ERR_FATAL, packfile + " has " + numpackfiles - + " files"); - - newfiles = new Hashtable<>(numpackfiles); - - packhandle.position(header.dirofs); - - // parse the directory - packfile_t entry; - - for (int i = 0; i < numpackfiles; i++) { - packhandle.get(tmpText); - - entry = new packfile_t(); - entry.name = new String(tmpText).trim(); - entry.filepos = packhandle.getInt(); - entry.filelen = packhandle.getInt(); - - newfiles.put(entry.name.toLowerCase(), entry); - UnpackTool.add(new UnpackTool.Entry( - entry.name, - entry.filepos, - entry.filelen, - packfile - )); - } - - } catch (IOException e) { - Com.DPrintf(e.getMessage() + '\n'); - return null; - } - - pack = new pack_t(); - pack.filename = packfile; - pack.handle = file; - pack.numfiles = numpackfiles; - pack.files = newfiles; - - log.info("Added packfile {} ({} files)", packfile, numpackfiles); - - return pack; - } - - /* - * AddGameDirectory - * - * Sets fs_gamedir, adds the directory to the head of the path, then loads - * and adds pak1.pak pak2.pak ... - */ - private void addGameDirectory(String dir) { - int i; - pack_t pak; - String pakfile; - - fs_gamedir = dir; - - // - // add the directory to the search path - // ensure fs_userdir is first in searchpath - searchpath_t search = new searchpath_t(); - search.filename = dir; - if (fs_searchpaths != null) { - search.next = fs_searchpaths.next; - fs_searchpaths.next = search; - } else { - fs_searchpaths = search; - } - - // - // add any pak files in the format pak0.pak pak1.pak, ... - // - for (i = 0; i < 10; i++) { - pakfile = dir + "/pak" + i + ".pak"; - if (!(new File(pakfile).canRead())) - continue; - - pak = loadPackFile(pakfile); - if (pak == null) - continue; - - search = new searchpath_t(); - search.pack = pak; - search.filename = ""; - search.next = fs_searchpaths; - fs_searchpaths = search; - } - - UnpackTool.printList(); - - final File baseq2UnpackDir = new File(dir, "_unpack"); - baseq2UnpackDir.mkdirs(); - - UnpackTool.list().forEach(entry -> { - File file = new File(baseq2UnpackDir, entry.getName()); - if (file.exists()) { - return; - } - - file.getParentFile().mkdirs(); - try (FileOutputStream fos = new FileOutputStream(file)) { - log.info("Write '{}'...", entry.getName()); - fos.write(entry.getBytes()); - } catch (IOException e) { - log.error("Can't write file '{}': {}", entry.getName(), e.getMessage()); - } - }); - } - - /* - * Gamedir - * - * Called to find where to write a file (demos, savegames, etc) - * this is modified to /.lwjake2 - */ - @Override - public String getGamedir() { - return (fs_userdir != null) ? fs_userdir : Globals.BASEDIRNAME; - } - - /* - * BaseGamedir - * - * Called to find where to write a downloaded file - */ - @Override - public String getBaseGamedir() { - return (fs_gamedir != null) ? fs_gamedir : Globals.BASEDIRNAME; - } - - /* - * ExecAutoexec - */ - @Override - public void execAutoexec() { - String dir = fs_userdir; - - String name; - if (dir != null && dir.length() > 0) { - name = dir + "/autoexec.cfg"; - } else { - name = fs_basedir.string + '/' + Globals.BASEDIRNAME - + "/autoexec.cfg"; - } - - int canthave = Defines.SFF_SUBDIR | Defines.SFF_HIDDEN - | Defines.SFF_SYSTEM; - - if (Sys.FindAll(name, 0, canthave) != null) { - Cbuf.AddText("exec autoexec.cfg\n"); - } - } - - /* - * SetGamedir - * - * Sets the gamedir and path to a different directory. - */ - @Override - public void setGamedir(String dir) { - searchpath_t next; - - if (dir.contains("..") || dir.contains("/") || dir.contains("\\") || dir.contains(":")) { - log.warn("Gamedir should be a single filename, not a path"); - return; - } - - // - // free up any current game dir info - // - while (fs_searchpaths != fs_base_searchpaths) { - if (fs_searchpaths.pack != null) { - try { - fs_searchpaths.pack.handle.close(); - } catch (IOException e) { - Com.DPrintf(e.getMessage() + '\n'); - } - // clear the hashtable - fs_searchpaths.pack.files.clear(); - fs_searchpaths.pack.files = null; - fs_searchpaths.pack = null; - } - next = fs_searchpaths.next; - fs_searchpaths = next; - } - - // - // flush all data, so it will be forced to reload - // - if ((Globals.dedicated != null) && (Globals.dedicated.value == 0.0f)) - Cbuf.AddText("vid_restart\nsnd_restart\n"); - - fs_gamedir = fs_basedir.string + '/' + dir; - - if (dir.equals(Globals.BASEDIRNAME) || (dir.length() == 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 != null && fs_cddir.string.length() > 0) - addGameDirectory(fs_cddir.string + '/' + dir); - - addGameDirectory(fs_basedir.string + '/' + dir); - } - } - - /* - * Link_f - * - * Creates a filelink_t - */ - private void link_f() { - filelink_t entry; - - if (Cmd.Argc() != 3) { - log.info("USAGE: link "); - return; - } - - // see if the link already exists - for (Iterator it = fs_links.iterator(); it.hasNext();) { - entry = it.next(); - - if (entry.from.equals(Cmd.Argv(1))) { - if (Cmd.Argv(2).length() < 1) { - // delete it - it.remove(); - return; - } - entry.to = Cmd.Argv(2); - return; - } - } - - // create a new link if the is not empty - if (Cmd.Argv(2).length() > 0) { - entry = new filelink_t(); - entry.from = Cmd.Argv(1); - entry.fromlength = entry.from.length(); - entry.to = Cmd.Argv(2); - fs_links.add(entry); - } - } - - /* - * ListFiles - */ - @Override - public String[] listFiles(String findname, int musthave, int canthave) { - String[] list = new String[0]; - - File[] files = Sys.FindAll(findname, musthave, canthave); - - if (files != null) { - list = new String[files.length]; - for (int i = 0; i < files.length; i++) { - list[i] = files[i].getPath(); - } - } - - return list; - } - - /* - * Dir_f - */ - private void dir_f() { - String path = null; - String findname; - String wildcard = "*.*"; - String[] dirnames; - - if (Cmd.Argc() != 1) { - wildcard = Cmd.Argv(1); - } - - while ((path = nextPath(path)) != null) { - findname = path + '/' + wildcard; - - log.info("Directory of {}", findname); - log.info("----"); - - dirnames = listFiles(findname, 0, 0); - - if (dirnames.length != 0) { - int index; - for (String dirname : dirnames) { - if ((index = dirname.lastIndexOf('/')) > 0) { - log.info(dirname.substring(index + 1, dirname.length())); - } else { - log.info(dirname); - } - } - } - - } - } - - /* - * Path_f - */ - private void path_f() { - searchpath_t s; - - log.info("Current search path:"); - for (s = fs_searchpaths; s != null; s = s.next) { - if (s == fs_base_searchpaths) - log.info("----------"); - if (s.pack != null) - log.info("{} ({} files)", s.pack.filename, s.pack.numfiles); - else - log.info(s.filename); - } - - log.info("Links:"); - for (filelink_t link : fs_links) { - log.info("{} : {}", link.from, link.to); - } - } - - /* - * NextPath - * - * Allows enumerating all of the directories in the search path - */ - @Override - public String nextPath(String prevpath) { - searchpath_t s; - String prev; - - if (prevpath == null || prevpath.length() == 0) - return fs_gamedir; - - prev = fs_gamedir; - for (s = fs_searchpaths; s != null; s = s.next) { - if (s.pack != null) - continue; - - if (prevpath.equals(prev)) - return s.filename; - - prev = s.filename; - } - - return null; - } - - /* - * InitFilesystem - */ - @Override - public void init() { - Cmd.AddCommand("path", this::path_f); - Cmd.AddCommand("link", this::link_f); - Cmd.AddCommand("dir", this::dir_f); - - fs_userdir = System.getProperty("user.home") + "/.lwjake2"; - createPath(fs_userdir + "/"); - addGameDirectory(fs_userdir); - - // - // basedir - // allows the game to run from outside the data tree - // - fs_basedir = Cvar.Get("basedir", ".", CVAR_NOSET); - - // - // cddir - // Logically concatenates the cddir after the basedir for - // allows the game to run from outside the data tree - // - - setCDDir(); - - // - // start up with baseq2 by default - // - addGameDirectory(fs_basedir.string + '/' + Globals.BASEDIRNAME); - - // any set gamedirs will be freed up to here - markBaseSearchPaths(); - - // check for game override - checkOverride(); - } - - /** - * set baseq2 directory - */ - @Override - public void setCDDir() { - fs_cddir = Cvar.Get("cddir", "", CVAR_ARCHIVE); - if (fs_cddir != null && fs_cddir.string.length() > 0) - addGameDirectory(fs_cddir.string + '/' + Globals.BASEDIRNAME); - } - - /** - * Check for "+set game" override - Used to properly set gamedir - */ - @Override - public void checkOverride() { - fs_gamedirvar = Cvar.Get("game", "", CVAR_LATCH | CVAR_SERVERINFO); - - if (fs_gamedirvar != null && fs_gamedirvar.string.length() > 0) { - setGamedir(fs_gamedirvar.string); - } - } - - @Override - public void markBaseSearchPaths() { - // any set gamedirs will be freed up to here - fs_base_searchpaths = fs_searchpaths; - } - - // RAFAEL - /* - * Developer_searchpath - */ - @Override - public int developer_searchpath(int who) { - // PMM - warning removal - // char *start; - searchpath_t s; - - for (s = fs_searchpaths; s != null; s = s.next) { - if (s.filename.contains("xatrix")) - return 1; - - if (s.filename.contains("rogue")) - return 2; - } - - return 0; - } - - @Override - public int getFileFromPak() { - return file_from_pak; - } - - @Override - public cvar_t getGamedirVar() { - return fs_gamedirvar; - } -} \ No newline at end of file diff --git a/src/main/java/lwjake2/qcommon/CM.java b/src/main/java/lwjake2/qcommon/CM.java index 7fd03c1..07b4821 100644 --- a/src/main/java/lwjake2/qcommon/CM.java +++ b/src/main/java/lwjake2/qcommon/CM.java @@ -21,6 +21,7 @@ package lwjake2.qcommon; import lwjake2.Defines; import lwjake2.ErrorCode; import lwjake2.Globals; +import lwjake2.UnpackLoader; import lwjake2.game.cmodel_t; import lwjake2.game.cplane_t; import lwjake2.game.cvar_t; @@ -38,7 +39,7 @@ import java.nio.IntBuffer; import java.util.Arrays; public class CM { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; public static class cnode_t { cplane_t plane; // ptr @@ -250,7 +251,7 @@ public class CM { // // load the file // - buf = fileSystem.loadFile(name); + buf = UnpackLoader.loadFile(name); if (buf == null) Com.Error(ErrorCode.ERR_DROP, "Couldn't load " + name); diff --git a/src/main/java/lwjake2/qcommon/Cvar.java b/src/main/java/lwjake2/qcommon/Cvar.java index 966b7bc..fc99cd1 100644 --- a/src/main/java/lwjake2/qcommon/Cvar.java +++ b/src/main/java/lwjake2/qcommon/Cvar.java @@ -36,7 +36,7 @@ import static lwjake2.Globals.cvar_vars; * Cvar implements console variables. The original code is located in cvar.c */ public class Cvar { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; /** * @param var_name diff --git a/src/main/java/lwjake2/qcommon/Qcommon.java b/src/main/java/lwjake2/qcommon/Qcommon.java index 473d616..3ba914a 100644 --- a/src/main/java/lwjake2/qcommon/Qcommon.java +++ b/src/main/java/lwjake2/qcommon/Qcommon.java @@ -20,10 +20,12 @@ package lwjake2.qcommon; import lombok.extern.slf4j.Slf4j; import lwjake2.Globals; +import lwjake2.UnpackLoader; import lwjake2.client.CL; import lwjake2.client.Key; import lwjake2.client.SCR; import lwjake2.game.Cmd; +import lwjake2.game.cvar_t; import lwjake2.server.SV_MAIN; import lwjake2.sys.NET; import lwjake2.sys.Sys; @@ -41,10 +43,15 @@ import static lwjake2.Defines.*; */ @Slf4j public final class Qcommon { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; public static final String BUILDSTRING = "Java " + System.getProperty("java.version");; public static final String CPUSTRING = System.getProperty("os.arch"); + private static void fileSystemInit() { + cvar_t basedir = Cvar.Get("basedir", ".", CVAR_NOSET); + UnpackLoader.setRootPath(basedir.string + '/' + Globals.BASEDIRNAME + "/_unpack"); + } + /** * This function initializes the different subsystems of * the game engine. The setjmp/longjmp mechanism of the original @@ -72,13 +79,13 @@ public final class Qcommon { Cbuf.AddEarlyCommands(false); Cbuf.Execute(); - fileSystem.init(); + fileSystemInit(); reconfigure(false); - fileSystem.setCDDir(); // use cddir from config.cfg - fileSystem.markBaseSearchPaths(); // mark the default search paths - fileSystem.checkOverride(); +// fileSystem.setCDDir(); // use cddir from config.cfg +// fileSystem.markBaseSearchPaths(); // mark the default search paths +// fileSystem.checkOverride(); reconfigure(true); // reload default.cfg and config.cfg diff --git a/src/main/java/lwjake2/render/lwjgl/Image.java b/src/main/java/lwjake2/render/lwjgl/Image.java index 848764c..0e93436 100644 --- a/src/main/java/lwjake2/render/lwjgl/Image.java +++ b/src/main/java/lwjake2/render/lwjgl/Image.java @@ -20,6 +20,7 @@ package lwjake2.render.lwjgl; import lwjake2.Defines; import lwjake2.ErrorCode; +import lwjake2.UnpackLoader; import lwjake2.client.VID; import lwjake2.client.particle_t; import lwjake2.game.cvar_t; @@ -49,7 +50,7 @@ import org.lwjgl.opengl.GL11; * @author cwei */ public abstract class Image extends Main { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; image_t draw_chars; @@ -448,7 +449,7 @@ public abstract class Image extends Main { // // load the file // - byte[] raw = fileSystem.loadFile(filename); + byte[] raw = UnpackLoader.loadFile(filename); if (raw == null) { VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + '\n'); @@ -545,7 +546,7 @@ public abstract class Image extends Main { // // load the file // - raw = fileSystem.loadFile(name); + raw = UnpackLoader.loadFile(name); if (raw == null) { @@ -1428,7 +1429,7 @@ public abstract class Image extends Main { image_t image; - byte[] raw = fileSystem.loadFile(name); + byte[] raw = UnpackLoader.loadFile(name); if (raw == null) { VID.Printf(Defines.PRINT_ALL, "GL_FindImage: can't load " + name + '\n'); return r_notexture; @@ -1612,7 +1613,7 @@ public abstract class Image extends Main { Draw_GetPalette(); if (qglColorTableEXT) { - gl_state.d_16to8table = fileSystem.loadFile("pics/16to8.dat"); + gl_state.d_16to8table = UnpackLoader.loadFile("pics/16to8.dat"); if (gl_state.d_16to8table == null) Com.Error(ErrorCode.ERR_FATAL, "Couldn't load pics/16to8.pcx"); } diff --git a/src/main/java/lwjake2/render/lwjgl/Misc.java b/src/main/java/lwjake2/render/lwjgl/Misc.java index 3ef03bb..71a85a5 100644 --- a/src/main/java/lwjake2/render/lwjgl/Misc.java +++ b/src/main/java/lwjake2/render/lwjgl/Misc.java @@ -19,8 +19,8 @@ package lwjake2.render.lwjgl; import lwjake2.Defines; +import lwjake2.Globals; import lwjake2.client.VID; -import lwjake2.qcommon.BaseQ2FileSystem; import java.io.File; import java.io.IOException; @@ -43,7 +43,7 @@ import org.lwjgl.opengl.GL12; * @author cwei */ public abstract class Misc extends Mesh { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; /* ================== @@ -123,7 +123,7 @@ public abstract class Misc extends Mesh { ================== */ void GL_ScreenShot_f() { - StringBuffer sb = new StringBuffer(fileSystem.getGamedir() + "/scrshot/jake00.tga"); + StringBuffer sb = new StringBuffer(Globals.BASEDIRNAME + "/scrshot/jake00.tga"); fileSystem.createPath(sb.toString()); File file = new File(sb.toString()); // find a valid file name diff --git a/src/main/java/lwjake2/render/lwjgl/Model.java b/src/main/java/lwjake2/render/lwjgl/Model.java index 532b107..5d68418 100644 --- a/src/main/java/lwjake2/render/lwjgl/Model.java +++ b/src/main/java/lwjake2/render/lwjgl/Model.java @@ -26,7 +26,7 @@ import lwjake2.game.cvar_t; import lwjake2.qcommon.Com; import lwjake2.qcommon.Cvar; import lwjake2.qcommon.FileSystem; -import lwjake2.qcommon.BaseQ2FileSystem; +import lwjake2.UnpackLoader; import lwjake2.qcommon.lump_t; import lwjake2.qcommon.qfiles; import lwjake2.qcommon.texinfo_t; @@ -56,7 +56,7 @@ import org.lwjgl.BufferUtils; * @author cwei */ public abstract class Model extends Surf { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; // models.c -- model loading and caching @@ -274,7 +274,7 @@ public abstract class Model extends Surf { // // load the file // - fileBuffer = fileSystem.loadFile(name); + fileBuffer = UnpackLoader.loadFile(name); if (fileBuffer == null) { diff --git a/src/main/java/lwjake2/server/SV_CCMDS.java b/src/main/java/lwjake2/server/SV_CCMDS.java index 87ed5d8..24d588a 100644 --- a/src/main/java/lwjake2/server/SV_CCMDS.java +++ b/src/main/java/lwjake2/server/SV_CCMDS.java @@ -31,7 +31,7 @@ import lwjake2.qcommon.CM; import lwjake2.qcommon.Com; import lwjake2.qcommon.Cvar; import lwjake2.qcommon.FileSystem; -import lwjake2.qcommon.BaseQ2FileSystem; +import lwjake2.UnpackLoader; import lwjake2.qcommon.MSG; import lwjake2.qcommon.Netchan; import lwjake2.qcommon.SZ; @@ -51,7 +51,7 @@ import java.util.Calendar; @Slf4j public class SV_CCMDS { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; /* =============================================================================== @@ -178,13 +178,13 @@ public class SV_CCMDS { Com.DPrintf("SV_WipeSaveGame(" + savename + ")\n"); - name = fileSystem.getGamedir() + "/save/" + savename + "/server.ssv"; + name = Globals.BASEDIRNAME + "/save/" + savename + "/server.ssv"; remove(name); - name = fileSystem.getGamedir() + "/save/" + savename + "/game.ssv"; + name = Globals.BASEDIRNAME + "/save/" + savename + "/game.ssv"; remove(name); - name = fileSystem.getGamedir() + "/save/" + savename + "/*.sav"; + name = Globals.BASEDIRNAME + "/save/" + savename + "/*.sav"; File f = Sys.FindFirst(name, 0, 0); while (f != null) { @@ -193,7 +193,7 @@ public class SV_CCMDS { } Sys.FindClose(); - name = fileSystem.getGamedir() + "/save/" + savename + "/*.sv2"; + name = Globals.BASEDIRNAME + "/save/" + savename + "/*.sv2"; f = Sys.FindFirst(name, 0, 0); @@ -283,23 +283,23 @@ public class SV_CCMDS { SV_WipeSavegame(dst); // copy the savegame over - name = fileSystem.getGamedir() + "/save/" + src + "/server.ssv"; - name2 = fileSystem.getGamedir() + "/save/" + dst + "/server.ssv"; - fileSystem.createPath(name2); + name = Globals.BASEDIRNAME + "/save/" + src + "/server.ssv"; + name2 = Globals.BASEDIRNAME + "/save/" + dst + "/server.ssv"; +// fileSystem.createPath(name2); CopyFile(name, name2); - name = fileSystem.getGamedir() + "/save/" + src + "/game.ssv"; - name2 = fileSystem.getGamedir() + "/save/" + dst + "/game.ssv"; + name = Globals.BASEDIRNAME + "/save/" + src + "/game.ssv"; + name2 = Globals.BASEDIRNAME + "/save/" + dst + "/game.ssv"; CopyFile(name, name2); - String name1 = fileSystem.getGamedir() + "/save/" + src + "/"; - name = fileSystem.getGamedir() + "/save/" + src + "/*.sav"; + String name1 = Globals.BASEDIRNAME + "/save/" + src + "/"; + name = Globals.BASEDIRNAME + "/save/" + src + "/*.sav"; found = Sys.FindFirst(name, 0, 0); while (found != null) { name = name1 + found.getName(); - name2 = fileSystem.getGamedir() + "/save/" + dst + "/" + found.getName(); + name2 = Globals.BASEDIRNAME + "/save/" + dst + "/" + found.getName(); CopyFile(name, name2); @@ -326,7 +326,7 @@ public class SV_CCMDS { Com.DPrintf("SV_WriteLevelFile()\n"); - name = fileSystem.getGamedir() + "/save/current/" + SV_INIT.sv.name + ".sv2"; + name = Globals.BASEDIRNAME + "/save/current/" + SV_INIT.sv.name + ".sv2"; try { f = new QuakeFile(name, "rw"); @@ -342,7 +342,7 @@ public class SV_CCMDS { e.printStackTrace(); } - name = fileSystem.getGamedir() + "/save/current/" + SV_INIT.sv.name + ".sav"; + name = Globals.BASEDIRNAME + "/save/current/" + SV_INIT.sv.name + ".sav"; GameSave.WriteLevel(name); } /* @@ -358,7 +358,7 @@ public class SV_CCMDS { Com.DPrintf("SV_ReadLevelFile()\n"); - name = fileSystem.getGamedir() + "/save/current/" + SV_INIT.sv.name + ".sv2"; + name = Globals.BASEDIRNAME + "/save/current/" + SV_INIT.sv.name + ".sv2"; try { f = new QuakeFile(name, "r"); @@ -374,7 +374,7 @@ public class SV_CCMDS { e1.printStackTrace(); } - name = fileSystem.getGamedir() + "/save/current/" + SV_INIT.sv.name + ".sav"; + name = Globals.BASEDIRNAME + "/save/current/" + SV_INIT.sv.name + ".sav"; GameSave.ReadLevel(name); } /* @@ -391,7 +391,7 @@ public class SV_CCMDS { Com.DPrintf("SV_WriteServerFile(" + (autosave ? "true" : "false") + ")\n"); - filename = fileSystem.getGamedir() + "/save/current/server.ssv"; + filename = Globals.BASEDIRNAME + "/save/current/server.ssv"; try { f = new QuakeFile(filename, "rw"); @@ -444,7 +444,7 @@ public class SV_CCMDS { } // write game state - filename = fileSystem.getGamedir() + "/save/current/game.ssv"; + filename = Globals.BASEDIRNAME + "/save/current/game.ssv"; GameSave.WriteGame(filename, autosave); } /* @@ -462,7 +462,7 @@ public class SV_CCMDS { Com.DPrintf("SV_ReadServerFile()\n"); - filename = fileSystem.getGamedir() + "/save/current/server.ssv"; + filename = Globals.BASEDIRNAME + "/save/current/server.ssv"; f = new QuakeFile(filename, "r"); @@ -489,7 +489,7 @@ public class SV_CCMDS { SV_INIT.svs.mapcmd = mapcmd; // read game state - filename = fileSystem.getGamedir() + "/save/current/game.ssv"; + filename = Globals.BASEDIRNAME + "/save/current/game.ssv"; GameSave.ReadGame(filename); } catch (Exception e) { @@ -540,7 +540,7 @@ public class SV_CCMDS { Com.DPrintf("SV_GameMap(" + Cmd.Argv(1) + ")\n"); - fileSystem.createPath(fileSystem.getGamedir() + "/save/current/"); +// fileSystem.createPath(Globals.BASEDIRNAME + "/save/current/"); // check for clearing the current savegame map = Cmd.Argv(1); @@ -601,7 +601,7 @@ public class SV_CCMDS { map = Cmd.Argv(1); if (map.indexOf(".") < 0) { expanded = "maps/" + map + ".bsp"; - if (fileSystem.loadFile(expanded) == null) { + if (UnpackLoader.loadFile(expanded) == null) { Com.Printf("Can't find " + expanded + "\n"); return; @@ -646,7 +646,7 @@ public class SV_CCMDS { } // make sure the server.ssv file exists - name = fileSystem.getGamedir() + "/save/" + Cmd.Argv(1) + "/server.ssv"; + name = Globals.BASEDIRNAME + "/save/" + Cmd.Argv(1) + "/server.ssv"; try { f = new RandomAccessFile(name, "r"); } @@ -915,7 +915,7 @@ public class SV_CCMDS { // // open the demo file // - name = fileSystem.getGamedir() + "/demos/" + Cmd.Argv(1) + ".dm2"; + name = Globals.BASEDIRNAME + "/demos/" + Cmd.Argv(1) + ".dm2"; Com.Printf("recording to " + name + ".\n"); fileSystem.createPath(name); diff --git a/src/main/java/lwjake2/server/SV_INIT.java b/src/main/java/lwjake2/server/SV_INIT.java index ecc1313..46b2d09 100644 --- a/src/main/java/lwjake2/server/SV_INIT.java +++ b/src/main/java/lwjake2/server/SV_INIT.java @@ -33,8 +33,6 @@ import lwjake2.qcommon.CM; import lwjake2.qcommon.Cbuf; import lwjake2.qcommon.Com; import lwjake2.qcommon.Cvar; -import lwjake2.qcommon.FileSystem; -import lwjake2.qcommon.BaseQ2FileSystem; import lwjake2.qcommon.MSG; import lwjake2.qcommon.PMove; import lwjake2.qcommon.SZ; @@ -47,7 +45,7 @@ import java.io.RandomAccessFile; @Slf4j public class SV_INIT { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; /** * SV_FindIndex. */ @@ -137,7 +135,7 @@ public class SV_INIT { if (Cvar.VariableValue("deathmatch") != 0) return; - name = fileSystem.getGamedir() + "/save/current/" + sv.name + ".sav"; + name = Globals.BASEDIRNAME + "/save/current/" + sv.name + ".sav"; try { f = new RandomAccessFile(name, "r"); } diff --git a/src/main/java/lwjake2/server/SV_USER.java b/src/main/java/lwjake2/server/SV_USER.java index 03a55d0..4332a03 100644 --- a/src/main/java/lwjake2/server/SV_USER.java +++ b/src/main/java/lwjake2/server/SV_USER.java @@ -21,6 +21,7 @@ package lwjake2.server; import lwjake2.Defines; import lwjake2.ErrorCode; import lwjake2.Globals; +import lwjake2.UnpackLoader; import lwjake2.game.Cmd; import lwjake2.game.GameBase; import lwjake2.game.Info; @@ -31,10 +32,8 @@ import lwjake2.game.usercmd_t; import lwjake2.qcommon.*; import lwjake2.util.Lib; -import java.io.IOException; - public class SV_USER { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; static edict_t sv_player; @@ -84,11 +83,7 @@ public class SV_USER { String name; name = "demos/" + SV_INIT.sv.name; - try { - SV_INIT.sv.demofile = fileSystem.FOpenFile(name); - } catch (IOException e) { - Com.Error(ErrorCode.ERR_DROP, "Couldn't open " + name + "\n"); - } + SV_INIT.sv.demofile = UnpackLoader.loadFileAsRAF(name); if (SV_INIT.sv.demofile == null) Com.Error(ErrorCode.ERR_DROP, "Couldn't open " + name + "\n"); } @@ -375,7 +370,7 @@ public class SV_USER { if (SV_MAIN.sv_client.download != null) SV_MAIN.sv_client.download = null; - SV_MAIN.sv_client.download = fileSystem.loadFile(name); + SV_MAIN.sv_client.download = UnpackLoader.loadFile(name); // rst: this handles loading errors, no message yet visible if (SV_MAIN.sv_client.download == null) @@ -393,7 +388,7 @@ public class SV_USER { // came from a pak file, don't // allow // download ZOID - || (name.startsWith("maps/") && fileSystem.getFileFromPak() != 0)) { + || (name.startsWith("maps/") /*&& fileSystem.getFileFromPak() != 0*/)) { Com.DPrintf("Couldn't download " + name + " to " + SV_MAIN.sv_client.name + "\n"); if (SV_MAIN.sv_client.download != null) { diff --git a/src/main/java/lwjake2/sound/WaveLoader.java b/src/main/java/lwjake2/sound/WaveLoader.java index 605d641..ab472dd 100644 --- a/src/main/java/lwjake2/sound/WaveLoader.java +++ b/src/main/java/lwjake2/sound/WaveLoader.java @@ -21,16 +21,15 @@ package lwjake2.sound; import lombok.extern.slf4j.Slf4j; import lwjake2.Defines; import lwjake2.ErrorCode; -import lwjake2.qcommon.BaseQ2FileSystem; +import lwjake2.UnpackLoader; import lwjake2.qcommon.Com; -import lwjake2.qcommon.FileSystem; /** * SND_MEM */ @Slf4j public class WaveLoader { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); +// private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; /** * The ResampleSfx can squeeze and stretch samples to a default sample rate. * Since Joal and lwjgl sound drivers support this, we don't need it and the samples @@ -69,7 +68,7 @@ public class WaveLoader { else namebuffer = "sound/" + name; - byte[] data = fileSystem.loadFile(namebuffer); + byte[] data = UnpackLoader.loadFile(namebuffer); if (data == null) { Com.DPrintf("Couldn't load " + namebuffer + "\n"); diff --git a/src/main/java/lwjake2/sound/lwjgl/LWJGLSoundImpl.java b/src/main/java/lwjake2/sound/lwjgl/LWJGLSoundImpl.java index 0a9c4b9..7297347 100644 --- a/src/main/java/lwjake2/sound/lwjgl/LWJGLSoundImpl.java +++ b/src/main/java/lwjake2/sound/lwjgl/LWJGLSoundImpl.java @@ -22,6 +22,7 @@ import lombok.extern.slf4j.Slf4j; import lwjake2.Defines; import lwjake2.ErrorCode; import lwjake2.Globals; +import lwjake2.UnpackLoader; import lwjake2.game.Cmd; import lwjake2.game.GameBase; import lwjake2.game.cvar_t; @@ -33,7 +34,6 @@ import lwjake2.sound.WaveLoader; import lwjake2.sound.sfx_t; import lwjake2.sound.sfxcache_t; import lwjake2.util.Lib; -import lwjake2.util.Vargs; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -56,7 +56,7 @@ import org.lwjgl.openal.OpenALException; */ @Slf4j public final class LWJGLSoundImpl implements Sound { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; static { S.register(new LWJGLSoundImpl()); }; @@ -363,7 +363,7 @@ public final class LWJGLSoundImpl implements Sound { // fall back strategies // // not found , so see if it exists - if (fileSystem.fileLength(sexedFilename.substring(1)) > 0) { + if (UnpackLoader.exists(sexedFilename.substring(1))) { // yes, register it return RegisterSound(sexedFilename); } diff --git a/src/main/java/lwjake2/util/Lib.java b/src/main/java/lwjake2/util/Lib.java index 626f72d..d096e2d 100644 --- a/src/main/java/lwjake2/util/Lib.java +++ b/src/main/java/lwjake2/util/Lib.java @@ -20,7 +20,6 @@ package lwjake2.util; import lombok.extern.slf4j.Slf4j; import lwjake2.Globals; -import lwjake2.qcommon.BaseQ2FileSystem; import lwjake2.qcommon.Com; import lwjake2.qcommon.FileSystem; @@ -35,7 +34,7 @@ import java.nio.IntBuffer; @Slf4j public class Lib { - private static final FileSystem fileSystem = BaseQ2FileSystem.getInstance(); + private static final FileSystem fileSystem = null/*BaseQ2FileSystem.getInstance()*/; /** Converts a vector to a string. */ public static String vtos(float[] v) { return (int) v[0] + " " + (int) v[1] + " " + (int) v[2]; From 5aa02c5d8dfbdf49044e63fb0f2babcd7b6fbda7 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 21 Mar 2019 17:15:20 +0300 Subject: [PATCH 3/3] gradle fix run --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index e57f221..70fccae 100644 --- a/build.gradle +++ b/build.gradle @@ -67,3 +67,8 @@ tasks.run.doFirst { mainClassName = 'lwjake2.LWJake2' applicationDefaultJvmArgs = ["-Djava.library.path=$buildDir/natives/$platform"] }.dependsOn(unpackNatibeLibraries) + +run { + mainClassName = 'lwjake2.LWJake2' + applicationDefaultJvmArgs = ["-Djava.library.path=$buildDir/natives/$platform"] +} \ No newline at end of file