From 6fb0a0a24bcc06be95274de82c079bf38ed1b421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Fri, 26 Aug 2022 18:41:17 +0200 Subject: [PATCH] [Editor] Enable serialization/deserialization of auto tile layer --- .../editor/main/controller/MainController.kt | 63 +++++++++++++------ .../editor/map/model/layer/AutoTileLayer.kt | 44 +++++++++++++ .../base/editor/map/serial/MapDeserializer.kt | 2 +- .../map/serial/ProtobufMapDeserializer.kt | 24 ++++--- .../map/serial/ProtobufMapSerializer.kt | 6 ++ .../project/context/DefaultProjectContext.kt | 10 ++- .../editor/project/context/ProjectContext.kt | 12 ++-- 7 files changed, 127 insertions(+), 34 deletions(-) create mode 100644 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/AutoTileLayer.kt diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt index 8de1538a..65d05be3 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/main/controller/MainController.kt @@ -8,6 +8,7 @@ import com.bartlomiejpluta.base.editor.asset.view.select.SelectGraphicAssetFragm import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM import com.bartlomiejpluta.base.editor.audio.view.importing.ImportSoundFragment import com.bartlomiejpluta.base.editor.audio.viewmodel.SoundAssetDataVM +import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset import com.bartlomiejpluta.base.editor.autotile.view.importing.ImportAutoTileFragment import com.bartlomiejpluta.base.editor.autotile.viewmodel.AutoTileAssetDataVM import com.bartlomiejpluta.base.editor.characterset.view.importing.ImportCharacterSetFragment @@ -94,32 +95,54 @@ class MainController : Controller() { setInScope(vm, scope) find(scope).apply { onComplete { - val map = projectContext.importMapFromFile(vm.name, vm.handler, File(vm.file)) { name, uid -> - var newUid = "" - - find>( - Scope(), - SelectGraphicAssetFragment::assets to projectContext.project?.tileSets!!, - SelectGraphicAssetFragment::comment to "You are importing a tile layer which originally was defined\nwith an other Tile Set asset data with UID: [$uid].\nPlease select asset you would like to apply for layer $name.\n".toProperty(), - SelectGraphicAssetFragment::cancelable to false.toProperty() - ).apply { - title = "Select Tile Set for layer $name" - - onComplete { - newUid = it.uid - } - - openModal(block = true, resizable = false, stageStyle = StageStyle.UNDECORATED) - } - - newUid - } + val map = projectContext.importMapFromFile(vm.name, vm.handler, File(vm.file), ::askForNewTileSetAsset, ::askForNewAutoTileAsset) openItems[scope] = GameMapVM(map) } openModal(block = true, resizable = false) } } + private fun askForNewTileSetAsset(name: String, uid: String): String { + var newUid = "" + + find>( + Scope(), + SelectGraphicAssetFragment::assets to projectContext.project?.tileSets!!, + SelectGraphicAssetFragment::comment to "You are importing a tile layer which originally was defined\nwith an other Tile Set asset data with UID: [$uid].\nPlease select asset you would like to apply for layer $name.\n".toProperty(), + SelectGraphicAssetFragment::cancelable to false.toProperty() + ).apply { + title = "Select Tile Set for layer $name" + + onComplete { + newUid = it.uid + } + + openModal(block = true, resizable = false, stageStyle = StageStyle.UNDECORATED) + } + + return newUid + } + + private fun askForNewAutoTileAsset(name: String, uid: String): String { + var newUid = "" + + find>( + Scope(), + SelectGraphicAssetFragment::assets to projectContext.project?.autoTiles!!, + SelectGraphicAssetFragment::comment to "You are importing a tile layer which originally was defined\nwith an other Auto Tile asset data with UID: [$uid].\nPlease select asset you would like to apply for layer $name.\n".toProperty(), + SelectGraphicAssetFragment::cancelable to false.toProperty() + ).apply { + title = "Select Auto Tile for layer $name" + + onComplete { + newUid = it.uid + } + + openModal(block = true, resizable = false, stageStyle = StageStyle.UNDECORATED) + } + + return newUid + } fun openProject() { chooseFile( diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/AutoTileLayer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/AutoTileLayer.kt new file mode 100644 index 00000000..193ad9b7 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/AutoTileLayer.kt @@ -0,0 +1,44 @@ +package com.bartlomiejpluta.base.editor.map.model.layer + +import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset +import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset +import com.bartlomiejpluta.base.editor.tileset.model.Tile +import com.bartlomiejpluta.base.editor.tileset.model.TileSet +import javafx.beans.binding.Bindings +import javafx.beans.property.SimpleStringProperty +import javafx.scene.image.Image +import tornadofx.getValue +import tornadofx.setValue +import tornadofx.toProperty + +class AutoTileLayer( + name: String, + rows: Int, + columns: Int, + autoTileAsset: AutoTileAsset, + layer: Array> = Array(rows) { Array(columns) { false } } +) : Layer { + var layer = layer + private set + + val autoTileAssetProperty = autoTileAsset.toProperty() + var autoTileAsset by autoTileAssetProperty + +// val autoTileProperty = Bindings.createObjectBinding({ +// autoTileAsset.file.inputStream().use { fis -> +// // create AutoTile +// } +// }, autoTileAssetProperty) + + override val nameProperty = SimpleStringProperty(name) + + override fun resize(rows: Int, columns: Int) { + layer = Array(rows) { row -> + Array(columns) { column -> + layer.getOrNull(row)?.getOrNull(column) ?: false + } + } + } + + override var name: String by nameProperty +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt index 3a8ee51f..a3738828 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt @@ -7,5 +7,5 @@ import com.bartlomiejpluta.base.editor.tileset.model.TileSet import java.io.InputStream interface MapDeserializer : Deserializer { - fun deserialize(input: InputStream, replaceTileSet: (String, String) -> String): GameMap + fun deserialize(input: InputStream, replaceTileSet: (String, String) -> String, replaceAutoTile: (String, String) -> String): GameMap } \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt index 56f51d71..b0f1560c 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt @@ -6,9 +6,7 @@ import com.bartlomiejpluta.base.editor.map.model.layer.* import com.bartlomiejpluta.base.editor.map.model.map.GameMap import com.bartlomiejpluta.base.editor.map.model.obj.MapObject import com.bartlomiejpluta.base.editor.project.context.ProjectContext -import com.bartlomiejpluta.base.editor.tileset.asset.TileSetAsset import com.bartlomiejpluta.base.editor.tileset.model.Tile -import com.bartlomiejpluta.base.editor.tileset.model.TileSet import com.bartlomiejpluta.base.proto.GameMapProto import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.ApplicationContext @@ -25,9 +23,9 @@ class ProtobufMapDeserializer : MapDeserializer { appContext.getBean(ProjectContext::class.java) } - override fun deserialize(input: InputStream) = deserialize(input) { _, uid -> uid } + override fun deserialize(input: InputStream) = deserialize(input, { _, uid -> uid }, { _, uid -> uid }) - override fun deserialize(input: InputStream, replaceTileSet: (String, String) -> String): GameMap { + override fun deserialize(input: InputStream, replaceTileSet: (String, String) -> String, replaceAutoTile: (String, String) -> String): GameMap { val proto = GameMapProto.GameMap.parseFrom(input) val map = GameMap(proto.tileWidth.toDouble(), proto.tileHeight.toDouble()) map.uid = proto.uid @@ -36,15 +34,16 @@ class ProtobufMapDeserializer : MapDeserializer { map.handler = proto.handler proto.layersList - .filter { it.hasTileLayer() || it.hasObjectLayer() || it.hasColorLayer() } - .forEach { map.layers.add(deserializeLayer(map.rows, map.columns, it, replaceTileSet)) } + .filter { it.hasTileLayer() || it.hasAutoTileLayer() || it.hasObjectLayer() || it.hasColorLayer() } + .forEach { map.layers.add(deserializeLayer(map.rows, map.columns, it, replaceTileSet, replaceAutoTile)) } return map } - private fun deserializeLayer(rows: Int, columns: Int, proto: GameMapProto.Layer, replaceTileSet: (String, String) -> String): Layer { + private fun deserializeLayer(rows: Int, columns: Int, proto: GameMapProto.Layer, replaceTileSet: (String, String) -> String, replaceAutoTile: (String, String) -> String): Layer { return when { proto.hasTileLayer() -> deserializeTileLayer(rows, columns, proto, replaceTileSet) + proto.hasAutoTileLayer() -> deserializeAutoTileLayer(rows, columns, proto, replaceAutoTile) proto.hasObjectLayer() -> deserializeObjectLayer(rows, columns, proto) proto.hasColorLayer() -> deserializeColorLayer(proto) proto.hasImageLayer() -> deserializeImageLayer(proto) @@ -68,6 +67,17 @@ class ProtobufMapDeserializer : MapDeserializer { return TileLayer(proto.name, rows, columns, tileSetAsset, layer) } + private fun deserializeAutoTileLayer(rows: Int, columns: Int, proto: GameMapProto.Layer, replaceTileSet: (String, String) -> String): AutoTileLayer { + val layer: Array> = Array(rows) { Array(columns) { false } } + val autoTile = projectContext.findAutoTileAsset(replaceTileSet(proto.name, proto.autoTileLayer.autotileUID)) + + proto.autoTileLayer.tilesList.forEachIndexed { index, tile -> + layer[index / columns][index % columns] = tile + } + + return AutoTileLayer(proto.name, rows, columns, autoTile, layer) + } + private fun deserializeObjectLayer(rows: Int, columns: Int, proto: GameMapProto.Layer): Layer { val passageMap: Array> = Array(rows) { Array(columns) { PassageAbility.ALLOW } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt index 33a4ca90..b9eb139a 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt @@ -33,6 +33,12 @@ class ProtobufMapSerializer : MapSerializer { .build() .let { GameMapProto.Layer.newBuilder().setName(layer.name).setTileLayer(it).build() } + is AutoTileLayer -> layer.layer.flatMap { it.asIterable() } + .fold(GameMapProto.AutoTileLayer.newBuilder()) { acc, tile -> acc.addTiles(tile) } + .setAutotileUID(layer.autoTileAsset.uid) + .build() + .let { GameMapProto.Layer.newBuilder().setName(layer.name).setAutoTileLayer(it).build() } + is ObjectLayer -> layer.passageMap.flatMap { it.asIterable() } .fold(GameMapProto.ObjectLayer.newBuilder()) { acc, passage -> acc.addPassageMap( diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt index 30a9cfb1..d6548fb7 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/DefaultProjectContext.kt @@ -129,10 +129,11 @@ class DefaultProjectContext : ProjectContext { name: String, handler: String, file: File, - replaceTileSet: (String, String) -> String + replaceTileSet: (String, String) -> String, + replaceAutoTile: (String, String) -> String, ) = project?.let { project -> - val map = file.inputStream().use { mapDeserializer.deserialize(it, replaceTileSet) } + val map = file.inputStream().use { mapDeserializer.deserialize(it, replaceTileSet, replaceAutoTile) } UID.next(project.maps.map(Asset::uid)).let { uid -> val asset = GameMapAsset(project, uid, name) map.uid = uid @@ -208,6 +209,11 @@ class DefaultProjectContext : ProjectContext { ?: throw IllegalStateException("The Tile Set with uid [$uid] does not exist ") } ?: throw IllegalStateException("There is no open project in the context") + override fun findAutoTileAsset(uid: String) = project?.let { + it.autoTiles.firstOrNull { autoTile -> autoTile.uid == uid } + ?: throw IllegalStateException("The Auto Tile with uid [$uid] does not exist ") + } ?: throw IllegalStateException("There is no open project in the context") + override fun importImage(data: ImageAssetData) { project?.let { UID.next(it.images.map(Asset::uid)).let { uid -> diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt index 1d71eb90..7ebb782f 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/project/context/ProjectContext.kt @@ -3,9 +3,10 @@ package com.bartlomiejpluta.base.editor.project.context import com.bartlomiejpluta.base.editor.animation.asset.AnimationAssetData import com.bartlomiejpluta.base.editor.asset.model.Asset import com.bartlomiejpluta.base.editor.audio.asset.SoundAssetData +import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAssetData -import com.bartlomiejpluta.base.editor.code.model.Code import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAssetData +import com.bartlomiejpluta.base.editor.code.model.Code import com.bartlomiejpluta.base.editor.file.model.FileNode import com.bartlomiejpluta.base.editor.gui.font.asset.FontAssetData import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset @@ -31,15 +32,18 @@ interface ProjectContext { fun createNewProject(project: Project) fun importMap(name: String, map: GameMap) - fun importMapFromFile(name: String, handler: String, file: File, replaceTileSet: (String, String) -> String): GameMap + fun importMapFromFile(name: String, handler: String, file: File, replaceTileSet: (String, String) -> String, replaceAutoTile: (String, String) -> String, + ): GameMap fun loadMap(uid: String): GameMap fun saveMap(map: GameMap) fun importTileSet(data: TileSetAssetData) fun loadTileSet(uid: String): TileSet - fun importAutoTile(data: AutoTileAssetData) - fun findTileSetAsset(uid: String): TileSetAsset + + fun importAutoTile(data: AutoTileAssetData) + fun findAutoTileAsset(uid: String): AutoTileAsset + fun importImage(data: ImageAssetData) fun findImageAsset(uid: String): ImageAsset