[Editor] Enable basic game map serialization/deserialization

This commit is contained in:
2021-02-09 20:55:33 +01:00
parent 8175b0c966
commit 20d75042dd
9 changed files with 146 additions and 5 deletions

View File

@@ -0,0 +1,7 @@
package com.bartlomiejpluta.base.editor.common.serial
import java.io.InputStream
interface Deserializer<T> {
fun deserialize(input: InputStream): T
}

View File

@@ -0,0 +1,8 @@
package com.bartlomiejpluta.base.editor.common.serial
import java.io.InputStream
import java.io.OutputStream
interface Serializer<T> {
fun serialize(item: T, output: OutputStream)
}

View File

@@ -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<Tile?>> = Array(rows) { Array(columns) { null } }
class TileLayer(
name: String,
rows: Int,
columns: Int,
layer: Array<Array<Tile?>> = 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)
}
}
}

View File

@@ -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

View File

@@ -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<GameMap>

View File

@@ -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<GameMap>

View File

@@ -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<Tile?>> = 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)
}
}

View File

@@ -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")
}
}
}

23
proto/src/main/proto/map.proto Executable file
View File

@@ -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;
}