mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
custom asset archive loading
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Terrarum (no prebuild)" type="JarApplication">
|
<configuration default="false" name="Terrarum (no prebuild, release-mode assets)" type="JarApplication">
|
||||||
<option name="JAR_PATH" value="$PROJECT_DIR$/out/TerrarumBuild.jar" />
|
<option name="JAR_PATH" value="$PROJECT_DIR$/out/TerrarumBuild.jar" />
|
||||||
<option name="VM_PARAMETERS" value="-ea -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd" />
|
<option name="VM_PARAMETERS" value="-ea -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="--assets buildapp/out/assets.tevd" />
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
<option name="ALTERNATIVE_JRE_PATH" value="17" />
|
<option name="ALTERNATIVE_JRE_PATH" value="17" />
|
||||||
<module name="TerrarumBuild" />
|
<module name="TerrarumBuild" />
|
||||||
@@ -342,6 +342,14 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
public static boolean hasUpdate = true;
|
public static boolean hasUpdate = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to a specific .tevd assets archive supplied via the --assets command-line argument.
|
||||||
|
* When non-null, this archive is used exclusively; the default ./assets.tevd and the
|
||||||
|
* local ./assets/ directory are both ignored.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static String overrideAssetArchive = null;
|
||||||
|
|
||||||
public static Screen getCurrentScreen() {
|
public static Screen getCurrentScreen() {
|
||||||
return currentScreen;
|
return currentScreen;
|
||||||
}
|
}
|
||||||
@@ -381,6 +389,17 @@ public class App implements ApplicationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
// System.out.println("Arguments: "+String.join(",", args));
|
||||||
|
|
||||||
|
// Parse command-line arguments before anything else
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
if (args[i].equals("--assets") && i + 1 < args.length) {
|
||||||
|
overrideAssetArchive = args[i + 1];
|
||||||
|
System.out.println("Using custom assets: "+overrideAssetArchive);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loadedTime_t = getTIME_T();
|
loadedTime_t = getTIME_T();
|
||||||
|
|
||||||
updateBogoflops(100_000_000L);
|
updateBogoflops(100_000_000L);
|
||||||
@@ -441,7 +460,7 @@ public class App implements ApplicationListener {
|
|||||||
// load configs
|
// load configs
|
||||||
getDefaultDirectory();
|
getDefaultDirectory();
|
||||||
createDirs();
|
createDirs();
|
||||||
AssetCache.INSTANCE.init();
|
AssetCache.INSTANCE.init(overrideAssetArchive);
|
||||||
initialiseConfig();
|
initialiseConfig();
|
||||||
readConfigJson();
|
readConfigJson();
|
||||||
|
|
||||||
|
|||||||
@@ -19,20 +19,30 @@ import java.io.RandomAccessFile
|
|||||||
*/
|
*/
|
||||||
object AssetCache {
|
object AssetCache {
|
||||||
|
|
||||||
private val archivePath = File("./assets.tevd")
|
private val defaultArchivePath = File("./assets.tevd")
|
||||||
|
|
||||||
/** Whether we're running from a distribution archive */
|
/** Whether we're running from a distribution archive */
|
||||||
val isDistribution: Boolean get() = archivePath.exists()
|
val isDistribution: Boolean get() = dom != null
|
||||||
|
|
||||||
private var dom: ClusteredFormatDOM? = null
|
private var dom: ClusteredFormatDOM? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the archive on startup. Call early, after defaultDir is set.
|
* Open the archive on startup. Call early, after defaultDir is set.
|
||||||
|
*
|
||||||
|
* @param overridePath When non-null, load this specific .tevd archive exclusively,
|
||||||
|
* ignoring both the default ./assets.tevd and the ./assets/ directory.
|
||||||
*/
|
*/
|
||||||
fun init() {
|
@JvmOverloads
|
||||||
if (isDistribution) {
|
fun init(overridePath: String? = null) {
|
||||||
println("[AssetCache] Distribution mode: opening ${archivePath.path}")
|
if (overridePath != null) {
|
||||||
dom = ClusteredFormatDOM(RandomAccessFile(archivePath, "r"))
|
val f = File(overridePath)
|
||||||
|
if (!f.exists()) throw FileNotFoundException("Specified assets archive not found: $overridePath")
|
||||||
|
println("[AssetCache] Override archive: opening ${f.path}")
|
||||||
|
dom = ClusteredFormatDOM(RandomAccessFile(f, "r"))
|
||||||
|
println("[AssetCache] Override archive opened successfully")
|
||||||
|
} else if (defaultArchivePath.exists()) {
|
||||||
|
println("[AssetCache] Distribution mode: opening ${defaultArchivePath.path}")
|
||||||
|
dom = ClusteredFormatDOM(RandomAccessFile(defaultArchivePath, "r"))
|
||||||
println("[AssetCache] Archive opened successfully")
|
println("[AssetCache] Archive opened successfully")
|
||||||
} else {
|
} else {
|
||||||
println("[AssetCache] No archive found, using loose assets (development mode)")
|
println("[AssetCache] No archive found, using loose assets (development mode)")
|
||||||
@@ -41,13 +51,12 @@ object AssetCache {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a Clustfile for a path relative to the assets root.
|
* Get a Clustfile for a path relative to the assets root.
|
||||||
|
*
|
||||||
|
* Note: nothing guarantees the file's actual existence!
|
||||||
*/
|
*/
|
||||||
fun getClustfile(relativePath: String): Clustfile {
|
fun getClustfile(relativePath: String): Clustfile {
|
||||||
val path = if (relativePath.startsWith("/")) relativePath else "/$relativePath"
|
val path = if (relativePath.startsWith("/")) relativePath else "/$relativePath"
|
||||||
return Clustfile(dom!!, path).let {
|
return Clustfile(dom!!, path)
|
||||||
if (!it.exists()) throw FileNotFoundException("Clustfile not exists: /$relativePath")
|
|
||||||
else it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package net.torvald.terrarum
|
package net.torvald.terrarum
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Files
|
||||||
import com.badlogic.gdx.files.FileHandle
|
import com.badlogic.gdx.files.FileHandle
|
||||||
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.Clustfile
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.Clustfile
|
||||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClustfileInputStream
|
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClustfileInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A GDX FileHandle backed by a Clustfile from TerranVirtualDisk.
|
* A GDX FileHandle backed by a Clustfile from TerranVirtualDisk.
|
||||||
* Allows transparent asset loading from .tevd archives using all standard GDX APIs.
|
* Allows transparent asset loading from .tevd archives using all standard GDX APIs.
|
||||||
@@ -30,6 +33,10 @@ class ClustfileHandle(private val clustfile: Clustfile) : FileHandle() {
|
|||||||
|
|
||||||
override fun path(): String = clustfile.path
|
override fun path(): String = clustfile.path
|
||||||
|
|
||||||
|
init {
|
||||||
|
type = Files.FileType.Internal // just a dummy value
|
||||||
|
}
|
||||||
|
|
||||||
override fun extension(): String {
|
override fun extension(): String {
|
||||||
val n = name()
|
val n = name()
|
||||||
val dotIndex = n.lastIndexOf('.')
|
val dotIndex = n.lastIndexOf('.')
|
||||||
@@ -62,5 +69,12 @@ class ClustfileHandle(private val clustfile: Clustfile) : FileHandle() {
|
|||||||
return File(clustfile.path)
|
return File(clustfile.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun sibling(name: String?): FileHandle {
|
||||||
|
if (name == null) throw GdxRuntimeException("Sibling name must not be null.")
|
||||||
|
val parentPath = clustfile.parent ?: throw GdxRuntimeException("Cannot get the sibling of the root.")
|
||||||
|
val siblingPath = if (parentPath.endsWith("/")) "$parentPath$name" else "$parentPath/$name"
|
||||||
|
return ClustfileHandle(Clustfile(clustfile.DOM, siblingPath))
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String = clustfile.path
|
override fun toString(): String = clustfile.path
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -340,9 +340,7 @@ object ModMgr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
printdbgerr(this, "Module failed to load, skipping: $moduleName")
|
printdbgerr(this, "Module failed to load, skipping: $moduleName\nstacktrace:\n${e.stackTraceToString()}")
|
||||||
printdbgerr(this, "\t$e")
|
|
||||||
print(App.csiR); e.printStackTrace(System.out); print(App.csi0)
|
|
||||||
|
|
||||||
logError(LoadErrorType.YOUR_FAULT, moduleName, e)
|
logError(LoadErrorType.YOUR_FAULT, moduleName, e)
|
||||||
|
|
||||||
@@ -370,7 +368,7 @@ object ModMgr {
|
|||||||
printmsg(this, "Module processed: $moduleName")
|
printmsg(this, "Module processed: $moduleName")
|
||||||
}
|
}
|
||||||
catch (noSuchModule: FileNotFoundException) {
|
catch (noSuchModule: FileNotFoundException) {
|
||||||
printmsgerr(this, "No such module, skipping: $moduleName")
|
printmsgerr(this, "No such module, skipping: $moduleName\nstacktrace:\n${noSuchModule.stackTraceToString()}")
|
||||||
|
|
||||||
logError(LoadErrorType.NOT_EVEN_THERE, moduleName, noSuchModule)
|
logError(LoadErrorType.NOT_EVEN_THERE, moduleName, noSuchModule)
|
||||||
|
|
||||||
@@ -397,9 +395,7 @@ object ModMgr {
|
|||||||
// TODO: Instead of skipping module with error, just display the error message onto the face?
|
// TODO: Instead of skipping module with error, just display the error message onto the face?
|
||||||
|
|
||||||
|
|
||||||
printmsgerr(this, "There was an error while loading module $moduleName")
|
printmsgerr(this, "There was an error while loading module $moduleName\nstacktrace:\n${e.stackTraceToString()}")
|
||||||
printmsgerr(this, "\t$e")
|
|
||||||
print(App.csiR); e.printStackTrace(System.out); print(App.csi0)
|
|
||||||
|
|
||||||
logError(LoadErrorType.YOUR_FAULT, moduleName, e)
|
logError(LoadErrorType.YOUR_FAULT, moduleName, e)
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class Principii {
|
public class Principii {
|
||||||
|
|
||||||
private static KVHashMap gameConfig = new KVHashMap();
|
private static final KVHashMap gameConfig = new KVHashMap();
|
||||||
|
|
||||||
private static String OSName = System.getProperty("os.name");
|
private static final String OSName = System.getProperty("os.name");
|
||||||
|
|
||||||
private static String operationSystem;
|
private static String operationSystem;
|
||||||
/** %appdata%/Terrarum, without trailing slash */
|
/** %appdata%/Terrarum, without trailing slash */
|
||||||
@@ -27,27 +27,29 @@ public class Principii {
|
|||||||
/** defaultDir + "/config.json" */
|
/** defaultDir + "/config.json" */
|
||||||
private static String configDir;
|
private static String configDir;
|
||||||
|
|
||||||
|
private static final String GAME_NAME = TerrarumAppConfiguration.INSTANCE.getGAME_NAME_FOR_FILESYSTEM();
|
||||||
|
|
||||||
public static void getDefaultDirRoot() {
|
public static void getDefaultDirRoot() {
|
||||||
String OS = OSName.toUpperCase();
|
String OS = OSName.toUpperCase();
|
||||||
if (OS.contains("WIN")) {
|
if (OS.contains("WIN")) {
|
||||||
operationSystem = "WINDOWS";
|
operationSystem = "WINDOWS";
|
||||||
defaultDir = System.getenv("APPDATA") + "/Terrarum";
|
defaultDir = System.getenv("APPDATA") + "/" + GAME_NAME;
|
||||||
}
|
}
|
||||||
else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond
|
else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond
|
||||||
operationSystem = "OSX";
|
operationSystem = "OSX";
|
||||||
defaultDir = System.getProperty("user.home") + "/Library/Application Support/Terrarum";
|
defaultDir = System.getProperty("user.home") + "/Library/Application Support/" + GAME_NAME;
|
||||||
}
|
}
|
||||||
else if (OS.contains("NUX") || OS.contains("NIX") || OS.contains("BSD")) {
|
else if (OS.contains("NUX") || OS.contains("NIX") || OS.contains("BSD")) {
|
||||||
operationSystem = "LINUX";
|
operationSystem = "LINUX";
|
||||||
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
defaultDir = System.getProperty("user.home") + "/." + GAME_NAME;
|
||||||
}
|
}
|
||||||
else if (OS.contains("SUNOS")) {
|
else if (OS.contains("SUNOS")) {
|
||||||
operationSystem = "SOLARIS";
|
operationSystem = "SOLARIS";
|
||||||
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
defaultDir = System.getProperty("user.home") + "/." + GAME_NAME;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
operationSystem = "UNKNOWN";
|
operationSystem = "UNKNOWN";
|
||||||
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
defaultDir = System.getProperty("user.home") + "/." + GAME_NAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,8 +137,9 @@ public class Principii {
|
|||||||
cmd0.add("-Xms1G");
|
cmd0.add("-Xms1G");
|
||||||
cmd0.add("-Xmx"+xmx+"G");
|
cmd0.add("-Xmx"+xmx+"G");
|
||||||
cmd0.add("-cp");
|
cmd0.add("-cp");
|
||||||
cmd0.add("./out/TerrarumBuild.jar");
|
cmd0.add("./out/" + TerrarumAppConfiguration.JAR_NAME);
|
||||||
cmd0.add(cp);
|
cmd0.add(cp);
|
||||||
|
cmd0.addAll(List.of(args));
|
||||||
var cmd = cmd0.stream().filter((it) -> !it.isBlank()).toList();
|
var cmd = cmd0.stream().filter((it) -> !it.isBlank()).toList();
|
||||||
|
|
||||||
System.out.println(cmd);
|
System.out.println(cmd);
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ object TerrarumAppConfiguration {
|
|||||||
// CONFIGURATION FOR THE APP ITSELF //
|
// CONFIGURATION FOR THE APP ITSELF //
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
const val GAME_NAME = "Terrarum"
|
const val GAME_NAME = "Terrarum"
|
||||||
|
const val JAR_NAME = "TerrarumBuild.jar" // must match what's on the buildapp scripts
|
||||||
|
val GAME_NAME_FOR_FILESYSTEM = GAME_NAME.replace(' ', '_')
|
||||||
const val COPYRIGHT_DATE_NAME = "© 2013-2026 CuriousToꝛvald (minjaesong)"
|
const val COPYRIGHT_DATE_NAME = "© 2013-2026 CuriousToꝛvald (minjaesong)"
|
||||||
val COPYRIGHT_LICENSE: String; get() = Lang["COPYRIGHT_GNU_GPL_3"]
|
val COPYRIGHT_LICENSE: String; get() = Lang["COPYRIGHT_GNU_GPL_3"]
|
||||||
const val COPYRIGHT_LICENSE_ENGLISH = "Distributed under GNU GPL 3"
|
const val COPYRIGHT_LICENSE_ENGLISH = "Distributed under GNU GPL 3"
|
||||||
@@ -38,7 +40,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
# Modules are loaded from top to bottom.
|
# Modules are loaded from top to bottom.
|
||||||
# Name of the module corresponds with the name of the directory the module is stored in,
|
# Name of the module corresponds with the name of the directory the module is stored in,
|
||||||
# typically under:
|
# typically under:
|
||||||
# 1. assets/mods of the installation path (the modules comes with the release of the game)
|
# 1. assets.tevd/mods of the installation path (the modules comes with the release of the game)
|
||||||
# 2. %APPDATA%/Modules (the modules installed by the user)
|
# 2. %APPDATA%/Modules (the modules installed by the user)
|
||||||
# where %APPDATA% is:
|
# where %APPDATA% is:
|
||||||
# Windows -- C:\Users\<username>\AppData\Roaming\Terrarum
|
# Windows -- C:\Users\<username>\AppData\Roaming\Terrarum
|
||||||
|
|||||||
Reference in New Issue
Block a user