diff --git a/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/Galactifun2.kt b/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/Galactifun2.kt index 6a7ec86..7dcab93 100644 --- a/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/Galactifun2.kt +++ b/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/Galactifun2.kt @@ -15,6 +15,7 @@ import io.github.addoncommunity.galactifun.scripting.PlanetScript import io.github.addoncommunity.galactifun.scripting.dsl.* import io.github.addoncommunity.galactifun.scripting.dsl.gen.* import io.github.addoncommunity.galactifun.scripting.evalScript +import io.github.addoncommunity.galactifun.serial.BlockVectorSerializer import io.github.addoncommunity.galactifun.units.Angle.Companion.degrees import io.github.addoncommunity.galactifun.units.Distance.Companion.au import io.github.addoncommunity.galactifun.units.Distance.Companion.kilometers @@ -22,6 +23,7 @@ import io.github.addoncommunity.galactifun.units.Mass.Companion.kilograms import io.github.addoncommunity.galactifun.util.bukkit.plus import io.github.addoncommunity.galactifun.util.general.log import io.github.seggan.sf4k.AbstractAddon +import io.github.seggan.sf4k.serial.serializers.CustomSerializerRegistry import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion import io.github.thebusybiscuit.slimefun4.implementation.Slimefun import io.github.thebusybiscuit.slimefun4.libraries.paperlib.PaperLib @@ -58,6 +60,7 @@ open class Galactifun2 : AbstractAddon() { if (!isTest) { Bukkit.spigot().config["world-settings.default.verbose"] = false } + CustomSerializerRegistry.register(BlockVectorSerializer) } override suspend fun onEnableAsync() { diff --git a/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/serial/BlockVectorSerializer.kt b/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/serial/BlockVectorSerializer.kt new file mode 100644 index 0000000..e082af0 --- /dev/null +++ b/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/serial/BlockVectorSerializer.kt @@ -0,0 +1,10 @@ +package io.github.addoncommunity.galactifun.serial + +import io.github.seggan.sf4k.serial.serializers.DelegatingSerializer +import kotlinx.serialization.builtins.IntArraySerializer +import org.bukkit.util.BlockVector + +object BlockVectorSerializer : DelegatingSerializer(IntArraySerializer()) { + override fun toData(value: BlockVector): IntArray = intArrayOf(value.blockX, value.blockY, value.blockZ) + override fun fromData(value: IntArray): BlockVector = BlockVector(value[0], value[1], value[2]) +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/util/SlimefunStructure.kt b/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/util/SlimefunStructure.kt new file mode 100644 index 0000000..c0b9dca --- /dev/null +++ b/plugin/src/main/kotlin/io/github/addoncommunity/galactifun/util/SlimefunStructure.kt @@ -0,0 +1,180 @@ +package io.github.addoncommunity.galactifun.util + +import io.github.addoncommunity.galactifun.util.bukkit.copy +import io.github.addoncommunity.galactifun.util.bukkit.key +import io.github.seggan.sf4k.serial.pdc.get +import io.github.seggan.sf4k.serial.pdc.set +import me.mrCookieSlime.Slimefun.api.BlockStorage +import org.bukkit.Location +import org.bukkit.Material +import org.bukkit.RegionAccessor +import org.bukkit.block.structure.Mirror +import org.bukkit.block.structure.StructureRotation +import org.bukkit.structure.Structure +import org.bukkit.util.BlockTransformer +import org.bukkit.util.BlockVector +import org.bukkit.util.EntityTransformer +import org.bukkit.util.Vector +import java.util.* +import kotlin.collections.set + +@Suppress("UnstableApiUsage") +class SlimefunStructure(private val delegate: Structure) : Structure by delegate { + + private var center: Vector = resetCenter() + + companion object { + private val blockStorageKey = "block_storage".key() + } + + override fun place( + location: Location, + includeEntities: Boolean, + structureRotation: StructureRotation, + mirror: Mirror, + palette: Int, + integrity: Float, + random: Random, + blockTransformers: MutableCollection, + entityTransformers: MutableCollection + ) { + place( + location.world, + location.toVector().toBlockVector(), + includeEntities, + structureRotation, + mirror, + palette, + integrity, + random, + blockTransformers, + entityTransformers + ) + } + + override fun place( + regionAccessor: RegionAccessor, + location: BlockVector, + includeEntities: Boolean, + structureRotation: StructureRotation, + mirror: Mirror, + palette: Int, + integrity: Float, + random: Random + ) { + place( + regionAccessor, + location, + includeEntities, + structureRotation, + mirror, + palette, + integrity, + random, + mutableListOf(), + mutableListOf() + ) + } + + override fun place( + location: Location, + includeEntities: Boolean, + structureRotation: StructureRotation, + mirror: Mirror, + palette: Int, + integrity: Float, + random: Random + ) { + place( + location, + includeEntities, + structureRotation, + mirror, + palette, + integrity, + random, + mutableListOf(), + mutableListOf() + ) + } + + override fun place( + regionAccessor: RegionAccessor, + location: BlockVector, + includeEntities: Boolean, + structureRotation: StructureRotation, + mirror: Mirror, + palette: Int, + integrity: Float, + random: Random, + blockTransformers: MutableCollection, + entityTransformers: MutableCollection + ) { + val data = persistentDataContainer.get>>(blockStorageKey) ?: emptyMap() + val rotated = data.mapKeys { (vector, _) -> + val newVec = structureRotation.rotateAroundCenter(vector) + when (mirror) { + Mirror.NONE -> newVec + Mirror.FRONT_BACK -> newVec.copy(x = -newVec.x) + Mirror.LEFT_RIGHT -> newVec.copy(z = -newVec.z) + } + } + blockTransformers.add(BlockTransformer { region, x, y, z, current, _ -> + val vector = BlockVector(x, y, z).subtract(location) + val (json, material) = rotated[vector] ?: return@BlockTransformer current + if (current.type != material) return@BlockTransformer current // Block has been changed + val realLocation = Location(region.world, x.toDouble(), y.toDouble(), z.toDouble()) + BlockStorage.setBlockInfo(realLocation, json, true) + return@BlockTransformer current + }) + delegate.place( + regionAccessor, + location, + includeEntities, + structureRotation, + mirror, + palette, + integrity, + random, + blockTransformers, + entityTransformers + ) + } + + override fun fill(origin: Location, size: BlockVector, includeEntities: Boolean) { + val data = mutableMapOf>() + for (x in 0 until size.blockX) { + for (y in 0 until size.blockY) { + for (z in 0 until size.blockZ) { + val vector = BlockVector(x, y, z) + val block = origin.clone().add(vector).block + if (BlockStorage.hasBlockInfo(block)) { + data[vector] = BlockStorage.getBlockInfoAsJson(block) to block.type + } + } + } + } + delegate.fill(origin, size, includeEntities) + persistentDataContainer.set(blockStorageKey, data) + center = resetCenter() + } + + override fun fill(corner1: Location, corner2: Location, includeEntities: Boolean) { + fill(corner1, corner2.clone().subtract(corner1).toVector().toBlockVector(), includeEntities) + } + + private fun resetCenter(): Vector { + return size.clone().multiply(0.5).setY(0) + } + + private fun StructureRotation.rotateAroundCenter(location: Vector): BlockVector { + val centered = location.clone().subtract(center) + val rotated = when (this) { + StructureRotation.NONE -> centered + StructureRotation.CLOCKWISE_90 -> centered.copy(x = -centered.z, z = centered.x) + StructureRotation.CLOCKWISE_180 -> centered.copy(x = -centered.x, z = -centered.z) + StructureRotation.COUNTERCLOCKWISE_90 -> centered.copy(x = centered.z, z = -centered.x) + } + return rotated.add(center).toBlockVector() + } +} \ No newline at end of file