support for texture packs

This commit is contained in:
minjaesong
2022-02-23 17:59:38 +09:00
parent 841a77403b
commit 7c966b0da8
36 changed files with 2818 additions and 142 deletions

View File

@@ -29,7 +29,7 @@ import net.torvald.tsvm.peripheral.VMProgramRom
class FixtureHomeComputer : FixtureBase { class FixtureHomeComputer : FixtureBase {
private val vm = VM(0x200000, TheRealWorld(), arrayOf( private val vm = VM(0x200000, TheRealWorld(), arrayOf(
VMProgramRom(ModMgr.getPath("dwarventech", "bios/tsvmbios.js")) VMProgramRom(ModMgr.getGdxFile("dwarventech", "bios/tsvmbios.js").path())
)) ))
private val vmRunner: VMRunner private val vmRunner: VMRunner
private val coroutineJob: Job private val coroutineJob: Job
@@ -49,7 +49,7 @@ class FixtureHomeComputer : FixtureBase {
actorValue[AVKey.BASEMASS] = 20.0 actorValue[AVKey.BASEMASS] = 20.0
val gpu = ReferenceGraphicsAdapter(ModMgr.getPath("dwarventech", "gui"), vm) val gpu = ReferenceGraphicsAdapter(ModMgr.getGdxFile("dwarventech", "gui").path(), vm)
// vm.getIO().blockTransferPorts[0].attachDevice(TestDiskDrive(vm, 0, ...)) // vm.getIO().blockTransferPorts[0].attachDevice(TestDiskDrive(vm, 0, ...))
vm.peripheralTable[1] = PeripheralEntry( vm.peripheralTable[1] = PeripheralEntry(
@@ -65,7 +65,7 @@ class FixtureHomeComputer : FixtureBase {
(mainUI as UIHomeComputer).vm = vm (mainUI as UIHomeComputer).vm = vm
vmRunner = VMRunnerFactory(ModMgr.getPath("dwarventech", "bios"), vm, "js") vmRunner = VMRunnerFactory(ModMgr.getGdxFile("dwarventech", "bios").path(), vm, "js")
coroutineJob = GlobalScope.launch { coroutineJob = GlobalScope.launch {
vmRunner.executeCommand(vm.roms[0]!!.readAll()) vmRunner.executeCommand(vm.roms[0]!!.readAll())
} }

View File

@@ -41,8 +41,8 @@ class ItemWearableWorldRadar(originalID: String) : GameItem(originalID) {
private val vm = VM(73728, TheRealWorld(), arrayOf( private val vm = VM(73728, TheRealWorld(), arrayOf(
VMProgramRom(ModMgr.getPath("dwarventech", "bios/pipboot.rom")), VMProgramRom(ModMgr.getGdxFile("dwarventech", "bios/pipboot.rom").path()),
VMProgramRom(ModMgr.getPath("dwarventech", "bios/pipcode.bas")) VMProgramRom(ModMgr.getGdxFile("dwarventech", "bios/pipcode.bas").path())
)) ))
private val vmRunner: VMRunner private val vmRunner: VMRunner
private val coroutineJob: Job private val coroutineJob: Job
@@ -62,7 +62,7 @@ class ItemWearableWorldRadar(originalID: String) : GameItem(originalID) {
vm.getErrorStream = { System.err } vm.getErrorStream = { System.err }
vm.getInputStream = { System.`in` } vm.getInputStream = { System.`in` }
vmRunner = VMRunnerFactory(ModMgr.getPath("dwarventech", "bios"), vm, "js") vmRunner = VMRunnerFactory(ModMgr.getGdxFile("dwarventech", "bios").path(), vm, "js")
coroutineJob = GlobalScope.launch { coroutineJob = GlobalScope.launch {
vmRunner.executeCommand(vm.roms[0]!!.readAll()) vmRunner.executeCommand(vm.roms[0]!!.readAll())
} }

View File

@@ -16,5 +16,7 @@
"MENU_OPTIONS_DITHER": "Farbmischung", "MENU_OPTIONS_DITHER": "Farbmischung",
"MENU_OPTIONS_BLUR": "Weichzeichnen", "MENU_OPTIONS_BLUR": "Weichzeichnen",
"MENU_OPTIONS_PARTICLES": "Partikel", "MENU_OPTIONS_PARTICLES": "Partikel",
"MENU_IO_IMPORT": "Importieren" "MENU_IO_IMPORT": "Importieren",
"APP_NOMODULE_1": "Derzeit ist kein Modul geladen.",
"APP_NOMODULE_2": "Bitte konfigurieren Sie Ihren Ladeauftrag neu auf:"
} }

View File

@@ -20,5 +20,7 @@
"MENU_OPTIONS_DITHER": "Dithering", "MENU_OPTIONS_DITHER": "Dithering",
"MENU_OPTIONS_BLUR": "Blur", "MENU_OPTIONS_BLUR": "Blur",
"MENU_OPTIONS_PARTICLES": "Particles", "MENU_OPTIONS_PARTICLES": "Particles",
"MENU_IO_IMPORT": "Import" "MENU_IO_IMPORT": "Import",
"APP_NOMODULE_1": "No Module is currently loaded.",
"APP_NOMODULE_2": "Please reconfigure your Load Order on:"
} }

View File

@@ -16,5 +16,7 @@
"MENU_OPTIONS_DITHER": "Interpolación de colores", "MENU_OPTIONS_DITHER": "Interpolación de colores",
"MENU_OPTIONS_BLUR": "Desenfocar", "MENU_OPTIONS_BLUR": "Desenfocar",
"MENU_OPTIONS_PARTICLES": "Partícula", "MENU_OPTIONS_PARTICLES": "Partícula",
"MENU_IO_IMPORT": "Importar" "MENU_IO_IMPORT": "Importar",
"APP_NOMODULE_1": "Actualmente no hay ningún módulo cargado.",
"APP_NOMODULE_2": "Vuelva a configurar su orden de carga en:"
} }

View File

@@ -16,5 +16,7 @@
"MENU_OPTIONS_DITHER": "Sekoitussävytys", "MENU_OPTIONS_DITHER": "Sekoitussävytys",
"MENU_OPTIONS_BLUR": "Sumea", "MENU_OPTIONS_BLUR": "Sumea",
"MENU_OPTIONS_PARTICLES": "Hiukkaset", "MENU_OPTIONS_PARTICLES": "Hiukkaset",
"MENU_IO_IMPORT": "Tuo" "MENU_IO_IMPORT": "Tuo",
"APP_NOMODULE_1": "Moduulia ei ole ladattu tällä hetkellä.",
"APP_NOMODULE_2": "Määritä lataustilauksesi uudelleen:"
} }

