From bf6628ec89dea8ebd8f41c79a81ff32a1a75ac0d Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:15:00 +0100 Subject: [PATCH 01/12] Implement Litematic support. Refactor stencil system --- .../kevindagame/brush/SchematicBrush.kt | 15 ++- .../schematic/DataFolderSchematicReader.kt | 102 +++++++++++++++ .../util/schematic/ISchematicReader.kt | 12 ++ .../util/schematic/SchematicReader.kt | 122 ------------------ .../util/schematic/VoxelSchematicLoader.kt | 41 ++++++ .../util/schematic/SchematicLoaderTest.kt | 118 +++++++++++++++++ .../voxelsniperforge/VoxelSniperForge.java | 5 +- 7 files changed, 284 insertions(+), 131 deletions(-) create mode 100644 VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt create mode 100644 VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/ISchematicReader.kt delete mode 100644 VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/SchematicReader.kt create mode 100644 VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/VoxelSchematicLoader.kt create mode 100644 VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt index 3a78e1c4..d8714b68 100644 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt @@ -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 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")) @@ -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) { @@ -212,7 +215,7 @@ class SchematicBrush : AbstractBrush() { override fun registerArgumentValues(): HashMap> { 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() }, diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt new file mode 100644 index 00000000..9b8205e4 --- /dev/null +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt @@ -0,0 +1,102 @@ +package com.github.kevindagame.util.schematic + +import com.github.kevindagame.VoxelSniper +import net.sandrohc.schematic4j.SchematicLoader +import java.io.File + +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 = SchematicLoader.load(file) + val voxelSchematicBuilder = VoxelSchematicBuilder() + + voxelSchematicBuilder.name = file.nameWithoutExtension + + for (y in 0 until schematic.height()) { + for (x in 0 until schematic.width()) { + for (z in 0 until schematic.length()) { + + val block = schematic.block(x, y, z) + voxelSchematicBuilder.addBlock(x.toDouble(), y.toDouble(), z.toDouble(), block) + } + } + } + return voxelSchematicBuilder.build() + } + + override fun readSchematicFolder(folder: File): List { + val schematics = mutableListOf() + + 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 { + val schematics = mutableListOf() + 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 { it.extension == "schem" } == true) { + schematics.add(file.name) + } + } + } + } + } + return schematics + } + + companion object { + const val SCHEMATIC_FILE_ROOT_PATH = "schematics/" + + fun initialize() { + val schematicsFolder = VoxelSniper.voxelsniper.fileHandler.getDataFile("schematics") + if (!schematicsFolder.exists()) { + schematicsFolder.mkdir() + } + } + } +} \ No newline at end of file diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/ISchematicReader.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/ISchematicReader.kt new file mode 100644 index 00000000..ae434782 --- /dev/null +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/ISchematicReader.kt @@ -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 + fun getPossibleSchematicNames(): List +} diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/SchematicReader.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/SchematicReader.kt deleted file mode 100644 index 403974d6..00000000 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/SchematicReader.kt +++ /dev/null @@ -1,122 +0,0 @@ -package com.github.kevindagame.util.schematic - -import com.github.kevindagame.VoxelSniper -import net.sandrohc.schematic4j.SchematicLoader - -import java.io.File - -object SchematicReader { - - private fun readSchematic(file: File): VoxelSchematic { - val schematic = SchematicLoader.load(file) - val voxelSchematicBuilder = VoxelSchematicBuilder() - - voxelSchematicBuilder.name = file.nameWithoutExtension - - for (y in 0 until schematic.height()) { - for (x in 0 until schematic.width()) { - for (z in 0 until schematic.length()) { - - val block = schematic.block(x,y,z) - voxelSchematicBuilder.addBlock(x.toDouble(), y.toDouble(), z.toDouble(), block) - } - } - } - return voxelSchematicBuilder.build() - } - - private fun readSchematics(folder: File): MutableList { - if (!folder.exists()) { - throw IllegalArgumentException("Folder $folder does not exist") - } - val schematicFiles = folder.listFiles() - if (schematicFiles != null) { - if(schematicFiles.none { it.extension == "schem" }) { - throw IllegalArgumentException("Folder $folder does not contain any schematics") - } - } - val schematics = mutableListOf() - if (schematicFiles != null) { - for (schematic in schematicFiles) { - if (schematic.isFile) { - if (schematic.extension == "schem") { - schematics.add(readSchematic(schematic)) - } - } - } - } - return schematics - } - - /** - * Reads a schematic from a file or a folder. - * If the name ends with .schem, then it will read the file. - * If there is no file with the name.schem, then it will throw an IllegalArgumentException. - * If the name does not end with .schem, then it will check if there is a folder with that 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 read(name: String): List { - - //if name ends with .schem, then check if it exists. if yes, then call readFile with the file. - if (name.endsWith(".schem")) { - val file = VoxelSniper.voxelsniper.fileHandler.getDataFile("schematics/$name") - if (!file.exists()) { - throw IllegalArgumentException("File $name does not exist") - } - return listOf(readSchematic(file)) - } - - // If name does not end with .schem, then check if there is a folder with that name. If yes, then call readFolder with the folder. - val folder = VoxelSniper.voxelsniper.fileHandler.getDataFile("schematics/$name") - if (folder.exists()) { - return readSchematics(folder) - } - - // If no, check if there is a file with the name.schem. If yes, then call readFile with the file. - val file = VoxelSniper.voxelsniper.fileHandler.getDataFile("schematics/$name.schem") - if (file.exists()) { - return listOf(readSchematic(file)) - } - - // If no, then throw an exception. - throw IllegalArgumentException("File $name does not exist") - - } - - fun getPossibleNames(): List { - val schematicsFolder = VoxelSniper.voxelsniper.fileHandler.getDataFile("schematics") - val schematics = mutableListOf() - if (schematicsFolder.exists()) { - val files = schematicsFolder.listFiles() - if (files != null) { - for (file in files) { - if (file.isFile) { - if (file.extension == "schem") { - schematics.add(file.nameWithoutExtension) - } - } else if (file.isDirectory) { - if (file.listFiles()?.any { it.extension == "schem" } == true) { - schematics.add(file.name) - } - } - } - } - } - return schematics - } - - @JvmStatic - fun initialize() { - val schematicsFolder = VoxelSniper.voxelsniper.fileHandler.getDataFile("schematics") - if (!schematicsFolder.exists()) { - schematicsFolder.mkdir() - } - } -} \ No newline at end of file diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/VoxelSchematicLoader.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/VoxelSchematicLoader.kt new file mode 100644 index 00000000..544eb66f --- /dev/null +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/VoxelSchematicLoader.kt @@ -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 .schem. + * If there is a file with the .schem, then it will read the file. + * If there is no file with the .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 .schem or no folder with that name. + */ + fun gatherSchematics(name: String): List { + 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 { + return schematicReader.getPossibleSchematicNames() + } +} \ No newline at end of file diff --git a/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt b/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt new file mode 100644 index 00000000..2bb7da81 --- /dev/null +++ b/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt @@ -0,0 +1,118 @@ +package com.github.kevindagame.util.schematic + +import org.junit.Test +import org.mockito.Mockito +import java.io.File + +class SchematicLoaderTest { + + @Test + fun gatherSchematics_match_empty_folder_throw_IllegalArgumentException() { + // Arrange + val folder = File("empty_folder") + val schematicReaderMock = Mockito.mock(ISchematicReader::class.java) + Mockito.`when`(schematicReaderMock.getSchematicFolder("empty_folder")).thenReturn(folder) + Mockito.`when`(schematicReaderMock.readSchematicFolder(folder)).thenReturn(emptyList()) + + val schematicLoader = VoxelSchematicLoader(schematicReaderMock) + + val name = "empty_folder" + + // Act + val exception = try { + schematicLoader.gatherSchematics(name) + null + } catch (e: IllegalArgumentException) { + e + } + + // Assert + assert(exception != null) + assert(exception!!.message!!.contains(name)) + } + + @Test + fun gatherSchematics_match_non_empty_folder_returns_Schematics() { + // Arrange + val folder = File("empty_folder") + val schematicInFolder = VoxelSchematic(listOf(), "Fancy tree") + val schematicReaderMock = Mockito.mock(ISchematicReader::class.java) + Mockito.`when`(schematicReaderMock.getSchematicFolder("empty_folder")).thenReturn(folder) + Mockito.`when`(schematicReaderMock.readSchematicFolder(folder)).thenReturn(listOf(schematicInFolder)) + + val schematicLoader = VoxelSchematicLoader(schematicReaderMock) + val name = "empty_folder" + + // Act + val schematics = schematicLoader.gatherSchematics(name) + + // Assert + assert(schematics.size == 1) + assert(schematics[0] == schematicInFolder) + } + + @Test + fun gatherSchematics_match_file_returns_Schematic() { + // Arrange + val schematicFile = File("fancy_tree.schem") + val schematic = VoxelSchematic(listOf(), "Fancy tree") + val schematicReaderMock = Mockito.mock(ISchematicReader::class.java) + + Mockito.`when`(schematicReaderMock.getSchematicFolder("fancy_tree")).thenReturn(null) + Mockito.`when`(schematicReaderMock.getSchematicFile("fancy_tree")).thenReturn(schematicFile) + Mockito.`when`(schematicReaderMock.readSchematicFile(schematicFile)).thenReturn(schematic) + + val schematicLoader = VoxelSchematicLoader(schematicReaderMock) + val name = "fancy_tree" + + // Act + val schematics = schematicLoader.gatherSchematics(name) + + // Assert + assert(schematics.size == 1) + assert(schematics[0] == schematic) + } + + @Test + fun gatherSchematics_match_file_but_null_throws_IllegalArgumentException() { + // Arrange + val schematicFile = File("fancy_tree.schem") + val schematicReaderMock = Mockito.mock(ISchematicReader::class.java) + + Mockito.`when`(schematicReaderMock.getSchematicFolder("fancy_tree")).thenReturn(null) + Mockito.`when`(schematicReaderMock.getSchematicFile("fancy_tree")).thenReturn(schematicFile) + Mockito.`when`(schematicReaderMock.readSchematicFile(schematicFile)).thenReturn(null) + + val schematicLoader = VoxelSchematicLoader(schematicReaderMock) + val name = "fancy_tree" + + // Act + val exception = try { + schematicLoader.gatherSchematics(name) + null + } catch (e: IllegalArgumentException) { + e + } + + // Assert + assert(exception != null) + assert(exception!!.message!!.contains(name)) + } + + @Test + fun `getSchematicNamesForAutoComplete should return list of schematic names`() { + // Arrange + val expectedSchematicNames = listOf("schematic1", "schematic2", "schematic3") + + val schematicReader = Mockito.mock(ISchematicReader::class.java) + Mockito.`when`(schematicReader.getPossibleSchematicNames()).thenReturn(expectedSchematicNames) + val schematicLoader = VoxelSchematicLoader(schematicReader) + + //Act + val schematicNames = schematicLoader.getSchematicNamesForAutoComplete() + + // Assert + assert(schematicNames == expectedSchematicNames) + } + +} \ No newline at end of file diff --git a/VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/VoxelSniperForge.java b/VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/VoxelSniperForge.java index 6b8bbb3e..e471905e 100644 --- a/VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/VoxelSniperForge.java +++ b/VoxelSniperForge/src/main/java/com/github/kevindagame/voxelsniperforge/VoxelSniperForge.java @@ -4,7 +4,7 @@ import com.github.kevindagame.VoxelSniper; import com.github.kevindagame.command.VoxelCommandManager; import com.github.kevindagame.util.Messages; -import com.github.kevindagame.util.schematic.SchematicReader; +import com.github.kevindagame.util.schematic.DataFolderSchematicReader; import com.github.kevindagame.voxelsniper.Environment; import com.github.kevindagame.voxelsniper.IVoxelsniper; import com.github.kevindagame.voxelsniper.biome.VoxelBiome; @@ -107,11 +107,10 @@ public final void registerPermissionNodes(final PermissionGatherEvent.Nodes even ForgePermissionManager.register(event); } - // You can use SubscribeEvent and let the Event Bus discover methods to call @SubscribeEvent public void onServerStarting(ServerStartingEvent event) { this.fileHandler = new ForgeFileHandler(this); - SchematicReader.initialize(); + DataFolderSchematicReader.Companion.initialize(); Messages.load(this); voxelSniperConfiguration = new VoxelSniperConfiguration(this); From 7073d43559662c6a2b98656929d009734bc86d66 Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:27:49 +0100 Subject: [PATCH 02/12] Add a final catch to brush commands to ensure exceptions are logged to console --- .../java/com/github/kevindagame/command/VoxelCommand.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/command/VoxelCommand.java b/VoxelSniperCore/src/main/java/com/github/kevindagame/command/VoxelCommand.java index f628a360..412aac7f 100644 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/command/VoxelCommand.java +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/command/VoxelCommand.java @@ -24,7 +24,12 @@ 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(); + return true; + } } else { player.sendMessage(Messages.NO_PERMISSION_MESSAGE.replace("%permission%", getPermission())); return true; From 2cf62e87572ad27841d9d399dc159ccd192e328e Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:28:29 +0100 Subject: [PATCH 03/12] Handle any exceptions from schematic4j --- .../java/com/github/kevindagame/brush/SchematicBrush.kt | 2 +- .../util/schematic/DataFolderSchematicReader.kt | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt index d8714b68..2052abc2 100644 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt @@ -166,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")) } } } diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt index 9b8205e4..5727e430 100644 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt @@ -2,6 +2,7 @@ package com.github.kevindagame.util.schematic import com.github.kevindagame.VoxelSniper import net.sandrohc.schematic4j.SchematicLoader +import net.sandrohc.schematic4j.schematic.Schematic import java.io.File class DataFolderSchematicReader : ISchematicReader { @@ -37,7 +38,13 @@ class DataFolderSchematicReader : ISchematicReader { } override fun readSchematicFile(file: File): VoxelSchematic { - val schematic = SchematicLoader.load(file) + 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 From be61c4db4cd24d4995982e2ec81d1c6ab3a14aaf Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:30:41 +0100 Subject: [PATCH 04/12] Add missing unit test --- .../util/schematic/SchematicLoaderTest.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt b/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt index 2bb7da81..710d639a 100644 --- a/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt +++ b/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt @@ -99,6 +99,30 @@ class SchematicLoaderTest { assert(exception!!.message!!.contains(name)) } + @Test + fun gatherSchematics_no_match_throws_IllegalArgumentException() { + // Arrange + val schematicReaderMock = Mockito.mock(ISchematicReader::class.java) + + Mockito.`when`(schematicReaderMock.getSchematicFolder("fancy_tree")).thenReturn(null) + Mockito.`when`(schematicReaderMock.getSchematicFile("fancy_tree")).thenReturn(null) + + val schematicLoader = VoxelSchematicLoader(schematicReaderMock) + val name = "fancy_tree" + + // Act + val exception = try { + schematicLoader.gatherSchematics(name) + null + } catch (e: IllegalArgumentException) { + e + } + + // Assert + assert(exception != null) + assert(exception!!.message!!.contains(name)) + } + @Test fun `getSchematicNamesForAutoComplete should return list of schematic names`() { // Arrange From 60fdb0ac9e186dd36b7f9e68dd79e093fb3c74b6 Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:42:09 +0100 Subject: [PATCH 05/12] =?UTF-8?q?Fix=20for=20spigot=20and=20fabric=20?= =?UTF-8?q?=F0=9F=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../github/kevdadev/voxelsniperfabric/VoxelSniperFabric.kt | 4 ++-- .../com/github/kevindagame/voxelsniper/SpigotVoxelSniper.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VoxelSniperFabric/src/main/java/com/github/kevdadev/voxelsniperfabric/VoxelSniperFabric.kt b/VoxelSniperFabric/src/main/java/com/github/kevdadev/voxelsniperfabric/VoxelSniperFabric.kt index 634c9d0d..6ee09130 100644 --- a/VoxelSniperFabric/src/main/java/com/github/kevdadev/voxelsniperfabric/VoxelSniperFabric.kt +++ b/VoxelSniperFabric/src/main/java/com/github/kevdadev/voxelsniperfabric/VoxelSniperFabric.kt @@ -7,7 +7,7 @@ import com.github.kevindagame.VoxelBrushManager import com.github.kevindagame.VoxelSniper import com.github.kevindagame.command.VoxelCommandManager import com.github.kevindagame.util.Messages -import com.github.kevindagame.util.schematic.SchematicReader +import com.github.kevindagame.util.schematic.DataFolderSchematicReader import com.github.kevindagame.voxelsniper.Environment import com.github.kevindagame.voxelsniper.IVoxelsniper import com.github.kevindagame.voxelsniper.biome.VoxelBiome @@ -53,7 +53,7 @@ class VoxelSniperFabric : ModInitializer, IVoxelsniper { fileHandler = FabricFileHandler() - SchematicReader.initialize() + DataFolderSchematicReader.Companion.initialize() Messages.load(this) voxelSniperConfiguration = VoxelSniperConfiguration(this) diff --git a/VoxelSniperSpigot/src/main/java/com/github/kevindagame/voxelsniper/SpigotVoxelSniper.java b/VoxelSniperSpigot/src/main/java/com/github/kevindagame/voxelsniper/SpigotVoxelSniper.java index 5d4f7fba..69ddcb79 100644 --- a/VoxelSniperSpigot/src/main/java/com/github/kevindagame/voxelsniper/SpigotVoxelSniper.java +++ b/VoxelSniperSpigot/src/main/java/com/github/kevindagame/voxelsniper/SpigotVoxelSniper.java @@ -4,7 +4,7 @@ import com.github.kevindagame.VoxelSniper; import com.github.kevindagame.util.Messages; import com.github.kevindagame.util.VersionChecker; -import com.github.kevindagame.util.schematic.SchematicReader; +import com.github.kevindagame.util.schematic.DataFolderSchematicReader; import com.github.kevindagame.voxelsniper.biome.VoxelBiome; import com.github.kevindagame.voxelsniper.entity.entitytype.VoxelEntityType; import com.github.kevindagame.voxelsniper.entity.player.IPlayer; @@ -97,7 +97,7 @@ public void onEnable() { new BrushUsersCounter().registerListeners(); // Initialize commands - SchematicReader.initialize(); + DataFolderSchematicReader.Companion.initialize(); SpigotCommandManager.initialize(); // Initialize metrics From 689a5d3d30d09b6633ec5170d97b4ba593637d91 Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:49:28 +0100 Subject: [PATCH 06/12] Bump voxelsniper version to 8.13.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 01aa13fb..3ffc677e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -voxelsniper.version=8.12.5 +voxelsniper.version=8.13.0 org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false From 3b4f059c894cc7dc76996028d9d3def9f9be1bee Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:56:24 +0100 Subject: [PATCH 07/12] Fix forge build (again) --- buildSrc/src/main/kotlin/voxel-core.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/buildSrc/src/main/kotlin/voxel-core.gradle.kts b/buildSrc/src/main/kotlin/voxel-core.gradle.kts index 2e98268f..330bd695 100644 --- a/buildSrc/src/main/kotlin/voxel-core.gradle.kts +++ b/buildSrc/src/main/kotlin/voxel-core.gradle.kts @@ -41,6 +41,7 @@ dependencies { implementation(kotlin("stdlib-jdk8")) implementation("net.sandrohc:schematic4j:1.1.0") { exclude("org.checkerframework", "") + exclude("org.slf4j", "") } shadowNoRuntime("com.google.code.gson:gson:2.10.1") shadow("org.yaml:snakeyaml:1.33") From 23f40e36497655d2a4e7be79aae62b46e98b99ea Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:59:45 +0100 Subject: [PATCH 08/12] Add default argument error message --- .../main/java/com/github/kevindagame/brush/SchematicBrush.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt index 2052abc2..71a598eb 100644 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/brush/SchematicBrush.kt @@ -205,6 +205,10 @@ class SchematicBrush : AbstractBrush() { } } + else -> { + v.sendMessage(Messages.INVALID_BRUSH_PARAM) + } + } } } From 1a8211ea4592fceed3d265bc198a907e01ec0939 Mon Sep 17 00:00:00 2001 From: kevin <65958288+KevinDaGame@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:27:15 +0100 Subject: [PATCH 09/12] Add dedicated error message to user when a command fails due to an exception. (This is a failsafe. Ideally this shouldn't happen at all) --- .../main/java/com/github/kevindagame/command/VoxelCommand.java | 1 + .../src/main/java/com/github/kevindagame/util/Messages.java | 2 +- VoxelSniperCore/src/main/resources/lang.yml | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/command/VoxelCommand.java b/VoxelSniperCore/src/main/java/com/github/kevindagame/command/VoxelCommand.java index 412aac7f..f5914f25 100644 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/command/VoxelCommand.java +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/command/VoxelCommand.java @@ -28,6 +28,7 @@ public boolean execute(IPlayer player, String[] args) { return doCommand(player, args); } catch (Exception e) { e.printStackTrace(); + player.sendMessage(Messages.COMMAND_ERROR); return true; } } else { diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/Messages.java b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/Messages.java index 4a043a8e..6801bf9a 100644 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/Messages.java +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/Messages.java @@ -372,7 +372,7 @@ public enum Messages implements ComponentLike { SCHEMATIC_SET_ROTATION, SCHEMATIC_SET_FLIP, SCHEMATIC_SET_MODE, - ; + COMMAND_ERROR; // diff --git a/VoxelSniperCore/src/main/resources/lang.yml b/VoxelSniperCore/src/main/resources/lang.yml index 49eed365..10c4f760 100644 --- a/VoxelSniperCore/src/main/resources/lang.yml +++ b/VoxelSniperCore/src/main/resources/lang.yml @@ -603,4 +603,5 @@ SCHEMATIC_LOADED_ONE: "Loaded schematic: %schematic%" SCHEMATIC_LOADED_MULTIPLE: "Loaded schematics: %schematics%" SCHEMATIC_SET_ROTATION: "Rotation set to: %rotation% degrees" SCHEMATIC_SET_FLIP: "Flip set to: %flip%" -SCHEMATIC_SET_MODE: "Paste mode set to: %mode%" \ No newline at end of file +SCHEMATIC_SET_MODE: "Paste mode set to: %mode%" +COMMAND_ERROR: "Something went wrong while executing this command" \ No newline at end of file From 11ea2700cbc760f2d1311036ca51f0eb8524f4a7 Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Fri, 22 Dec 2023 22:33:09 +0100 Subject: [PATCH 10/12] Apply suggestions by @SandroHc --- .../schematic/DataFolderSchematicReader.kt | 24 ++++++++++++------- ...derTest.kt => VoxelSchematicLoaderTest.kt} | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) rename VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/{SchematicLoaderTest.kt => VoxelSchematicLoaderTest.kt} (99%) diff --git a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt index 5727e430..cb434cc6 100644 --- a/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt +++ b/VoxelSniperCore/src/main/java/com/github/kevindagame/util/schematic/DataFolderSchematicReader.kt @@ -1,9 +1,11 @@ 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? { @@ -49,14 +51,13 @@ class DataFolderSchematicReader : ISchematicReader { voxelSchematicBuilder.name = file.nameWithoutExtension - for (y in 0 until schematic.height()) { - for (x in 0 until schematic.width()) { - for (z in 0 until schematic.length()) { - - val block = schematic.block(x, y, z) - voxelSchematicBuilder.addBlock(x.toDouble(), y.toDouble(), z.toDouble(), block) - } - } + schematic.blocks().forEach { block -> + voxelSchematicBuilder.addBlock( + block.left.x.toDouble(), + block.left.y.toDouble(), + block.left.z.toDouble(), + block.right + ) } return voxelSchematicBuilder.build() } @@ -86,7 +87,7 @@ class DataFolderSchematicReader : ISchematicReader { if (file.isFile) { schematics.add(file.nameWithoutExtension) } else if (file.isDirectory) { - if (file.listFiles()?.any { it.extension == "schem" } == true) { + if (file.listFiles()?.any { SCHEMATIC_VALID_EXTENSIONS.contains(it.extension) } == true) { schematics.add(file.name) } } @@ -99,6 +100,11 @@ class DataFolderSchematicReader : ISchematicReader { companion object { const val SCHEMATIC_FILE_ROOT_PATH = "schematics/" + val SCHEMATIC_VALID_EXTENSIONS: List = Arrays.stream(SchematicFormat.values()) + .map { f: SchematicFormat -> f.fileExtension } + .distinct() + .toList() + fun initialize() { val schematicsFolder = VoxelSniper.voxelsniper.fileHandler.getDataFile("schematics") if (!schematicsFolder.exists()) { diff --git a/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt b/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/VoxelSchematicLoaderTest.kt similarity index 99% rename from VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt rename to VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/VoxelSchematicLoaderTest.kt index 710d639a..74b418fc 100644 --- a/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/SchematicLoaderTest.kt +++ b/VoxelSniperCore/src/test/java/com/github/kevindagame/util/schematic/VoxelSchematicLoaderTest.kt @@ -4,7 +4,7 @@ import org.junit.Test import org.mockito.Mockito import java.io.File -class SchematicLoaderTest { +class VoxelSchematicLoaderTest { @Test fun gatherSchematics_match_empty_folder_throw_IllegalArgumentException() { From 9677e14edbe9b0ac9b318b9562bd743e19d8c161 Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Fri, 22 Dec 2023 22:47:22 +0100 Subject: [PATCH 11/12] Fix test dependency --- buildSrc/src/main/kotlin/voxel-core.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/buildSrc/src/main/kotlin/voxel-core.gradle.kts b/buildSrc/src/main/kotlin/voxel-core.gradle.kts index 330bd695..32102658 100644 --- a/buildSrc/src/main/kotlin/voxel-core.gradle.kts +++ b/buildSrc/src/main/kotlin/voxel-core.gradle.kts @@ -50,6 +50,10 @@ dependencies { testImplementation("junit:junit:4.13.2") testImplementation("org.mockito:mockito-core:4.5.1") testImplementation("org.mockito:mockito-inline:4.5.1") + testImplementation("net.sandrohc:schematic4j:1.1.0") { + exclude("org.checkerframework", "") + exclude("org.slf4j", "") + } } From 9f75ee65dc58edec47dd4175ae4058cbcba392aa Mon Sep 17 00:00:00 2001 From: KevDaDev <65958288+KevinDaGame@users.noreply.github.com> Date: Fri, 22 Dec 2023 22:56:27 +0100 Subject: [PATCH 12/12] Actually fix tests now --- buildSrc/src/main/kotlin/voxel-core.gradle.kts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/buildSrc/src/main/kotlin/voxel-core.gradle.kts b/buildSrc/src/main/kotlin/voxel-core.gradle.kts index 32102658..2e98268f 100644 --- a/buildSrc/src/main/kotlin/voxel-core.gradle.kts +++ b/buildSrc/src/main/kotlin/voxel-core.gradle.kts @@ -41,7 +41,6 @@ dependencies { implementation(kotlin("stdlib-jdk8")) implementation("net.sandrohc:schematic4j:1.1.0") { exclude("org.checkerframework", "") - exclude("org.slf4j", "") } shadowNoRuntime("com.google.code.gson:gson:2.10.1") shadow("org.yaml:snakeyaml:1.33") @@ -50,10 +49,6 @@ dependencies { testImplementation("junit:junit:4.13.2") testImplementation("org.mockito:mockito-core:4.5.1") testImplementation("org.mockito:mockito-inline:4.5.1") - testImplementation("net.sandrohc:schematic4j:1.1.0") { - exclude("org.checkerframework", "") - exclude("org.slf4j", "") - } }