ImageReference, SpriteAnimator и почти избавились от старого FrameGrid
This commit is contained in:
parent
9357835f4e
commit
69a5061e9e
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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]
|
||||
|
||||
/**
|
||||
* Возвращает разницу между последним и первым кадром анимации
|
||||
*/
|
@ -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<BoundSprite>,
|
||||
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)
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<String, AtlasDefinition>()
|
||||
private val cache = ConcurrentHashMap<String, AtlasConfiguration>()
|
||||
|
||||
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<AtlasConfiguration?> = Starbound.stringTypeAdapter.transform(read = read@{ get(it ?: return@read it as AtlasConfiguration?) }, write = write@{ it?.name })
|
||||
|
||||
fun registerGson(gsonBuilder: GsonBuilder) {
|
||||
gsonBuilder.registerTypeAdapter(ADAPTER)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<ImageReference>() {
|
||||
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()}")
|
||||
}
|
||||
}
|
||||
}
|
@ -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<SpriteReference>() {
|
||||
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 {
|
||||
|
@ -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<ConfigurableProjectile, ConfiguredPr
|
||||
lightColor = lightColor,
|
||||
onlyHitTerrain = onlyHitTerrain,
|
||||
orientationLocked = orientationLocked,
|
||||
image = IFrameGrid.loadFrameStrip(ensureAbsolutePath(requireNotNull(image) { "image is null" }, directory), weak = true),
|
||||
image = ImageReference(Starbound.readingFolderTransformer(requireNotNull(image) { "image is null" })),
|
||||
timeToLive = timeToLive,
|
||||
animationCycle = animationCycle,
|
||||
bounces = bounces,
|
||||
|
@ -6,6 +6,7 @@ import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.AssembledPrototype
|
||||
import ru.dbotthepony.kstarbound.defs.DamageType
|
||||
import ru.dbotthepony.kstarbound.defs.FrameSet
|
||||
import ru.dbotthepony.kstarbound.defs.animation.ImageReference
|
||||
import ru.dbotthepony.kstarbound.world.entities.projectile.AbstractProjectileMovementController
|
||||
import ru.dbotthepony.kstarbound.world.entities.projectile.Projectile
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
@ -21,7 +22,7 @@ class ConfiguredProjectile(
|
||||
val lightColor: Color?,
|
||||
val onlyHitTerrain: Boolean,
|
||||
val orientationLocked: Boolean,
|
||||
val image: FrameSet,
|
||||
val image: ImageReference,
|
||||
val timeToLive: Double,
|
||||
val animationCycle: Double,
|
||||
val bounces: Int,
|
||||
|
@ -29,14 +29,14 @@ fun <T> TypeAdapter<T>.transformWrite(transformer: (T) -> T): TypeAdapter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> TypeAdapter<T>.transform(transformRead: (T) -> T, transformWrite: (T) -> T): TypeAdapter<T> {
|
||||
return object : TypeAdapter<T>() {
|
||||
override fun write(out: JsonWriter, value: T) {
|
||||
return this@transform.write(out, transformWrite(value))
|
||||
fun <In, Out> TypeAdapter<In>.transform(read: (In) -> Out, write: (Out) -> In): TypeAdapter<Out> {
|
||||
return object : TypeAdapter<Out>() {
|
||||
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`))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user