View File

@@ -17,5 +17,7 @@
"MENU_OPTIONS_DITHER": "Tramage", "MENU_OPTIONS_DITHER": "Tramage",
"MENU_OPTIONS_BLUR": "Flou", "MENU_OPTIONS_BLUR": "Flou",
"MENU_OPTIONS_PARTICLES": "Particules", "MENU_OPTIONS_PARTICLES": "Particules",
"MENU_IO_IMPORT": "Importer" "MENU_IO_IMPORT": "Importer",
"APP_NOMODULE_1": "Aucun module nest actuellement chargé.",
"APP_NOMODULE_2": "Veuillez reconfigurer votre ordre de chargement sur :"
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
{
"CONTEXT_CHARACTER": "अवतार",
"MENU_LABEL_COPYRIGHT": "कॉपीराइट",
"COPYRIGHT_ALL_RIGHTS_RESERVED": "All rights reserved",
"COPYRIGHT_GNU_GPL_3": "GNU GPL 3 के तहत वितरित ",
"APP_WARNING_HEALTH_AND_SAFETY": "चेतावनी-स्वास्थ्य और सुरक्षा",
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
"MENU_MODULES" : "मॉड्यूल",
"GAME_ACTION_MOVE_VERB" : "हिलना",
"GAME_ACTION_ZOOM" : "ज़ूम",
"MENU_LABEL_RESET" : "रीसेट",
"MENU_OPTION_STREAMERS_LAYOUT": "Chat Overlay",
"MENU_LABEL_RESTART_REQUIRED": "पुनः शुरआत जरुरी है",
"MENU_LABEL_KEYBOARD_LAYOUT": "कीबोर्ड विन्यास",
"MENU_LABEL_IME": "इनपुट विधि",
"MENU_OPTIONS_DITHER": "Dithering",
"MENU_OPTIONS_BLUR": "Blur",
"MENU_OPTIONS_PARTICLES": "कणों",
"MENU_IO_IMPORT": "Import",
"APP_NOMODULE_1": "वर्तमान में कोई मॉड्यूल लोड नहीं है।",
"APP_NOMODULE_2": "कृपया निम्न फ़ाइल पर अपना लोड ऑर्डर पुन: कॉन्फ़िगर करें:"
}

View File

@@ -16,5 +16,7 @@
"MENU_OPTIONS_DITHER": "ディザリング", "MENU_OPTIONS_DITHER": "ディザリング",
"MENU_OPTIONS_BLUR": "ぼかし", "MENU_OPTIONS_BLUR": "ぼかし",
"MENU_OPTIONS_PARTICLES": "粒子の数", "MENU_OPTIONS_PARTICLES": "粒子の数",
"MENU_IO_IMPORT": "インポート" "MENU_IO_IMPORT": "インポート",
"APP_NOMODULE_1": "現在ロードされたモジュールがありません。",
"APP_NOMODULE_2": "次のファイルでロードオーダーを再設定してください。"
} }

View File

@@ -19,5 +19,7 @@
"MENU_OPTIONS_DITHER": "디더링", "MENU_OPTIONS_DITHER": "디더링",
"MENU_OPTIONS_BLUR": "흐림", "MENU_OPTIONS_BLUR": "흐림",
"MENU_OPTIONS_PARTICLES": "입자 수", "MENU_OPTIONS_PARTICLES": "입자 수",
"MENU_IO_IMPORT": "가져오기" "MENU_IO_IMPORT": "가져오기",
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 재설정하십시오."
} }

View File

@@ -15,5 +15,7 @@
"MENU_OPTIONS_DITHER": "Сглаживание", "MENU_OPTIONS_DITHER": "Сглаживание",
"MENU_OPTIONS_BLUR": "Размытие", "MENU_OPTIONS_BLUR": "Размытие",
"MENU_OPTIONS_PARTICLES": "Частица", "MENU_OPTIONS_PARTICLES": "Частица",
"MENU_IO_IMPORT": "Импорт" "MENU_IO_IMPORT": "Импорт",
"APP_NOMODULE_1": "В настоящее время модуль не загружен.",
"APP_NOMODULE_2": "Измените конфигурацию вашего порядка загрузки на:"
} }

View File

@@ -22,5 +22,7 @@
"MENU_OPTIONS_DITHER": "递色", "MENU_OPTIONS_DITHER": "递色",
"MENU_OPTIONS_BLUR": "模糊", "MENU_OPTIONS_BLUR": "模糊",
"MENU_OPTIONS_PARTICLES": "微粒数", "MENU_OPTIONS_PARTICLES": "微粒数",
"MENU_IO_IMPORT": "匯入" "MENU_IO_IMPORT": "匯入",
"APP_NOMODULE_1": "当前未加载任何模块。",
"APP_NOMODULE_2": "请重新配置您的加载顺序:"
} }

