diff --git a/src/main/kotlin/io/github/dockyardmc/extentions/ExtendedIntArray.kt b/src/main/kotlin/io/github/dockyardmc/extentions/ExtendedIntArray.kt new file mode 100644 index 000000000..77a9b6209 --- /dev/null +++ b/src/main/kotlin/io/github/dockyardmc/extentions/ExtendedIntArray.kt @@ -0,0 +1,8 @@ +package io.github.dockyardmc.extentions + +import io.github.dockyardmc.maths.vectors.Vector3 + +fun IntArray.toVector3(): Vector3 { + require(this.size == 3) { "IntArray must have exactly 3 elements" } + return Vector3(this[0], this[1], this[2]) +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/dockyardmc/maths/vectors/Vector3.kt b/src/main/kotlin/io/github/dockyardmc/maths/vectors/Vector3.kt index 573857998..29feda458 100644 --- a/src/main/kotlin/io/github/dockyardmc/maths/vectors/Vector3.kt +++ b/src/main/kotlin/io/github/dockyardmc/maths/vectors/Vector3.kt @@ -1,6 +1,5 @@ package io.github.dockyardmc.maths.vectors -import io.github.dockyardmc.extentions.readVarInt import io.github.dockyardmc.extentions.writeVarInt import io.github.dockyardmc.location.Location import io.github.dockyardmc.protocol.NetworkReadable @@ -146,11 +145,7 @@ data class Vector3( ) override fun read(buffer: ByteBuf): Vector3 { - return Vector3( - buffer.readVarInt(), - buffer.readVarInt(), - buffer.readVarInt() - ) + return STREAM_CODEC.read(buffer) } } } \ No newline at end of file diff --git a/src/main/kotlin/io/github/dockyardmc/schematics/Schematic.kt b/src/main/kotlin/io/github/dockyardmc/schematics/Schematic.kt index b99de588d..6e03ff993 100644 --- a/src/main/kotlin/io/github/dockyardmc/schematics/Schematic.kt +++ b/src/main/kotlin/io/github/dockyardmc/schematics/Schematic.kt @@ -4,19 +4,20 @@ package io.github.dockyardmc.schematics import cz.lukynka.prettylog.LogType import cz.lukynka.prettylog.log +import io.github.dockyardmc.extentions.getOrThrow import io.github.dockyardmc.extentions.readVarInt import io.github.dockyardmc.extentions.reversed import io.github.dockyardmc.extentions.toByteBuf import io.github.dockyardmc.location.Location -import io.github.dockyardmc.registry.Blocks -import io.github.dockyardmc.world.chunk.ChunkUtils import io.github.dockyardmc.maths.vectors.Vector3 -import io.github.dockyardmc.world.chunk.Chunk +import io.github.dockyardmc.registry.Blocks import io.github.dockyardmc.world.World import io.github.dockyardmc.world.block.Block +import io.github.dockyardmc.world.chunk.Chunk +import io.github.dockyardmc.world.chunk.ChunkPos import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap -import it.unimi.dsi.fastutil.objects.ObjectArrayList import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet +import net.kyori.adventure.nbt.CompoundBinaryTag import java.util.concurrent.CompletableFuture data class Schematic( @@ -24,64 +25,21 @@ data class Schematic( var offset: Vector3, var palette: Object2IntOpenHashMap, var blocks: ByteArray, + var blockEntities: Map ) { - companion object { - val empty = Schematic(Vector3(), Vector3(), Object2IntOpenHashMap(), ByteArray(0)) - val RED_STAINED_GLASS = Blocks.RED_STAINED_GLASS.toBlock() + sealed interface SchematicBlock { + + data class Normal(val localSpaceLocation: Location, val location: Location, val id: Int) : SchematicBlock + + data class BlockEntity(val localSpaceLocation: Location, val location: Location, val block: Block, val data: CompoundBinaryTag) : SchematicBlock } -} -fun World.placeSchematicAsync(schematic: Schematic, location: Location): CompletableFuture { - return location.world.scheduler.runAsync { - location.world.placeSchematic(schematic, location) + companion object { + val empty = Schematic(Vector3(), Vector3(), Object2IntOpenHashMap(), ByteArray(0), mapOf()) + val RED_STAINED_GLASS = Blocks.RED_STAINED_GLASS.toBlock() } } -fun World.placeSchematic( - schematic: Schematic, - location: Location, -) { - val blocks = schematic.blocks.toByteBuf() - val updateChunks = ObjectOpenHashSet() - val loadChunk = ObjectOpenHashSet>() - val batchBlockUpdate = ObjectArrayList>() - val flippedPallet = schematic.palette.reversed() - - for (y in 0 until schematic.size.y) { - for (z in 0 until schematic.size.z) { - for (x in 0 until schematic.size.x) { - - val placeLoc = Location(x, y, z, location.world).add(location) - val id = blocks.readVarInt() - val block = flippedPallet[id] ?: Schematic.RED_STAINED_GLASS - - val chunkX = ChunkUtils.getChunkCoordinate(placeLoc.x) - val chunkZ = ChunkUtils.getChunkCoordinate(placeLoc.z) - loadChunk.add(chunkX to chunkZ) - val chunk = placeLoc.world.getOrGenerateChunk( - ChunkUtils.getChunkCoordinate(placeLoc.x), - ChunkUtils.getChunkCoordinate(placeLoc.z) - ) - updateChunks.add(chunk) - batchBlockUpdate.add(placeLoc to block.getProtocolId()) - } - } - } - - batchBlockUpdate.forEach { - try { - this.setBlockRaw(it.first, it.second, false) - } catch (ex: Exception) { - log("Error while placing block in schematic at ${it.first}: $ex", LogType.ERROR) - log(ex) - } - } - - updateChunks.forEach { chunk -> - chunk.updateCache() - chunk.sendUpdateToViewers() - } -} \ No newline at end of file diff --git a/src/main/kotlin/io/github/dockyardmc/schematics/SchematicReader.kt b/src/main/kotlin/io/github/dockyardmc/schematics/SchematicReader.kt index 87847d001..6f8224826 100644 --- a/src/main/kotlin/io/github/dockyardmc/schematics/SchematicReader.kt +++ b/src/main/kotlin/io/github/dockyardmc/schematics/SchematicReader.kt @@ -1,8 +1,11 @@ package io.github.dockyardmc.schematics +import io.github.dockyardmc.extentions.toByteArraySafe +import io.github.dockyardmc.extentions.toVector3 import io.github.dockyardmc.maths.vectors.Vector3 import io.github.dockyardmc.scroll.extensions.contains import io.github.dockyardmc.world.block.Block +import io.netty.buffer.ByteBuf import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap import net.kyori.adventure.nbt.BinaryTagIO import net.kyori.adventure.nbt.CompoundBinaryTag @@ -12,11 +15,15 @@ import java.io.File object SchematicReader { - val READER = BinaryTagIO.unlimitedReader() + private val READER = BinaryTagIO.unlimitedReader() fun read(file: File): Schematic { - if (!file.exists()) throw Exception("File $file does not exist!") - return read(file.readBytes()) + require(file.exists()) { "File $file does not exist!" } + return this.read(file.readBytes()) + } + + fun read(buffer: ByteBuf): Schematic { + return this.read(buffer.toByteArraySafe()) } fun read(byteArray: ByteArray): Schematic { @@ -62,11 +69,20 @@ object SchematicReader { blocks[block] = id } + val blockEntities = mutableMapOf() + val blockEntitiesCompound = nbt.getCompound("Blocks").getList("BlockEntities") + blockEntitiesCompound.forEach { blockEntity -> + if (blockEntity !is CompoundBinaryTag) return@forEach + val pos = blockEntity.getIntArray("Pos") + blockEntities[pos.toVector3()] = blockEntity + } + val schematic = Schematic( size = Vector3(width, height, length), offset = offset, palette = blocks, - blocks = blockArray.copyOf() + blocks = blockArray.copyOf(), + blockEntities ) return schematic diff --git a/src/main/kotlin/io/github/dockyardmc/world/World.kt b/src/main/kotlin/io/github/dockyardmc/world/World.kt index 3ca945ad6..cfab3ad6e 100644 --- a/src/main/kotlin/io/github/dockyardmc/world/World.kt +++ b/src/main/kotlin/io/github/dockyardmc/world/World.kt @@ -9,9 +9,7 @@ import io.github.dockyardmc.entity.EntityManager.despawnEntity import io.github.dockyardmc.entity.EntityManager.spawnEntity import io.github.dockyardmc.entity.LightningBolt import io.github.dockyardmc.events.* -import io.github.dockyardmc.extentions.SHA256Long -import io.github.dockyardmc.extentions.hasUpperCase -import io.github.dockyardmc.extentions.removeIfPresent +import io.github.dockyardmc.extentions.* import io.github.dockyardmc.location.Location import io.github.dockyardmc.maths.vectors.Vector2f import io.github.dockyardmc.maths.vectors.Vector3 @@ -30,17 +28,21 @@ import io.github.dockyardmc.registry.registries.RegistryBlock import io.github.dockyardmc.scheduler.CustomRateScheduler import io.github.dockyardmc.scheduler.runLaterAsync import io.github.dockyardmc.scheduler.runnables.ticks +import io.github.dockyardmc.schematics.Schematic import io.github.dockyardmc.sounds.playSound import io.github.dockyardmc.utils.* import io.github.dockyardmc.world.WorldManager.mainWorld import io.github.dockyardmc.world.block.BatchBlockUpdate import io.github.dockyardmc.world.block.Block +import io.github.dockyardmc.world.block.BlockEntity import io.github.dockyardmc.world.chunk.Chunk import io.github.dockyardmc.world.chunk.ChunkPos import io.github.dockyardmc.world.chunk.ChunkUtils import io.github.dockyardmc.world.generators.VoidWorldGenerator import io.github.dockyardmc.world.generators.WorldGenerator import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet +import net.kyori.adventure.nbt.CompoundBinaryTag import java.util.* import java.util.concurrent.CompletableFuture @@ -56,6 +58,7 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType: val worldSeed = UUID.randomUUID().leastSignificantBits.toString() var seed: Long = worldSeed.SHA256Long() + val random = Random(seed) val difficulty: Bindable = bindablePool.provideBindable(Difficulty.NORMAL) val worldBorder = WorldBorder(this) @@ -285,7 +288,6 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType: fun setBlock(x: Int, y: Int, z: Int, block: Block) { val chunk = getChunkAt(x, z) ?: throw IllegalStateException("Chunk at $x, $y is does not exist!") chunk.setBlock(x, y, z, block, true) - chunk.sendUpdateToViewers() } fun getBlock(location: Location): Block = this.getBlock(location.x.toInt(), location.y.toInt(), location.z.toInt()) @@ -340,10 +342,27 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType: setBlockRaw(location.x.toInt(), location.y.toInt(), location.z.toInt(), blockStateId, updateChunk) } + fun getBlockEntityDataOrNull(location: Location): BlockEntity? { + return getBlockEntityDataOrNull(location.x.toInt(), location.y.toInt(), location.z.toInt()) + } + + fun getBlockEntityDataOrNull(x: Int, y: Int, z: Int): BlockEntity? { + val chunk = getChunkAt(x, z) ?: throw IllegalStateException("Chunk at $x, $y is does not exist!") + return chunk.getBlockEntityDataOrNull(x, y, z) + } + + fun setBlockEntityData(location: Location, data: CompoundBinaryTag, registryBlock: RegistryBlock, shouldCache: Boolean) { + this.setBlockEntityData(location.x.toInt(), location.y.toInt(), location.z.toInt(), data, registryBlock, shouldCache) + } + + fun setBlockEntityData(x: Int, y: Int, z: Int, data: CompoundBinaryTag, registryBlock: RegistryBlock, shouldCache: Boolean = true) { + val chunk = getChunkAt(x, z) ?: throw IllegalStateException("Chunk at $x, $y is does not exist!") + chunk.setBlockEntityData(x, y, z, data, registryBlock, shouldCache) + } + fun setBlockRaw(x: Int, y: Int, z: Int, blockStateId: Int, updateChunk: Boolean = true) { val chunk = getChunkAt(x, z) ?: return chunk.setBlockRaw(x, y, z, blockStateId, updateChunk) - if (updateChunk) chunk.sendUpdateToViewers() } inline fun batchBlockUpdate(builder: BatchBlockUpdate.() -> Unit): CompletableFuture { @@ -367,8 +386,7 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType: setBlockRaw(location, block.getProtocolId(), false) } chunks.forEach { chunk -> - chunk.updateCache() - chunk.sendUpdateToViewers() + chunk.update() } future.complete(this) @@ -429,7 +447,7 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType: } } } - chunk.updateCache() + chunk.update() if (getChunk(x, z) == null) { synchronized(chunks) { chunks[ChunkUtils.getChunkIndex(x, z)] = (chunk) @@ -463,7 +481,71 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType: return Location(vector.x, vector.y, vector.z, this) } - fun getRandom(): Random = Random(seed) + fun World.placeSchematicAsync(schematic: Schematic, location: Location): CompletableFuture { + return this.scheduler.runAsync { + this.placeSchematic(schematic, location) + } + } + + fun placeSchematic( + schematic: Schematic, + location: Location, + ) { + val blocks = schematic.blocks.toByteBuf() + val updateChunks = ObjectOpenHashSet() + val loadChunk = ObjectOpenHashSet() + val batchBlockUpdate = ObjectOpenHashSet() + val flippedPallet = schematic.palette.reversed() + + for (y in 0 until schematic.size.y) { + for (z in 0 until schematic.size.z) { + for (x in 0 until schematic.size.x) { + + val localSpacePlaceVec = Vector3(x, y, z) + val localSpacePlaceLoc = localSpacePlaceVec.toLocation(location.world) + val placeLoc = localSpacePlaceLoc.add(location) + val id = blocks.readVarInt() + val block = flippedPallet[id] ?: Schematic.RED_STAINED_GLASS + + val chunkPos = ChunkPos.fromLocation(placeLoc) + val chunk = placeLoc.world.getOrGenerateChunk(chunkPos) + + loadChunk.add(chunkPos) + updateChunks.add(chunk) + + val schematicBlock: Schematic.SchematicBlock = if (schematic.blockEntities.containsKey(localSpacePlaceVec)) { + Schematic.SchematicBlock.BlockEntity(localSpacePlaceLoc, placeLoc, block, schematic.blockEntities.getOrThrow(localSpacePlaceVec)) + } else { + Schematic.SchematicBlock.Normal(localSpacePlaceLoc, placeLoc, block.getProtocolId()) + } + batchBlockUpdate.add(schematicBlock) + } + } + } + + batchBlockUpdate.forEach { schematicBlock -> + try { + when (schematicBlock) { + is Schematic.SchematicBlock.Normal -> { + this.setBlockRaw(schematicBlock.location, schematicBlock.id, false) + } + + is Schematic.SchematicBlock.BlockEntity -> { + this.setBlockRaw(schematicBlock.location, schematicBlock.block.getProtocolId(), false) + this.setBlockEntityData(schematicBlock.location, schematicBlock.data, schematicBlock.block.registryBlock, false) + } + } + + } catch (ex: Exception) { + log("Error while placing block in schematic at ${location}: $ex", LogType.ERROR) + log(ex) + } + } + + updateChunks.forEach { chunk -> + chunk.update() + } + } override fun dispose() { players.forEach { player -> diff --git a/src/main/kotlin/io/github/dockyardmc/world/chunk/Chunk.kt b/src/main/kotlin/io/github/dockyardmc/world/chunk/Chunk.kt index 37fec1bfd..3cd0d7bd7 100644 --- a/src/main/kotlin/io/github/dockyardmc/world/chunk/Chunk.kt +++ b/src/main/kotlin/io/github/dockyardmc/world/chunk/Chunk.kt @@ -2,11 +2,11 @@ package io.github.dockyardmc.world.chunk import io.github.dockyardmc.extentions.sendPacket import io.github.dockyardmc.location.Location -import io.github.dockyardmc.nbt.nbt import io.github.dockyardmc.player.Player import io.github.dockyardmc.protocol.packets.play.clientbound.ClientboundChunkDataPacket import io.github.dockyardmc.protocol.packets.play.clientbound.ClientboundUnloadChunkPacket import io.github.dockyardmc.registry.registries.Biome +import io.github.dockyardmc.registry.registries.RegistryBlock import io.github.dockyardmc.utils.viewable.Viewable import io.github.dockyardmc.world.Light import io.github.dockyardmc.world.World @@ -43,7 +43,7 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { val packet: ClientboundChunkDataPacket get() { - if (!this::cachedPacket.isInitialized) updateCache() + if (!this::cachedPacket.isInitialized) update() return cachedPacket } @@ -56,10 +56,10 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { getOrCreateHeightmap(type) ChunkHeightmap.generate(this, setOf(type)) } - updateCache() + update() } - fun updateCache() { + fun update() { val heightmapData: MutableMap = mutableMapOf() heightmaps.forEach { (type, heightmap) -> @@ -67,14 +67,8 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { heightmapData[type] = heightmap.getRawData() } - val heightmapNbt = nbt { - heightmaps.forEach { map -> - if (map.key.sendToClient()) { - withLongArray(map.key.name, map.value.getRawData()) - } - } - } cachedPacket = ClientboundChunkDataPacket(chunkX, chunkZ, heightmapData, sections, blockEntities.values, light) + sendUpdateToViewers() } init { @@ -82,14 +76,14 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { repeat(sectionsAmount) { sections.add(ChunkSection.empty()) } - updateCache() + update() } fun setBlockRaw(x: Int, y: Int, z: Int, blockStateId: Int, shouldCache: Boolean = true) { val section = getSectionAt(y) - val relativeX = ChunkUtils.sectionRelative(x) - val relativeZ = ChunkUtils.sectionRelative(z) - val relativeY = ChunkUtils.sectionRelative(y) + val relativeX = ChunkUtils.chunkRelative(x) + val relativeZ = ChunkUtils.chunkRelative(z) + val relativeY = ChunkUtils.chunkRelative(y) section.setBlock(relativeX, relativeY, relativeZ, blockStateId) world.customDataBlocks.remove(Location(x, y, z, world).blockHash) @@ -100,26 +94,37 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { heightmaps.getValue(ChunkHeightmap.Type.OCEAN_FLOOR).update(relativeX, relativeY, relativeZ, block) heightmaps.getValue(ChunkHeightmap.Type.WORLD_SURFACE).update(relativeX, relativeY, relativeZ, block) - if (shouldCache) updateCache() + if (shouldCache) update() } fun setBiome(x: Int, y: Int, z: Int, biome: Biome, shouldCache: Boolean = true) { val section = getSectionAt(y) - val relativeX = ChunkUtils.sectionRelative(x) - val relativeZ = ChunkUtils.sectionRelative(z) - val relativeY = ChunkUtils.sectionRelative(y) + val relativeX = ChunkUtils.chunkRelative(x) + val relativeZ = ChunkUtils.chunkRelative(z) + val relativeY = ChunkUtils.chunkRelative(y) section.setBiome(relativeX, relativeY, relativeZ, biome.getProtocolId()) - if (shouldCache) updateCache() + if (shouldCache) update() + } + + fun setBlockEntityData(x: Int, y: Int, z: Int, data: CompoundBinaryTag, registryBlock: RegistryBlock, shouldCache: Boolean = true) { + + val relativeX = ChunkUtils.chunkRelative(x) + val relativeZ = ChunkUtils.chunkRelative(z) + val relativeY = ChunkUtils.chunkRelative(y) + + val blockIndex = ChunkUtils.chunkBlockIndex(relativeX, relativeY, relativeZ) + blockEntities[blockIndex] = BlockEntity(blockIndex, registryBlock, data) + if (shouldCache) update() } fun setBlock(x: Int, y: Int, z: Int, block: Block, shouldCache: Boolean = true) { val section = getSectionAt(y) - val relativeX = ChunkUtils.sectionRelative(x) - val relativeZ = ChunkUtils.sectionRelative(z) - val relativeY = ChunkUtils.sectionRelative(y) + val relativeX = ChunkUtils.chunkRelative(x) + val relativeZ = ChunkUtils.chunkRelative(z) + val relativeY = ChunkUtils.chunkRelative(y) if (block.customData != null) world.customDataBlocks[Location(x, y, z, world).blockHash] = block if (block.customData == null) world.customDataBlocks.remove(Location(x, y, z, world).blockHash) @@ -130,7 +135,7 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { heightmaps.getValue(ChunkHeightmap.Type.OCEAN_FLOOR).update(relativeX, y, relativeZ, block) heightmaps.getValue(ChunkHeightmap.Type.WORLD_SURFACE).update(relativeX, y, relativeZ, block) - val index = ChunkUtils.chunkBlockIndex(x, y, z) + val index = ChunkUtils.chunkBlockIndex(relativeX, relativeY, relativeZ) if (block.registryBlock.isBlockEntity) { val blockEntity = BlockEntity(index, block.registryBlock, CompoundBinaryTag.empty()) @@ -139,7 +144,20 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { blockEntities.remove(index) } - if (shouldCache) updateCache() + if (shouldCache) update() + } + + fun getBlockEntityData(x: Int, y: Int, z: Int): BlockEntity { + val relativeX = ChunkUtils.chunkRelative(x) + val relativeZ = ChunkUtils.chunkRelative(z) + val relativeY = ChunkUtils.chunkRelative(y) + + return getBlockEntityDataOrNull(relativeX, relativeY, relativeZ) ?: throw IllegalStateException("No entity data found at $x, $y, $z") + } + + fun getBlockEntityDataOrNull(x: Int, y: Int, z: Int): BlockEntity? { + val index = ChunkUtils.chunkBlockIndex(x, y, z) + return blockEntities[index] } fun getBlock(x: Int, y: Int, z: Int): Block { @@ -148,9 +166,9 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { val section = getSectionAt(y) - val relativeX = ChunkUtils.sectionRelative(x) - val relativeZ = ChunkUtils.sectionRelative(z) - val relativeY = ChunkUtils.sectionRelative(y) + val relativeX = ChunkUtils.chunkRelative(x) + val relativeZ = ChunkUtils.chunkRelative(z) + val relativeY = ChunkUtils.chunkRelative(y) val id = section.getBlock(relativeX, relativeY, relativeZ) return Block.getBlockByStateId(id) @@ -195,7 +213,7 @@ class Chunk(val chunkX: Int, val chunkZ: Int, val world: World) : Viewable() { fun getOrCreateHeightmap(type: ChunkHeightmap.Type): ChunkHeightmap = heightmaps.computeIfAbsent(type) { ChunkHeightmap(this, type) } - fun sendUpdateToViewers() { + private fun sendUpdateToViewers() { viewers.sendPacket(cachedPacket) } diff --git a/src/main/kotlin/io/github/dockyardmc/world/chunk/ChunkUtils.kt b/src/main/kotlin/io/github/dockyardmc/world/chunk/ChunkUtils.kt index 93b890d2c..600299d9b 100644 --- a/src/main/kotlin/io/github/dockyardmc/world/chunk/ChunkUtils.kt +++ b/src/main/kotlin/io/github/dockyardmc/world/chunk/ChunkUtils.kt @@ -1,5 +1,6 @@ package io.github.dockyardmc.world.chunk +import io.github.dockyardmc.location.Location import io.github.dockyardmc.maths.vectors.Vector3 import kotlin.math.abs import kotlin.math.sin @@ -14,6 +15,10 @@ object ChunkUtils { const val EPSILON: Float = 1.0E-5F const val TO_RADIANS_FACTOR = Math.PI.toFloat() / 180F + fun chunkBlockIndex(location: Location): Int { + return chunkBlockIndex(location.x.toInt(), location.y.toInt(), location.z.toInt()) + } + fun chunkBlockIndex(x: Int, y: Int, z: Int): Int { var xCoord = x var zCoord = z @@ -59,7 +64,7 @@ object ChunkUtils { fun getChunkCoordinate(xz: Int): Int = xz shr 4 - fun sectionRelative(xyz: Int): Int = xyz and 0xF + fun chunkRelative(xyz: Int): Int = xyz and 0xF fun getChunkIndex(chunk: Chunk): Long = getChunkIndex(chunk.chunkX, chunk.chunkZ) diff --git a/src/main/kotlin/io/github/dockyardmc/world/generators/SchematicWorldGenerator.kt b/src/main/kotlin/io/github/dockyardmc/world/generators/SchematicWorldGenerator.kt index 3c2cdc16e..5f74350c8 100644 --- a/src/main/kotlin/io/github/dockyardmc/world/generators/SchematicWorldGenerator.kt +++ b/src/main/kotlin/io/github/dockyardmc/world/generators/SchematicWorldGenerator.kt @@ -5,10 +5,9 @@ import io.github.dockyardmc.maths.vectors.Vector3 import io.github.dockyardmc.registry.Biomes import io.github.dockyardmc.registry.registries.Biome import io.github.dockyardmc.schematics.Schematic -import io.github.dockyardmc.schematics.placeSchematic import io.github.dockyardmc.world.World -class SchematicWorldGenerator(val schematic: Schematic, val origin: Vector3 = Vector3(), defaultBiome: Biome = Biomes.THE_VOID) : VoidWorldGenerator(defaultBiome) { +class SchematicWorldGenerator(val schematic: Schematic, val origin: Vector3 = Vector3(), defaultBiome: Biome = Biomes.PLAINS) : VoidWorldGenerator(defaultBiome) { override fun onWorldLoad(world: World) { world.placeSchematic(schematic, Location(origin, 0f, 0f, world)) } diff --git a/src/test/kotlin/io/github/dockyard/tests/schematic/SchematicTest.kt b/src/test/kotlin/io/github/dockyard/tests/schematic/SchematicTest.kt index f1782348a..a57b37ff5 100644 --- a/src/test/kotlin/io/github/dockyard/tests/schematic/SchematicTest.kt +++ b/src/test/kotlin/io/github/dockyard/tests/schematic/SchematicTest.kt @@ -3,13 +3,13 @@ package io.github.dockyard.tests.schematic import io.github.dockyard.tests.TestServer import io.github.dockyardmc.registry.Blocks import io.github.dockyardmc.schematics.SchematicReader -import io.github.dockyardmc.schematics.placeSchematic import io.github.dockyardmc.utils.Resources import io.github.dockyardmc.world.WorldManager import org.junit.jupiter.api.assertDoesNotThrow import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertNotNull class SchematicTest { @@ -28,5 +28,9 @@ class SchematicTest { assertEquals(Blocks.RED_WOOL, world.locationAt(0, 0, 0).block.registryBlock) assertEquals(Blocks.NETHER_BRICK_FENCE, world.locationAt(4, 1, 5).block.registryBlock) assertEquals(Blocks.STONE, world.locationAt(27, 1, 23).block.registryBlock) + + + assertEquals(Blocks.SCULK_SENSOR, world.locationAt(14, 1, 7).block.registryBlock) + assertNotNull(world.getBlockEntityDataOrNull(14, 1, 7)) } } \ No newline at end of file