mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
asset archiving wip, font update
This commit is contained in:
@@ -2017,15 +2017,15 @@ object BTeXParser {
|
||||
private lateinit var subtitleFont: TerrarumSansBitmap
|
||||
|
||||
fun preloadFonts() {
|
||||
testFont = TerrarumSansBitmap(App.FONT_DIR, shadowAlpha = bodyTextShadowAlpha, textCacheSize = 4096)
|
||||
partTitleFont = TerrarumSansBitmap(App.FONT_DIR, shadowAlpha = bodyTextShadowAlpha).also {
|
||||
testFont = TerrarumSansBitmap(shadowAlpha = bodyTextShadowAlpha, textCacheSize = 4096)
|
||||
partTitleFont = TerrarumSansBitmap(shadowAlpha = bodyTextShadowAlpha).also {
|
||||
it.interchar = 1
|
||||
}
|
||||
titleFont = TerrarumSansBitmap(App.FONT_DIR).also {
|
||||
titleFont = TerrarumSansBitmap().also {
|
||||
it.interchar = 1
|
||||
it.scale = 2
|
||||
}
|
||||
subtitleFont = TerrarumSansBitmap(App.FONT_DIR).also {
|
||||
subtitleFont = TerrarumSansBitmap().also {
|
||||
it.interchar = 1
|
||||
}
|
||||
fontInit = true
|
||||
|
||||
@@ -255,10 +255,6 @@ public class App implements ApplicationListener {
|
||||
public static DebugTimers debugTimers = new DebugTimers();
|
||||
|
||||
|
||||
public static final String FONT_DIR = "assets/graphics/fonts/terrarum-sans-bitmap";
|
||||
|
||||
|
||||
|
||||
public static Texture[] ditherPatterns = new Texture[4];
|
||||
// public static ShaderProgram shaderHicolour;
|
||||
public static ShaderProgram shaderDebugDiff;
|
||||
@@ -445,6 +441,7 @@ public class App implements ApplicationListener {
|
||||
// load configs
|
||||
getDefaultDirectory();
|
||||
createDirs();
|
||||
AssetCache.INSTANCE.init();
|
||||
initialiseConfig();
|
||||
readConfigJson();
|
||||
|
||||
@@ -582,13 +579,13 @@ public class App implements ApplicationListener {
|
||||
if (!loadOrder.isEmpty()) {
|
||||
var modname = loadOrder.get(0).get(0);
|
||||
|
||||
var textureFile = Gdx.files.internal("assets/mods/"+modname+"/splashback.png");
|
||||
var textureFile = AssetCache.INSTANCE.getFileHandle("mods/"+modname+"/splashback.png");
|
||||
if (textureFile.exists()) {
|
||||
splashBackdrop = new TextureRegion(new Texture(textureFile));
|
||||
splashTextCol = new Color(0xeeeeeeff);
|
||||
}
|
||||
|
||||
var logoFile = Gdx.files.internal("assets/mods/"+modname+"/splashlogo.png");
|
||||
var logoFile = AssetCache.INSTANCE.getFileHandle("mods/"+modname+"/splashlogo.png");
|
||||
if (logoFile.exists()) {
|
||||
splashScreenLogo = new TextureRegion(new Texture(logoFile));
|
||||
}
|
||||
@@ -604,10 +601,10 @@ public class App implements ApplicationListener {
|
||||
}
|
||||
|
||||
if (splashBackdrop == null) {
|
||||
splashBackdrop = new TextureRegion(new Texture("assets/graphics/background_white.png"));
|
||||
splashBackdrop = new TextureRegion(new Texture(AssetCache.INSTANCE.getFileHandle("graphics/background_white.png")));
|
||||
}
|
||||
if (splashScreenLogo == null) {
|
||||
splashScreenLogo = new TextureRegion(new Texture("assets/graphics/logo.png"));
|
||||
splashScreenLogo = new TextureRegion(new Texture(AssetCache.INSTANCE.getFileHandle("graphics/logo.png")));
|
||||
}
|
||||
|
||||
Gdx.graphics.setContinuousRendering(true);
|
||||
@@ -622,13 +619,13 @@ public class App implements ApplicationListener {
|
||||
|
||||
ShaderMgr.INSTANCE.compile(Gdx.files.classpath("shaders/shaders.csv"));
|
||||
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("title_health1", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_take_a_break.tga")));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("title_health2", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_distance.tga")));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bup", () -> new MusicContainer("haptic_bup", Gdx.files.internal("./assets/audio/effects/haptic_bup.ogg").file(), false, true, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bap", () -> new MusicContainer("haptic_bap", Gdx.files.internal("./assets/audio/effects/haptic_bap.ogg").file(), false, true, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bop", () -> new MusicContainer("haptic_bop", Gdx.files.internal("./assets/audio/effects/haptic_bop.ogg").file(), false, true, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bep", () -> new MusicContainer("haptic_bep", Gdx.files.internal("./assets/audio/effects/haptic_bep.ogg").file(), false, true, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bip", () -> new MusicContainer("haptic_bip", Gdx.files.internal("./assets/audio/effects/haptic_bip.ogg").file(), false, true, (AudioBank m) -> { highPrioritySoundPlaying = false; return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("title_health1", () -> new Texture(AssetCache.INSTANCE.getFileHandle("graphics/gui/health_take_a_break.tga")));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("title_health2", () -> new Texture(AssetCache.INSTANCE.getFileHandle("graphics/gui/health_distance.tga")));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bup", () -> new MusicContainer("haptic_bup", AssetCache.INSTANCE.getFileHandle("audio/effects/haptic_bup.ogg"), false, true, null, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bap", () -> new MusicContainer("haptic_bap", AssetCache.INSTANCE.getFileHandle("audio/effects/haptic_bap.ogg"), false, true, null, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bop", () -> new MusicContainer("haptic_bop", AssetCache.INSTANCE.getFileHandle("audio/effects/haptic_bop.ogg"), false, true, null, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bep", () -> new MusicContainer("haptic_bep", AssetCache.INSTANCE.getFileHandle("audio/effects/haptic_bep.ogg"), false, true, null, (AudioBank m) -> { return null; }));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("sound:haptic_bip", () -> new MusicContainer("haptic_bip", AssetCache.INSTANCE.getFileHandle("audio/effects/haptic_bip.ogg"), false, true, null, (AudioBank m) -> { highPrioritySoundPlaying = false; return null; }));
|
||||
// make loading list
|
||||
CommonResourcePool.INSTANCE.loadAll();
|
||||
|
||||
@@ -669,7 +666,7 @@ public class App implements ApplicationListener {
|
||||
rendererVendor = Gdx.graphics.getGLVersion().getVendorString();
|
||||
|
||||
|
||||
fontGame = new TerrarumSansBitmap(FONT_DIR, false, false, false,
|
||||
fontGame = new TerrarumSansBitmap(false, false, false,
|
||||
false,
|
||||
256, false, 0.5f, false
|
||||
);
|
||||
@@ -1062,6 +1059,8 @@ public class App implements ApplicationListener {
|
||||
|
||||
deleteTempfiles();
|
||||
|
||||
AssetCache.INSTANCE.dispose();
|
||||
|
||||
Toolkit.INSTANCE.dispose();
|
||||
BlurMgr.INSTANCE.dispose();
|
||||
|
||||
@@ -1157,11 +1156,11 @@ public class App implements ApplicationListener {
|
||||
long t1 = System.nanoTime();
|
||||
|
||||
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("blockmarkings_common", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/blocks/block_markings_common.tga"), 16, 16, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("blockmarkings_common", () -> new TextureRegionPack(AssetCache.INSTANCE.getFileHandle("graphics/blocks/block_markings_common.tga"), 16, 16, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("blockmarking_actor", () -> new BlockMarkerActor());
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("loading_circle_64", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/loading_circle_64.tga"), 64, 64, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("inline_loading_spinner", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/inline_loading_spinner.tga"), 20, 20, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("inventory_category", () -> new TextureRegionPack("./assets/graphics/gui/inventory/category.tga", 20, 20, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("loading_circle_64", () -> new TextureRegionPack(AssetCache.INSTANCE.getFileHandle("graphics/gui/loading_circle_64.tga"), 64, 64, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("inline_loading_spinner", () -> new TextureRegionPack(AssetCache.INSTANCE.getFileHandle("graphics/gui/inline_loading_spinner.tga"), 20, 20, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.addToLoadingList("inventory_category", () -> new TextureRegionPack(AssetCache.INSTANCE.getFileHandle("graphics/gui/inventory/category.tga"), 20, 20, 0, 0, 0, 0, false, false, false));
|
||||
CommonResourcePool.INSTANCE.loadAll();
|
||||
|
||||
// shaderHicolour = loadShaderFromClasspath("shaders/default.vert", "shaders/hicolour.frag");
|
||||
@@ -1226,12 +1225,12 @@ public class App implements ApplicationListener {
|
||||
else {
|
||||
environment = RunningEnvironment.PC;
|
||||
}*/
|
||||
fontUITitle = new TerrarumSansBitmap(FONT_DIR, false, false, false,
|
||||
fontUITitle = new TerrarumSansBitmap(false, false, false,
|
||||
false,
|
||||
64, false, 0.5f, false
|
||||
);
|
||||
fontUITitle.setInterchar(1);
|
||||
fontGameFBO = new TerrarumSansBitmap(FONT_DIR, false, true, false,
|
||||
fontGameFBO = new TerrarumSansBitmap(false, true, false,
|
||||
false,
|
||||
64, false, 203f/255f, false
|
||||
);
|
||||
@@ -1514,6 +1513,8 @@ public class App implements ApplicationListener {
|
||||
/** defaultDir + "/Custom/Music" */
|
||||
public static String customMusicDir;
|
||||
public static String customAmbientDir;
|
||||
/** defaultDir + "/Caches" */
|
||||
public static String cachesDir;
|
||||
|
||||
private static void getDefaultDirectory() {
|
||||
String OS = OSName.toUpperCase();
|
||||
@@ -1551,6 +1552,7 @@ public class App implements ApplicationListener {
|
||||
customDir = defaultDir + "/Custom";
|
||||
customMusicDir = customDir + "/Music";
|
||||
customAmbientDir = customDir + "/Ambient";
|
||||
cachesDir = defaultDir + "/Caches";
|
||||
|
||||
System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem));
|
||||
System.out.println(String.format("os.version = %s", OSVersion));
|
||||
|
||||
59
src/net/torvald/terrarum/AssetArchiveBuilder.kt
Normal file
59
src/net/torvald/terrarum/AssetArchiveBuilder.kt
Normal file
@@ -0,0 +1,59 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.Clustfile
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Build-time tool that creates assets.tevd from assets_release/ directory.
|
||||
*
|
||||
* Usage: java -cp <classpath> net.torvald.terrarum.AssetArchiveBuilderKt [assets_release_dir] [output_file]
|
||||
*/
|
||||
fun main(args: Array<String>) {
|
||||
val srcDir = File(if (args.isNotEmpty()) args[0] else "assets_release")
|
||||
val outFile = File(if (args.size > 1) args[1] else "out/assets.tevd")
|
||||
|
||||
if (!srcDir.exists() || !srcDir.isDirectory) {
|
||||
System.err.println("Error: Source directory '${srcDir.path}' does not exist or is not a directory.")
|
||||
System.exit(1)
|
||||
}
|
||||
|
||||
outFile.parentFile?.mkdirs()
|
||||
if (outFile.exists()) outFile.delete()
|
||||
|
||||
println("Scanning $srcDir...")
|
||||
var totalSize = 0L
|
||||
var fileCount = 0
|
||||
srcDir.walkTopDown().filter { it.isFile }.forEach {
|
||||
totalSize += it.length()
|
||||
fileCount++
|
||||
}
|
||||
|
||||
// Calculate capacity in sectors (4096 bytes per sector/cluster)
|
||||
// Add overhead for FAT entries and directory structures
|
||||
val clusterSize = ClusteredFormatDOM.CLUSTER_SIZE
|
||||
val sectorsForData = (totalSize + clusterSize - 1) / clusterSize
|
||||
// Add ~25% overhead for FAT, directory entries, and slack space
|
||||
val capacityInSectors = ((sectorsForData * 1.25) + fileCount + 256).toLong()
|
||||
.coerceAtMost(ClusteredFormatDOM.MAX_CAPA_IN_SECTORS.toLong())
|
||||
.toInt()
|
||||
|
||||
println(" Files: $fileCount")
|
||||
println(" Total size: ${totalSize / 1024} KB")
|
||||
println(" Allocating $capacityInSectors sectors...")
|
||||
|
||||
println("Creating archive: ${outFile.path}")
|
||||
val diskArchive = ClusteredFormatDOM.createNewArchive(outFile, Charsets.UTF_8, "Terrarum Assets", capacityInSectors)
|
||||
val dom = ClusteredFormatDOM(diskArchive)
|
||||
|
||||
println("Importing files from ${srcDir.path}...")
|
||||
val root = Clustfile(dom, "/")
|
||||
root.importFrom(srcDir)
|
||||
|
||||
println("Trimming archive...")
|
||||
dom.trimArchive()
|
||||
dom.dispose()
|
||||
|
||||
println("Done. Output:")
|
||||
println(" ${outFile.path} (${outFile.length() / 1024} KB, $fileCount files)")
|
||||
}
|
||||
68
src/net/torvald/terrarum/AssetCache.kt
Normal file
68
src/net/torvald/terrarum/AssetCache.kt
Normal file
@@ -0,0 +1,68 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.Clustfile
|
||||
import java.io.File
|
||||
import java.io.RandomAccessFile
|
||||
|
||||
/**
|
||||
* Central accessor for the TerranVirtualDisk asset archive.
|
||||
* In distribution mode, assets are read directly from assets.tevd.
|
||||
* In development mode, assets are read from the local ./assets/ directory.
|
||||
*/
|
||||
object AssetCache {
|
||||
|
||||
private val archivePath = File("./assets.tevd")
|
||||
|
||||
/** Whether we're running from a distribution archive */
|
||||
val isDistribution: Boolean get() = archivePath.exists()
|
||||
|
||||
private var dom: ClusteredFormatDOM? = null
|
||||
|
||||
/**
|
||||
* Open the archive on startup. Call early, after defaultDir is set.
|
||||
*/
|
||||
fun init() {
|
||||
if (isDistribution) {
|
||||
println("[AssetCache] Distribution mode: opening ${archivePath.path}")
|
||||
dom = ClusteredFormatDOM(RandomAccessFile(archivePath, "r"))
|
||||
println("[AssetCache] Archive opened successfully")
|
||||
} else {
|
||||
println("[AssetCache] No archive found, using loose assets (development mode)")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Clustfile for a path relative to the assets root.
|
||||
*/
|
||||
fun getClustfile(relativePath: String): Clustfile {
|
||||
val path = if (relativePath.startsWith("/")) relativePath else "/$relativePath"
|
||||
return Clustfile(dom!!, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a GDX FileHandle — returns ClustfileHandle in distribution, Gdx.files.internal in dev.
|
||||
*/
|
||||
fun getFileHandle(relativePath: String): FileHandle {
|
||||
return if (isDistribution) ClustfileHandle(getClustfile(relativePath))
|
||||
else Gdx.files.internal("./assets/$relativePath")
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a path string. In dev mode returns local path; in distribution mode throws
|
||||
* as callers should use getFileHandle() instead.
|
||||
*/
|
||||
fun resolve(relativePath: String): String {
|
||||
return if (isDistribution) throw UnsupportedOperationException(
|
||||
"Use AssetCache.getFileHandle(\"$relativePath\") in distribution mode"
|
||||
)
|
||||
else "./assets/$relativePath"
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
dom?.dispose()
|
||||
dom = null
|
||||
}
|
||||
}
|
||||
64
src/net/torvald/terrarum/ClustfileHandle.kt
Normal file
64
src/net/torvald/terrarum/ClustfileHandle.kt
Normal file
@@ -0,0 +1,64 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.Clustfile
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClustfileInputStream
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
* A GDX FileHandle backed by a Clustfile from TerranVirtualDisk.
|
||||
* Allows transparent asset loading from .tevd archives using all standard GDX APIs.
|
||||
*/
|
||||
class ClustfileHandle(private val clustfile: Clustfile) : FileHandle() {
|
||||
|
||||
override fun read(): InputStream = ClustfileInputStream(clustfile)
|
||||
|
||||
override fun readBytes(): ByteArray = clustfile.readBytes()
|
||||
|
||||
override fun readString(charset: String?): String = String(readBytes(), charset(charset ?: "UTF-8"))
|
||||
|
||||
override fun exists(): Boolean = clustfile.exists()
|
||||
|
||||
override fun length(): Long = clustfile.length()
|
||||
|
||||
override fun isDirectory(): Boolean = clustfile.isDirectory
|
||||
|
||||
override fun name(): String = clustfile.name
|
||||
|
||||
override fun path(): String = clustfile.path
|
||||
|
||||
override fun extension(): String {
|
||||
val n = name()
|
||||
val dotIndex = n.lastIndexOf('.')
|
||||
return if (dotIndex == -1) "" else n.substring(dotIndex + 1)
|
||||
}
|
||||
|
||||
override fun nameWithoutExtension(): String {
|
||||
val n = name()
|
||||
val dotIndex = n.lastIndexOf('.')
|
||||
return if (dotIndex == -1) n else n.substring(0, dotIndex)
|
||||
}
|
||||
|
||||
override fun list(): Array<FileHandle> {
|
||||
return clustfile.listFiles()?.map { ClustfileHandle(it) }?.toTypedArray() ?: arrayOf()
|
||||
}
|
||||
|
||||
override fun child(name: String): FileHandle {
|
||||
val childPath = if (clustfile.path.endsWith("/")) "${clustfile.path}$name" else "${clustfile.path}/$name"
|
||||
return ClustfileHandle(Clustfile(clustfile.DOM, childPath))
|
||||
}
|
||||
|
||||
override fun parent(): FileHandle {
|
||||
val parentFile = clustfile.parentFile
|
||||
return if (parentFile != null) ClustfileHandle(parentFile)
|
||||
else ClustfileHandle(Clustfile(clustfile.DOM, "/"))
|
||||
}
|
||||
|
||||
override fun file(): File {
|
||||
// Return a dummy File for logging/toString purposes only
|
||||
return File(clustfile.path)
|
||||
}
|
||||
|
||||
override fun toString(): String = clustfile.path
|
||||
}
|
||||
@@ -103,7 +103,7 @@ object ModMgr {
|
||||
NOT_EVEN_THERE
|
||||
}
|
||||
|
||||
const val modDirInternal = "./assets/mods"
|
||||
val modDirInternal: String get() = "./assets/mods"
|
||||
val modDirExternal = "${App.defaultDir}/Modules"
|
||||
|
||||
/** Module name (directory name), ModuleMetadata */
|
||||
@@ -161,21 +161,46 @@ object ModMgr {
|
||||
try {
|
||||
val modMetadata = Properties()
|
||||
|
||||
val _internalFile = File("$modDirInternal/$moduleName/$metaFilename")
|
||||
val _externalFile = File("$modDirExternal/$moduleName/$metaFilename")
|
||||
|
||||
// external mod has precedence over the internal
|
||||
val isInternal = if (_externalFile.exists()) false else if (_internalFile.exists()) true else throw FileNotFoundException()
|
||||
val file = if (isInternal) _internalFile else _externalFile
|
||||
val internalExists = if (AssetCache.isDistribution)
|
||||
AssetCache.getFileHandle("mods/$moduleName/$metaFilename").exists()
|
||||
else
|
||||
File("$modDirInternal/$moduleName/$metaFilename").exists()
|
||||
val isInternal = if (_externalFile.exists()) false else if (internalExists) true else throw FileNotFoundException()
|
||||
val modDir = if (isInternal) modDirInternal else modDirExternal
|
||||
|
||||
fun getGdxFile(path: String) = if (isInternal) Gdx.files.internal(path) else Gdx.files.absolute(path)
|
||||
fun getGdxFileLocal(path: String) = if (isInternal) {
|
||||
if (AssetCache.isDistribution) AssetCache.getFileHandle(path.removePrefix("./assets/"))
|
||||
else Gdx.files.internal(path)
|
||||
} else Gdx.files.absolute(path)
|
||||
|
||||
modMetadata.load(FileInputStream(file))
|
||||
// Load metadata
|
||||
if (isInternal && AssetCache.isDistribution) {
|
||||
val metaHandle = AssetCache.getFileHandle("mods/$moduleName/$metaFilename")
|
||||
modMetadata.load(metaHandle.read())
|
||||
} else {
|
||||
val file = if (isInternal) File("$modDirInternal/$moduleName/$metaFilename") else _externalFile
|
||||
modMetadata.load(FileInputStream(file))
|
||||
}
|
||||
|
||||
if (File("$modDir/$moduleName/$defaultConfigFilename").exists()) {
|
||||
// Load default config
|
||||
val defaultConfigHandle = if (isInternal && AssetCache.isDistribution)
|
||||
AssetCache.getFileHandle("mods/$moduleName/$defaultConfigFilename")
|
||||
else
|
||||
null
|
||||
val defaultConfigExists = if (defaultConfigHandle != null)
|
||||
defaultConfigHandle.exists()
|
||||
else
|
||||
File("$modDir/$moduleName/$defaultConfigFilename").exists()
|
||||
|
||||
if (defaultConfigExists) {
|
||||
try {
|
||||
val defaultConfig = JsonFetcher("$modDir/$moduleName/$defaultConfigFilename")
|
||||
val defaultConfig = if (defaultConfigHandle != null)
|
||||
JsonFetcher.invoke(defaultConfigHandle)
|
||||
else
|
||||
JsonFetcher("$modDir/$moduleName/$defaultConfigFilename")
|
||||
|
||||
// read config and store it to the game
|
||||
var entry: JsonValue? = defaultConfig.child
|
||||
@@ -208,16 +233,29 @@ object ModMgr {
|
||||
val jar = modMetadata.getProperty("jar")
|
||||
val jarHash = modMetadata.getProperty("jarhash").uppercase()
|
||||
val dependency = modMetadata.getProperty("dependency").split(Regex(""";[ ]*""")).filter { it.isNotEmpty() }.toTypedArray()
|
||||
val isDir = FileSystems.getDefault().getPath("$modDir/$moduleName").toFile().isDirectory
|
||||
val isDir = if (isInternal && AssetCache.isDistribution)
|
||||
true // internal mods in archive are always "directories"
|
||||
else
|
||||
FileSystems.getDefault().getPath("$modDir/$moduleName").toFile().isDirectory
|
||||
|
||||
val configPlan = ArrayList<String>()
|
||||
File("$modDir/$moduleName/configplan.csv").let {
|
||||
if (it.exists() && it.isFile) {
|
||||
configPlan.addAll(it.readLines(Common.CHARSET).filter { it.isNotBlank() })
|
||||
val configPlanHandle = if (isInternal && AssetCache.isDistribution)
|
||||
AssetCache.getFileHandle("mods/$moduleName/configplan.csv")
|
||||
else
|
||||
null
|
||||
if (configPlanHandle != null) {
|
||||
if (configPlanHandle.exists()) {
|
||||
configPlan.addAll(configPlanHandle.readString("UTF-8").lines().filter { it.isNotBlank() })
|
||||
}
|
||||
} else {
|
||||
File("$modDir/$moduleName/configplan.csv").let {
|
||||
if (it.exists() && it.isFile) {
|
||||
configPlan.addAll(it.readLines(Common.CHARSET).filter { it.isNotBlank() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module = ModuleMetadata(index, isDir, getGdxFile("$modDir/$moduleName/icon.png"), properName, description, descTranslations, author, packageName, entryPoint, releaseDate, version, jar, dependency, isInternal, configPlan)
|
||||
module = ModuleMetadata(index, isDir, getGdxFileLocal("$modDir/$moduleName/icon.png"), properName, description, descTranslations, author, packageName, entryPoint, releaseDate, version, jar, dependency, isInternal, configPlan)
|
||||
|
||||
val versionNumeral = version.split('.')
|
||||
val versionNumber = versionNumeral.toVersionNumber()
|
||||
@@ -447,24 +485,36 @@ object ModMgr {
|
||||
/** Returning files are read-only */
|
||||
fun getGdxFile(module: String, path: String): FileHandle {
|
||||
checkExistence(module)
|
||||
return if (moduleInfo[module]!!.isInternal)
|
||||
Gdx.files.internal("$modDirInternal/$module/$path")
|
||||
return if (moduleInfo[module]!!.isInternal) {
|
||||
if (AssetCache.isDistribution)
|
||||
ClustfileHandle(AssetCache.getClustfile("mods/$module/$path"))
|
||||
else
|
||||
Gdx.files.internal("$modDirInternal/$module/$path")
|
||||
}
|
||||
else
|
||||
Gdx.files.absolute("$modDirExternal/$module/$path")
|
||||
}
|
||||
fun getFile(module: String, path: String): File {
|
||||
// getGdxFile is preferred due to asset archiving
|
||||
/*fun getFile(module: String, path: String): File {
|
||||
checkExistence(module)
|
||||
return if (moduleInfo[module]!!.isInternal)
|
||||
FileSystems.getDefault().getPath("$modDirInternal/$module/$path").toFile()
|
||||
return if (moduleInfo[module]!!.isInternal) {
|
||||
if (AssetCache.isDistribution)
|
||||
throw UnsupportedOperationException("Use getGdxFile() for internal mod files in distribution mode (module=$module, path=$path)")
|
||||
else
|
||||
FileSystems.getDefault().getPath("$modDirInternal/$module/$path").toFile()
|
||||
}
|
||||
else
|
||||
FileSystems.getDefault().getPath("$modDirExternal/$module/$path").toFile()
|
||||
}
|
||||
}*/
|
||||
fun hasFile(module: String, path: String): Boolean {
|
||||
if (!moduleInfo.containsKey(module)) return false
|
||||
return getFile(module, path).exists()
|
||||
return getGdxFile(module, path).exists()
|
||||
}
|
||||
fun getFiles(module: String, path: String): Array<File> {
|
||||
// getGdxFile is preferred due to asset archiving
|
||||
/*fun getFiles(module: String, path: String): Array<File> {
|
||||
checkExistence(module)
|
||||
if (moduleInfo[module]!!.isInternal && AssetCache.isDistribution)
|
||||
throw UnsupportedOperationException("Use getGdxFiles() for internal mod files in distribution mode (module=$module, path=$path)")
|
||||
val dir = getFile(module, path)
|
||||
if (!dir.isDirectory) {
|
||||
throw FileNotFoundException("The path is not a directory")
|
||||
@@ -472,7 +522,7 @@ object ModMgr {
|
||||
else {
|
||||
return dir.listFiles()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
fun getGdxFiles(module: String, path: String): Array<FileHandle> {
|
||||
checkExistence(module)
|
||||
val dir = getGdxFile(module, path)
|
||||
@@ -487,20 +537,21 @@ object ModMgr {
|
||||
/** Get a common file (literal file or directory) from all the installed mods. Files are guaranteed to exist. If a mod does not
|
||||
* contain the file, the mod will be skipped.
|
||||
*
|
||||
* @return List of pairs<modname, file>
|
||||
* @return List of pairs<modname, filehandle>
|
||||
*/
|
||||
fun getFilesFromEveryMod(path: String): List<Pair<String, File>> {
|
||||
// getGdxFile is preferred due to asset archiving
|
||||
/*fun getFilesFromEveryMod(path: String): List<Pair<String, FileHandle>> {
|
||||
val path = path.sanitisePath()
|
||||
val moduleNames = moduleInfo.keys.toList()
|
||||
|
||||
val filesList = ArrayList<Pair<String, File>>()
|
||||
val filesList = ArrayList<Pair<String, FileHandle>>()
|
||||
moduleNames.forEach {
|
||||
val file = getFile(it, path)
|
||||
val file = getGdxFile(it, path)
|
||||
if (file.exists()) filesList.add(it to file)
|
||||
}
|
||||
|
||||
return filesList.toList()
|
||||
}
|
||||
}*/
|
||||
|
||||
/** Get a common file (literal file or directory) from all the installed mods. Files are guaranteed to exist. If a mod does not
|
||||
* contain the file, the mod will be skipped.
|
||||
@@ -739,7 +790,7 @@ object ModMgr {
|
||||
const val langPath = "locales/"
|
||||
|
||||
@JvmStatic operator fun invoke(module: String) {
|
||||
Lang.load(getFile(module, langPath))
|
||||
Lang.load(getGdxFile(module, langPath))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,25 +798,25 @@ object ModMgr {
|
||||
const val keebPath = "keylayout/"
|
||||
|
||||
@JvmStatic operator fun invoke(module: String) {
|
||||
val FILE = getFile(module, keebPath)
|
||||
val DIR = getGdxFile(module, keebPath)
|
||||
|
||||
FILE.listFiles { file, s -> s.endsWith(".${IME.KEYLAYOUT_EXTENSION}") }.sortedBy { it.name }.forEach {
|
||||
printdbg(this, "Registering Low layer ${it.nameWithoutExtension.lowercase()}")
|
||||
IME.registerLowLayer(it.nameWithoutExtension.lowercase(), IME.parseKeylayoutFile(it))
|
||||
DIR.list().filter { it.extension().equals(IME.KEYLAYOUT_EXTENSION, ignoreCase = true) }.sortedBy { it.name() }.forEach {
|
||||
printdbg(this, "Registering Low layer ${it.nameWithoutExtension().lowercase()}")
|
||||
IME.registerLowLayer(it.nameWithoutExtension().lowercase(), IME.parseKeylayoutFile(it))
|
||||
}
|
||||
|
||||
FILE.listFiles { file, s -> s.endsWith(".${IME.IME_EXTENSION}") }.sortedBy { it.name }.forEach {
|
||||
printdbg(this, "Registering High layer ${it.nameWithoutExtension.lowercase()}")
|
||||
IME.registerHighLayer(it.nameWithoutExtension.lowercase(), IME.parseImeFile(it))
|
||||
DIR.list().filter { it.extension().equals(IME.IME_EXTENSION, ignoreCase = true) }.sortedBy { it.name() }.forEach {
|
||||
printdbg(this, "Registering High layer ${it.nameWithoutExtension().lowercase()}")
|
||||
IME.registerHighLayer(it.nameWithoutExtension().lowercase(), IME.parseImeFile(it))
|
||||
}
|
||||
|
||||
val iconFile = getFile(module, keebPath + "icons.tga").let {
|
||||
if (it.exists()) it else getFile(module, keebPath + "icons.png")
|
||||
val iconFile = getGdxFile(module, keebPath + "icons.tga").let {
|
||||
if (it.exists()) it else getGdxFile(module, keebPath + "icons.png")
|
||||
}
|
||||
|
||||
if (iconFile.exists()) {
|
||||
val iconSheet = TextureRegionPack(iconFile.path, 20, 20)
|
||||
val iconPixmap = Pixmap(Gdx.files.absolute(iconFile.path))
|
||||
val iconSheet = TextureRegionPack(iconFile, 20, 20)
|
||||
val iconPixmap = Pixmap(iconFile)
|
||||
for (k in 0 until iconPixmap.height step 20) {
|
||||
val langCode = StringBuilder()
|
||||
for (c in 0 until 20) {
|
||||
@@ -855,7 +906,7 @@ object ModMgr {
|
||||
}
|
||||
|
||||
@JvmStatic operator fun invoke(module: String) {
|
||||
getFiles(module, weatherPath).filter { it.isFile && it.name.lowercase().endsWith(".json") }.forEach {
|
||||
getGdxFile(module, weatherPath).list().filter { !it.isDirectory && it.name().lowercase().endsWith(".json") }.forEach {
|
||||
Terrarum.weatherCodex.readFromJson(module, it)
|
||||
}
|
||||
}
|
||||
@@ -878,32 +929,21 @@ object ModMgr {
|
||||
}
|
||||
|
||||
@JvmStatic operator fun invoke(module: String) {
|
||||
val targetModNames = getFiles(module, retexturesPath).filter { it.isDirectory }
|
||||
val targetModNames = getGdxFile(module, retexturesPath).list().filter { it.isDirectory }
|
||||
targetModNames.forEach { baseTargetModDir ->
|
||||
// modules/<module>/retextures/basegame
|
||||
// printdbg(this, "baseTargetModDir = $baseTargetModDir")
|
||||
|
||||
retexables.forEach { category ->
|
||||
val dir = File(baseTargetModDir, category)
|
||||
// modules/<module>/retextures/basegame/blocks
|
||||
|
||||
// printdbg(this, "cats: ${dir.path}")
|
||||
val dir = baseTargetModDir.child(category)
|
||||
|
||||
if (dir.isDirectory && dir.exists()) {
|
||||
dir.listFiles { it: File ->
|
||||
it.name.contains('-')
|
||||
}?.forEach {
|
||||
// <other modname>-<hopefully a number>.tga or .png
|
||||
val tokens = it.name.split('-')
|
||||
dir.list().filter { it.name().contains('-') }.forEach {
|
||||
val tokens = it.name().split('-')
|
||||
if (tokens.size > 1) {
|
||||
val modname = tokens[0]
|
||||
val filename = tokens.tail().joinToString("-")
|
||||
altFilePaths["$modDirInternal/$modname/$category/$filename"] = getGdxFile(module, "$retexturesPath${baseTargetModDir.name}/$category/${it.name}")
|
||||
altFilePaths["$modDirInternal/$modname/$category/$filename"] = getGdxFile(module, "$retexturesPath${baseTargetModDir.name()}/$category/${it.name()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// retexableCallbacks[category]?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,12 +957,12 @@ object ModMgr {
|
||||
const val smeltingPath = "smelting/"
|
||||
|
||||
@JvmStatic operator fun invoke(module: String) {
|
||||
getFile(module, recipePath).listFiles { it: File -> it.name.lowercase().endsWith(".json") }?.forEach { jsonFile ->
|
||||
Terrarum.craftingCodex.addFromJson(JsonFetcher(jsonFile), module, jsonFile.name)
|
||||
getGdxFile(module, recipePath).list().filter { !it.isDirectory && it.name().lowercase().endsWith(".json") }.forEach { jsonHandle ->
|
||||
Terrarum.craftingCodex.addFromJson(JsonFetcher.invoke(jsonHandle), module, jsonHandle.name())
|
||||
}
|
||||
|
||||
getFile(module, smeltingPath).listFiles { it: File -> it.name.lowercase().endsWith(".json") }?.forEach { jsonFile ->
|
||||
Terrarum.craftingCodex.addSmeltingFromJson(JsonFetcher(jsonFile), module, jsonFile.name)
|
||||
getGdxFile(module, smeltingPath).list().filter { !it.isDirectory && it.name().lowercase().endsWith(".json") }.forEach { jsonHandle ->
|
||||
Terrarum.craftingCodex.addSmeltingFromJson(JsonFetcher.invoke(jsonHandle), module, jsonHandle.name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package net.torvald.terrarum.audio
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.reflection.forceInvoke
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.CommonResourcePool
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.serialise.toUint
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2024-01-24.
|
||||
@@ -26,7 +26,7 @@ object AudioHelper {
|
||||
return fft
|
||||
}
|
||||
else {
|
||||
val ir = ModMgr.getFile(module, path)
|
||||
val ir = ModMgr.getGdxFile(module, path)
|
||||
val fft = createIR(ir)
|
||||
|
||||
CommonResourcePool.addToLoadingList(id) { fft }
|
||||
@@ -36,19 +36,20 @@ object AudioHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIR(ir: File): Array<ComplexArray> {
|
||||
private fun createIR(ir: FileHandle): Array<ComplexArray> {
|
||||
if (!ir.exists()) {
|
||||
throw IllegalArgumentException("Impulse Response file '${ir.path}' does not exist.")
|
||||
throw IllegalArgumentException("Impulse Response file '${ir.path()}' does not exist.")
|
||||
}
|
||||
|
||||
val sampleCount = (ir.length().toInt() / 8)//.coerceAtMost(65536)
|
||||
val irBytes = ir.readBytes()
|
||||
val sampleCount = (irBytes.size / 8)//.coerceAtMost(65536)
|
||||
val fftLen = FastMath.nextPowerOfTwo(sampleCount)
|
||||
|
||||
printdbg(this, "IR '${ir.path}' Sample Count = $sampleCount; FFT Length = $fftLen")
|
||||
printdbg(this, "IR '${ir.path()}' Sample Count = $sampleCount; FFT Length = $fftLen")
|
||||
|
||||
val conv = Array(2) { FloatArray(fftLen) }
|
||||
|
||||
ir.inputStream().let {
|
||||
java.io.ByteArrayInputStream(irBytes).let {
|
||||
for (i in 0 until sampleCount) {
|
||||
val f1 = Float.fromBits(it.read().and(255) or
|
||||
it.read().and(255).shl(8) or
|
||||
@@ -79,7 +80,7 @@ object AudioHelper {
|
||||
return CommonResourcePool.getAs<Array<FloatArray>>(id)
|
||||
}
|
||||
else {
|
||||
val file = ModMgr.getFile(module, path)
|
||||
val file = ModMgr.getGdxFile(module, path)
|
||||
val samples = createAudioInSamples(file)
|
||||
|
||||
CommonResourcePool.addToLoadingList(id) { samples }
|
||||
@@ -89,8 +90,8 @@ object AudioHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAudioInSamples(static: File): Array<FloatArray> {
|
||||
val music = Gdx.audio.newMusic(Gdx.files.absolute(static.absolutePath))
|
||||
private fun createAudioInSamples(static: FileHandle): Array<FloatArray> {
|
||||
val music = Gdx.audio.newMusic(static)
|
||||
val readbuf = ByteArray(AudioProcessBuf.MP3_CHUNK_SIZE * 4)
|
||||
val OUTBUF_BLOCK_SIZE_IN_BYTES = (48000 * 60) * 2 * 2
|
||||
var outbuf = ByteArray(OUTBUF_BLOCK_SIZE_IN_BYTES)
|
||||
|
||||
@@ -18,13 +18,15 @@ import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RAT
|
||||
import net.torvald.terrarum.serialise.toUint
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
import net.torvald.unsafe.UnsafePtr
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import javax.sound.sampled.AudioSystem
|
||||
|
||||
class MusicContainer(
|
||||
override val name: String,
|
||||
val file: File,
|
||||
val file: File?,
|
||||
val fileHandle: FileHandle?,
|
||||
val looping: Boolean = false,
|
||||
val toRAM: Boolean = false,
|
||||
val samplingRateOverride: Float?, // this is FIXED sampling rate
|
||||
@@ -34,6 +36,15 @@ class MusicContainer(
|
||||
override var channels: Int
|
||||
val codec: String
|
||||
|
||||
// File-based constructors (existing API)
|
||||
constructor(
|
||||
name: String,
|
||||
file: File,
|
||||
looping: Boolean = false,
|
||||
toRAM: Boolean = false,
|
||||
samplingRateOverride: Float?,
|
||||
songFinishedHook: (AudioBank) -> Unit = {}
|
||||
) : this(name, file, null, looping, toRAM, samplingRateOverride, songFinishedHook)
|
||||
// make Java code shorter
|
||||
constructor(
|
||||
name: String,
|
||||
@@ -41,27 +52,37 @@ class MusicContainer(
|
||||
looping: Boolean = false,
|
||||
toRAM: Boolean = false,
|
||||
songFinishedHook: (AudioBank) -> Unit = {}
|
||||
) : this(name, file, looping, toRAM, null, songFinishedHook)
|
||||
) : this(name, file, null, looping, toRAM, null, songFinishedHook)
|
||||
// make Java code shorter
|
||||
constructor(
|
||||
name: String,
|
||||
file: File,
|
||||
looping: Boolean = false,
|
||||
songFinishedHook: (AudioBank) -> Unit = {}
|
||||
) : this(name, file, looping, false, null, songFinishedHook)
|
||||
) : this(name, file, null, looping, false, null, songFinishedHook)
|
||||
// make Java code shorter
|
||||
constructor(
|
||||
name: String,
|
||||
file: File,
|
||||
songFinishedHook: (AudioBank) -> Unit = {}
|
||||
) : this(name, file, false, false, null, songFinishedHook)
|
||||
) : this(name, file, null, false, false, null, songFinishedHook)
|
||||
|
||||
// FileHandle-based constructor (for TEVD archive support)
|
||||
constructor(
|
||||
name: String,
|
||||
fileHandle: FileHandle,
|
||||
looping: Boolean = false,
|
||||
toRAM: Boolean = false,
|
||||
samplingRateOverride: Float? = null,
|
||||
songFinishedHook: (AudioBank) -> Unit = {}
|
||||
) : this(name, null, fileHandle, looping, toRAM, samplingRateOverride, songFinishedHook)
|
||||
|
||||
|
||||
var samplesReadCount = 0L; internal set
|
||||
override var totalSizeInSamples: Long
|
||||
private val totalSizeInBytes: Long
|
||||
|
||||
private val gdxMusic: Music = Gdx.audio.newMusic(FileHandle(file))
|
||||
private val gdxMusic: Music = if (file != null) Gdx.audio.newMusic(FileHandle(file)) else Gdx.audio.newMusic(fileHandle!!)
|
||||
|
||||
private var soundBuf: UnsafePtr? = null; private set
|
||||
|
||||
@@ -94,7 +115,10 @@ class MusicContainer(
|
||||
rate.toFloat()
|
||||
}
|
||||
is Mp3.Music -> {
|
||||
val tempMusic = Gdx.audio.newMusic(Gdx.files.absolute(file.absolutePath))
|
||||
val tempMusic = if (file == null)
|
||||
Gdx.audio.newMusic(fileHandle)
|
||||
else
|
||||
Gdx.audio.newMusic(Gdx.files.absolute(file.absolutePath))
|
||||
val bitstream = tempMusic.extortField<Bitstream>("bitstream")!!
|
||||
val header = bitstream.readFrame()
|
||||
val rate = header.sampleRate
|
||||
@@ -118,11 +142,22 @@ class MusicContainer(
|
||||
if (it.last() == "Music") it.dropLast(1).last() else it.last()
|
||||
}
|
||||
|
||||
totalSizeInSamples = when (gdxMusic) {
|
||||
is Wav.Music -> getWavFileSampleCount(file)
|
||||
is Ogg.Music -> getOggFileSampleCount(file)
|
||||
is Mp3.Music -> getMp3FileSampleCount(file)
|
||||
else -> Long.MAX_VALUE
|
||||
totalSizeInSamples = if (file != null) {
|
||||
when (gdxMusic) {
|
||||
is Wav.Music -> getWavFileSampleCount(file)
|
||||
is Ogg.Music -> getOggFileSampleCount(file)
|
||||
is Mp3.Music -> getMp3FileSampleCount(file)
|
||||
else -> Long.MAX_VALUE
|
||||
}
|
||||
} else if (fileHandle != null) {
|
||||
when (gdxMusic) {
|
||||
is Wav.Music -> getWavFileSampleCountFromHandle(fileHandle)
|
||||
is Ogg.Music -> getOggFileSampleCountFromHandle(fileHandle)
|
||||
is Mp3.Music -> getMp3FileSampleCountFromHandle(fileHandle)
|
||||
else -> Long.MAX_VALUE
|
||||
}
|
||||
} else {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
totalSizeInBytes = totalSizeInSamples * 2 * channels
|
||||
|
||||
@@ -329,10 +364,65 @@ class MusicContainer(
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString() = if (name.isEmpty()) file.nameWithoutExtension else name
|
||||
private fun getWavFileSampleCountFromHandle(fh: FileHandle): Long {
|
||||
return try {
|
||||
val ais = AudioSystem.getAudioInputStream(BufferedInputStream(fh.read()))
|
||||
val r = ais.frameLength
|
||||
ais.close()
|
||||
r
|
||||
}
|
||||
catch (_: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) = this.file.path == (other as MusicContainer).file.path
|
||||
fun equalInstance(other: Any?) = this.file.path == (other as MusicContainer).file.path && this.hash == (other as MusicContainer).hash
|
||||
private fun getOggFileSampleCountFromHandle(fh: FileHandle): Long {
|
||||
return try {
|
||||
// VorbisFile requires a file path; use a temp file
|
||||
val tempFile = java.io.File.createTempFile("terrarum_ogg_", ".ogg")
|
||||
tempFile.deleteOnExit()
|
||||
tempFile.writeBytes(fh.readBytes())
|
||||
val vorbisFile = VorbisFile(tempFile.absolutePath)
|
||||
val r = vorbisFile.pcm_total(0)
|
||||
tempFile.delete()
|
||||
r
|
||||
}
|
||||
catch (_: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMp3FileSampleCountFromHandle(fh: FileHandle): Long {
|
||||
return try {
|
||||
val input = BufferedInputStream(fh.read())
|
||||
val bs = Bitstream(input)
|
||||
|
||||
var header = bs.readFrame()
|
||||
val rate = header.frequency()
|
||||
var totalSamples = 0L
|
||||
|
||||
while (header != null) {
|
||||
totalSamples += (header.ms_per_frame() * rate / 1000).toLong()
|
||||
bs.closeFrame()
|
||||
header = bs.readFrame()
|
||||
}
|
||||
|
||||
bs.close()
|
||||
input.close()
|
||||
|
||||
totalSamples
|
||||
}
|
||||
catch (_: Throwable) {
|
||||
Long.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
private val identPath: String get() = file?.path ?: fileHandle?.path() ?: name
|
||||
|
||||
override fun toString() = if (name.isEmpty()) (file?.nameWithoutExtension ?: fileHandle?.nameWithoutExtension() ?: "") else name
|
||||
|
||||
override fun equals(other: Any?) = this.identPath == (other as MusicContainer).identPath
|
||||
fun equalInstance(other: Any?) = this.identPath == (other as MusicContainer).identPath && this.hash == (other as MusicContainer).hash
|
||||
|
||||
override fun dispose() {
|
||||
gdxMusic.dispose()
|
||||
@@ -340,7 +430,10 @@ class MusicContainer(
|
||||
}
|
||||
|
||||
override fun makeCopy(): AudioBank {
|
||||
val new = MusicContainer(name, file, looping, false, samplingRateOverride, songFinishedHook)
|
||||
val new = if (file != null)
|
||||
MusicContainer(name, file, looping, false, samplingRateOverride, songFinishedHook)
|
||||
else
|
||||
MusicContainer(name, fileHandle!!, looping, false, samplingRateOverride, songFinishedHook)
|
||||
|
||||
synchronized(this) {
|
||||
if (this.toRAM) {
|
||||
|
||||
@@ -38,13 +38,13 @@ object CommandDict {
|
||||
|
||||
((listOf("$" to "net.torvald.terrarum")) + ModMgr.loadOrder.reversed().map { it to ModMgr.moduleInfo[it]?.packageName }).forEach { (modName, packageRoot) ->
|
||||
if (modName == "$" || modName != "$" && ModMgr.hasFile(modName, "commands.csv")) {
|
||||
val commandsList = if (modName == "$") engineCommandList else ModMgr.getFile(modName, "commands.csv").readLines()
|
||||
val commandsList = if (modName == "$") engineCommandList else ModMgr.getGdxFile(modName, "commands.csv").readString("UTF-8").lines()
|
||||
val packageConsole = "$packageRoot.console"
|
||||
|
||||
printdbg(this, "Loading console commands from '${packageConsole}'")
|
||||
// printdbg(this, commandsList.joinToString())
|
||||
|
||||
commandsList.forEach { commandName ->
|
||||
commandsList.filter { it.isNotBlank() }.forEach { commandName ->
|
||||
val canonicalName = "$packageConsole.$commandName"
|
||||
val it = ModMgr.moduleClassloader[modName].let {
|
||||
if (it != null)
|
||||
|
||||
@@ -15,7 +15,7 @@ object FactionFactory {
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun create(module: String, path: String): Faction {
|
||||
val jsonObj = JsonFetcher(ModMgr.getFile(module, path))
|
||||
val jsonObj = JsonFetcher(ModMgr.getGdxFile(module, path))
|
||||
val factionObj = Faction(jsonObj.getString("factionname"))
|
||||
|
||||
jsonObj.get("factionamicable").asStringArray().forEach { factionObj.addFactionAmicable(it) }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.torvald.terrarum.gamecontroller
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.App
|
||||
@@ -173,8 +174,13 @@ object IME {
|
||||
else -> throw IllegalArgumentException("Unknown candidates mode: $this")
|
||||
}
|
||||
|
||||
fun parseKeylayoutFile(file: File): TerrarumKeyLayout {
|
||||
val src = file.readText(Charsets.UTF_8)
|
||||
fun parseKeylayoutFile(fileHandle: FileHandle): TerrarumKeyLayout =
|
||||
parseKeylayoutFromString(fileHandle.readString("UTF-8"))
|
||||
|
||||
fun parseKeylayoutFile(file: File): TerrarumKeyLayout =
|
||||
parseKeylayoutFromString(file.readText(Charsets.UTF_8))
|
||||
|
||||
private fun parseKeylayoutFromString(src: String): TerrarumKeyLayout {
|
||||
val jsval = context.eval("js", "'use strict';Object.freeze($src)")
|
||||
val name = jsval.getMember("n").asString()
|
||||
val capsmode = jsval.getMember("capslock").asString().toCapsMode()
|
||||
@@ -201,8 +207,6 @@ object IME {
|
||||
}
|
||||
}
|
||||
|
||||
// println("[IME] Test Keymap print for $name:"); for (keycode in 0 until 256) { print("$keycode:\t"); println(out[keycode].joinToString("\t")) }
|
||||
|
||||
return TerrarumKeyLayout(name, capsmode, out, physicalLayout)
|
||||
}
|
||||
|
||||
@@ -215,8 +219,13 @@ object IME {
|
||||
else -> throw IllegalArgumentException("Unknown operation mode: $this")
|
||||
}
|
||||
|
||||
fun parseImeFile(file: File): TerrarumIME {
|
||||
val code = file.readText(Charsets.UTF_8)
|
||||
fun parseImeFile(fileHandle: FileHandle): TerrarumIME =
|
||||
parseImeFromString(fileHandle.readString("UTF-8"))
|
||||
|
||||
fun parseImeFile(file: File): TerrarumIME =
|
||||
parseImeFromString(file.readText(Charsets.UTF_8))
|
||||
|
||||
private fun parseImeFromString(code: String): TerrarumIME {
|
||||
val jsval = context.eval("js", "\"use strict\";(function(){$code})()")
|
||||
val name = jsval.getMember("n").asString()
|
||||
val candidatesCount = jsval.getMember("v").asString().toViewCount()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.torvald.terrarum.langpack
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.tail
|
||||
@@ -82,47 +83,62 @@ object Lang {
|
||||
}
|
||||
}
|
||||
|
||||
fun load(localesHandle: FileHandle) {
|
||||
printdbg(this, "Loading languages from ${localesHandle.path()}")
|
||||
|
||||
localesHandle.list().filter { it.isDirectory }.forEach { languageList.add(it.name()) }
|
||||
|
||||
// temporary filter
|
||||
languageList.remove("jaJPysi")
|
||||
|
||||
for (lang in languageList) {
|
||||
printdbg(this, "Loading langpack from ${localesHandle.path()}/$lang/")
|
||||
|
||||
val langFiles = localesHandle.child(lang).list()
|
||||
|
||||
langFiles.forEach {
|
||||
if (!it.name().startsWith("Polyglot") && it.name().endsWith(".json")) {
|
||||
processRegularLangfile(it, lang)
|
||||
}
|
||||
else if (it.name().startsWith("Polyglot") && it.name().endsWith(".json")) {
|
||||
processPolyglotLangFile(it, lang)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processRegularLangfile(file: File, lang: String) {
|
||||
val json = JsonFetcher(file)
|
||||
/*
|
||||
* Terrarum langpack JSON structure is:
|
||||
*
|
||||
* (root object)
|
||||
* "<<STRING ID>>" = "<<LOCALISED TEXT>>"
|
||||
*/
|
||||
//println(json.entrySet())
|
||||
JsonFetcher.forEachSiblings(json) { key, value ->
|
||||
langpack.put("${key}_$lang", value.asString().trim())
|
||||
}
|
||||
}
|
||||
|
||||
private fun processRegularLangfile(fileHandle: FileHandle, lang: String) {
|
||||
val json = JsonFetcher(fileHandle)
|
||||
JsonFetcher.forEachSiblings(json) { key, value ->
|
||||
langpack.put("${key}_$lang", value.asString().trim())
|
||||
}
|
||||
}
|
||||
|
||||
private fun processPolyglotLangFile(file: File, lang: String) {
|
||||
val json = JsonFetcher(file)
|
||||
/*
|
||||
* Polyglot JSON structure is:
|
||||
*
|
||||
* (root object)
|
||||
* "resources": object
|
||||
* "polyglot": object
|
||||
* (polyglot meta)
|
||||
* "data": array
|
||||
* [0]: object
|
||||
* n = "CONTEXT_CHARACTER_CLASS"
|
||||
* s = "Class"
|
||||
* [1]: object
|
||||
* n = "CONTEXT_CHARACTER_DELETE"
|
||||
* s = "Delecte Character"
|
||||
* (the array continues)
|
||||
*
|
||||
*/
|
||||
JsonFetcher.forEachSiblings(json.get("resources").get("data")) { _, entry ->
|
||||
langpack.put(
|
||||
"${entry.getString("n")}_$lang",
|
||||
entry.getString("s").trim()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processPolyglotLangFile(fileHandle: FileHandle, lang: String) {
|
||||
val json = JsonFetcher(fileHandle)
|
||||
JsonFetcher.forEachSiblings(json.get("resources").get("data")) { _, entry ->
|
||||
langpack.put(
|
||||
"${entry.getString("n")}_$lang",
|
||||
entry.getString("s").trim()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val bindOp = ">>="
|
||||
|
||||
@@ -161,10 +161,10 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
try {
|
||||
val file = ModMgr.getFile("basegame", "demoworld")
|
||||
val reader = java.io.FileReader(file)
|
||||
val fileHandle = ModMgr.getGdxFile("basegame", "demoworld")
|
||||
val reader = fileHandle.reader("UTF-8")
|
||||
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
||||
val world = ReadSimpleWorld(reader, file)
|
||||
val world = ReadSimpleWorld(reader, fileHandle.file())
|
||||
demoWorld = world
|
||||
demoWorld.worldTime.timeDelta = 30
|
||||
printdbg(this, "Demo world loaded")
|
||||
|
||||
@@ -46,7 +46,7 @@ object InstrumentLoader {
|
||||
CommonResourcePool.getAs<Pair<FloatArray, FloatArray>>("${baseResourceName}_$it")
|
||||
}
|
||||
|
||||
val masterFile = MusicContainer("${idBase}_${initialNote}", ModMgr.getFile(module, path))
|
||||
val masterFile = MusicContainer("${idBase}_${initialNote}", ModMgr.getGdxFile(module, path))
|
||||
val masterSamplesL = FloatArray(masterFile.totalSizeInSamples.toInt())
|
||||
val masterSamplesR = FloatArray(masterFile.totalSizeInSamples.toInt())
|
||||
masterFile.readSamples(masterSamplesL, masterSamplesR)
|
||||
|
||||
@@ -23,7 +23,7 @@ open class ActorLobbed(throwPitch: Float) : ActorWithBody() {
|
||||
|
||||
@Transient private val pitch = throwPitch.coerceIn(0.5f, 2f)
|
||||
@Transient private val whooshSound = MusicContainer(
|
||||
"throw_low_short", ModMgr.getFile("basegame", "audio/effects/throwing/throw_low_short.wav"),
|
||||
"throw_low_short", ModMgr.getGdxFile("basegame", "audio/effects/throwing/throw_low_short.wav"),
|
||||
toRAM = true,
|
||||
samplingRateOverride = 48000f * pitch
|
||||
)
|
||||
@@ -63,17 +63,17 @@ open class ActorPrimedBomb(
|
||||
private var explosionCalled = false
|
||||
|
||||
@Transient private val boomSound = MusicContainer(
|
||||
"boom", ModMgr.getFile("basegame", "audio/effects/explosion/bang_bomb.wav"), toRAM = true
|
||||
"boom", ModMgr.getGdxFile("basegame", "audio/effects/explosion/bang_bomb.wav"), toRAM = true
|
||||
) {
|
||||
this.flagDespawn()
|
||||
}
|
||||
@Transient private val fuseSound = MusicContainer(
|
||||
"fuse", ModMgr.getFile("basegame", "audio/effects/explosion/fuse.wav"), toRAM = true
|
||||
"fuse", ModMgr.getGdxFile("basegame", "audio/effects/explosion/fuse.wav"), toRAM = true
|
||||
) {
|
||||
this.flagDespawn()
|
||||
}
|
||||
@Transient private val fuseSoundCont = MusicContainer(
|
||||
"fuse_continue", ModMgr.getFile("basegame", "audio/effects/explosion/fuse_continue.wav"), toRAM = true
|
||||
"fuse_continue", ModMgr.getGdxFile("basegame", "audio/effects/explosion/fuse_continue.wav"), toRAM = true
|
||||
) {
|
||||
this.flagDespawn()
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ class FixtureAlloyingFurnace : FixtureBase {
|
||||
}
|
||||
|
||||
|
||||
@Transient val static = MusicContainer("bonfire", ModMgr.getFile("basegame", "audio/effects/static/bonfire.ogg"), true)
|
||||
@Transient val static = MusicContainer("bonfire", ModMgr.getGdxFile("basegame", "audio/effects/static/bonfire.ogg"), true)
|
||||
@Transient val light = Cvec(0.5f, 0.18f, 0f, 0f)
|
||||
|
||||
@Transient override var lightBoxList = arrayListOf(Lightbox(Hitbox(0.0, 0.0, TILE_SIZED * 2, TILE_SIZED * 2), light))
|
||||
|
||||
@@ -57,7 +57,7 @@ class FixtureFurnaceAndAnvil : FixtureBase, CraftingStation {
|
||||
}
|
||||
}
|
||||
|
||||
@Transient val static = MusicContainer("bonfire", ModMgr.getFile("basegame", "audio/effects/static/bonfire.ogg"), true)
|
||||
@Transient val static = MusicContainer("bonfire", ModMgr.getGdxFile("basegame", "audio/effects/static/bonfire.ogg"), true)
|
||||
|
||||
@Transient override var lightBoxList = arrayListOf(Lightbox(Hitbox(0.0, 0.0, TerrarumAppConfiguration.TILE_SIZED * 2, TerrarumAppConfiguration.TILE_SIZED * 2), Cvec(0.5f, 0.18f, 0f, 0f)))
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ class FixtureSmelterBasic : FixtureBase {
|
||||
this.mainUI = UISmelterBasic(this)
|
||||
}
|
||||
|
||||
@Transient val static = MusicContainer("bonfire", ModMgr.getFile("basegame", "audio/effects/static/bonfire.ogg"), true)
|
||||
@Transient val static = MusicContainer("bonfire", ModMgr.getGdxFile("basegame", "audio/effects/static/bonfire.ogg"), true)
|
||||
@Transient val light = Cvec(0.5f, 0.18f, 0f, 0f)
|
||||
|
||||
@Transient override var lightBoxList = arrayListOf(Lightbox(Hitbox(0.0, 2*TILE_SIZED, TILE_SIZED * 2, TILE_SIZED * 2), light))
|
||||
|
||||
@@ -98,7 +98,7 @@ class FixtureTypewriter : FixtureBase {
|
||||
|
||||
internal class TestLeafletPrimaryUseHandler : FileRefItemPrimaryUseHandler {
|
||||
override fun use(item: ItemFileRef): Long {
|
||||
println(item.getAsFile().readText(Common.CHARSET))
|
||||
println(item.getAsGdxFile().readString(Common.CHARSET.displayName()))
|
||||
return 0L
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ object InjectCreatureRaw {
|
||||
* @param jsonFileName with extension
|
||||
*/
|
||||
operator fun invoke(actorValueRef: ActorValue, module: String, jsonFileName: String) {
|
||||
val jsonObj = JsonFetcher(ModMgr.getFile(module, "creatures/$jsonFileName"))
|
||||
val jsonObj = JsonFetcher(ModMgr.getGdxFile(module, "creatures/$jsonFileName"))
|
||||
|
||||
|
||||
JsonFetcher.forEachSiblings(jsonObj) { key, value -> if (!key.startsWith("_")) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
@@ -42,7 +43,7 @@ open class ItemFileRef(originalID: ItemID) : GameItem(originalID) {
|
||||
*/
|
||||
open var refIsShared: Boolean = false
|
||||
|
||||
@Transient open lateinit var ref: File
|
||||
@Transient open lateinit var ref: FileHandle
|
||||
|
||||
/**
|
||||
* Application-defined.
|
||||
@@ -101,10 +102,10 @@ open class ItemFileRef(originalID: ItemID) : GameItem(originalID) {
|
||||
else
|
||||
ModMgr.getGdxFile(refModuleName, refPath)
|
||||
|
||||
fun getAsFile() = if (refIsShared)
|
||||
/*fun getAsFile() = if (refIsShared)
|
||||
File(App.saveSharedDir + "/$refPath")
|
||||
else
|
||||
ModMgr.getFile(refModuleName, refPath)
|
||||
ModMgr.getFile(refModuleName, refPath)*/
|
||||
|
||||
@Transient private var classCache: FileRefItemPrimaryUseHandler? = null
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ data class MusicDiscMetadata(val title: String, val author: String, val album: S
|
||||
object MusicDiscHelper {
|
||||
fun getMetadata(musicFile: FileHandle): MusicDiscMetadata {
|
||||
val musicdbFile = musicFile.sibling("_musicdb.json")
|
||||
val musicdb = JsonFetcher.invoke(musicdbFile.file())
|
||||
val musicdb = JsonFetcher.invoke(musicdbFile)
|
||||
val propForThisFile = musicdb.get(musicFile.name())
|
||||
|
||||
val artist = propForThisFile.get("artist").asString()
|
||||
@@ -37,7 +37,7 @@ open class MusicDiscPrototype(originalID: ItemID, module: String, path: String)
|
||||
override var refPath = path
|
||||
override var refModuleName = module
|
||||
override val canBeDynamic = false
|
||||
@Transient override var ref = ModMgr.getFile(refModuleName, refPath)
|
||||
@Transient override var ref = ModMgr.getGdxFile(refModuleName, refPath)
|
||||
override var mediumIdentifier = "music_disc"
|
||||
|
||||
init {
|
||||
|
||||
@@ -273,7 +273,7 @@ object PickaxeCore : TooltipListener() {
|
||||
|
||||
private val soundCue = MusicContainer(
|
||||
"pickaxe_sound_cue",
|
||||
ModMgr.getFile("basegame", "audio/effects/accessibility/pickaxe_valuable.ogg"),
|
||||
ModMgr.getGdxFile("basegame", "audio/effects/accessibility/pickaxe_valuable.ogg"),
|
||||
toRAM = false
|
||||
).also {
|
||||
App.disposables.add(it)
|
||||
|
||||
@@ -30,7 +30,7 @@ class UIElemTest : ApplicationAdapter() {
|
||||
private lateinit var ui: UICanvas
|
||||
|
||||
override fun create() {
|
||||
App.fontGame = TerrarumSansBitmap(App.FONT_DIR, false, true, false,
|
||||
App.fontGame = TerrarumSansBitmap(false, true, false,
|
||||
false,
|
||||
256, false, 0.5f, false
|
||||
)
|
||||
|
||||
@@ -40,7 +40,10 @@ object CSVFetcher {
|
||||
return csvRecordList
|
||||
}
|
||||
|
||||
fun readFromModule(module: String, path: String) = net.torvald.terrarum.utils.CSVFetcher.readFromFile(ModMgr.getGdxFile(module, path).path())
|
||||
fun readFromModule(module: String, path: String): List<org.apache.commons.csv.CSVRecord> {
|
||||
val content = ModMgr.getGdxFile(module, path).readString("UTF-8")
|
||||
return readFromString(content)
|
||||
}
|
||||
|
||||
fun readFromString(csv: String): List<org.apache.commons.csv.CSVRecord> {
|
||||
val preprocessed = preprocessCSV(csv)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.torvald.terrarum.utils
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.utils.JsonReader
|
||||
import com.badlogic.gdx.utils.JsonValue
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
@@ -36,6 +37,13 @@ object JsonFetcher {
|
||||
return JsonReader().parse(jsonString.toString())
|
||||
}
|
||||
|
||||
@Throws(java.io.IOException::class)
|
||||
operator fun invoke(fileHandle: FileHandle): JsonValue {
|
||||
val content = fileHandle.readString("UTF-8")
|
||||
printdbg(this, "Reading JSON ${fileHandle.path()}")
|
||||
return JsonReader().parse(content)
|
||||
}
|
||||
|
||||
fun readFromJsonString(stringReader: Reader): JsonValue {
|
||||
return JsonReader().parse(stringReader.readText())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.torvald.terrarum.weather
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
@@ -40,24 +41,17 @@ class WeatherCodex : Disposable {
|
||||
|
||||
fun readFromJson(modname: String, file: File) = readFromJson(modname, file.path)
|
||||
|
||||
fun readFromJson(modname: String, fileHandle: FileHandle) {
|
||||
readFromJsonValue(modname, JsonFetcher.invoke(fileHandle))
|
||||
}
|
||||
|
||||
private val pathToImage = "weathers"
|
||||
|
||||
fun readFromJson(modname: String, path: String) {
|
||||
/* JSON structure:
|
||||
{
|
||||
"skyboxGradColourMap": "colourmap/sky_colour.tga", // string (path to image) for dynamic. Image must be RGBA8888 or RGB888
|
||||
"extraImages": [
|
||||
// if any, it will be like:
|
||||
sun01.tga,
|
||||
clouds01.tga,
|
||||
clouds02.tga,
|
||||
auroraBlueViolet.tga
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
val JSON = JsonFetcher(path)
|
||||
readFromJsonValue(modname, JsonFetcher(path))
|
||||
}
|
||||
|
||||
private fun readFromJsonValue(modname: String, JSON: com.badlogic.gdx.utils.JsonValue) {
|
||||
val skyboxModel = JSON.getString("skyboxGradColourMap")
|
||||
val lightboxModel = JSON.getString("daylightClut")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user