@@ -9,9 +9,7 @@ import io.github.dockyardmc.entity.EntityManager.despawnEntity
99import io.github.dockyardmc.entity.EntityManager.spawnEntity
1010import io.github.dockyardmc.entity.LightningBolt
1111import io.github.dockyardmc.events.*
12- import io.github.dockyardmc.extentions.SHA256Long
13- import io.github.dockyardmc.extentions.hasUpperCase
14- import io.github.dockyardmc.extentions.removeIfPresent
12+ import io.github.dockyardmc.extentions.*
1513import io.github.dockyardmc.location.Location
1614import io.github.dockyardmc.maths.vectors.Vector2f
1715import io.github.dockyardmc.maths.vectors.Vector3
@@ -30,17 +28,21 @@ import io.github.dockyardmc.registry.registries.RegistryBlock
3028import io.github.dockyardmc.scheduler.CustomRateScheduler
3129import io.github.dockyardmc.scheduler.runLaterAsync
3230import io.github.dockyardmc.scheduler.runnables.ticks
31+ import io.github.dockyardmc.schematics.Schematic
3332import io.github.dockyardmc.sounds.playSound
3433import io.github.dockyardmc.utils.*
3534import io.github.dockyardmc.world.WorldManager.mainWorld
3635import io.github.dockyardmc.world.block.BatchBlockUpdate
3736import io.github.dockyardmc.world.block.Block
37+ import io.github.dockyardmc.world.block.BlockEntity
3838import io.github.dockyardmc.world.chunk.Chunk
3939import io.github.dockyardmc.world.chunk.ChunkPos
4040import io.github.dockyardmc.world.chunk.ChunkUtils
4141import io.github.dockyardmc.world.generators.VoidWorldGenerator
4242import io.github.dockyardmc.world.generators.WorldGenerator
4343import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
44+ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
45+ import net.kyori.adventure.nbt.CompoundBinaryTag
4446import java.util.*
4547import java.util.concurrent.CompletableFuture
4648
@@ -56,6 +58,7 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType:
5658
5759 val worldSeed = UUID .randomUUID().leastSignificantBits.toString()
5860 var seed: Long = worldSeed.SHA256Long ()
61+ val random = Random (seed)
5962
6063 val difficulty: Bindable <Difficulty > = bindablePool.provideBindable(Difficulty .NORMAL )
6164 val worldBorder = WorldBorder (this )
@@ -285,7 +288,6 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType:
285288 fun setBlock (x : Int , y : Int , z : Int , block : Block ) {
286289 val chunk = getChunkAt(x, z) ? : throw IllegalStateException (" Chunk at $x , $y is does not exist!" )
287290 chunk.setBlock(x, y, z, block, true )
288- chunk.sendUpdateToViewers()
289291 }
290292
291293 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:
340342 setBlockRaw(location.x.toInt(), location.y.toInt(), location.z.toInt(), blockStateId, updateChunk)
341343 }
342344
345+ fun getBlockEntityDataOrNull (location : Location ): BlockEntity ? {
346+ return getBlockEntityDataOrNull(location.x.toInt(), location.y.toInt(), location.z.toInt())
347+ }
348+
349+ fun getBlockEntityDataOrNull (x : Int , y : Int , z : Int ): BlockEntity ? {
350+ val chunk = getChunkAt(x, z) ? : throw IllegalStateException (" Chunk at $x , $y is does not exist!" )
351+ return chunk.getBlockEntityDataOrNull(x, y, z)
352+ }
353+
354+ fun setBlockEntityData (location : Location , data : CompoundBinaryTag , registryBlock : RegistryBlock , shouldCache : Boolean ) {
355+ this .setBlockEntityData(location.x.toInt(), location.y.toInt(), location.z.toInt(), data, registryBlock, shouldCache)
356+ }
357+
358+ fun setBlockEntityData (x : Int , y : Int , z : Int , data : CompoundBinaryTag , registryBlock : RegistryBlock , shouldCache : Boolean = true) {
359+ val chunk = getChunkAt(x, z) ? : throw IllegalStateException (" Chunk at $x , $y is does not exist!" )
360+ chunk.setBlockEntityData(x, y, z, data, registryBlock, shouldCache)
361+ }
362+
343363 fun setBlockRaw (x : Int , y : Int , z : Int , blockStateId : Int , updateChunk : Boolean = true) {
344364 val chunk = getChunkAt(x, z) ? : return
345365 chunk.setBlockRaw(x, y, z, blockStateId, updateChunk)
346- if (updateChunk) chunk.sendUpdateToViewers()
347366 }
348367
349368 inline fun batchBlockUpdate (builder : BatchBlockUpdate .() -> Unit ): CompletableFuture <World > {
@@ -367,8 +386,7 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType:
367386 setBlockRaw(location, block.getProtocolId(), false )
368387 }
369388 chunks.forEach { chunk ->
370- chunk.updateCache()
371- chunk.sendUpdateToViewers()
389+ chunk.update()
372390 }
373391
374392 future.complete(this )
@@ -429,7 +447,7 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType:
429447 }
430448 }
431449 }
432- chunk.updateCache ()
450+ chunk.update ()
433451 if (getChunk(x, z) == null ) {
434452 synchronized(chunks) {
435453 chunks[ChunkUtils .getChunkIndex(x, z)] = (chunk)
@@ -463,7 +481,71 @@ class World(var name: String, var generator: WorldGenerator, var dimensionType:
463481 return Location (vector.x, vector.y, vector.z, this )
464482 }
465483
466- fun getRandom (): Random = Random (seed)
484+ fun World.placeSchematicAsync (schematic : Schematic , location : Location ): CompletableFuture <Unit > {
485+ return this .scheduler.runAsync {
486+ this .placeSchematic(schematic, location)
487+ }
488+ }
489+
490+ fun placeSchematic (
491+ schematic : Schematic ,
492+ location : Location ,
493+ ) {
494+ val blocks = schematic.blocks.toByteBuf()
495+ val updateChunks = ObjectOpenHashSet <Chunk >()
496+ val loadChunk = ObjectOpenHashSet <ChunkPos >()
497+ val batchBlockUpdate = ObjectOpenHashSet <Schematic .SchematicBlock >()
498+ val flippedPallet = schematic.palette.reversed()
499+
500+ for (y in 0 until schematic.size.y) {
501+ for (z in 0 until schematic.size.z) {
502+ for (x in 0 until schematic.size.x) {
503+
504+ val localSpacePlaceVec = Vector3 (x, y, z)
505+ val localSpacePlaceLoc = localSpacePlaceVec.toLocation(location.world)
506+ val placeLoc = localSpacePlaceLoc.add(location)
507+ val id = blocks.readVarInt()
508+ val block = flippedPallet[id] ? : Schematic .RED_STAINED_GLASS
509+
510+ val chunkPos = ChunkPos .fromLocation(placeLoc)
511+ val chunk = placeLoc.world.getOrGenerateChunk(chunkPos)
512+
513+ loadChunk.add(chunkPos)
514+ updateChunks.add(chunk)
515+
516+ val schematicBlock: Schematic .SchematicBlock = if (schematic.blockEntities.containsKey(localSpacePlaceVec)) {
517+ Schematic .SchematicBlock .BlockEntity (localSpacePlaceLoc, placeLoc, block, schematic.blockEntities.getOrThrow(localSpacePlaceVec))
518+ } else {
519+ Schematic .SchematicBlock .Normal (localSpacePlaceLoc, placeLoc, block.getProtocolId())
520+ }
521+ batchBlockUpdate.add(schematicBlock)
522+ }
523+ }
524+ }
525+
526+ batchBlockUpdate.forEach { schematicBlock ->
527+ try {
528+ when (schematicBlock) {
529+ is Schematic .SchematicBlock .Normal -> {
530+ this .setBlockRaw(schematicBlock.location, schematicBlock.id, false )
531+ }
532+
533+ is Schematic .SchematicBlock .BlockEntity -> {
534+ this .setBlockRaw(schematicBlock.location, schematicBlock.block.getProtocolId(), false )
535+ this .setBlockEntityData(schematicBlock.location, schematicBlock.data, schematicBlock.block.registryBlock, false )
536+ }
537+ }
538+
539+ } catch (ex: Exception ) {
540+ log(" Error while placing block in schematic at ${location} : $ex " , LogType .ERROR )
541+ log(ex)
542+ }
543+ }
544+
545+ updateChunks.forEach { chunk ->
546+ chunk.update()
547+ }
548+ }
467549
468550 override fun dispose () {
469551 players.forEach { player ->
0 commit comments