View File

@@ -18,5 +18,7 @@
"MENU_OPTIONS_DITHER": "遞色", "MENU_OPTIONS_DITHER": "遞色",
"MENU_OPTIONS_BLUR": "模糊", "MENU_OPTIONS_BLUR": "模糊",
"MENU_OPTIONS_PARTICLES": "粒子数", "MENU_OPTIONS_PARTICLES": "粒子数",
"MENU_IO_IMPORT": "Import" "MENU_IO_IMPORT": "Import",
"APP_NOMODULE_1": "當前未加載任何模塊。",
"APP_NOMODULE_2": "請重新配置您的加載順序:"
} }

View File

@@ -1,6 +0,0 @@
# Load Order
# Modules are loaded from top to bottom.
# You can disable basegame, but we don't recommend.
basegame
#dwarventech
1 # Load Order
2 # Modules are loaded from top to bottom.
3 # You can disable basegame, but we don't recommend.
4 basegame
5 #dwarventech

View File

@@ -46,6 +46,7 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack;
import net.torvald.util.DebugTimers; import net.torvald.util.DebugTimers;
import java.io.File; import java.io.File;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.*; import java.util.*;
@@ -1050,6 +1051,7 @@ public class App implements ApplicationListener {
public static String OSName = System.getProperty("os.name"); public static String OSName = System.getProperty("os.name");
public static String OSVersion = System.getProperty("os.version"); public static String OSVersion = System.getProperty("os.version");
private static String tempDir = System.getProperty("java.io.tmpdir");
public static String operationSystem; public static String operationSystem;
/** %appdata%/Terrarum, without trailing slash */ /** %appdata%/Terrarum, without trailing slash */
public static String defaultDir; public static String defaultDir;
@@ -1063,6 +1065,9 @@ public class App implements ApplicationListener {
public static String worldsDir; public static String worldsDir;
/** defaultDir + "/config.json" */ /** defaultDir + "/config.json" */
public static String configDir; public static String configDir;
/** defaultDir + "/LoadOrder.txt" */
public static String loadOrderDir;
public static RunningEnvironment environment; public static RunningEnvironment environment;
private static void getDefaultDirectory() { private static void getDefaultDirectory() {
@@ -1093,6 +1098,7 @@ public class App implements ApplicationListener {
playersDir = defaultDir + "/Players"; playersDir = defaultDir + "/Players";
worldsDir = defaultDir + "/Worlds"; worldsDir = defaultDir + "/Worlds";
configDir = defaultDir + "/config.json"; configDir = defaultDir + "/config.json";
loadOrderDir = defaultDir + "/LoadOrder.txt";
System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem)); System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem));
System.out.println(String.format("os.version = %s", OSVersion)); System.out.println(String.format("os.version = %s", OSVersion));
@@ -1101,18 +1107,30 @@ public class App implements ApplicationListener {
} }
private static void createDirs() { private static void createDirs() {
File[] dirs = {new File(saveDir), new File(saveSharedDir), new File(playersDir), new File(worldsDir)}; File[] dirs = {
new File(saveDir),
new File(saveSharedDir),
new File(playersDir),
new File(worldsDir)
};
for (File it : dirs) { for (File it : dirs) {
if (!it.exists()) if (!it.exists())
it.mkdirs(); it.mkdirs();
} }
try {
createLoadOrderFile();
}
catch (IOException e) {
e.printStackTrace();
}
//dirs.forEach { if (!it.exists()) it.mkdirs() } //dirs.forEach { if (!it.exists()) it.mkdirs() }
} }
public static File newTempFile(String filename) { public static File newTempFile(String filename) {
File tempfile = new File("./tmp_" + filename); File tempfile = new File(tempDir, filename);
tempFilePool.add(tempfile); tempFilePool.add(tempfile);
return tempfile; return tempfile;
} }
@@ -1127,6 +1145,16 @@ public class App implements ApplicationListener {
public static KVHashMap gameConfig = new KVHashMap(); public static KVHashMap gameConfig = new KVHashMap();
private static void createLoadOrderFile() throws IOException {
File loadOrderFile = new File(loadOrderDir);
if (!loadOrderFile.exists() || loadOrderFile.length() == 0L) {
var writer = new FileWriter(loadOrderFile);
writer.write(TerrarumAppConfiguration.DEFAULT_LOADORDER_FILE);
writer.flush(); writer.close();
}
}
private static void createConfigJson() throws IOException { private static void createConfigJson() throws IOException {
File configFile = new File(configDir); File configFile = new File(configDir);

View File

@@ -34,7 +34,7 @@ import java.util.function.Consumer
* Although the game (as product) can have infinitely many stages/planets/etc., those stages must be manually managed by YOU; * Although the game (as product) can have infinitely many stages/planets/etc., those stages must be manually managed by YOU;
* this instance only stores the stage that is currently being used. * this instance only stores the stage that is currently being used.
*/ */
open class IngameInstance(val batch: SpriteBatch, val isMultiplayer: Boolean = false) : TerrarumGamescreen { open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boolean = false) : TerrarumGamescreen {
var WORLD_UPDATE_TIMER = Random().nextInt(1020) + 1; protected set var WORLD_UPDATE_TIMER = Random().nextInt(1020) + 1; protected set

View File

@@ -17,8 +17,10 @@ import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVParser import org.apache.commons.csv.CSVParser
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
import java.io.File import java.io.File
import java.io.FileFilter
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.FilenameFilter
import java.net.MalformedURLException import java.net.MalformedURLException
import java.net.URL import java.net.URL
import java.net.URLClassLoader import java.net.URLClassLoader
@@ -79,7 +81,8 @@ object ModMgr {
NOT_EVEN_THERE NOT_EVEN_THERE
} }
const val modDir = "./assets/mods" const val modDirInternal = "./assets/mods"
val modDirExternal = "${App.defaultDir}/Modules"
/** Module name (directory name), ModuleMetadata */ /** Module name (directory name), ModuleMetadata */
val moduleInfo = HashMap<String, ModuleMetadata>() val moduleInfo = HashMap<String, ModuleMetadata>()
@@ -99,7 +102,7 @@ object ModMgr {
/** /**
* Try to create an instance of a "titlescreen" from the current load order set. * Try to create an instance of a "titlescreen" from the current load order set.
*/ */
fun getTitleScreen(batch: SpriteBatch): IngameInstance? = entryPointClasses.getOrNull(0)?.getTitleScreen(batch) fun getTitleScreen(batch: FlippingSpriteBatch): IngameInstance? = entryPointClasses.getOrNull(0)?.getTitleScreen(batch)
private fun List<String>.toVersionNumber() = 0L or private fun List<String>.toVersionNumber() = 0L or
(this[0].replaceFirst('*','0').removeSuffix("+").toLong().shl(24)) or (this[0].replaceFirst('*','0').removeSuffix("+").toLong().shl(24)) or
@@ -108,7 +111,7 @@ object ModMgr {
init { init {
val loadOrderFile = FileSystems.getDefault().getPath("$modDir/LoadOrder.csv").toFile() val loadOrderFile = FileSystems.getDefault().getPath("${App.defaultDir}/LoadOrder.txt").toFile()
if (loadOrderFile.exists()) { if (loadOrderFile.exists()) {
// load modules // load modules
@@ -128,10 +131,10 @@ object ModMgr {
try { try {
val modMetadata = Properties() val modMetadata = Properties()
modMetadata.load(FileInputStream("$modDir/$moduleName/$metaFilename")) modMetadata.load(FileInputStream("$modDirInternal/$moduleName/$metaFilename"))
if (File("$modDir/$moduleName/$defaultConfigFilename").exists()) { if (File("$modDirInternal/$moduleName/$defaultConfigFilename").exists()) {
val defaultConfig = JsonFetcher("$modDir/$moduleName/$defaultConfigFilename") val defaultConfig = JsonFetcher("$modDirInternal/$moduleName/$defaultConfigFilename")
// read config and store it to the game // read config and store it to the game
// write to user's config file // write to user's config file
@@ -148,7 +151,7 @@ object ModMgr {
val version = modMetadata.getProperty("version") val version = modMetadata.getProperty("version")
val jar = modMetadata.getProperty("jar") val jar = modMetadata.getProperty("jar")
val dependency = modMetadata.getProperty("dependency").split(Regex(""";[ ]*""")).filter { it.isNotEmpty() }.toTypedArray() val dependency = modMetadata.getProperty("dependency").split(Regex(""";[ ]*""")).filter { it.isNotEmpty() }.toTypedArray()
val isDir = FileSystems.getDefault().getPath("$modDir/$moduleName").toFile().isDirectory val isDir = FileSystems.getDefault().getPath("$modDirInternal/$moduleName").toFile().isDirectory
val versionNumeral = version.split('.') val versionNumeral = version.split('.')
@@ -170,10 +173,15 @@ object ModMgr {
} }
moduleInfo[moduleName] = ModuleMetadata(index, isDir, Gdx.files.internal("$modDir/$moduleName/icon.png"), properName, description, author, packageName, entryPoint, releaseDate, version, jar, dependency) moduleInfo[moduleName] = ModuleMetadata(index, isDir, Gdx.files.internal("$modDirInternal/$moduleName/icon.png"), properName, description, author, packageName, entryPoint, releaseDate, version, jar, dependency)
printdbg(this, moduleInfo[moduleName]) printdbg(this, moduleInfo[moduleName])
// do retexturing if retextures directory exists
if (hasFile(moduleName, "retextures")) {
printdbg(this, "Trying to load Retextures on ${moduleName}")
GameRetextureLoader(moduleName)
}
// run entry script in entry point // run entry script in entry point
if (entryPoint.isNotBlank()) { if (entryPoint.isNotBlank()) {
@@ -184,7 +192,7 @@ object ModMgr {
val urls = arrayOf<URL>() val urls = arrayOf<URL>()
val cl = JarFileLoader(urls) val cl = JarFileLoader(urls)
cl.addFile("${File(modDir).absolutePath}/$moduleName/$jar") cl.addFile("${File(modDirInternal).absolutePath}/$moduleName/$jar")
moduleClassloader[moduleName] = cl moduleClassloader[moduleName] = cl
newClass = cl.loadClass(entryPoint) newClass = cl.loadClass(entryPoint)
} }
@@ -310,21 +318,31 @@ object ModMgr {
fun getPath(module: String, path: String): String { /*fun getPath(module: String, path: String): String {
checkExistence(module) checkExistence(module)
return "$modDir/$module/${path.sanitisePath()}" return "$modDirInternal/$module/${path.sanitisePath()}"
} }*/
/** Returning files are read-only */ /** Returning files are read-only */
fun getGdxFile(module: String, path: String): FileHandle { fun getGdxFile(module: String, path: String): FileHandle {
return Gdx.files.internal(getPath(module, path)) checkExistence(module)
return if (true) // TODO if module is internal...
Gdx.files.internal("$modDirInternal/$module/$path")
else
Gdx.files.absolute("$modDirExternal/$module/$path")
} }
fun getFile(module: String, path: String): File { fun getFile(module: String, path: String): File {
checkExistence(module) checkExistence(module)
return FileSystems.getDefault().getPath(getPath(module, path)).toFile() return if (true) // TODO if module is internal...
FileSystems.getDefault().getPath("$modDirInternal/$module/$path").toFile()
else
FileSystems.getDefault().getPath("$modDirExternal/$module/$path").toFile()
}
fun hasFile(module: String, path: String): Boolean {
return getFile(module, path).exists()
} }
fun getFiles(module: String, path: String): Array<File> { fun getFiles(module: String, path: String): Array<File> {
checkExistence(module) checkExistence(module)
val dir = FileSystems.getDefault().getPath(getPath(module, path)).toFile() val dir = getFile(module, path)
if (!dir.isDirectory) { if (!dir.isDirectory) {
throw FileNotFoundException("The path is not a directory") throw FileNotFoundException("The path is not a directory")
} }
@@ -344,8 +362,7 @@ object ModMgr {
val filesList = ArrayList<Pair<String, File>>() val filesList = ArrayList<Pair<String, File>>()
moduleNames.forEach { moduleNames.forEach {
val file = File(getPath(it, path)) val file = getFile(it, path)
if (file.exists()) filesList.add(it to file) if (file.exists()) filesList.add(it to file)
} }
@@ -364,8 +381,7 @@ object ModMgr {
val filesList = ArrayList<Pair<String, FileHandle>>() val filesList = ArrayList<Pair<String, FileHandle>>()
moduleNames.forEach { moduleNames.forEach {
val file = Gdx.files.internal(getPath(it, path)) val file = getGdxFile(it, path)
if (file.exists()) filesList.add(it to file) if (file.exists()) filesList.add(it to file)
} }
@@ -440,7 +456,7 @@ object ModMgr {
val langPath = "locales/" val langPath = "locales/"
@JvmStatic operator fun invoke(module: String) { @JvmStatic operator fun invoke(module: String) {
Lang.load(getPath(module, langPath)) Lang.load(getFile(module, langPath))
} }
} }
@@ -455,6 +471,58 @@ object ModMgr {
Terrarum.materialCodex.fromModule(module, matePath + "materials.csv") Terrarum.materialCodex.fromModule(module, matePath + "materials.csv")
} }
} }
/**
* A sugar-library for easy texture pack creation
*/
object GameRetextureLoader {
val retexturesPath = "retextures/"
val retexables = listOf("blocks","wires")
val altFilePaths = HashMap<String, FileHandle>()
val retexableCallbacks = HashMap<String, () -> Unit>()
init {
retexableCallbacks["blocks"] = {
App.tileMaker(true)
}
}
@JvmStatic operator fun invoke(module: String) {
val targetModNames = getFiles(module, retexturesPath).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}")
if (dir.isDirectory && dir.exists()) {
dir.listFiles { it: File ->
it?.name?.contains('-') == true
}.forEach {
// <other modname>-<hopefully a number>.tga or .png
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}")
}
}
}
// retexableCallbacks[category]?.invoke()
}
}
printdbg(this, "ALT FILE PATHS")
altFilePaths.forEach { (k, v) -> printdbg(this, "$k -> $v") }
}
}
} }
private class JarFileLoader(urls: Array<URL>) : URLClassLoader(urls) { private class JarFileLoader(urls: Array<URL>) : URLClassLoader(urls) {

View File

@@ -1,6 +1,5 @@
package net.torvald.terrarum package net.torvald.terrarum
import com.badlogic.gdx.graphics.g2d.SpriteBatch
/** /**
* Created by minjaesong on 2018-06-21. * Created by minjaesong on 2018-06-21.
@@ -8,5 +7,5 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
abstract class ModuleEntryPoint { abstract class ModuleEntryPoint {
abstract fun invoke() abstract fun invoke()
abstract fun dispose() abstract fun dispose()
open fun getTitleScreen(batch: SpriteBatch): IngameInstance? = null open fun getTitleScreen(batch: FlippingSpriteBatch): IngameInstance? = null
} }

View File

@@ -4,44 +4,15 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.FrameBuffer
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.ui.Toolkit
/** /**
* Created by minjaesong on 2021-12-11. * Created by minjaesong on 2021-12-11.
*/ */
class NoModuleDefaultTitlescreen(batch: SpriteBatch) : IngameInstance(batch) { class NoModuleDefaultTitlescreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
private val wot = """No Module is currently loaded. private val wot = "${Lang["APP_NOMODULE_1"]}\n${Lang["APP_NOMODULE_2"]}\n\u115F\n\u115F".split('\n')
Please reconfigure your Load Order on:
Derzeit ist kein Modul geladen.
Bitte konfigurieren Sie Ihren Ladeauftrag neu auf:
Actualmente no hay ningún módulo cargado.
Vuelva a configurar su orden de carga en:
Moduulia ei ole ladattu tällä hetkellä.
Määritä lataustilauksesi uudelleen:
Aucun module nest actuellement chargé.
Veuillez reconfigurer votre ordre de chargement sur :
現在ロードされたモジュールがありません。
次のファイルでロードオーダーを再設定してください。
현재 불러와진 모듈이 없습니다.
다음의 파일에서 불러오기 순서를 재설정하십시오.
В настоящее время модуль не загружен.
Измените конфигурацию вашего порядка загрузки на:
ไม่มีการโหลดโมดูลในขณะนี้
โปรดกำหนดค่าคำสั่งซื้อการโหลดของคุณใหม่เมื่อ:
当前未加载任何模块。请重新配置您的加载顺序:
當前未加載任何模塊。請重新配置您的加載順序:
\c\a assets/mods/LoadOrder.csv""".split('\n')
private val maxtw = wot.maxOf { App.fontGameFBO.getWidth(it) } private val maxtw = wot.maxOf { App.fontGameFBO.getWidth(it) }
@@ -49,11 +20,13 @@ Veuillez reconfigurer votre ordre de chargement sur :
private var init = false private var init = false
private val pathText = App.loadOrderDir
override fun render(updateRate: Float) { override fun render(updateRate: Float) {
gdxClearAndSetBlend(0f, 0f, 0f, 0f) gdxClearAndSetBlend(0f, 0f, 0f, 0f)
if (!init) { if (!init) {
val lh = 20f val lh = 28f
val pbreak = 8f val pbreak = 8f
val th = lh * wot.size val th = lh * wot.size
@@ -72,19 +45,9 @@ Veuillez reconfigurer votre ordre de chargement sur :
batch.inUse { batch.inUse {
batch.color = Color.WHITE batch.color = Color.WHITE
wot.reversed().forEachIndexed { index, s -> wot.reversed().forEachIndexed { index, s ->
if (s.startsWith('\\')) { if (index == 0) {
val tagsSplit = s.indexOfFirst { it == ' ' } batch.color = Toolkit.Theme.COL_HIGHLIGHT
val tagsBulk = s.substring(0, tagsSplit) App.fontGameFBO.draw(batch, pathText, (Toolkit.drawWidth - App.fontGameFBO.getWidth(pathText)) / 2f, heights[index] + centering)
val tags = tagsBulk.split('\\').filter { it.isNotBlank() }
val text = s.substring(tagsSplit + 1)
if (tags.contains("a")) batch.color = Toolkit.Theme.COL_HIGHLIGHT else batch.color = Color.WHITE
if (tags.contains("c"))
App.fontGameFBO.draw(batch, text, (Toolkit.drawWidth - App.fontGameFBO.getWidth(text)) / 2f, heights[index] + centering)
else
App.fontGameFBO.draw(batch, text, (Toolkit.drawWidth - maxtw) / 2f, heights[index] + centering)
} }
else { else {
batch.color = Color.WHITE batch.color = Color.WHITE

View File

@@ -28,6 +28,12 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
const val DEFAULT_LOADORDER_FILE = """# Load Order
# Modules are loaded from top to bottom.
# You can disable basegame, but we don't recommend.
basegame
""" """
/** /**

View File

@@ -70,7 +70,7 @@ class WireCodex {
val wireid = id.split(':').last().toInt() val wireid = id.split(':').last().toInt()
CommonResourcePool.addToLoadingList(id) { CommonResourcePool.addToLoadingList(id) {
val t = TextureRegionPack(ModMgr.getPath(module, "$path$wireid.tga"), TILE_SIZE, TILE_SIZE) val t = TextureRegionPack(ModMgr.getGdxFile(module, "$path$wireid.tga"), TILE_SIZE, TILE_SIZE)
/*return*/t /*return*/t
} }
} }

View File

@@ -37,45 +37,46 @@ object CommandDict {
printdbg(this, ModMgr.loadOrder.reversed().map { ModMgr.moduleInfo[it]?.packageName }) printdbg(this, ModMgr.loadOrder.reversed().map { ModMgr.moduleInfo[it]?.packageName })
((listOf("$" to "net.torvald.terrarum")) + ModMgr.loadOrder.reversed().map { it to ModMgr.moduleInfo[it]?.packageName }).forEach { (modName, packageRoot) -> ((listOf("$" to "net.torvald.terrarum")) + ModMgr.loadOrder.reversed().map { it to ModMgr.moduleInfo[it]?.packageName }).forEach { (modName, packageRoot) ->
val commandsList = if (modName == "$") engineCommandList else ModMgr.getFile(modName, "commands.csv").readLines() if (modName != "$" && ModMgr.hasFile(modName, "commands.csv")) {
val packageConsole = "$packageRoot.console" val commandsList = if (modName == "$") engineCommandList else ModMgr.getFile(modName, "commands.csv").readLines()
val packageConsole = "$packageRoot.console"
printdbg(this, "Loading console commands from '${packageConsole}'") printdbg(this, "Loading console commands from '${packageConsole}'")
// printdbg(this, commandsList.joinToString()) // printdbg(this, commandsList.joinToString())
commandsList.forEach { commandName -> commandsList.forEach { commandName ->
val canonicalName = "$packageConsole.$commandName" val canonicalName = "$packageConsole.$commandName"
val it = Class.forName(canonicalName) val it = Class.forName(canonicalName)
printdbg(this, "> Trying to instantiate ${it.canonicalName}") printdbg(this, "> Trying to instantiate ${it.canonicalName}")
try { try {
val instance = it.kotlin.objectInstance ?: it.kotlin.java.newInstance() val instance = it.kotlin.objectInstance ?: it.kotlin.java.newInstance()
val aliases = instance.javaClass.getAnnotation(ConsoleAlias::class.java)?.aliasesCSV?.split(',')?.map { it.trim() } val aliases = instance.javaClass.getAnnotation(ConsoleAlias::class.java)?.aliasesCSV?.split(',')?.map { it.trim() }
val noexport = instance.javaClass.getAnnotation(ConsoleNoExport::class.java) val noexport = instance.javaClass.getAnnotation(ConsoleNoExport::class.java)
if (noexport == null) { if (noexport == null) {
dict[instance.javaClass.simpleName.lowercase()] = instance as ConsoleCommand dict[instance.javaClass.simpleName.lowercase()] = instance as ConsoleCommand
aliases?.forEach { aliases?.forEach {
dict[it] = instance as ConsoleCommand dict[it] = instance as ConsoleCommand
}
printdbg(this, "Class instantiated: ${instance.javaClass.simpleName}")
if (aliases != null)
printdbg(this, " Annotations: $aliases")
} }
}
printdbg(this, "Class instantiated: ${instance.javaClass.simpleName}") catch (e: ClassCastException) {
if (aliases != null) printdbgerr(this, "${it.canonicalName} is not a ConsoleCommand")
printdbg(this, " Annotations: $aliases") }
catch (e: InstantiationException) {
printdbgerr(this, "Could not instantiate ${it.canonicalName}")
e.printStackTrace(System.err)
} }
} }
catch (e: ClassCastException) {
printdbgerr(this, "${it.canonicalName} is not a ConsoleCommand")
}
catch (e: InstantiationException) {
printdbgerr(this, "Could not instantiate ${it.canonicalName}")
e.printStackTrace(System.err)
}
} }
} }

View File

@@ -44,17 +44,15 @@ object Lang {
init { init {
// load base langs // load base langs
load("./assets/locales/") load(File("./assets/locales/"))
} }
@JvmStatic operator fun invoke() { /* dummy method for manual initialisation */ } @JvmStatic operator fun invoke() { /* dummy method for manual initialisation */ }
fun load(localesDir: String) { fun load(localesDir: File) {
printdbg(this, "Loading languages from $localesDir") printdbg(this, "Loading languages from $localesDir")
val localesDir = File(localesDir)
// get all of the languages installed // get all of the languages installed
localesDir.listFiles().filter { it.isDirectory }.forEach { languageList.add(it.name) } localesDir.listFiles().filter { it.isDirectory }.forEach { languageList.add(it.name) }

View File

@@ -28,7 +28,7 @@ import net.torvald.util.CircularArray
/** /**
* Created by minjaesong on 2018-07-06. * Created by minjaesong on 2018-07-06.
*/ */
class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) { class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
private val menuYaml = Yaml(""" private val menuYaml = Yaml("""
- File - File

View File

@@ -20,7 +20,7 @@ class EntryPoint : ModuleEntryPoint() {
private val moduleName = "basegame" private val moduleName = "basegame"
override fun getTitleScreen(batch: SpriteBatch): IngameInstance? { override fun getTitleScreen(batch: FlippingSpriteBatch): IngameInstance? {
return TitleScreen(batch) return TitleScreen(batch)
} }

View File

@@ -61,7 +61,7 @@ import java.util.*
* Created by minjaesong on 2017-06-16. * Created by minjaesong on 2017-06-16.
*/ */
open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
var historicalFigureIDBucket: ArrayList<Int> = ArrayList<Int>() var historicalFigureIDBucket: ArrayList<Int> = ArrayList<Int>()

View File

@@ -41,7 +41,7 @@ import kotlin.math.sin
/** /**
* Created by minjaesong on 2017-09-02. * Created by minjaesong on 2017-09-02.
*/ */
class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) { class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
// todo register titlescreen as the ingame, similar in a way that the buildingmaker did // todo register titlescreen as the ingame, similar in a way that the buildingmaker did

View File

@@ -24,7 +24,7 @@ object InjectCreatureRaw {
* @param jsonFileName with extension * @param jsonFileName with extension
*/ */
operator fun invoke(actorValueRef: ActorValue, module: String, jsonFileName: String) { operator fun invoke(actorValueRef: ActorValue, module: String, jsonFileName: String) {
val jsonObj = JsonFetcher(ModMgr.getPath(module, "creatures/$jsonFileName")) val jsonObj = JsonFetcher(ModMgr.getFile(module, "creatures/$jsonFileName"))
JsonFetcher.forEach(jsonObj) { key, value -> if (!key.startsWith("_")) { JsonFetcher.forEach(jsonObj) { key, value -> if (!key.startsWith("_")) {

View File

@@ -10,8 +10,8 @@ import net.torvald.terrarum.gameactors.AVKey
object PlayerBuilderTestSubject1 { object PlayerBuilderTestSubject1 {
operator fun invoke(): IngamePlayer { operator fun invoke(): IngamePlayer {
val p: IngamePlayer = IngamePlayer( val p: IngamePlayer = IngamePlayer(
ModMgr.getPath("basegame", "sprites/test_sprite.properties"), ModMgr.getGdxFile("basegame", "sprites/test_sprite.properties").path(),
ModMgr.getPath("basegame", "sprites/test_sprite_glow.properties"), ModMgr.getGdxFile("basegame", "sprites/test_sprite_glow.properties").path(),
-589141658L // random value thrown -589141658L // random value thrown
) )
InjectCreatureRaw(p.actorValue, "basegame", "CreatureHuman.json") InjectCreatureRaw(p.actorValue, "basegame", "CreatureHuman.json")

View File

@@ -11,8 +11,8 @@ import net.torvald.terrarum.gameactors.AVKey
object PlayerBuilderWerebeastTest { object PlayerBuilderWerebeastTest {
operator fun invoke(): IngamePlayer { operator fun invoke(): IngamePlayer {
val p: IngamePlayer = IngamePlayer( val p: IngamePlayer = IngamePlayer(
ModMgr.getPath("basegame", "sprites/taimu.properties"), ModMgr.getGdxFile("basegame", "sprites/taimu.properties").path(),
ModMgr.getPath("basegame", "sprites/taimu_glow.properties"), ModMgr.getGdxFile("basegame", "sprites/taimu_glow.properties").path(),
-589141658L // random value thrown -589141658L // random value thrown
) )
InjectCreatureRaw(p.actorValue, "basegame", "CreatureWerebeastBase.json") InjectCreatureRaw(p.actorValue, "basegame", "CreatureWerebeastBase.json")

View File

@@ -29,7 +29,7 @@ class UIBasicInfo() : UICanvas() {
private var ELon = false private var ELon = false
private var watchFont = WatchFont private var watchFont = WatchFont
private var atlas = TextureRegionPack(ModMgr.getPath("basegame", "gui/basic_info1.tga"), width, height) private var atlas = TextureRegionPack(ModMgr.getGdxFile("basegame", "gui/basic_info1.tga"), width, height)
private var font = Watch7SegSmall private var font = Watch7SegSmall

View File

@@ -23,10 +23,10 @@ class UITierOneWatch() : UICanvas() {
private val ELuptime = 4f private val ELuptime = 4f
private var ELon = false private var ELon = false
private var atlas = TextureRegionPack(ModMgr.getPath("basegame", "gui/watchface_atlas.tga"), width, height) private var atlas = TextureRegionPack(ModMgr.getGdxFile("basegame", "gui/watchface_atlas.tga"), width, height)
private var watchFont = WatchFont private var watchFont = WatchFont
private var moonDial = TextureRegionPack(ModMgr.getPath("basegame", "fonts/watch_17pxmoondial.tga"), 17, 17) private var moonDial = TextureRegionPack(ModMgr.getGdxFile("basegame", "fonts/watch_17pxmoondial.tga"), 17, 17)
private var moonDialCount = moonDial.horizontalCount private var moonDialCount = moonDial.horizontalCount
private val drawCol = Color(1f, 1f, 1f, UIQuickslotBar.DISPLAY_OPACITY) private val drawCol = Color(1f, 1f, 1f, UIQuickslotBar.DISPLAY_OPACITY)

View File

@@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.utils.GdxRuntimeException
import net.torvald.terrarum.App import net.torvald.terrarum.App
import net.torvald.terrarum.CommonResourcePool import net.torvald.terrarum.CommonResourcePool
import net.torvald.terrarum.ModMgr import net.torvald.terrarum.ModMgr
@@ -28,7 +29,12 @@ class UIItemModuleInfoCell(
private val modErrored = (ModMgr.moduleInfo[modName] == null) private val modErrored = (ModMgr.moduleInfo[modName] == null)
private val modIcon = TextureRegion(Texture(modProp.iconFile)) private val modIcon = try {
TextureRegion(Texture(modProp.iconFile))
}
catch (_: GdxRuntimeException) {
CommonResourcePool.getAsTextureRegion("itemplaceholder_48")
}
private val modVer = modProp.version private val modVer = modProp.version
private val modDate = modProp.releaseDate private val modDate = modProp.releaseDate
private val modAuthor = modProp.author private val modAuthor = modProp.author

View File

@@ -36,7 +36,7 @@ object CSVFetcher {
return csvRecordList return csvRecordList
} }
fun readFromModule(module: String, path: String) = net.torvald.terrarum.utils.CSVFetcher.readFromFile(ModMgr.getPath(module, path)) fun readFromModule(module: String, path: String) = net.torvald.terrarum.utils.CSVFetcher.readFromFile(ModMgr.getGdxFile(module, path).path())
fun readFromString(csv: String): List<org.apache.commons.csv.CSVRecord> { fun readFromString(csv: String): List<org.apache.commons.csv.CSVRecord> {
val csvParser = org.apache.commons.csv.CSVParser.parse( val csvParser = org.apache.commons.csv.CSVParser.parse(

View File

@@ -107,8 +107,11 @@ class CreateTileAtlas {
// filter files that do not exist on the blockcodex // filter files that do not exist on the blockcodex
dir.list().filter { tgaFile -> !tgaFile.isDirectory && (BlockCodex.getOrNull("$modname:${tgaFile.nameWithoutExtension()}") != null) } dir.list().filter { tgaFile -> !tgaFile.isDirectory && (BlockCodex.getOrNull("$modname:${tgaFile.nameWithoutExtension()}") != null) }
.sortedBy { it.nameWithoutExtension().toInt() }.forEach { tgaFile -> // toInt() to sort by the number, not lexicographically .sortedBy { it.nameWithoutExtension().toInt() }.forEach { tgaFile: FileHandle -> // toInt() to sort by the number, not lexicographically
tgaList.add(modname to tgaFile) // tgaFile be like: ./assets/mods/basegame/blocks/32.tga (which is not always .tga)
val newFile = ModMgr.GameRetextureLoader.altFilePaths.getOrDefault(tgaFile.path(), tgaFile)
tgaList.add(modname to newFile)
// printdbg(this, "modname = $modname, file = $newFile")
} }
} }
@@ -225,7 +228,7 @@ class CreateTileAtlas {
private fun fileToAtlantes(modname: String, matte: FileHandle, glow: FileHandle?) { private fun fileToAtlantes(modname: String, matte: FileHandle, glow: FileHandle?) {
val tilesPixmap = Pixmap(matte) val tilesPixmap = Pixmap(matte)
val tilesGlowPixmap = if (glow != null) Pixmap(glow) else nullTile val tilesGlowPixmap = if (glow != null) Pixmap(glow) else nullTile
val blockName = matte.nameWithoutExtension().toInt() // basically a filename val blockName = matte.nameWithoutExtension().split('-').last().toInt() // basically a filename
val blockID = "$modname:$blockName" val blockID = "$modname:$blockName"
// determine the type of the block (populate tags list) // determine the type of the block (populate tags list)