Json function parsing?

This commit is contained in:
DBotThePony 2022-03-09 00:39:21 +07:00
parent bf458c2921
commit b02477fc1a
Signed by: DBot
GPG Key ID: DCC23B5715498507
5 changed files with 158 additions and 14 deletions
build.gradle.kts
src/main/kotlin/ru/dbotthepony/kstarbound

View File

@ -17,7 +17,7 @@ repositories {
mavenCentral()
maven {
url = uri("https://maven.dbotthepony.ru")
url = uri("https://maven.dbotthepony.ru/")
}
}

View File

@ -31,8 +31,8 @@ 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)
// class TileDefLoadingException(message: String, cause: Throwable? = null) : IllegalStateException(message, cause)
// class ProjectileDefLoadingException(message: String, cause: Throwable? = null) : IllegalStateException(message, cause)
object Starbound : IVFS {
private val LOGGER = LogManager.getLogger()
@ -40,10 +40,12 @@ object Starbound : IVFS {
private val tiles = HashMap<String, TileDefinition>()
private val projectiles = HashMap<String, ConfiguredProjectile>()
private val parallax = HashMap<String, Parallax>()
private val functions = HashMap<String, JsonFunction>()
val tilesAccess: Map<String, TileDefinition> = Collections.unmodifiableMap(tiles)
val projectilesAccess: Map<String, ConfiguredProjectile> = Collections.unmodifiableMap(projectiles)
val parallaxAccess: Map<String, Parallax> = Collections.unmodifiableMap(parallax)
val functionsAccess: Map<String, JsonFunction> = Collections.unmodifiableMap(functions)
val gson: Gson = GsonBuilder()
.enableComplexMapKeySerialization()
@ -65,6 +67,7 @@ object Starbound : IVFS {
.also(SkyParameters::registerGson)
.also(DungeonWorldDef::registerGson)
.also(Parallax::registerGson)
.also(JsonFunction::registerGson)
.registerTypeAdapter(DamageType::class.java, CustomEnumTypeAdapter(DamageType.values()).nullSafe())
@ -149,6 +152,7 @@ object Starbound : IVFS {
}
}
loadStage(callback, this::loadFunctions, "functions")
loadStage(callback, this::loadTileMaterials, "materials")
loadStage(callback, this::loadProjectiles, "projectiles")
loadStage(callback, this::loadParallax, "parallax definitions")
@ -229,7 +233,8 @@ object Starbound : IVFS {
check(tiles[tileDef.materialName] == null) { "Already has material with ID ${tileDef.materialName} loaded!" }
tiles[tileDef.materialName] = tileDef
} catch (err: Throwable) {
throw TileDefLoadingException("Loading tile file $listedFile", err)
//throw TileDefLoadingException("Loading tile file $listedFile", err)
LOGGER.error("Loading tile file $listedFile", err)
}
}
}
@ -238,18 +243,35 @@ object Starbound : IVFS {
private fun loadProjectiles(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.listAllFiles("projectiles")) {
if (listedFile.endsWith(".projectile")) {
try {
callback("Loading $listedFile")
for (listedFile in fs.listAllFilesWithExtension("projectile")) {
try {
callback("Loading $listedFile")
val def = gson.fromJson(getReader(listedFile), ConfigurableProjectile::class.java).configure(getPathFolder(listedFile))
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)
val def = gson.fromJson(getReader(listedFile), ConfigurableProjectile::class.java).configure(getPathFolder(listedFile))
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)
}
}
}
}
private fun loadFunctions(callback: (String) -> Unit) {
for (fs in fileSystems) {
for (listedFile in fs.listAllFilesWithExtension("functions")) {
try {
callback("Loading $listedFile")
val readObject = loadJson(listedFile) 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)
}
}
}

View File

