[Editor] Add support for 2x2 autotiles | create connect auto tile option #2
This commit is contained in:
@@ -1,8 +1,15 @@
|
||||
package com.bartlomiejpluta.base.editor.autotile.asset
|
||||
|
||||
import com.bartlomiejpluta.base.editor.asset.model.GraphicAsset
|
||||
import com.bartlomiejpluta.base.editor.autotile.model.AutoTile
|
||||
import com.bartlomiejpluta.base.editor.autotile.model.AutoTileLayout
|
||||
import com.bartlomiejpluta.base.editor.project.model.Project
|
||||
|
||||
class AutoTileAsset(project: Project, uid: String, source: String, name: String, rows: Int, columns: Int) :
|
||||
GraphicAsset(project.autoTilesDirectoryProperty, uid, source, name, rows, columns)
|
||||
class AutoTileAsset(
|
||||
project: Project,
|
||||
uid: String,
|
||||
source: String,
|
||||
name: String,
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
val layout: AutoTileLayout
|
||||
) : GraphicAsset(project.autoTilesDirectoryProperty, uid, source, name, rows, columns)
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bartlomiejpluta.base.editor.autotile.asset
|
||||
|
||||
import com.bartlomiejpluta.base.editor.autotile.model.AutoTile
|
||||
import com.bartlomiejpluta.base.editor.autotile.model.AutoTileLayout
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
@@ -26,4 +27,7 @@ class AutoTileAssetData {
|
||||
|
||||
val fileProperty = SimpleObjectProperty<File>()
|
||||
var file by fileProperty
|
||||
|
||||
val layoutProperty = SimpleObjectProperty(AutoTileLayout.LAYOUT_2X2)
|
||||
var layout by layoutProperty
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import tornadofx.div
|
||||
import tornadofx.getValue
|
||||
|
||||
// Algorithm source: https://love2d.org/forums/viewtopic.php?t=7826
|
||||
class AutoTile(uid: String, name: String, image: Image, rows: Int, columns: Int) {
|
||||
class AutoTile(uid: String, name: String, image: Image, rows: Int, columns: Int, layout: AutoTileLayout) {
|
||||
val uidProperty = ReadOnlyStringWrapper(uid)
|
||||
val uid by uidProperty
|
||||
|
||||
@@ -33,10 +33,10 @@ class AutoTile(uid: String, name: String, image: Image, rows: Int, columns: Int)
|
||||
val tileSetHeightProperty = SimpleIntegerProperty(image.height.toInt() / rows)
|
||||
val tileSetHeight by tileSetHeightProperty
|
||||
|
||||
val tileWidthProperty = tileSetWidthProperty.div(COLUMNS)
|
||||
val tileWidthProperty = tileSetWidthProperty.div(layout.columns)
|
||||
val tileWidth by tileWidthProperty
|
||||
|
||||
val tileHeightProperty = tileSetHeightProperty.div(ROWS)
|
||||
val tileHeightProperty = tileSetHeightProperty.div(layout.rows)
|
||||
val tileHeight by tileHeightProperty
|
||||
|
||||
val widthProperty = SimpleIntegerProperty(image.width.toInt())
|
||||
@@ -44,15 +44,34 @@ class AutoTile(uid: String, name: String, image: Image, rows: Int, columns: Int)
|
||||
|
||||
val heightProperty = SimpleIntegerProperty(image.height.toInt() )
|
||||
val height by heightProperty
|
||||
|
||||
val layoutProperty = SimpleObjectProperty(layout)
|
||||
val layout by layoutProperty
|
||||
|
||||
|
||||
val islandSubTiles: Array<Array<Image>>
|
||||
val topLeftSubTiles: Array<Array<Image>>
|
||||
val topRightSubTiles: Array<Array<Image>>
|
||||
val bottomLeftSubTiles: Array<Array<Image>>
|
||||
val bottomRightSubTiles: Array<Array<Image>>
|
||||
lateinit var islandSubTiles: Array<Array<Image>>
|
||||
private set
|
||||
|
||||
lateinit var topLeftSubTiles: Array<Array<Image>>
|
||||
private set
|
||||
|
||||
lateinit var topRightSubTiles: Array<Array<Image>>
|
||||
private set
|
||||
|
||||
lateinit var bottomLeftSubTiles: Array<Array<Image>>
|
||||
private set
|
||||
|
||||
lateinit var bottomRightSubTiles: Array<Array<Image>>
|
||||
private set
|
||||
|
||||
init {
|
||||
when(layout) {
|
||||
AutoTileLayout.LAYOUT_2X3 -> init2x3()
|
||||
AutoTileLayout.LAYOUT_2X2 -> init2x2()
|
||||
}
|
||||
}
|
||||
|
||||
private fun init2x3() {
|
||||
val islandSubTiles: MutableList<Array<Image>> = mutableListOf()
|
||||
val topLeftSubTiles: MutableList<Array<Image>> = mutableListOf()
|
||||
val topRightSubTiles: MutableList<Array<Image>> = mutableListOf()
|
||||
@@ -88,6 +107,7 @@ class AutoTile(uid: String, name: String, image: Image, rows: Int, columns: Int)
|
||||
bottomLeftSubTiles += arrayOf(bl0, bl1, bl2, bl3, bl4)
|
||||
bottomRightSubTiles += arrayOf(br0, br1, br2, br3, br4)
|
||||
}
|
||||
|
||||
this.islandSubTiles = islandSubTiles.toTypedArray()
|
||||
this.topLeftSubTiles = topLeftSubTiles.toTypedArray()
|
||||
this.topRightSubTiles = topRightSubTiles.toTypedArray()
|
||||
@@ -95,7 +115,56 @@ class AutoTile(uid: String, name: String, image: Image, rows: Int, columns: Int)
|
||||
this.bottomRightSubTiles = bottomRightSubTiles.toTypedArray()
|
||||
}
|
||||
|
||||
fun getTile(layer: AutoTileLayer, row: Int, column: Int): Array<Image> {
|
||||
private fun init2x2() {
|
||||
val topLeftSubTiles: MutableList<Array<Image>> = mutableListOf()
|
||||
val topRightSubTiles: MutableList<Array<Image>> = mutableListOf()
|
||||
val bottomLeftSubTiles: MutableList<Array<Image>> = mutableListOf()
|
||||
val bottomRightSubTiles: MutableList<Array<Image>> = mutableListOf()
|
||||
|
||||
for (i in 0 until columns * rows) {
|
||||
val tileSet = cropTileSet(i)
|
||||
val topLeftCornerTile = cropTile(tileSet, 0, 0)
|
||||
val topRightCornerTile = cropTile(tileSet, 1, 0)
|
||||
val bottomLeftCornerTile = cropTile(tileSet, 0, 1)
|
||||
val bottomRightCornerTile = cropTile(tileSet, 1, 1)
|
||||
|
||||
/*
|
||||
* Indexes:
|
||||
* 0 - No connected tiles
|
||||
* 1 - Left tile is connected
|
||||
* 2 - Right tile is connected
|
||||
* 3 - Left, Right, and Center tiles are connected.
|
||||
*/
|
||||
val (tl0, tr2, bl1, br3) = cutSubTiles(topLeftCornerTile)
|
||||
val (tl1, tr0, bl3, br2) = cutSubTiles(topRightCornerTile)
|
||||
val (tl2, tr3, bl0, br1) = cutSubTiles(bottomLeftCornerTile)
|
||||
val (tl3, tr1, bl2, br0) = cutSubTiles(bottomRightCornerTile)
|
||||
|
||||
topLeftSubTiles += arrayOf(tl0, tl1, tl2, tl3)
|
||||
topRightSubTiles += arrayOf(tr0, tr1, tr2, tr3)
|
||||
bottomLeftSubTiles += arrayOf(bl0, bl1, bl2, bl3)
|
||||
bottomRightSubTiles += arrayOf(br0, br1, br2, br3)
|
||||
}
|
||||
|
||||
this.topLeftSubTiles = topLeftSubTiles.toTypedArray()
|
||||
this.topRightSubTiles = topRightSubTiles.toTypedArray()
|
||||
this.bottomLeftSubTiles = bottomLeftSubTiles.toTypedArray()
|
||||
this.bottomRightSubTiles = bottomRightSubTiles.toTypedArray()
|
||||
|
||||
this.islandSubTiles = this.topLeftSubTiles
|
||||
}
|
||||
|
||||
fun getTile(layer: AutoTileLayer, row: Int, column: Int, connect: Boolean) = when(layout!!) {
|
||||
AutoTileLayout.LAYOUT_2X3 -> getTile2x3(layer, row, column, connect)
|
||||
AutoTileLayout.LAYOUT_2X2 -> getTile2x2(layer, row, column, connect)
|
||||
}
|
||||
|
||||
private fun isAdjacent(currentId: Int, centerId: Int, connect: Boolean) = when (connect) {
|
||||
true -> currentId > 0
|
||||
false -> currentId == centerId
|
||||
}
|
||||
|
||||
private fun getTile2x3(layer: AutoTileLayer, row: Int, column: Int, connect: Boolean): Array<Image> {
|
||||
var topLeft = 0
|
||||
var topRight = 0
|
||||
var bottomLeft = 0
|
||||
@@ -104,51 +173,91 @@ class AutoTile(uid: String, name: String, image: Image, rows: Int, columns: Int)
|
||||
val id = layer.layer[row][column]
|
||||
|
||||
// Top
|
||||
if (row > 0 && layer.layer[row - 1][column] > 0) {
|
||||
if (row > 0 && isAdjacent(layer.layer[row - 1][column] , id, connect)) {
|
||||
topLeft += 2
|
||||
topRight += 1
|
||||
}
|
||||
|
||||
// Bottom
|
||||
if (row < layer.rows - 1 && layer.layer[row + 1][column] > 0) {
|
||||
if (row < layer.rows - 1 && isAdjacent(layer.layer[row + 1][column] , id, connect)) {
|
||||
bottomLeft += 1
|
||||
bottomRight += 2
|
||||
}
|
||||
|
||||
// Left
|
||||
if (column > 0 && layer.layer[row][column - 1] > 0) {
|
||||
if (column > 0 && isAdjacent(layer.layer[row][column - 1] , id, connect)) {
|
||||
topLeft += 1
|
||||
bottomLeft += 2
|
||||
}
|
||||
|
||||
// Right
|
||||
if (column < layer.columns - 1 && layer.layer[row][column + 1] > 0) {
|
||||
if (column < layer.columns - 1 && isAdjacent(layer.layer[row][column + 1] , id, connect)) {
|
||||
topRight += 2
|
||||
bottomRight += 1
|
||||
}
|
||||
|
||||
// Top left
|
||||
if (row > 0 && column > 0 && layer.layer[row - 1][column - 1] > 0 && topLeft == 3) {
|
||||
if (row > 0 && column > 0 && isAdjacent(layer.layer[row - 1][column - 1] , id, connect) && topLeft == 3) {
|
||||
topLeft = 4
|
||||
}
|
||||
|
||||
// Top right
|
||||
if (row > 0 && column < layer.columns - 1 && layer.layer[row - 1][column + 1] > 0 && topRight == 3) {
|
||||
if (row > 0 && column < layer.columns - 1 && isAdjacent(layer.layer[row - 1][column + 1] , id, connect) && topRight == 3) {
|
||||
topRight = 4
|
||||
}
|
||||
|
||||
// Bottom left
|
||||
if (row < layer.rows - 1 && column > 0 && layer.layer[row + 1][column - 1] > 0 && bottomLeft == 3) {
|
||||
if (row < layer.rows - 1 && column > 0 && isAdjacent(layer.layer[row + 1][column - 1] , id, connect) && bottomLeft == 3) {
|
||||
bottomLeft = 4
|
||||
}
|
||||
|
||||
// Bottom right
|
||||
if (row < layer.rows - 1 && column < layer.columns - 1 && layer.layer[row + 1][column + 1] > 0 && bottomRight == 3) {
|
||||
if (row < layer.rows - 1 && column < layer.columns - 1 && isAdjacent(layer.layer[row + 1][column + 1] , id, connect) && bottomRight == 3) {
|
||||
bottomRight = 4
|
||||
}
|
||||
|
||||
if (topLeft == 0 && topRight == 0 && bottomLeft == 0 && bottomRight == 0) {
|
||||
return islandSubTiles[id - 1]
|
||||
return islandSubTiles!![id - 1]
|
||||
}
|
||||
|
||||
return arrayOf(
|
||||
topLeftSubTiles[id - 1][topLeft],
|
||||
topRightSubTiles[id - 1][topRight],
|
||||
bottomLeftSubTiles[id - 1][bottomLeft],
|
||||
bottomRightSubTiles[id - 1][bottomRight]
|
||||
)
|
||||
}
|
||||
|
||||
private fun getTile2x2(layer: AutoTileLayer, row: Int, column: Int, connect: Boolean): Array<Image> {
|
||||
var topLeft = 0
|
||||
var topRight = 0
|
||||
var bottomLeft = 0
|
||||
var bottomRight = 0
|
||||
|
||||
val id = layer.layer[row][column]
|
||||
|
||||
// Top
|
||||
if (row > 0 && isAdjacent(layer.layer[row - 1][column] , id, connect)) {
|
||||
topLeft += 2
|
||||
topRight += 1
|
||||
}
|
||||
|
||||
// Bottom
|
||||
if (row < layer.rows - 1 && isAdjacent(layer.layer[row + 1][column] , id, connect)) {
|
||||
bottomLeft += 1
|
||||
bottomRight += 2
|
||||
}
|
||||
|
||||
// Left
|
||||
if (column > 0 && isAdjacent(layer.layer[row][column - 1] , id, connect)) {
|
||||
topLeft += 1
|
||||
bottomLeft += 2
|
||||
}
|
||||
|
||||
// Right
|
||||
if (column < layer.columns - 1 && isAdjacent(layer.layer[row][column + 1] , id, connect)) {
|
||||
topRight += 2
|
||||
bottomRight += 1
|
||||
}
|
||||
|
||||
return arrayOf(
|
||||
@@ -177,9 +286,4 @@ class AutoTile(uid: String, name: String, image: Image, rows: Int, columns: Int)
|
||||
|
||||
return arrayOf(topLeft, topRight, bottomLeft, bottomRight)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ROWS = 3
|
||||
const val COLUMNS = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.bartlomiejpluta.base.editor.autotile.model
|
||||
|
||||
enum class AutoTileLayout(val columns: Int, val rows: Int) {
|
||||
LAYOUT_2X2(2, 2),
|
||||
LAYOUT_2X3(2, 3);
|
||||
|
||||
override fun toString() = "$columns x $rows"
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.editor.autotile.view.importing
|
||||
import com.bartlomiejpluta.base.editor.asset.component.GraphicAssetViewCanvas
|
||||
import com.bartlomiejpluta.base.editor.asset.viewmodel.GraphicAssetVM
|
||||
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAssetData
|
||||
import com.bartlomiejpluta.base.editor.autotile.model.AutoTileLayout
|
||||
import com.bartlomiejpluta.base.editor.autotile.viewmodel.AutoTileAssetDataVM
|
||||
import com.bartlomiejpluta.base.editor.util.fx.TextFieldUtil
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
@@ -95,6 +96,12 @@ class ImportAutoTileFragment : Fragment("Import Auto Tile") {
|
||||
}
|
||||
}
|
||||
|
||||
field("Auto Tile Layout") {
|
||||
combobox(values = AutoTileLayout.values().asList(), property = dataVM.layoutProperty) {
|
||||
required()
|
||||
}
|
||||
}
|
||||
|
||||
field("Auto Tile Rows") {
|
||||
enableWhen(imagePreview.isNotNull)
|
||||
spinner(min = 1, max = Integer.MAX_VALUE, property = dataVM.rowsProperty, editable = true) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.bartlomiejpluta.base.editor.autotile.viewmodel
|
||||
|
||||
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAssetData
|
||||
import com.bartlomiejpluta.base.editor.autotile.model.AutoTileLayout
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import tornadofx.*
|
||||
|
||||
class AutoTileAssetDataVM : ItemViewModel<AutoTileAssetData>(AutoTileAssetData()) {
|
||||
@@ -21,4 +23,7 @@ class AutoTileAssetDataVM : ItemViewModel<AutoTileAssetData>(AutoTileAssetData()
|
||||
|
||||
val fileProperty = bind(AutoTileAssetData::fileProperty)
|
||||
var file by fileProperty
|
||||
|
||||
val layoutProperty = bind(AutoTileAssetData::layoutProperty)
|
||||
var layout by layoutProperty
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class MapCanvas(val map: GameMapVM, private val editorStateVM: EditorStateVM, pr
|
||||
}
|
||||
|
||||
private fun renderAutoTile(gc: GraphicsContext, autoTile: AutoTile, layer: AutoTileLayer, column: Int, row: Int) {
|
||||
val (topLeft, topRight, bottomLeft, bottomRight) = autoTile.getTile(layer, row, column)
|
||||
val (topLeft, topRight, bottomLeft, bottomRight) = autoTile.getTile(layer, row, column, layer.connect)
|
||||
val x = column * tileWidth
|
||||
val y = row * tileHeight
|
||||
gc.drawImage(topLeft, x, y)
|
||||
|
||||
@@ -16,6 +16,7 @@ class AutoTileLayer(
|
||||
autoTileAsset: AutoTileAsset,
|
||||
animated: Boolean,
|
||||
animationDuration: Double,
|
||||
connect: Boolean,
|
||||
layer: Array<Array<Int>> = Array(rows) { Array(columns) { 0 } }
|
||||
) : Layer {
|
||||
var layer = layer
|
||||
@@ -36,6 +37,9 @@ class AutoTileLayer(
|
||||
val animationDurationProperty = animationDuration.toProperty()
|
||||
var animationDuration by animationDurationProperty
|
||||
|
||||
val connectProperty = connect.toProperty()
|
||||
var connect by connectProperty
|
||||
|
||||
val autoTileProperty = Bindings.createObjectBinding({
|
||||
autoTileAsset.file.inputStream().use { fis ->
|
||||
AutoTile(
|
||||
@@ -43,7 +47,8 @@ class AutoTileLayer(
|
||||
autoTileAsset.name,
|
||||
Image(fis),
|
||||
autoTileAsset.rows,
|
||||
autoTileAsset.columns
|
||||
autoTileAsset.columns,
|
||||
autoTileAsset.layout
|
||||
)
|
||||
}
|
||||
}, autoTileAssetProperty)
|
||||
|
||||
@@ -33,10 +33,16 @@ class AutoTileLayerParametersBinder : LayerParametersBinder<AutoTileLayer> {
|
||||
submit()
|
||||
}
|
||||
|
||||
val connect = BooleanParameter("connect", layer.connect) { _, _, submit ->
|
||||
onCommit()
|
||||
submit()
|
||||
}
|
||||
|
||||
autoTile.bindBidirectional(layer.autoTileAssetProperty)
|
||||
animated.bindBidirectional(layer.animatedProperty)
|
||||
animationDuration.bindBidirectional(layer.animationDurationProperty)
|
||||
connect.bindBidirectional(layer.connectProperty)
|
||||
|
||||
parameters.addAll(autoTile, animated, animationDuration)
|
||||
parameters.addAll(autoTile, animated, animationDuration, connect)
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,7 @@ class ProtobufMapDeserializer : MapDeserializer {
|
||||
autoTile,
|
||||
proto.autoTileLayer.animated,
|
||||
proto.autoTileLayer.animationDuration,
|
||||
proto.autoTileLayer.connect,
|
||||
layer
|
||||
)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ class ProtobufMapSerializer : MapSerializer {
|
||||
.setAutotileUID(layer.autoTileAsset.uid)
|
||||
.setAnimated(layer.animated)
|
||||
.setAnimationDuration(layer.animationDuration)
|
||||
.setConnect(layer.connect)
|
||||
.build()
|
||||
.let { GameMapProto.Layer.newBuilder().setName(layer.name).setAutoTileLayer(it).build() }
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class MapLayersView : View() {
|
||||
find<SelectGraphicAssetFragment<AutoTileAsset>>(scope, SelectGraphicAssetFragment<AutoTileAsset>::assets to projectContext.project?.autoTiles!!).apply {
|
||||
onComplete {
|
||||
val layer =
|
||||
AutoTileLayer("Layer ${mapVM.layers.size + 1}", mapVM.rows, mapVM.columns, it, false, 1.0)
|
||||
AutoTileLayer("Layer ${mapVM.layers.size + 1}", mapVM.rows, mapVM.columns, it, false, 1.0, false)
|
||||
val command = CreateLayerCommand(mapVM.item, layer)
|
||||
command.execute()
|
||||
layersPane.selectionModel.select(mapVM.layers.size - 1)
|
||||
|
||||
@@ -188,7 +188,7 @@ class DefaultProjectContext : ProjectContext {
|
||||
val source = "$uid.${data.file.extension}"
|
||||
val targetFile = File(it.autoTilesDirectory, source)
|
||||
data.file.copyTo(targetFile)
|
||||
it.autoTiles += AutoTileAsset(it, uid, source, data.name, data.rows, data.columns)
|
||||
it.autoTiles += AutoTileAsset(it, uid, source, data.name, data.rows, data.columns, data.layout)
|
||||
|
||||
save()
|
||||
}
|
||||
@@ -202,7 +202,7 @@ class DefaultProjectContext : ProjectContext {
|
||||
|
||||
val image = File(it.autoTilesDirectory, asset.source).inputStream().use { fis -> Image(fis) }
|
||||
|
||||
AutoTile(uid, asset.name, image, asset.rows, asset.columns)
|
||||
AutoTile(uid, asset.name, image, asset.rows, asset.columns, asset.layout)
|
||||
} ?: throw IllegalStateException("There is no open project in the context")
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.bartlomiejpluta.base.editor.project.serial
|
||||
import com.bartlomiejpluta.base.editor.animation.asset.AnimationAsset
|
||||
import com.bartlomiejpluta.base.editor.audio.asset.SoundAsset
|
||||
import com.bartlomiejpluta.base.editor.autotile.asset.AutoTileAsset
|
||||
import com.bartlomiejpluta.base.editor.autotile.model.AutoTileLayout
|
||||
import com.bartlomiejpluta.base.editor.characterset.asset.CharacterSetAsset
|
||||
import com.bartlomiejpluta.base.editor.gui.font.asset.FontAsset
|
||||
import com.bartlomiejpluta.base.editor.gui.widget.asset.WidgetAsset
|
||||
@@ -58,7 +59,8 @@ class ProtobufProjectDeserializer : ProjectDeserializer {
|
||||
source = autoTile.source,
|
||||
name = autoTile.name,
|
||||
rows = autoTile.rows,
|
||||
columns = autoTile.columns
|
||||
columns = autoTile.columns,
|
||||
layout = AutoTileLayout.valueOf(autoTile.layout.name)
|
||||
)
|
||||
|
||||
private fun deserializeImage(project: Project, image: ProjectProto.ImageAsset) = ImageAsset(
|
||||
|
||||
@@ -55,6 +55,7 @@ class ProtobufProjectSerializer : ProjectSerializer {
|
||||
.setName(autoTile.name)
|
||||
.setRows(autoTile.rows)
|
||||
.setColumns(autoTile.columns)
|
||||
.setLayout(ProjectProto.AutoTileLayout.valueOf(autoTile.layout.name))
|
||||
.build()
|
||||
|
||||
private fun serializeImage(image: ImageAsset) = ProjectProto.ImageAsset.newBuilder()
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
package com.bartlomiejpluta.base.engine.world.autotile.model;public enum AutoTileLayout {
|
||||
}
|
||||
Reference in New Issue
Block a user