Skip to content

Commit

Permalink
Merge pull request #233 from KevinDaGame/feat/litematic_support
Browse files Browse the repository at this point in the history
Feat/litematic support
  • Loading branch information
KevinDaGame authored Dec 22, 2023
2 parents de02683 + 9f75ee6 commit ce5f286
Show file tree
Hide file tree
Showing 13 changed files with 341 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ import com.github.kevindagame.snipe.SnipeData
import com.github.kevindagame.util.Messages
import com.github.kevindagame.util.VoxelMessage
import com.github.kevindagame.util.brushOperation.BlockOperation
import com.github.kevindagame.util.schematic.SchematicReader
import com.github.kevindagame.util.schematic.VoxelSchematic
import com.github.kevindagame.util.schematic.VoxelSchematicBlock
import com.github.kevindagame.util.schematic.*
import com.github.kevindagame.voxelsniper.location.BaseLocation
import com.github.kevindagame.voxelsniper.material.VoxelMaterial

class SchematicBrush : AbstractBrush() {
private val schematicLoader: VoxelSchematicLoader
private lateinit var schematicName: String
private lateinit var schematics: List<VoxelSchematic>
private var mode = PasteMode.FULL
private var rotation = RotateMode.DEGREES_0
private var flip = FlipMode.NONE

init {
val schematicReader: ISchematicReader = DataFolderSchematicReader()
this.schematicLoader = VoxelSchematicLoader(schematicReader)
}
override fun info(vm: VoxelMessage) {
vm.brushName(this.name)
vm.custom(Messages.CHOSEN_SCHEMATIC.replace("%schematics%", if(this::schematics.isInitialized) schematics.joinToString(", ") { it.name } else "None"))
Expand Down Expand Up @@ -148,13 +151,13 @@ class SchematicBrush : AbstractBrush() {
if (params.isNotEmpty()) {
when (params[0]) {
"list" -> {
v.sendMessage(Messages.SCHEMATIC_LIST.replace("%schematics%", SchematicReader.getPossibleNames().joinToString(", ")))
v.sendMessage(Messages.SCHEMATIC_LIST.replace("%schematics%", schematicLoader.getSchematicNamesForAutoComplete().joinToString(", ")))
}

"schem" -> {
if (params.size > 1) {
try {
val schematics = SchematicReader.read(params[1])
val schematics = schematicLoader.gatherSchematics(params[1])
this.schematicName = params[1]
this.schematics = schematics
if (schematics.size == 1) {
Expand All @@ -163,7 +166,7 @@ class SchematicBrush : AbstractBrush() {
v.sendMessage(Messages.SCHEMATIC_LOADED_MULTIPLE.replace("%schematics%", this.schematics.joinToString(", ") { it.name }))
}
} catch (e: IllegalArgumentException) {
v.sendMessage(Messages.INVALID_BRUSH_PARAM)
v.sendMessage(Messages.FILE_LOAD_FAIL.replace("%exception.getMessage%", e.message ?: "Unknown error"))
}
}
}
Expand Down Expand Up @@ -202,6 +205,10 @@ class SchematicBrush : AbstractBrush() {
}
}

else -> {
v.sendMessage(Messages.INVALID_BRUSH_PARAM)
}

}
}
}
Expand All @@ -212,7 +219,7 @@ class SchematicBrush : AbstractBrush() {

override fun registerArgumentValues(): HashMap<String, List<String>> {
return hashMapOf(
"schem" to SchematicReader.getPossibleNames(),
"schem" to schematicLoader.getSchematicNamesForAutoComplete(),
"rotate" to RotateMode.values().map { it.name.lowercase().replace("degrees_", "") },
"flip" to FlipMode.values().map { it.name.lowercase() },
"mode" to PasteMode.values().map { it.name.lowercase() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ public VoxelCommand(String name) {

public boolean execute(IPlayer player, String[] args) {
if (getPermission() == null || getPermission().isEmpty() || player.hasPermission(getPermission())) {
return doCommand(player, args);
try {
return doCommand(player, args);
} catch (Exception e) {
e.printStackTrace();
player.sendMessage(Messages.COMMAND_ERROR);
return true;
}
} else {
player.sendMessage(Messages.NO_PERMISSION_MESSAGE.replace("%permission%", getPermission()));
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ public enum Messages implements ComponentLike {
SCHEMATIC_SET_ROTATION,
SCHEMATIC_SET_FLIP,
SCHEMATIC_SET_MODE,
;
COMMAND_ERROR;
//</editor-fold>


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.github.kevindagame.util.schematic

import com.github.kevindagame.VoxelSniper
import net.sandrohc.schematic4j.SchematicFormat
import net.sandrohc.schematic4j.SchematicLoader
import net.sandrohc.schematic4j.schematic.Schematic
import java.io.File
import java.util.*

class DataFolderSchematicReader : ISchematicReader {
override fun getSchematicFile(name: String): File? {
//check for exact name
val exactSchematic = VoxelSniper.voxelsniper.fileHandler.getDataFile(SCHEMATIC_FILE_ROOT_PATH + name)
if (exactSchematic.isFile) {
return exactSchematic
}

//if no, check for name with any extension
val schematicFiles = VoxelSniper.voxelsniper.fileHandler.getDataFile(SCHEMATIC_FILE_ROOT_PATH).listFiles()
if (schematicFiles != null) {
for (schematic in schematicFiles) {
if (schematic.isFile) {
if (schematic.nameWithoutExtension == name) {
return schematic
}
}
}
}

return null
}

override fun getSchematicFolder(name: String): File? {
val path = SCHEMATIC_FILE_ROOT_PATH + name
val schematicFolder = VoxelSniper.voxelsniper.fileHandler.getDataFile(path)
if (schematicFolder.isDirectory) {
return schematicFolder
}
return null
}

override fun readSchematicFile(file: File): VoxelSchematic {
val schematic: Schematic
try {
schematic = SchematicLoader.load(file)
} catch (e: Exception) {
throw IllegalArgumentException("Schematic ${file.name} is not valid")
}

val voxelSchematicBuilder = VoxelSchematicBuilder()

voxelSchematicBuilder.name = file.nameWithoutExtension

schematic.blocks().forEach { block ->
voxelSchematicBuilder.addBlock(
block.left.x.toDouble(),
block.left.y.toDouble(),
block.left.z.toDouble(),
block.right
)
}
return voxelSchematicBuilder.build()
}

override fun readSchematicFolder(folder: File): List<VoxelSchematic> {
val schematics = mutableListOf<VoxelSchematic>()

val schematicFiles = folder.listFiles() ?: throw IllegalStateException("Folder $folder does not exist")

for (schematicFile in schematicFiles) {
if (schematicFile.isFile) {

schematics.add(readSchematicFile(schematicFile))
}

}
return schematics
}

override fun getPossibleSchematicNames(): List<String> {
val schematics = mutableListOf<String>()
val schematicsFolder = VoxelSniper.voxelsniper.fileHandler.getDataFile(SCHEMATIC_FILE_ROOT_PATH)
if (schematicsFolder.exists()) {
val files = schematicsFolder.listFiles()
if (files != null) {
for (file in files) {
if (file.isFile) {
schematics.add(file.nameWithoutExtension)
} else if (file.isDirectory) {
if (file.listFiles()?.any { SCHEMATIC_VALID_EXTENSIONS.contains(it.extension) } == true) {
schematics.add(file.name)
}
}
}
}
}
return schematics
}

companion object {
const val SCHEMATIC_FILE_ROOT_PATH = "schematics/"

val SCHEMATIC_VALID_EXTENSIONS: List<String> = Arrays.stream(SchematicFormat.values())
.map { f: SchematicFormat -> f.fileExtension }
.distinct()
.toList()

fun initialize() {
val schematicsFolder = VoxelSniper.voxelsniper.fileHandler.getDataFile("schematics")
if (!schematicsFolder.exists()) {
schematicsFolder.mkdir()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.github.kevindagame.util.schematic

import java.io.File

interface ISchematicReader {
fun getSchematicFile(name: String): File?
fun getSchematicFolder(name: String): File?

fun readSchematicFile(file: File): VoxelSchematic?
fun readSchematicFolder(folder: File): List<VoxelSchematic>
fun getPossibleSchematicNames(): List<String>
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.github.kevindagame.util.schematic

class VoxelSchematicLoader(private val schematicReader: ISchematicReader) {
/**
* Reads a schematic from a file or a folder.
* check if there is a folder with the name.
* If there is a folder with that name, then it will read all schematics in that folder.
* If there are no schematics in that folder, then it will throw an IllegalArgumentException.
* If there is no folder with that name, then it will check if there is a file with the <name>.schem.
* If there is a file with the <name>.schem, then it will read the file.
* If there is no file with the <name>.schem, then it will throw an IllegalArgumentException.
*
* @param name The name of the schematic or the folder.
* @return A list of schematics.
* @throws IllegalArgumentException If there is no file with the <name>.schem or no folder with that name.
*/
fun gatherSchematics(name: String): List<VoxelSchematic> {
val schematicFolder = schematicReader.getSchematicFolder(name)
if (schematicFolder != null) {
val schematics = schematicReader.readSchematicFolder(schematicFolder)
if (schematics.isEmpty()) {
throw IllegalArgumentException("Folder $name does not contain any schematics")
}
return schematics
}

val schematicFile = schematicReader.getSchematicFile(name)
if (schematicFile != null) {
val schematic = schematicReader.readSchematicFile(schematicFile)
?: throw IllegalArgumentException("Schematic $name is not valid")

return listOf(schematic)
}

throw IllegalArgumentException("No schematic file or folder with name $name")
}

fun getSchematicNamesForAutoComplete(): List<String> {
return schematicReader.getPossibleSchematicNames()
}
}
Loading

0 comments on commit ce5f286

Please sign in to comment.