From 20d75042ddfef248e6e6d03635690c70ad154cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Tue, 9 Feb 2021 20:55:33 +0100 Subject: [PATCH] [Editor] Enable basic game map serialization/deserialization --- .../base/editor/common/serial/Deserializer.kt | 7 +++ .../base/editor/common/serial/Serializer.kt | 8 +++ .../base/editor/map/model/layer/TileLayer.kt | 11 ++-- .../base/editor/map/model/map/GameMap.kt | 4 +- .../base/editor/map/serial/MapDeserializer.kt | 6 +++ .../base/editor/map/serial/MapSerializer.kt | 6 +++ .../map/serial/ProtobufMapDeserializer.kt | 52 +++++++++++++++++++ .../map/serial/ProtobufMapSerializer.kt | 34 ++++++++++++ proto/src/main/proto/map.proto | 23 ++++++++ 9 files changed, 146 insertions(+), 5 deletions(-) create mode 100755 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Deserializer.kt create mode 100755 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Serializer.kt create mode 100755 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt create mode 100755 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapSerializer.kt create mode 100755 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt create mode 100755 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt create mode 100755 proto/src/main/proto/map.proto diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Deserializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Deserializer.kt new file mode 100755 index 00000000..dafb4827 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Deserializer.kt @@ -0,0 +1,7 @@ +package com.bartlomiejpluta.base.editor.common.serial + +import java.io.InputStream + +interface Deserializer { + fun deserialize(input: InputStream): T +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Serializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Serializer.kt new file mode 100755 index 00000000..123d699b --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/common/serial/Serializer.kt @@ -0,0 +1,8 @@ +package com.bartlomiejpluta.base.editor.common.serial + +import java.io.InputStream +import java.io.OutputStream + +interface Serializer { + fun serialize(item: T, output: OutputStream) +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt index a0341083..d62c70eb 100755 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/layer/TileLayer.kt @@ -5,8 +5,13 @@ import javafx.beans.property.SimpleStringProperty import tornadofx.getValue import tornadofx.setValue -class TileLayer(name: String, rows: Int, columns: Int) : Layer { - var layer: Array> = Array(rows) { Array(columns) { null } } +class TileLayer( + name: String, + rows: Int, + columns: Int, + layer: Array> = Array(rows) { Array(columns) { null } } +) : Layer { + var layer = layer private set override val nameProperty = SimpleStringProperty(name) @@ -15,7 +20,7 @@ class TileLayer(name: String, rows: Int, columns: Int) : Layer { override fun resize(rows: Int, columns: Int) { layer = Array(rows) { row -> Array(columns) { column -> - layer.getOrNull(row) ?. getOrNull(column) + layer.getOrNull(row)?.getOrNull(column) } } } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt index 3fc19fe4..ea1def88 100755 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/model/map/GameMap.kt @@ -20,10 +20,10 @@ class GameMap(val tileSet: TileSet) { val tileHeight = tileSet.tileHeight.toDouble() val rowsProperty = SimpleIntegerProperty(INITIAL_ROWS) - val rows by rowsProperty + var rows by rowsProperty val columnsProperty = SimpleIntegerProperty(INITIAL_COLUMNS) - val columns by columnsProperty + var columns by columnsProperty val widthProperty = SimpleDoubleProperty(INITIAL_COLUMNS * tileWidth) var width by widthProperty 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 new file mode 100755 index 00000000..e2618f47 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapDeserializer.kt @@ -0,0 +1,6 @@ +package com.bartlomiejpluta.base.editor.map.serial + +import com.bartlomiejpluta.base.editor.common.serial.Deserializer +import com.bartlomiejpluta.base.editor.map.model.map.GameMap + +interface MapDeserializer : Deserializer \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapSerializer.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapSerializer.kt new file mode 100755 index 00000000..2190d62a --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/MapSerializer.kt @@ -0,0 +1,6 @@ +package com.bartlomiejpluta.base.editor.map.serial + +import com.bartlomiejpluta.base.editor.common.serial.Serializer +import com.bartlomiejpluta.base.editor.map.model.map.GameMap + +interface MapSerializer : Serializer \ 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 new file mode 100755 index 00000000..00c503ae --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapDeserializer.kt @@ -0,0 +1,52 @@ +package com.bartlomiejpluta.base.editor.map.serial + +import com.bartlomiejpluta.base.editor.map.model.layer.Layer +import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer +import com.bartlomiejpluta.base.editor.map.model.map.GameMap +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.stereotype.Component +import tornadofx.ResourceLookup +import java.io.InputStream + +@Component +class ProtobufMapDeserializer : MapDeserializer { + private val resources = ResourceLookup(this) + private val tileset = TileSet(resources.image("/textures/tileset.png"), 160, 8) + + override fun deserialize(input: InputStream): GameMap { + val map = GameMap(tileset) + val proto = GameMapProto.GameMap.parseFrom(input) + map.name = proto.name + map.rows = proto.rows + map.columns = proto.columns + + proto.layersList.forEach { + map.layers.add(deserializeLayer(map.rows, map.columns, tileset, it)) + } + + return map + } + + private fun deserializeLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer { + return when { + proto.hasTileLayer() -> deserializeTileLayer(rows, columns, tileSet, proto) + + else -> throw IllegalStateException("Not supported layer type") + } + } + + private fun deserializeTileLayer(rows: Int, columns: Int, tileSet: TileSet, proto: GameMapProto.Layer): Layer { + val layer: Array> = Array(rows) { Array(columns) { null } } + + proto.tileLayer.tilesList.forEachIndexed { index, tile -> + layer[index / columns][index % columns] = when(tile) { + 0 -> null + else -> tileSet.getTile(tile-1) + } + } + + return TileLayer(proto.name, rows, columns, layer) + } +} \ No newline at end of file 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 new file mode 100755 index 00000000..b8e915af --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/map/serial/ProtobufMapSerializer.kt @@ -0,0 +1,34 @@ +package com.bartlomiejpluta.base.editor.map.serial + +import com.bartlomiejpluta.base.editor.map.model.layer.Layer +import com.bartlomiejpluta.base.editor.map.model.layer.TileLayer +import com.bartlomiejpluta.base.editor.map.model.map.GameMap +import com.bartlomiejpluta.base.proto.GameMapProto +import org.springframework.stereotype.Component +import java.io.OutputStream + +@Component +class ProtobufMapSerializer : MapSerializer { + + override fun serialize(map: GameMap, output: OutputStream) { + val protoMap = GameMapProto.GameMap.newBuilder() + protoMap.name = map.name + protoMap.rows = map.rows + protoMap.columns = map.columns + + map.layers.forEach { layer -> protoMap.addLayers(serializeLayer(layer)) } + + protoMap.build().writeTo(output) + } + + private fun serializeLayer(layer: Layer): GameMapProto.Layer { + return when (layer) { + is TileLayer -> layer.layer.flatMap { it.asIterable() } + .fold(GameMapProto.TileLayer.newBuilder()) { acc, tile -> acc.addTiles((tile?.id?.plus(1)) ?: 0) } + .build() + .let { GameMapProto.Layer.newBuilder().setName(layer.name).setTileLayer(it).build() } + + else -> throw IllegalStateException("Not supported layer type") + } + } +} \ No newline at end of file diff --git a/proto/src/main/proto/map.proto b/proto/src/main/proto/map.proto new file mode 100755 index 00000000..5edfd653 --- /dev/null +++ b/proto/src/main/proto/map.proto @@ -0,0 +1,23 @@ +package com.bartlomiejpluta.base.proto; + +option java_package = "com.bartlomiejpluta.base.proto"; +option java_outer_classname = "GameMapProto"; + +message GameMap { + required string name = 1; + required uint32 rows = 2; + required uint32 columns = 3; + repeated Layer layers = 4; +} + +message Layer { + required string name = 1; + + oneof layer { + TileLayer tileLayer = 2; + } +} + +message TileLayer { + repeated uint32 tiles = 1; +} \ No newline at end of file