From 69a5061e9eb8a73a0933d66592d7704a12428192 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 1 Jan 2023 18:07:46 +0700 Subject: [PATCH] =?UTF-8?q?ImageReference,=20SpriteAnimator=20=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D1=87=D1=82=D0=B8=20=D0=B8=D0=B7=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D0=B8=D1=81=D1=8C=20=D0=BE=D1=82=20=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D1=80=D0=BE=D0=B3=D0=BE=20FrameGrid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/dbotthepony/kstarbound/Starbound.kt | 20 +++++++ .../kstarbound/client/render/BoundSprite.kt | 22 +++++--- .../{FrameSetAnimator.kt => FrameAnimator.kt} | 29 ++++------ .../client/render/SpriteAnimator.kt | 56 +++++++++++++++++++ .../render/entity/ProjectileRenderer.kt | 23 ++++---- ...lasDefinition.kt => AtlasConfiguration.kt} | 42 +++++++++++--- .../defs/animation/ImageReference.kt | 45 +++++++++++++++ .../defs/animation/SpriteReference.kt | 11 ++-- .../defs/projectile/Configurable.kt | 3 +- .../kstarbound/defs/projectile/Configured.kt | 3 +- .../ru/dbotthepony/kstarbound/io/json/Ext.kt | 12 ++-- 11 files changed, 207 insertions(+), 59 deletions(-) rename src/main/kotlin/ru/dbotthepony/kstarbound/client/render/{FrameSetAnimator.kt => FrameAnimator.kt} (77%) create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/client/render/SpriteAnimator.kt rename src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/{AtlasDefinition.kt => AtlasConfiguration.kt} (79%) create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/ImageReference.kt diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt index 0df4979c..f8d3d142 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt @@ -15,6 +15,7 @@ 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.animation.AtlasConfiguration import ru.dbotthepony.kstarbound.defs.animation.SpriteReference import ru.dbotthepony.kstarbound.defs.item.ItemDefinition import ru.dbotthepony.kstarbound.defs.item.ItemRarity @@ -65,6 +66,9 @@ object Starbound { private set fun readingFolderTransformer(input: String): String { + val readingFolder = readingFolder + require(readingFolder != null) { "Not reading an asset on current thread" } + if (input[0] == '/') return input @@ -72,6 +76,8 @@ object Starbound { } fun readingFolderTransformerNullable(input: String?): String? { + require(readingFolder != null) { "Not reading an asset on current thread" } + if (input != null) return readingFolderTransformer(input) @@ -158,6 +164,7 @@ object Starbound { .also(ItemDefinition::registerGson) .also(ItemRarity::registerGson) .also(SpriteReference::registerGson) + .also(AtlasConfiguration::registerGson) .registerTypeAdapter(DamageType::class.java, CustomEnumTypeAdapter(DamageType.values()).nullSafe()) @@ -371,6 +378,7 @@ object Starbound { try { callback("Loading $listedFile") + readingFolder = 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 @@ -384,6 +392,8 @@ object Starbound { } } } + + readingFolder = null } private fun loadFunctions(callback: (String) -> Unit) { @@ -392,6 +402,7 @@ object Starbound { try { callback("Loading $listedFile") + readingFolder = listedFile.computeDirectory() val readObject = JsonParser.parseReader(listedFile.reader()) as JsonObject for (key in readObject.keySet()) { @@ -407,6 +418,8 @@ object Starbound { } } } + + readingFolder = null } private fun loadParallax(callback: (String) -> Unit) { @@ -415,6 +428,7 @@ object Starbound { try { callback("Loading $listedFile") + readingFolder = listedFile.computeDirectory() val def = gson.fromJson(listedFile.reader(), ParallaxPrototype::class.java) parallax[listedFile.name.substringBefore('.')] = def } catch(err: Throwable) { @@ -426,6 +440,8 @@ object Starbound { } } } + + readingFolder = null } private fun loadMaterialModifiers(callback: (String) -> Unit) { @@ -478,6 +494,8 @@ object Starbound { } } } + + readingFolder = null } private fun loadItemDefinitions(callback: (String) -> Unit) { @@ -502,5 +520,7 @@ object Starbound { } } } + + readingFolder = null } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/BoundSprite.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/BoundSprite.kt index a435856b..58874298 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/BoundSprite.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/BoundSprite.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound.client.render import ru.dbotthepony.kstarbound.client.gl.GLStateTracker import ru.dbotthepony.kstarbound.client.gl.GLTexture2D import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers +import ru.dbotthepony.kstarbound.defs.animation.AtlasConfiguration import ru.dbotthepony.kstarbound.defs.animation.IUVCoordinates import ru.dbotthepony.kstarbound.defs.animation.SpriteReference @@ -10,20 +11,18 @@ import ru.dbotthepony.kstarbound.defs.animation.SpriteReference * Связка текстуры-атласа + координат спрайта на ней */ class BoundSprite( - val reference: SpriteReference, + val sprite: AtlasConfiguration.Sprite, val texture: GLTexture2D ) : IUVCoordinates { - inline val sprite get() = reference.sprite - /** * Настоящая ширина спрайта, в пикселях */ - inline val width get() = reference.sprite.width(texture.width) + inline val width get() = sprite.width(texture.width) /** * Настоящая высота спрайта, в пикселях */ - inline val height get() = reference.sprite.height(texture.height) + inline val height get() = sprite.height(texture.height) override val u0: Float override val v0: Float @@ -31,7 +30,7 @@ class BoundSprite( override val v1: Float init { - val coords = reference.sprite.compute(texture) + val coords = sprite.compute(texture) this.u0 = coords.u0 this.v0 = coords.v0 @@ -47,12 +46,19 @@ class BoundSprite( * Создаёт связку текстуры-атласа + координгат спрайта на ней */ fun SpriteReference.bind(texture: GLTexture2D): BoundSprite { - return BoundSprite(this, texture) + return BoundSprite(sprite, texture) } /** * Создаёт связку текстуры-атласа, которая загружается через [GLStateTracker.loadNamedTextureSafe] + координгат спрайта на ней */ fun SpriteReference.bind(state: GLStateTracker): BoundSprite { - return BoundSprite(this, state.loadNamedTextureSafe(path)) + return BoundSprite(sprite, state.loadNamedTextureSafe(image)) +} + +/** + * Создаёт связку текстуры-атласа + координгат спрайта на ней + */ +fun AtlasConfiguration.Sprite.bind(texture: GLTexture2D): BoundSprite { + return BoundSprite(this, texture) } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/FrameSetAnimator.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/FrameAnimator.kt similarity index 77% rename from src/main/kotlin/ru/dbotthepony/kstarbound/client/render/FrameSetAnimator.kt rename to src/main/kotlin/ru/dbotthepony/kstarbound/client/render/FrameAnimator.kt index 6840dc29..d1df4c7d 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/FrameSetAnimator.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/FrameAnimator.kt @@ -1,13 +1,20 @@ package ru.dbotthepony.kstarbound.client.render import org.lwjgl.glfw.GLFW.glfwGetTime -import ru.dbotthepony.kstarbound.defs.FrameSet /** - * Анимирует заданный FrameSet + * Таймер для анимирования набора спрайтов */ -class FrameSetAnimator( - val set: FrameSet, +open class FrameAnimator( + /** + * Первый кадр в анимации + */ + var firstFrame: Int = 0, + + /** + * Последний кадр в анимации + */ + var lastFrame: Int, /** * Сколько времени занимает один кадр @@ -17,23 +24,11 @@ class FrameSetAnimator( /** * Зациклить ли анимацию */ - var animationLoops: Boolean, + var animationLoops: Boolean = true, ) { - /** - * Последний кадр анимации - */ - var lastFrame = set.frameCount - 1 - - /** - * Первый кадр анимации - */ - var firstFrame = 0 - var frame = 0 private set - val frameObj get() = set.frames[frame + firstFrame] - /** * Возвращает разницу между последним и первым кадром анимации */ diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/SpriteAnimator.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/SpriteAnimator.kt new file mode 100644 index 00000000..f90a7779 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/SpriteAnimator.kt @@ -0,0 +1,56 @@ +package ru.dbotthepony.kstarbound.client.render + +import com.google.common.collect.ImmutableList +import ru.dbotthepony.kstarbound.client.gl.GLStateTracker +import ru.dbotthepony.kstarbound.client.gl.GLTexture2D +import ru.dbotthepony.kstarbound.defs.animation.AtlasConfiguration +import ru.dbotthepony.kstarbound.defs.animation.ImageReference + +class SpriteAnimator( + val sprites: List, + animationCycle: Double, + animationLoops: Boolean = true, + firstFrame: Int = 0, + lastFrame: Int = sprites.size - 1 +) : FrameAnimator( + firstFrame = firstFrame, + lastFrame = lastFrame, + animationCycle = animationCycle, + animationLoops = animationLoops, +) { + constructor( + image: GLTexture2D, + atlas: AtlasConfiguration, + animationCycle: Double, + animationLoops: Boolean = true, + firstFrame: Int = 0, + lastFrame: Int = atlas.spriteList.size - 1 + ) : this( + atlas.spriteList.stream().map { it.bind(image) }.collect(ImmutableList.toImmutableList()), + animationCycle = animationCycle, + animationLoops = animationLoops, + firstFrame = firstFrame, + lastFrame = lastFrame, + ) + + constructor( + image: ImageReference, + state: GLStateTracker, + animationCycle: Double, + animationLoops: Boolean = true, + firstFrame: Int = 0, + lastFrame: Int = image.config.spriteList.size - 1 + ) : this(state.loadNamedTextureSafe(image.image), image.config, animationCycle, animationLoops, firstFrame, lastFrame) + + val sprite get() = sprites[frame] +} + +fun ImageReference.makeSpriteAnimator( + state: GLStateTracker, + animationCycle: Double, + animationLoops: Boolean = true, + firstFrame: Int = 0, + lastFrame: Int = config.spriteList.size - 1 +): SpriteAnimator { + return SpriteAnimator(this, state, animationCycle, animationLoops, firstFrame, lastFrame) +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ProjectileRenderer.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ProjectileRenderer.kt index 6276f13a..76a53abf 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ProjectileRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ProjectileRenderer.kt @@ -5,39 +5,36 @@ import ru.dbotthepony.kstarbound.client.ClientChunk import ru.dbotthepony.kstarbound.client.gl.GLStateTracker import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers import ru.dbotthepony.kstarbound.client.gl.vertex.quadRotatedZ -import ru.dbotthepony.kstarbound.client.render.FrameSetAnimator +import ru.dbotthepony.kstarbound.client.render.FrameAnimator +import ru.dbotthepony.kstarbound.client.render.SpriteAnimator +import ru.dbotthepony.kstarbound.client.render.makeSpriteAnimator import ru.dbotthepony.kstarbound.world.entities.projectile.Projectile import ru.dbotthepony.kvector.matrix.Matrix4fStack open class ProjectileRenderer(state: GLStateTracker, entity: Projectile, chunk: ClientChunk?) : EntityRenderer(state, entity, chunk) { private val def = entity.def - private val texture = state.loadNamedTextureSafe(def.image.texture) - private val animator = FrameSetAnimator(def.image, def.animationCycle, entity.def.animationLoops) + private val animator = def.image.makeSpriteAnimator(state, def.animationCycle, def.animationLoops) override fun render(stack: Matrix4fStack) { state.shaderVertexTexture.use() state.shaderVertexTexture.transform.set(stack.last) state.activeTexture = 0 state.shaderVertexTexture["_texture"] = 0 - texture.bind() animator.advance() + val sprite = animator.sprite + sprite.texture.bind() val builder = state.flat2DTexturedQuads.small builder.begin() - val (u0, v0) = texture.pixelToUV(animator.frameObj.texturePosition) - val (u1, v1) = texture.pixelToUV(animator.frameObj.textureEndPosition) + val width = (sprite.width / PIXELS_IN_STARBOUND_UNITf) / 2f + val height = (sprite.height / PIXELS_IN_STARBOUND_UNITf) / 2f - val width = (animator.frameObj.width / PIXELS_IN_STARBOUND_UNITf) / 2f - val height = (animator.frameObj.height / PIXELS_IN_STARBOUND_UNITf) / 2f - - builder.quadRotatedZ(-width, -height, width, height, 5f, 0f, 0f, entity.movement.angle, - QuadTransformers.uv(u0, v0, u1, v1) - ) + builder.quadRotatedZ(-width, -height, width, height, 5f, 0f, 0f, entity.movement.angle, sprite.transformer) builder.upload() builder.draw() } -} \ No newline at end of file +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasConfiguration.kt similarity index 79% rename from src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasDefinition.kt rename to src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasConfiguration.kt index ee5b7983..df98232a 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasConfiguration.kt @@ -2,15 +2,19 @@ package ru.dbotthepony.kstarbound.defs.animation import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableMap +import com.google.gson.GsonBuilder import com.google.gson.JsonArray import com.google.gson.JsonNull import com.google.gson.JsonObject import com.google.gson.JsonSyntaxException +import com.google.gson.TypeAdapter import com.google.gson.internal.bind.TypeAdapters import com.google.gson.stream.JsonReader import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.client.gl.GLTexture2D import ru.dbotthepony.kstarbound.io.json.stream +import ru.dbotthepony.kstarbound.io.json.transform +import ru.dbotthepony.kstarbound.registerTypeAdapter import ru.dbotthepony.kvector.vector.nint.Vector2i import ru.dbotthepony.kvector.vector.nint.Vector4i import java.util.concurrent.ConcurrentHashMap @@ -22,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap * * Несмотря на название, НЕ ЯВЛЯЕТСЯ изображением, а лишь метаданными для *множества* возможных изображений */ -class AtlasDefinition private constructor( +class AtlasConfiguration private constructor( /** * Имя данного атласа (путь к файлу) */ @@ -149,14 +153,14 @@ class AtlasDefinition private constructor( } companion object { - val EMPTY: AtlasDefinition + val EMPTY: AtlasConfiguration init { val sprite = Sprite("root", Vector4i(0, 0, 0, 0)) - EMPTY = AtlasDefinition("null", ImmutableMap.of("root", sprite, "default", sprite, "0", sprite), ImmutableList.of(sprite)) + EMPTY = AtlasConfiguration("null", ImmutableMap.of("root", sprite, "default", sprite, "0", sprite), ImmutableList.of(sprite)) } - private val cache = ConcurrentHashMap() + private val cache = ConcurrentHashMap() private fun generateFakeNames(dimensions: Vector2i): JsonArray { return JsonArray(dimensions.y).also { @@ -175,7 +179,7 @@ class AtlasDefinition private constructor( } } - private fun parseFrames(input: JsonReader, name: String): AtlasDefinition { + private fun parseFrames(input: JsonReader, name: String): AtlasConfiguration { val read = TypeAdapters.JSON_ELEMENT.read(input) if (read !is JsonObject) { @@ -241,10 +245,10 @@ class AtlasDefinition private constructor( sprites[k] = sprites[v.asString] ?: throw JsonSyntaxException("$k want to refer to sprite $v, but it does not exist") } - return AtlasDefinition(name, ImmutableMap.copyOf(sprites), spriteList) + return AtlasConfiguration(name, ImmutableMap.copyOf(sprites), spriteList) } - private fun recursiveGet(name: String, folder: String): AtlasDefinition? { + private fun recursiveGet(name: String, folder: String): AtlasConfiguration? { var current = folder while (current != "/" && current != "") { @@ -272,10 +276,24 @@ class AtlasDefinition private constructor( return null } - fun get(path: String): AtlasDefinition { + /** + * Пытается найти конфигурацию (файл "frames") атласа для заданного пути (заданного изображения/атласа) + * + * Алгоритм поиска конфигурации таков: + * * Проверяется папка с целевым файлом на наличие файла с таким же именем, но с расширением frames; + * * Если файл не был найден, процесс повторяется переходом в папку выше, пока не будет достигнут корень файловой системы; + * * Если файл не был найден, процесс начинается заново, внутри целевой папки, но уже происходит поиск файла с именем default.frames; + * * Процесс повторяется как в пункте 2 пока не будет найден файл в одной из вышестоящих папок. + * + * Если ни один файл не был найден, то возвращается [EMPTY] + * + * Данная функция кеширует результаты поиска + * + */ + fun get(path: String): AtlasConfiguration { require(path[0] == '/') { "$path is not an absolute path" } val folder = path.substringBeforeLast('/').lowercase() - val filename = path.substringAfterLast('/').substringBefore('.').lowercase() + val filename = path.substringAfterLast('/').substringBefore(':').substringBefore('.').lowercase() val direct = recursiveGet(filename, folder) if (direct != null) return direct @@ -285,5 +303,11 @@ class AtlasDefinition private constructor( return EMPTY } + + val ADAPTER: TypeAdapter = Starbound.stringTypeAdapter.transform(read = read@{ get(it ?: return@read it as AtlasConfiguration?) }, write = write@{ it?.name }) + + fun registerGson(gsonBuilder: GsonBuilder) { + gsonBuilder.registerTypeAdapter(ADAPTER) + } } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/ImageReference.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/ImageReference.kt new file mode 100644 index 00000000..eeaf78bb --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/ImageReference.kt @@ -0,0 +1,45 @@ +package ru.dbotthepony.kstarbound.defs.animation + +import com.google.gson.JsonSyntaxException +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 + +/** + * Хранит данные (пару) вида "/example/animated.png" у которого, вероятнее всего, есть "/example/animated.frames" + * + * @see [AtlasConfiguration.Companion.get] + */ +data class ImageReference( + val image: String, + val config: AtlasConfiguration, +) { + /** + * Вызывает [AtlasConfiguration.Companion.get] автоматически + * + * @see ImageReference + */ + constructor(image: String) : this(image, AtlasConfiguration.get(image)) + + companion object : TypeAdapter() { + override fun write(out: JsonWriter, value: ImageReference) { + out.value(value.image) + } + + override fun read(`in`: JsonReader): ImageReference { + if (`in`.peek() == JsonToken.STRING) { + val image = Starbound.readingFolderTransformer(`in`.nextString()) + + if (image.contains(':')) { + throw JsonSyntaxException("Expected atlas/image reference, but got sprite reference: $image") + } + + return ImageReference(image, AtlasConfiguration.get(image)) + } + + throw JsonSyntaxException("Expected atlas/image reference, but got: ${`in`.peek()}") + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/SpriteReference.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/SpriteReference.kt index 32725582..78263e56 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/SpriteReference.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/SpriteReference.kt @@ -7,13 +7,16 @@ import com.google.gson.stream.JsonWriter import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.registerTypeAdapter +/** + * Хранит данные (пару) вида "/example/image.png:sprite.name" + */ data class SpriteReference( - val path: String, - val sprite: AtlasDefinition.Sprite + val image: String, + val sprite: AtlasConfiguration.Sprite ) { companion object : TypeAdapter() { fun parse(input: String): SpriteReference { - val grid = AtlasDefinition.get(input.substringBefore(':')) + val grid = AtlasConfiguration.get(input.substringBefore(':')) return when (input.count { it == ':' }) { 0 -> SpriteReference(input, grid.any()) @@ -23,7 +26,7 @@ data class SpriteReference( } override fun write(out: JsonWriter, value: SpriteReference) { - out.value(value.path + ":" + value.sprite.name) + out.value(value.image + ":" + value.sprite.name) } override fun read(`in`: JsonReader): SpriteReference { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/projectile/Configurable.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/projectile/Configurable.kt index 5ecc68ff..6ca03077 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/projectile/Configurable.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/projectile/Configurable.kt @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArraySet import org.apache.logging.log4j.LogManager import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.defs.* +import ru.dbotthepony.kstarbound.defs.animation.ImageReference import ru.dbotthepony.kstarbound.io.json.BuilderAdapter import ru.dbotthepony.kstarbound.io.json.CustomEnumTypeAdapter import ru.dbotthepony.kstarbound.registerTypeAdapter @@ -79,7 +80,7 @@ class ConfigurableProjectile : RawPrototype TypeAdapter.transformWrite(transformer: (T) -> T): TypeAdapter { } } -fun TypeAdapter.transform(transformRead: (T) -> T, transformWrite: (T) -> T): TypeAdapter { - return object : TypeAdapter() { - override fun write(out: JsonWriter, value: T) { - return this@transform.write(out, transformWrite(value)) +fun TypeAdapter.transform(read: (In) -> Out, write: (Out) -> In): TypeAdapter { + return object : TypeAdapter() { + override fun write(out: JsonWriter, value: Out) { + return this@transform.write(out, write(value)) } - override fun read(`in`: JsonReader): T { - return transformRead(this@transform.read(`in`)) + override fun read(`in`: JsonReader): Out { + return read(this@transform.read(`in`)) } } }