[Editor] Add support for importing maps from files
This commit is contained in:
@@ -18,6 +18,7 @@ class AssetsListView : View() {
|
||||
|
||||
private val maps = AssetCategory("Maps").apply {
|
||||
menuitem("New Map...") { mainController.createEmptyMap() }
|
||||
menuitem("Import Map...") { mainController.importMap() }
|
||||
}
|
||||
|
||||
private val tileSets = AssetCategory("Tile Sets").apply {
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.bartlomiejpluta.base.editor.image.viewmodel.ImageAssetDataVM
|
||||
import com.bartlomiejpluta.base.editor.map.asset.GameMapAsset
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.map.view.wizard.MapCreationWizard
|
||||
import com.bartlomiejpluta.base.editor.map.view.wizard.MapImportWizard
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapVM
|
||||
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
|
||||
@@ -35,6 +36,7 @@ import javafx.scene.control.TextInputDialog
|
||||
import javafx.stage.FileChooser
|
||||
import org.springframework.stereotype.Component
|
||||
import tornadofx.*
|
||||
import java.io.File
|
||||
import kotlin.collections.set
|
||||
|
||||
@Component
|
||||
@@ -78,6 +80,21 @@ class MainController : Controller() {
|
||||
}
|
||||
}
|
||||
|
||||
fun importMap() {
|
||||
val scope = UndoableScope()
|
||||
val vm = GameMapBuilderVM()
|
||||
setInScope(vm, scope)
|
||||
find<MapImportWizard>(scope).apply {
|
||||
onComplete {
|
||||
val tileSet = projectContext.loadTileSet(vm.tileSetAsset.uid)
|
||||
val map = projectContext.importMapFromFile(vm.name, vm.handler, File(vm.file), tileSet)
|
||||
openItems[scope] = GameMapVM(map)
|
||||
}
|
||||
|
||||
openModal(block = true, resizable = false)
|
||||
}
|
||||
}
|
||||
|
||||
fun openProject() {
|
||||
chooseFile(
|
||||
title = "Load Project",
|
||||
@@ -262,6 +279,7 @@ class MainController : Controller() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun closeScript(fsNode: FileNode) {
|
||||
openItems.entries.firstOrNull { (_, item) -> item is CodeVM && item.fileNode.absolutePath == fsNode.absolutePath }?.key?.let {
|
||||
openItems.remove(it)
|
||||
@@ -274,7 +292,6 @@ class MainController : Controller() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun clearResources() {
|
||||
openItems.clear()
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@ class MainMenuView : View() {
|
||||
}
|
||||
|
||||
menu("Import") {
|
||||
item("Map...") {
|
||||
action {
|
||||
mainController.importMap()
|
||||
}
|
||||
}
|
||||
|
||||
item("Tile Set...") {
|
||||
action {
|
||||
mainController.importTileSet()
|
||||
|
||||
@@ -6,6 +6,7 @@ import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.getValue
|
||||
import tornadofx.setValue
|
||||
import java.io.File
|
||||
|
||||
class GameMapBuilder {
|
||||
val tileSetAssetProperty = SimpleObjectProperty<TileSetAsset>()
|
||||
@@ -22,4 +23,7 @@ class GameMapBuilder {
|
||||
|
||||
val handlerProperty = SimpleStringProperty()
|
||||
var handler by handlerProperty
|
||||
|
||||
val fileProperty = SimpleStringProperty("")
|
||||
var file by fileProperty
|
||||
}
|
||||
@@ -2,5 +2,9 @@ package com.bartlomiejpluta.base.editor.map.serial
|
||||
|
||||
import com.bartlomiejpluta.base.editor.common.serial.Deserializer
|
||||
import com.bartlomiejpluta.base.editor.map.model.map.GameMap
|
||||
import com.bartlomiejpluta.base.editor.tileset.model.TileSet
|
||||
import java.io.InputStream
|
||||
|
||||
interface MapDeserializer : Deserializer<GameMap>
|
||||
interface MapDeserializer : Deserializer<GameMap> {
|
||||
fun deserialize(input: InputStream, tileSet: TileSet): GameMap
|
||||
}
|
||||
@@ -35,6 +35,21 @@ class ProtobufMapDeserializer : MapDeserializer {
|
||||
return map
|
||||
}
|
||||
|
||||
override fun deserialize(input: InputStream, tileSet: TileSet): GameMap {
|
||||
val proto = GameMapProto.GameMap.parseFrom(input)
|
||||
val map = GameMap(tileSet)
|
||||
map.uid = proto.uid
|
||||
map.rows = proto.rows
|
||||
map.columns = proto.columns
|
||||
map.handler = proto.handler
|
||||
|
||||
proto.layersList
|
||||
.filter { it.hasTileLayer() || it.hasObjectLayer() || it.hasColorLayer() }
|
||||
.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)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.bartlomiejpluta.base.editor.map.view.wizard
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM
|
||||
import javafx.beans.binding.Bindings
|
||||
import javafx.stage.FileChooser
|
||||
import tornadofx.*
|
||||
import java.io.File
|
||||
|
||||
class MapImportBasicDataView : View("Basic Data") {
|
||||
private val mapBuilderVM = find<GameMapBuilderVM>()
|
||||
|
||||
override val complete = mapBuilderVM.valid(
|
||||
mapBuilderVM.fileProperty,
|
||||
mapBuilderVM.nameProperty,
|
||||
mapBuilderVM.rowsProperty,
|
||||
mapBuilderVM.columnsProperty,
|
||||
mapBuilderVM.handlerProperty
|
||||
)
|
||||
|
||||
override val root = form {
|
||||
fieldset("Map Settings") {
|
||||
|
||||
field("Map file") {
|
||||
hbox {
|
||||
textfield(mapBuilderVM.fileProperty) {
|
||||
trimWhitespace()
|
||||
whenDocked { requestFocus() }
|
||||
|
||||
mapBuilderVM.validationContext.addValidator(this, mapBuilderVM.fileProperty) {
|
||||
when {
|
||||
it.isNullOrBlank() -> error("Field is required")
|
||||
!File(it).exists() -> error("Provide valid path to the file")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button("Choose") {
|
||||
action {
|
||||
mapBuilderVM.fileProperty.value = chooseFile(
|
||||
title = "Map file location",
|
||||
filters = arrayOf(FileChooser.ExtensionFilter("Map files (*.dat)", "*.dat"))
|
||||
).getOrNull(0)?.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label("Only tile, object and color layers will be imported. Any image layers will be dropped out.")
|
||||
|
||||
field("Map name") {
|
||||
textfield(mapBuilderVM.nameProperty) {
|
||||
required()
|
||||
}
|
||||
}
|
||||
|
||||
field("Map Handler class") {
|
||||
textfield(mapBuilderVM.handlerProperty) {
|
||||
required()
|
||||
trimWhitespace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.bartlomiejpluta.base.editor.map.view.wizard
|
||||
|
||||
import com.bartlomiejpluta.base.editor.map.viewmodel.GameMapBuilderVM
|
||||
import org.kordamp.ikonli.javafx.FontIcon
|
||||
import tornadofx.Wizard
|
||||
|
||||
class MapImportWizard : Wizard("Import Map", "Provide map information") {
|
||||
private val mapBuilderVM = find<GameMapBuilderVM>()
|
||||
|
||||
init {
|
||||
graphic = FontIcon("fa-map").apply {
|
||||
iconSize = 40
|
||||
}
|
||||
|
||||
add(MapImportBasicDataView::class)
|
||||
add(MapTileSetSelectionView::class)
|
||||
}
|
||||
}
|
||||
@@ -20,4 +20,7 @@ class GameMapBuilderVM : ItemViewModel<GameMapBuilder>(GameMapBuilder()) {
|
||||
|
||||
val handlerProperty = bind(GameMapBuilder::handlerProperty, autocommit = true)
|
||||
var handler by handlerProperty
|
||||
|
||||
val fileProperty = bind(GameMapBuilder::fileProperty, autocommit = true)
|
||||
var file by fileProperty
|
||||
}
|
||||
@@ -113,6 +113,26 @@ class DefaultProjectContext : ProjectContext {
|
||||
}
|
||||
}
|
||||
|
||||
override fun importMapFromFile(name: String, handler: String, file: File, tileSet: TileSet) =
|
||||
project?.let { project ->
|
||||
val map = file.inputStream().use { mapDeserializer.deserialize(it, tileSet) }
|
||||
UID.next(project.maps.map(Asset::uid)).let { uid ->
|
||||
val asset = GameMapAsset(project, uid, name)
|
||||
map.uid = uid
|
||||
project.maps += asset
|
||||
|
||||
save()
|
||||
|
||||
javaClassService.createClassFile(handler, project.codeFSNode, "map_handler.ftl") { model ->
|
||||
model["mapUid"] = uid
|
||||
}
|
||||
|
||||
File(project.mapsDirectory, asset.source).outputStream().use { fos -> mapSerializer.serialize(map, fos) }
|
||||
|
||||
map
|
||||
}
|
||||
} ?: throw IllegalStateException("There is no open project in the context")
|
||||
|
||||
override fun loadMap(uid: String) = project?.let {
|
||||
val asset = it.maps.firstOrNull { map -> map.uid == uid }
|
||||
?: throw IllegalStateException("The map with uid [$uid] does not exist ")
|
||||
|
||||
@@ -28,6 +28,7 @@ interface ProjectContext {
|
||||
fun createNewProject(project: Project)
|
||||
|
||||
fun importMap(name: String, map: GameMap)
|
||||
fun importMapFromFile(name: String, handler: String, file: File, tileSet: TileSet): GameMap
|
||||
fun loadMap(uid: String): GameMap
|
||||
fun saveMap(map: GameMap)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user