580 lines
20 KiB
Kotlin
580 lines
20 KiB
Kotlin
package ru.dbotthepony.kstarbound
|
||
|
||
import com.google.common.collect.ImmutableList
|
||
import com.google.common.collect.Interner
|
||
import com.google.common.collect.Interners
|
||
import com.google.gson.*
|
||
import com.google.gson.internal.bind.TypeAdapters
|
||
import com.google.gson.stream.JsonReader
|
||
import com.google.gson.stream.JsonWriter
|
||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||
import org.apache.logging.log4j.LogManager
|
||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
||
import ru.dbotthepony.kstarbound.api.NonExistingFile
|
||
import ru.dbotthepony.kstarbound.api.PhysicalFile
|
||
import ru.dbotthepony.kstarbound.api.explore
|
||
import ru.dbotthepony.kstarbound.defs.*
|
||
import ru.dbotthepony.kstarbound.defs.image.AtlasConfiguration
|
||
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
||
import ru.dbotthepony.kstarbound.defs.item.ArmorItemPrototype
|
||
import ru.dbotthepony.kstarbound.defs.item.ArmorPieceType
|
||
import ru.dbotthepony.kstarbound.defs.item.CurrencyItemPrototype
|
||
import ru.dbotthepony.kstarbound.defs.item.IArmorItemDefinition
|
||
import ru.dbotthepony.kstarbound.defs.item.IFossilItemDefinition
|
||
import ru.dbotthepony.kstarbound.defs.item.IItemDefinition
|
||
import ru.dbotthepony.kstarbound.defs.item.ItemPrototype
|
||
import ru.dbotthepony.kstarbound.defs.item.ItemRarity
|
||
import ru.dbotthepony.kstarbound.defs.item.ItemTooltipKind
|
||
import ru.dbotthepony.kstarbound.defs.item.LeveledStatusEffect
|
||
import ru.dbotthepony.kstarbound.defs.item.LiquidItemPrototype
|
||
import ru.dbotthepony.kstarbound.defs.item.MaterialItemPrototype
|
||
import ru.dbotthepony.kstarbound.defs.liquid.LiquidDefinition
|
||
import ru.dbotthepony.kstarbound.defs.parallax.ParallaxPrototype
|
||
import ru.dbotthepony.kstarbound.defs.projectile.*
|
||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||
import ru.dbotthepony.kstarbound.defs.tile.RenderParameters
|
||
import ru.dbotthepony.kstarbound.defs.tile.RenderTemplate
|
||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
||
import ru.dbotthepony.kstarbound.defs.world.SkyParameters
|
||
import ru.dbotthepony.kstarbound.defs.world.dungeon.DungeonWorldDef
|
||
import ru.dbotthepony.kstarbound.io.*
|
||
import ru.dbotthepony.kstarbound.io.json.AABBTypeAdapter
|
||
import ru.dbotthepony.kstarbound.io.json.AABBiTypeAdapter
|
||
import ru.dbotthepony.kstarbound.io.json.builder.EnumAdapter
|
||
import ru.dbotthepony.kstarbound.io.json.Vector2dTypeAdapter
|
||
import ru.dbotthepony.kstarbound.io.json.Vector2fTypeAdapter
|
||
import ru.dbotthepony.kstarbound.io.json.Vector2iTypeAdapter
|
||
import ru.dbotthepony.kstarbound.io.json.Vector4iTypeAdapter
|
||
import ru.dbotthepony.kstarbound.io.json.factory.ImmutableCollectionAdapterFactory
|
||
import ru.dbotthepony.kstarbound.math.*
|
||
import ru.dbotthepony.kvector.vector.Color
|
||
import java.io.*
|
||
import java.text.DateFormat
|
||
import java.util.*
|
||
import kotlin.collections.ArrayList
|
||
|
||
const val METRES_IN_STARBOUND_UNIT = 0.5
|
||
const val METRES_IN_STARBOUND_UNITf = 0.5f
|
||
|
||
const val PIXELS_IN_STARBOUND_UNIT = 8.0
|
||
const val PIXELS_IN_STARBOUND_UNITf = 8.0f
|
||
|
||
// class TileDefLoadingException(message: String, cause: Throwable? = null) : IllegalStateException(message, cause)
|
||
// class ProjectileDefLoadingException(message: String, cause: Throwable? = null) : IllegalStateException(message, cause)
|
||
|
||
fun String.sbIntern(): String = Starbound.STRING_INTERNER.intern(this)
|
||
|
||
object Starbound {
|
||
private val LOGGER = LogManager.getLogger()
|
||
|
||
/**
|
||
* Служит переменной для указания из какой папки происходит чтение asset'а в данном потоке
|
||
*/
|
||
var assetFolder by ThreadLocal<String>()
|
||
private set
|
||
|
||
fun assetFolder(input: String): String {
|
||
val assetFolder = assetFolder
|
||
require(assetFolder != null) { "Not reading an asset on current thread" }
|
||
|
||
if (input[0] == '/')
|
||
return input
|
||
|
||
return STRING_INTERNER.intern("$assetFolder/$input")
|
||
}
|
||
|
||
fun assetFolderNullable(input: String?): String? {
|
||
require(assetFolder != null) { "Not reading an asset on current thread" }
|
||
|
||
if (input != null)
|
||
return assetFolder(input)
|
||
|
||
return null
|
||
}
|
||
|
||
fun readingFolderListTransformer(input: List<String>?): List<String>? {
|
||
if (input == null)
|
||
return null
|
||
|
||
return input.stream().map { assetFolder(it) }.collect(ImmutableList.toImmutableList())
|
||
}
|
||
|
||
private val tiles = Object2ObjectOpenHashMap<String, TileDefinition>()
|
||
private val tilesByMaterialID = Int2ObjectOpenHashMap<TileDefinition>()
|
||
|
||
private val tileModifiers = Object2ObjectOpenHashMap<String, MaterialModifier>()
|
||
private val tileModifiersByID = Int2ObjectOpenHashMap<MaterialModifier>()
|
||
|
||
private val liquid = Object2ObjectOpenHashMap<String, LiquidDefinition>()
|
||
private val liquidByID = Int2ObjectOpenHashMap<LiquidDefinition>()
|
||
|
||
private val projectiles = Object2ObjectOpenHashMap<String, ConfiguredProjectile>()
|
||
private val parallax = Object2ObjectOpenHashMap<String, ParallaxPrototype>()
|
||
private val functions = Object2ObjectOpenHashMap<String, JsonFunction>()
|
||
|
||
private val items = Object2ObjectOpenHashMap<String, IItemDefinition>()
|
||
|
||
val LIQUID: Map<String, LiquidDefinition> = Collections.unmodifiableMap(liquid)
|
||
val LIQUID_BY_ID: Map<Int, LiquidDefinition> = Collections.unmodifiableMap(liquidByID)
|
||
val TILE_MODIFIER: Map<String, MaterialModifier> = Collections.unmodifiableMap(tileModifiers)
|
||
val TILE_MODIFIER_BY_ID: Map<Int, MaterialModifier> = Collections.unmodifiableMap(tileModifiersByID)
|
||
val TILE: Map<String, TileDefinition> = Collections.unmodifiableMap(tiles)
|
||
val TILE_BY_ID: Map<Int, TileDefinition> = Collections.unmodifiableMap(tilesByMaterialID)
|
||
val PROJECTILE: Map<String, ConfiguredProjectile> = Collections.unmodifiableMap(projectiles)
|
||
val PARALLAX: Map<String, ParallaxPrototype> = Collections.unmodifiableMap(parallax)
|
||
val FUNCTION: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
|
||
val ITEM: Map<String, IItemDefinition> = Collections.unmodifiableMap(items)
|
||
|
||
val STRING_INTERNER: Interner<String> = Interners.newWeakInterner()
|
||
|
||
val STRING_ADAPTER: TypeAdapter<String> = object : TypeAdapter<String>() {
|
||
override fun write(out: JsonWriter, value: String) {
|
||
out.value(value)
|
||
}
|
||
|
||
override fun read(`in`: JsonReader): String {
|
||
return STRING_INTERNER.intern(TypeAdapters.STRING.read(`in`))
|
||
}
|
||
}
|
||
|
||
val NULLABLE_STRING_ADAPTER: TypeAdapter<String?> = STRING_ADAPTER.nullSafe()
|
||
|
||
val GSON: Gson = GsonBuilder()
|
||
.enableComplexMapKeySerialization()
|
||
.serializeNulls()
|
||
.setDateFormat(DateFormat.LONG)
|
||
.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
|
||
.setPrettyPrinting()
|
||
.registerTypeAdapter(ColorTypeAdapter.nullSafe())
|
||
|
||
.registerTypeAdapterFactory(ImmutableCollectionAdapterFactory)
|
||
|
||
// чтоб строки всегда intern'ились
|
||
.registerTypeAdapter(NULLABLE_STRING_ADAPTER)
|
||
|
||
// math
|
||
.registerTypeAdapter(AABBTypeAdapter)
|
||
.registerTypeAdapter(AABBiTypeAdapter)
|
||
.registerTypeAdapter(Vector2dTypeAdapter)
|
||
.registerTypeAdapter(Vector2fTypeAdapter)
|
||
.registerTypeAdapter(Vector2iTypeAdapter)
|
||
.registerTypeAdapter(Vector4iTypeAdapter)
|
||
.registerTypeAdapter(PolyTypeAdapter)
|
||
|
||
.also(ConfigurableProjectile::registerGson)
|
||
.also(SkyParameters::registerGson)
|
||
.also(DungeonWorldDef::registerGson)
|
||
.also(ParallaxPrototype::registerGson)
|
||
.also(JsonFunction::registerGson)
|
||
.also(MaterialModifier::registerGson)
|
||
.also(RenderParameters::registerGson)
|
||
.also(RenderTemplate::registerGson)
|
||
.also(TileDefinition::registerGson)
|
||
.also(LiquidDefinition::registerGson)
|
||
.also(SpriteReference::registerGson)
|
||
.also(AtlasConfiguration::registerGson)
|
||
|
||
.registerTypeAdapter(LeveledStatusEffect.ADAPTER)
|
||
.registerTypeAdapter(MaterialReference.Companion)
|
||
.registerTypeAdapter(ThingDescription.Companion)
|
||
|
||
.registerTypeAdapter(ItemPrototype.ADAPTER)
|
||
.registerTypeAdapter(CurrencyItemPrototype.ADAPTER)
|
||
.registerTypeAdapter(ArmorItemPrototype.ADAPTER)
|
||
.registerTypeAdapter(MaterialItemPrototype.ADAPTER)
|
||
.registerTypeAdapter(LiquidItemPrototype.ADAPTER)
|
||
|
||
.registerTypeAdapter(IItemDefinition.InventoryIcon.ADAPTER)
|
||
.registerTypeAdapter(IFossilItemDefinition.FossilSetDescription.ADAPTER)
|
||
.registerTypeAdapter(IArmorItemDefinition.ArmorFrames.ADAPTER)
|
||
|
||
.registerTypeAdapter(EnumAdapter(DamageType::class, default = DamageType.NORMAL).neverNull())
|
||
.registerTypeAdapter(EnumAdapter(ItemRarity::class).neverNull())
|
||
.registerTypeAdapter(EnumAdapter(ItemTooltipKind::class).neverNull())
|
||
|
||
.create()
|
||
|
||
@Suppress("unchecked_cast")
|
||
fun <T> getTypeAdapter(type: Class<T>): TypeAdapter<T> {
|
||
return when (type) {
|
||
Float::class.java -> TypeAdapters.FLOAT as TypeAdapter<T>
|
||
Double::class.java -> TypeAdapters.DOUBLE as TypeAdapter<T>
|
||
String::class.java -> NULLABLE_STRING_ADAPTER as TypeAdapter<T>
|
||
Int::class.java -> TypeAdapters.INTEGER as TypeAdapter<T>
|
||
Long::class.java -> TypeAdapters.LONG as TypeAdapter<T>
|
||
Boolean::class.java -> TypeAdapters.BOOLEAN as TypeAdapter<T>
|
||
else -> GSON.getAdapter(type)
|
||
}
|
||
}
|
||
|
||
var initializing = false
|
||
private set
|
||
var initialized = false
|
||
private set
|
||
|
||
@Volatile
|
||
var terminateLoading = false
|
||
|
||
private val archivePaths = ArrayList<File>()
|
||
private val fileSystems = ArrayList<IStarboundFile>()
|
||
|
||
fun addFilePath(path: File) {
|
||
fileSystems.add(PhysicalFile(path))
|
||
}
|
||
|
||
fun addPak(pak: StarboundPak) {
|
||
fileSystems.add(pak.root)
|
||
}
|
||
|
||
fun exists(path: String): Boolean {
|
||
@Suppress("name_shadowing")
|
||
var path = path
|
||
|
||
if (path[0] == '/') {
|
||
path = path.substring(1)
|
||
}
|
||
|
||
for (fs in fileSystems) {
|
||
if (fs.locate(path).exists) {
|
||
return true
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
fun locate(path: String): IStarboundFile {
|
||
@Suppress("name_shadowing")
|
||
var path = path
|
||
|
||
if (path[0] == '/') {
|
||
path = path.substring(1)
|
||
}
|
||
|
||
for (fs in fileSystems) {
|
||
val file = fs.locate(path)
|
||
|
||
if (file.exists) {
|
||
return file
|
||
}
|
||
}
|
||
|
||
return NonExistingFile(path.split("/").last(), fullPath = path)
|
||
}
|
||
|
||
fun locate(vararg path: String): IStarboundFile {
|
||
for (p in path) {
|
||
val get = locate(p)
|
||
|
||
if (get.exists) {
|
||
return get
|
||
}
|
||
}
|
||
|
||
return NonExistingFile(path[0].split("/").last(), fullPath = path[0])
|
||
}
|
||
|
||
/**
|
||
* Добавляет pak к чтению при initializeGame
|
||
*/
|
||
fun addPakPath(pak: File) {
|
||
archivePaths.add(pak)
|
||
}
|
||
|
||
fun loadJson(path: String): JsonElement {
|
||
return JsonParser.parseReader(locate(path).reader())
|
||
}
|
||
|
||
fun readDirect(path: String) = locate(path).readDirect()
|
||
|
||
fun getTileDefinition(name: String) = tiles[name]
|
||
private val initCallbacks = ArrayList<() -> Unit>()
|
||
|
||
private fun loadStage(
|
||
callback: (Boolean, Boolean, String) -> Unit,
|
||
loader: ((String) -> Unit) -> Unit,
|
||
name: String,
|
||
) {
|
||
val time = System.currentTimeMillis()
|
||
callback(false, false, "Loading $name...")
|
||
LOGGER.info("Loading $name...")
|
||
|
||
loader {
|
||
if (terminateLoading) {
|
||
throw InterruptedException("Game is terminating")
|
||
}
|
||
|
||
callback(false, true, it)
|
||
}
|
||
|
||
callback(false, true, "Loaded $name in ${System.currentTimeMillis() - time}ms")
|
||
LOGGER.info("Loaded $name in ${System.currentTimeMillis() - time}ms")
|
||
}
|
||
|
||
fun initializeGame(callback: (finished: Boolean, replaceStatus: Boolean, status: String) -> Unit) {
|
||
if (initializing) {
|
||
throw IllegalStateException("Already initializing!")
|
||
}
|
||
|
||
if (initialized) {
|
||
throw IllegalStateException("Already initialized!")
|
||
}
|
||
|
||
initializing = true
|
||
|
||
Thread({
|
||
val time = System.currentTimeMillis()
|
||
|
||
if (archivePaths.isNotEmpty()) {
|
||
callback(false, false, "Reading pak archives...")
|
||
|
||
for (path in archivePaths) {
|
||
callback(false, false, "Reading ${path.name}...")
|
||
|
||
addPak(StarboundPak(path) { _, status ->
|
||
callback(false, true, "${path.name}: $status")
|
||
})
|
||
}
|
||
}
|
||
|
||
loadStage(callback, this::loadFunctions, "functions")
|
||
loadStage(callback, this::loadTileMaterials, "materials")
|
||
loadStage(callback, this::loadProjectiles, "projectiles")
|
||
loadStage(callback, this::loadParallax, "parallax definitions")
|
||
loadStage(callback, this::loadMaterialModifiers, "material modifier definitions")
|
||
loadStage(callback, this::loadLiquidDefinitions, "liquid definitions")
|
||
loadStage(callback, this::loadItemDefinitions, "item definitions")
|
||
|
||
initializing = false
|
||
initialized = true
|
||
callback(true, false, "Finished loading in ${System.currentTimeMillis() - time}ms")
|
||
}, "Asset Loader").start()
|
||
}
|
||
|
||
fun onInitialize(callback: () -> Unit) {
|
||
if (initialized) {
|
||
callback()
|
||
} else {
|
||
initCallbacks.add(callback)
|
||
}
|
||
}
|
||
|
||
fun pollCallbacks() {
|
||
if (initialized && initCallbacks.isNotEmpty()) {
|
||
for (callback in initCallbacks) {
|
||
callback()
|
||
}
|
||
|
||
initCallbacks.clear()
|
||
}
|
||
}
|
||
|
||
private fun loadTileMaterials(callback: (String) -> Unit) {
|
||
assetFolder = "/tiles/materials"
|
||
|
||
for (fs in fileSystems) {
|
||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".material") }) {
|
||
try {
|
||
callback("Loading $listedFile")
|
||
|
||
assetFolder = listedFile.computeDirectory()
|
||
val tileDef = GSON.fromJson(listedFile.reader(), TileDefinition::class.java)
|
||
|
||
check(tiles[tileDef.materialName] == null) { "Already has material with name ${tileDef.materialName} loaded!" }
|
||
check(tilesByMaterialID[tileDef.materialId] == null) { "Already has material with ID ${tileDef.materialId} loaded!" }
|
||
tilesByMaterialID[tileDef.materialId] = tileDef
|
||
tiles[tileDef.materialName] = tileDef
|
||
} catch (err: Throwable) {
|
||
//throw TileDefLoadingException("Loading tile file $listedFile", err)
|
||
LOGGER.error("Loading tile file $listedFile", err)
|
||
}
|
||
|
||
if (terminateLoading) {
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
assetFolder = null
|
||
}
|
||
|
||
private fun loadProjectiles(callback: (String) -> Unit) {
|
||
for (fs in fileSystems) {
|
||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".projectile") }) {
|
||
try {
|
||
callback("Loading $listedFile")
|
||
|
||
assetFolder = listedFile.computeDirectory()
|
||
val def = GSON.fromJson(listedFile.reader(), ConfigurableProjectile::class.java).assemble(listedFile.computeDirectory())
|
||
check(projectiles[def.projectileName] == null) { "Already has projectile with ID ${def.projectileName} loaded!" }
|
||
projectiles[def.projectileName] = def
|
||
} catch(err: Throwable) {
|
||
//throw ProjectileDefLoadingException("Loading projectile file $listedFile", err)
|
||
LOGGER.error("Loading projectile file $listedFile", err)
|
||
}
|
||
|
||
if (terminateLoading) {
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
assetFolder = null
|
||
}
|
||
|
||
private fun loadFunctions(callback: (String) -> Unit) {
|
||
for (fs in fileSystems) {
|
||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".functions") }) {
|
||
try {
|
||
callback("Loading $listedFile")
|
||
|
||
assetFolder = listedFile.computeDirectory()
|
||
val readObject = JsonParser.parseReader(listedFile.reader()) as JsonObject
|
||
|
||
for (key in readObject.keySet()) {
|
||
val def = GSON.fromJson(readObject[key], JsonFunction::class.java)
|
||
functions[key] = def
|
||
}
|
||
} catch(err: Throwable) {
|
||
LOGGER.error("Loading function file $listedFile", err)
|
||
}
|
||
|
||
if (terminateLoading) {
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
assetFolder = null
|
||
}
|
||
|
||
private fun loadParallax(callback: (String) -> Unit) {
|
||
for (fs in fileSystems) {
|
||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".parallax") }) {
|
||
try {
|
||
callback("Loading $listedFile")
|
||
|
||
assetFolder = listedFile.computeDirectory()
|
||
val def = GSON.fromJson(listedFile.reader(), ParallaxPrototype::class.java)
|
||
parallax[listedFile.name.substringBefore('.')] = def
|
||
} catch(err: Throwable) {
|
||
LOGGER.error("Loading parallax file $listedFile", err)
|
||
}
|
||
|
||
if (terminateLoading) {
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
assetFolder = null
|
||
}
|
||
|
||
private fun loadMaterialModifiers(callback: (String) -> Unit) {
|
||
assetFolder = "/tiles/materials"
|
||
|
||
for (fs in fileSystems) {
|
||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".matmod") }) {
|
||
try {
|
||
callback("Loading $listedFile")
|
||
|
||
assetFolder = listedFile.computeDirectory()
|
||
val tileDef = GSON.fromJson(listedFile.reader(), MaterialModifier::class.java)
|
||
|
||
check(tileModifiers[tileDef.modName] == null) { "Already has material with name ${tileDef.modName} loaded!" }
|
||
check(tileModifiersByID[tileDef.modId] == null) { "Already has material with ID ${tileDef.modId} loaded!" }
|
||
tileModifiersByID[tileDef.modId] = tileDef
|
||
tileModifiers[tileDef.modName] = tileDef
|
||
} catch (err: Throwable) {
|
||
//throw TileDefLoadingException("Loading tile file $listedFile", err)
|
||
LOGGER.error("Loading tile modifier file $listedFile", err)
|
||
}
|
||
|
||
if (terminateLoading) {
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
assetFolder = null
|
||
}
|
||
|
||
private fun loadLiquidDefinitions(callback: (String) -> Unit) {
|
||
for (fs in fileSystems) {
|
||
for (listedFile in fs.explore().filter { it.isFile }.filter { it.name.endsWith(".liquid") }) {
|
||
try {
|
||
callback("Loading $listedFile")
|
||
|
||
assetFolder = listedFile.computeDirectory()
|
||
val liquidDef = GSON.fromJson(listedFile.reader(), LiquidDefinition::class.java)
|
||
|
||
check(liquid.put(liquidDef.name, liquidDef) == null) { "Already has liquid with name ${liquidDef.name} loaded!" }
|
||
check(liquidByID.put(liquidDef.liquidId, liquidDef) == null) { "Already has liquid with ID ${liquidDef.liquidId} loaded!" }
|
||
} catch (err: Throwable) {
|
||
//throw TileDefLoadingException("Loading tile file $listedFile", err)
|
||
LOGGER.error("Loading liquid definition file $listedFile", err)
|
||
}
|
||
|
||
if (terminateLoading) {
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
assetFolder = null
|
||
}
|
||
|
||
private fun loadItemDefinitions(callback: (String) -> Unit) {
|
||
val files = listOf(".item", ".currency", ".head", ".chest", ".legs", ".back", ".activeitem", ".matitem", ".liqitem")
|
||
|
||
for (fs in fileSystems) {
|
||
for (listedFile in fs.explore().filter { it.isFile }.filter { f -> files.any { f.name.endsWith(it) } }) {
|
||
try {
|
||
callback("Loading $listedFile")
|
||
|
||
assetFolder = listedFile.computeDirectory()
|
||
|
||
if (listedFile.name.endsWith(".item")) {
|
||
val def = GSON.fromJson(listedFile.reader(), ItemPrototype::class.java)
|
||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||
} else if (listedFile.name.endsWith(".matitem")) {
|
||
val def = GSON.fromJson(listedFile.reader(), MaterialItemPrototype::class.java)
|
||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||
} else if (listedFile.name.endsWith(".liqitem")) {
|
||
val def = GSON.fromJson(listedFile.reader(), LiquidItemPrototype::class.java)
|
||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||
} else if (listedFile.name.endsWith(".currency")) {
|
||
val def = GSON.fromJson(listedFile.reader(), CurrencyItemPrototype::class.java)
|
||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||
} else if (listedFile.name.endsWith(".head")) {
|
||
val def = GSON.fromJson(listedFile.reader(), ArmorItemPrototype::class.java)
|
||
def.armorType = ArmorPieceType.HEAD
|
||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||
} else if (listedFile.name.endsWith(".chest")) {
|
||
val def = GSON.fromJson(listedFile.reader(), ArmorItemPrototype::class.java)
|
||
def.armorType = ArmorPieceType.CHEST
|
||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||
} else if (listedFile.name.endsWith(".legs")) {
|
||
val def = GSON.fromJson(listedFile.reader(), ArmorItemPrototype::class.java)
|
||
def.armorType = ArmorPieceType.LEGS
|
||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||
} else if (listedFile.name.endsWith(".back")) {
|
||
val def = GSON.fromJson(listedFile.reader(), ArmorItemPrototype::class.java)
|
||
def.armorType = ArmorPieceType.BACK
|
||
check(items.put(def.itemName, def.assemble()) == null) { "Already has item with name ${def.itemName} loaded!" }
|
||
}
|
||
} catch (err: Throwable) {
|
||
LOGGER.error("Loading item definition file $listedFile", err)
|
||
}
|
||
|
||
if (terminateLoading) {
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
assetFolder = null
|
||
}
|
||
}
|