@@ -29,8 +29,7 @@ import kotlin.io.path.*
2929 */
3030@OptIn(ExperimentalPathApi ::class )
3131@Suppress(" JavaIoSerializableObjectMustHaveReadResolve" )
32- object StructureRegistry
33- : ConcurrentHashMap <String , StructureTemplate ?>(), Loadable {
32+ object StructureRegistry : ConcurrentHashMap<String, StructureTemplate?>(), Loadable {
3433 private val levelSession = mc.levelStorage.createSession(FolderRegister .structure.path)
3534 private val structurePath = levelSession.getDirectory(WorldSavePath .ROOT ).normalize()
3635 private val pathWatcher = FileSystems .getDefault().newWatchService()
@@ -39,12 +38,12 @@ object StructureRegistry
3938 /* *
4039 * Map of file suffix to their respective read function
4140 */
42- val serializers = mapOf (
41+ private val serializers = mapOf (
4342 " nbt" to StructureTemplate ::readNbtOrException,
4443 " schem" to StructureTemplate ::readSpongeOrException,
4544 " litematica" to StructureTemplate ::readLitematicaOrException,
4645
47- // Not supported, who could guess that converting a format from 14 years ago would be hard ? :clueless:
46+ // Not supported, who could guess that converting a format from 14 years ago would be hard? :clueless:
4847 " schematic" to StructureTemplate ::readSchematicOrException,
4948 )
5049
@@ -54,7 +53,7 @@ object StructureRegistry
5453 * @param name The name of the structure file without the extension.
5554 * @return The corresponding [File] if found, or null otherwise.
5655 */
57- fun findStructureByName (name : String ): File ? =
56+ private fun findStructureByName (name : String ): File ? =
5857 serializers
5958 .keys
6059 .firstNotNullOfOrNull { extension ->
@@ -81,93 +80,94 @@ object StructureRegistry
8180 " Invalid structure template: $name " ,
8281 " The structure folder is not a folder"
8382 )
83+ return null
8484 }
8585
8686 // Poll directory file events to load many structures at once
8787 // They might not show up in the command suggestion, but they are
8888 // present in the map
89- pathWatcher.poll()
90- ?.let { key ->
91- key.pollEvents()?.forEach { event ->
92- @Suppress(" UNCHECKED_CAST" )
93- event as WatchEvent <Path >
94-
95- val kind = event.kind()
89+ pathWatcher.poll()?.let { key ->
90+ key.pollEvents()
91+ ?.filterIsInstance<WatchEvent <Path >>()
92+ ?.forEach { event ->
9693 val path = event.context()
9794 val nameNoExt = path.nameWithoutExtension
9895
99- when (kind) {
96+ when (event. kind() ) {
10097 ENTRY_DELETE -> remove(nameNoExt)
101- ENTRY_CREATE -> if (! contains(nameNoExt) && nameNoExt != name) loadStructureByName(path.nameWithoutExtension, convert = true )
98+ ENTRY_CREATE -> {
99+ if (! contains(nameNoExt) && nameNoExt != name) {
100+ loadStructureByName(path.nameWithoutExtension, convert = true )
101+ }
102+ }
102103 }
103104
104105 // Reset the key -- this step is critical if you want to
105106 // receive further watch events. If the key is no longer valid,
106107 // the directory is inaccessible so exit the loop.
107108 if (! key.reset()) return @forEach
108109 }
109- }
110+ }
110111
111- return computeIfAbsent(name.lowercase()) {
112- findStructureByName(name)
113- ?.let { it to it.extension }
114- ?.let { (file, extension) ->
115- file.inputStream().use { templateStream ->
116- val compound = NbtIo .readCompressed(templateStream, NbtSizeTracker .ofUnlimitedBytes())
117- val template = createStructure(compound, extension)
118-
119- // Only delete structure files that aren't NBT
120- if (convert && extension != " nbt" ) {
121- template
122- ?.let { saveStructure(name, it) }
123- ?.let { structurePath.resolve(" $name .$extension " ).deleteIfExists() }
124- }
112+ return computeIfAbsent(name.lowercase()) { loadFileAndCreate(name, convert) }
113+ }
125114
126- // Verify the structure integrity after it had been
127- // converted to a regular structure template
128- if (compound.isValidStructureTemplate()) template
129- else {
130- logError(
131- " Invalid structure template: $it " ,
132- " File does not match template format, it might have been corrupted" ,
133- )
134- null
135- }
115+ /* *
116+ * Loads the structure file and creates a [StructureTemplate].
117+ *
118+ * @param name The name of the structure file (without extension).
119+ * @param convert Whether to replace the file after converting it.
120+ * @return The created [StructureTemplate], or null if the structure is not found or invalid.
121+ */
122+ private fun loadFileAndCreate (name : String , convert : Boolean ) =
123+ findStructureByName(name)
124+ ?.let { it to it.extension }
125+ ?.let { (file, extension) ->
126+ file.inputStream().use { templateStream ->
127+ val compound = NbtIo .readCompressed(templateStream, NbtSizeTracker .ofUnlimitedBytes())
128+ val template = createStructure(compound, extension)
129+
130+ if (convert && extension != " nbt" ) {
131+ template?.let { saveStructure(name, it) }
132+ }
133+
134+ // Verify the structure integrity after it had been
135+ // converted to a regular structure template
136+ if (compound.isValidStructureTemplate()) {
137+ template
138+ } else {
139+ logError(
140+ " Invalid structure template: $name " ,
141+ " File does not match template format, it might have been corrupted" ,
142+ )
143+ null
136144 }
137145 }
138- }
139- }
146+ }
140147
141148 /* *
142149 * Creates a [StructureTemplate] from the provided NBT data.
143150 *
144151 * @param nbt The [NbtCompound] containing the structure's data.
145152 * @return The created [StructureTemplate], or null if there was an error.
146153 */
147- private fun createStructure (nbt : NbtCompound , suffix : String ): StructureTemplate ? {
148- val template = StructureTemplate ()
149-
150- serializers[suffix]
151- ?.invoke(
152- template,
153- Registries .BLOCK .readOnlyWrapper,
154- nbt,
155- )
156- ?.let { error ->
157- logError(" Could not create structure from file" , error.message ? : " " )
158- return null
159- }
160-
161- return template
162- }
154+ private fun createStructure (nbt : NbtCompound , suffix : String ): StructureTemplate ? =
155+ StructureTemplate ().apply {
156+ serializers[suffix]
157+ ?.invoke(this , Registries .BLOCK .readOnlyWrapper, nbt)
158+ ?.let { error ->
159+ logError(" Could not create structure from file" , error.message ? : " " )
160+ return null
161+ }
162+ }
163163
164164 /* *
165165 * Saves the provided [structure] to disk under the specified [name].
166166 *
167167 * @param name The name of the structure file (without the extension).
168168 * @param structure The [StructureTemplate] to save.
169169 */
170- fun saveStructure (name : String , structure : StructureTemplate ) {
170+ private fun saveStructure (name : String , structure : StructureTemplate ) {
171171 val path = structurePath.resolve(" $name .nbt" )
172172 val compound = structure.writeNbt(NbtCompound ())
173173
@@ -180,17 +180,16 @@ object StructureRegistry
180180 /* *
181181 * Verifies that the provided NBT data represents a valid Minecraft structure template.
182182 *
183- * @param this@isValidStructureTemplate The [NbtCompound] to validate.
183+ * @receiver The [NbtCompound] to validate.
184184 * @return True if the NBT contains valid structure template data, false otherwise.
185185 */
186186 private fun NbtCompound.isValidStructureTemplate () =
187187 contains(" DataVersion" ) && contains(" blocks" ) && contains(" palette" ) && contains(" size" )
188188
189189 override fun load (): String {
190- structurePath.walk().forEach { path ->
191- if (path.extension in serializers.keys)
192- loadStructureByName(path.nameWithoutExtension)
193- }
190+ structurePath.walk()
191+ .filter { it.extension in serializers.keys }
192+ .forEach { path -> loadStructureByName(path.nameWithoutExtension) }
194193
195194 return " Loaded $size structure templates"
196195 }
0 commit comments