@ -53,6 +53,19 @@ interface IVFS {
return ArrayList<String>(a.size + b.size).also { it.addAll(a); it.addAll(b) }
}
fun listAllFilesWithExtension(extension: String): Collection<String> {
val listing = ArrayList<String>()
val ext = ".$extension"
for (listedFile in listAllFiles("")) {
if (listedFile.endsWith(ext)) {
listing.add(listedFile)
}
}
return listing
}
fun listAllFiles(path: String): Collection<String> {
val lists = mutableListOf<Collection<String>>()

View File

@ -0,0 +1,93 @@
package ru.dbotthepony.kstarbound.defs
import com.google.common.collect.ImmutableList
import com.google.gson.GsonBuilder
import com.google.gson.JsonArray
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.io.CustomEnumTypeAdapter
import ru.dbotthepony.kstarbound.io.IStringSerializable
import ru.dbotthepony.kstarbound.io.Vector2dTypeAdapter
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
enum class JsonFunctionInterpolation(vararg aliases: String) : IStringSerializable {
LINEAR;
private val aliases: Array<String> = Array(aliases.size) { aliases[it].uppercase() }
override fun match(name: String): Boolean {
for (alias in aliases)
if (name == alias)
return true
return name == this.name
}
override fun write(out: JsonWriter) {
out.value(this.name)
}
companion object {
val ADAPTER: TypeAdapter<JsonFunctionInterpolation> = CustomEnumTypeAdapter(values()).nullSafe()
}
}
enum class JsonFunctionConstraint(vararg aliases: String) : IStringSerializable {
CLAMP;
private val aliases: Array<String> = Array(aliases.size) { aliases[it].uppercase() }
override fun match(name: String): Boolean {
for (alias in aliases)
if (name == alias)
return true
return name == this.name
}
override fun write(out: JsonWriter) {
out.value(this.name)
}
companion object {
val ADAPTER: TypeAdapter<JsonFunctionConstraint> = CustomEnumTypeAdapter(values()).nullSafe()
}
}
class JsonFunction(
val interpolation: JsonFunctionInterpolation,
val constraint: JsonFunctionConstraint,
val ranges: List<Vector2d>
) {
companion object : TypeAdapter<JsonFunction>() {
override fun write(out: JsonWriter, value: JsonFunction) {
TODO("Not yet implemented")
}
override fun read(reader: JsonReader): JsonFunction {
reader.beginArray()
val interpolation = JsonFunctionInterpolation.ADAPTER.read(reader)
val constraint = JsonFunctionConstraint.ADAPTER.read(reader)
val ranges = ArrayList<Vector2d>()
while (reader.peek() != JsonToken.END_ARRAY) {
ranges.add(Vector2dTypeAdapter.read(reader))
}
reader.endArray()
return JsonFunction(interpolation, constraint, ImmutableList.copyOf(ranges))
}
fun registerGson(gsonBuilder: GsonBuilder) {
gsonBuilder.registerTypeAdapter(JsonFunctionConstraint::class.java, JsonFunctionConstraint.ADAPTER)
gsonBuilder.registerTypeAdapter(JsonFunctionInterpolation::class.java, JsonFunctionInterpolation.ADAPTER)
gsonBuilder.registerTypeAdapter(JsonFunction::class.java, this)
}
}
}

View File

@ -1,10 +1,13 @@
package ru.dbotthepony.kstarbound.io
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import ru.dbotthepony.kstarbound.api.IVFS
import java.io.*
import java.nio.ByteBuffer
import java.nio.channels.Channels
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
private fun readHeader(reader: RandomAccessFile, required: Int) {
@ -124,6 +127,8 @@ class StarboundPakDirectory(val name: String, val parent: StarboundPakDirectory?
class StarboundPak(val path: File, callback: (finished: Boolean, status: String) -> Unit = { _, _ -> }) : Closeable, IVFS {
val reader = RandomAccessFile(path, "r")
private val filesByExtension = Object2ObjectArrayMap<String, ArrayList<StarboundPakFile>>()
private val filesByExtensionPath = Object2ObjectArrayMap<String, ArrayList<String>>()
init {
readHeader(reader, 0x53) // S
@ -184,6 +189,13 @@ class StarboundPak(val path: File, callback: (finished: Boolean, status: String)
indexNodes[read.name] = read
root.resolve(read.directoryHiearchy).writeFile(read)
val last = read.name.substringAfterLast('/').substringAfterLast('.', "")
if (last != "") {
filesByExtension.computeIfAbsent(last, Object2ObjectFunction { ArrayList() }).add(read)
filesByExtensionPath.computeIfAbsent(last, Object2ObjectFunction { ArrayList() }).add(read.name)
}
} catch (err: Throwable) {
throw IOException("Reading index node at $i", err)
}
@ -212,4 +224,8 @@ class StarboundPak(val path: File, callback: (finished: Boolean, status: String)
override fun close() {
reader.close()
}
override fun listAllFilesWithExtension(extension: String): Collection<String> {
return filesByExtensionPath[extension]?.let(Collections::unmodifiableList) ?: listOf()
}
}