diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java index f95fa84f01..902e5e4f16 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java @@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.casting.eval.vm.CastingImage; import at.petrak.hexcasting.api.misc.Result; import at.petrak.hexcasting.api.pigment.FrozenPigment; +import at.petrak.hexcasting.api.utils.ChunkScanning; import at.petrak.hexcasting.api.utils.HexUtils; import com.mojang.datafixers.util.Pair; import net.minecraft.ChatFormatting; @@ -95,13 +96,17 @@ protected CircleExecutionState(BlockPos impetusPos, Direction impetusDir, Set(); var seenGoodPositions = new ArrayList(); + var scanning = new ChunkScanning(level); while (!todo.isEmpty()) { var pair = todo.pop(); var enterDir = pair.getFirst(); var herePos = pair.getSecond(); + var hereBs = scanning.getBlock(herePos); - var hereBs = level.getBlockState(herePos); + if (hereBs == null){ + continue; + } if (!(hereBs.getBlock() instanceof ICircleComponent cmp)) { continue; } @@ -118,6 +123,7 @@ protected CircleExecutionState(BlockPos impetusPos, Direction impetusDir, Set(null); diff --git a/Common/src/main/java/at/petrak/hexcasting/api/utils/ChunkScanning.kt b/Common/src/main/java/at/petrak/hexcasting/api/utils/ChunkScanning.kt new file mode 100644 index 0000000000..4fc1c4b034 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/utils/ChunkScanning.kt @@ -0,0 +1,68 @@ +package at.petrak.hexcasting.api.utils + +import at.petrak.hexcasting.api.HexAPI +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap +import net.minecraft.core.BlockPos +import net.minecraft.server.level.ServerLevel +import net.minecraft.world.level.ChunkPos +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.level.chunk.ChunkStatus +import net.minecraft.world.level.chunk.ImposterProtoChunk + +/** + * This is a helper class to efficiently scan chunks in ways Minecraft did not intend for. This is for only reading chunks, not writing + */ +class ChunkScanning(var level: ServerLevel) { + var chunks: Long2ObjectLinkedOpenHashMap = Long2ObjectLinkedOpenHashMap() + + /** + * This attempts to cache a chunk to the local [chunks] + * @param ChunkPos the chunk to try to cache + * @return If the function could cache the chunk or not + */ + fun cacheChunk(chunk: ChunkPos): Boolean { + val chunkLong = chunk.toLong() + // We have the chunk already, so we can skip it + if (chunks.contains(chunkLong)){ + return true + } + val future = level.chunkSource.getChunkFuture(chunk.x,chunk.z, ChunkStatus.EMPTY,true).get() + if (future.left().isPresent){ + chunks.put(chunkLong, future.left().get() as ImposterProtoChunk) + return true + } + HexAPI.LOGGER.warn("Failed to get chunk at {}!",chunk) + return false + } + + fun cacheChunk(chunk: Long): Boolean{ + return cacheChunk(ChunkPos(chunk)) + } + + fun getBlock(blockPos: BlockPos): BlockState? { + val chunkPos = ChunkPos(blockPos).toLong() + if (!cacheChunk(chunkPos)){ + return null + } + return chunks.get(chunkPos).getBlockState(blockPos) + } + + fun getBlockEntity(blockPos: BlockPos): BlockEntity? { + val chunkPos = ChunkPos(blockPos).toLong() + if (!cacheChunk(chunkPos)){ + return null + } + return chunks.get(chunkPos).getBlockEntity(blockPos) + } + + // Maybe not required, but still not a bad idea to have a Clear method + fun clearCache(){ + chunks.clear() + } + + // Might not be needed + fun containsChunk(chunk: ChunkPos): Boolean{ + return chunks.contains(chunk.toLong()) + } +} \ No newline at end of file