mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2026-01-06 15:51:31 +00:00
* perf: SpatialPlayerIndex for isChunkNearPlayer * perf: ensureCapacity with collectTickingChunks * perf: optimize getSlopeDistance * perf: optimize AABB Intersections * perf: implement custom arrays for regions and caches * perf: Improve SortedArraySet sorting (needs testing) * rebase 1.21.4 * perf: optimize ClientBoundLightUpdatePacketData * perf: O(1) Array Writes during Chunk Loading * perf: Optimize LinearPalette (no not the linear format) * perf: Rewrite ConcurrentLongHashSet * rebase 1.21.4 * Fix Multithreaded Tracker (#236) * duke gonna arrest me * i hate git v2 * rebase * dont worry ill change the name of this patch * perf: Rewrite ConcurrentLongHashSet again * perf: Optimize sendChunk * [ci skip] * cleanup * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * cleanup * remove streams on LinearPalette and SerializableChunkData * actually commit them lmao * actually commit them lmao 2 * fix * rebase * perf: clone less (could help with skyblocks) * perf: more unload stuff * perf: manual loop unrolling and bulk copy * initial size for SerializeableChunkData * perf: async chunkSend * cleanup asyncChunkSend * remove experimental tag * rebase --------- Co-authored-by: Creeam <102713261+HaHaWTH@users.noreply.github.com> Co-authored-by: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
146 lines
6.8 KiB
Diff
146 lines
6.8 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Taiyou06 <kaandindar21@gmail.com>
|
|
Date: Sun, 16 Feb 2025 15:15:16 +0100
|
|
Subject: [PATCH] Use BFS on getSlopeDistance in fluids
|
|
|
|
|
|
diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java
|
|
index 4c2c2efd5380ff1fa5ad7553b51babae20f516ae..bd556e02f4e0822e2a62f53ceca7ad61bbfb736b 100644
|
|
--- a/net/minecraft/world/level/material/FlowingFluid.java
|
|
+++ b/net/minecraft/world/level/material/FlowingFluid.java
|
|
@@ -2,12 +2,16 @@ package net.minecraft.world.level.material;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
|
import it.unimi.dsi.fastutil.shorts.Short2BooleanMap;
|
|
import it.unimi.dsi.fastutil.shorts.Short2BooleanOpenHashMap;
|
|
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
|
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
+import java.util.Queue;
|
|
+import java.util.Set;
|
|
+
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
@@ -342,30 +346,65 @@ public abstract class FlowingFluid extends Fluid {
|
|
protected abstract void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state);
|
|
|
|
protected int getSlopeDistance(LevelReader level, BlockPos pos, int depth, Direction direction, BlockState state, FlowingFluid.SpreadContext spreadContext) {
|
|
- int i = 1000;
|
|
+ int maxDepth = this.getSlopeFindDistance(level);
|
|
+ int initialCapacity = (int) Math.pow(4, maxDepth); // Pre-size based on max possible nodes
|
|
+ Queue<QueueEntry> queue = new java.util.ArrayDeque<>(initialCapacity);
|
|
+ it.unimi.dsi.fastutil.longs.LongSet visited = new it.unimi.dsi.fastutil.longs.LongOpenHashSet();
|
|
+
|
|
+ queue.add(new QueueEntry(pos, depth, direction));
|
|
+ visited.add(encodeVisited(pos, direction));
|
|
+
|
|
+ while (!queue.isEmpty()) {
|
|
+ QueueEntry current = queue.poll();
|
|
+ BlockPos currentPos = current.pos;
|
|
+ int currentDepth = current.depth;
|
|
+ Direction excludeDir = current.excludeDir;
|
|
+
|
|
+ for (Direction dir : Direction.Plane.HORIZONTAL) {
|
|
+ if (dir == excludeDir) continue;
|
|
+
|
|
+ BlockPos nextPos = currentPos.relative(dir);
|
|
+ Direction nextExcludeDir = dir.getOpposite();
|
|
+ long nextKey = encodeVisited(nextPos, nextExcludeDir);
|
|
+
|
|
+ if (!visited.add(nextKey)) continue;
|
|
+
|
|
+ BlockState blockState = spreadContext.getBlockStateIfLoaded(nextPos);
|
|
+ if (blockState == null) continue;
|
|
|
|
- for (Direction direction1 : Direction.Plane.HORIZONTAL) {
|
|
- if (direction1 != direction) {
|
|
- BlockPos blockPos = pos.relative(direction1);
|
|
- BlockState blockState = spreadContext.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing
|
|
- if (blockState == null) continue; // Paper - Prevent chunk loading from fluid flowing
|
|
FluidState fluidState = blockState.getFluidState();
|
|
- if (this.canPassThrough(level, this.getFlowing(), pos, state, direction1, blockPos, blockState, fluidState)) {
|
|
- if (spreadContext.isHole(blockPos)) {
|
|
- return depth;
|
|
+ if (this.canPassThrough(level, this.getFlowing(), currentPos, state, dir, nextPos, blockState, fluidState)) {
|
|
+ if (spreadContext.isHole(nextPos)) {
|
|
+ return currentDepth;
|
|
}
|
|
|
|
- if (depth < this.getSlopeFindDistance(level)) {
|
|
- int slopeDistance = this.getSlopeDistance(level, blockPos, depth + 1, direction1.getOpposite(), blockState, spreadContext);
|
|
- if (slopeDistance < i) {
|
|
- i = slopeDistance;
|
|
- }
|
|
+ if (currentDepth + 1 <= maxDepth) {
|
|
+ queue.add(new QueueEntry(nextPos, currentDepth + 1, nextExcludeDir));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- return i;
|
|
+ return 1000;
|
|
+ }
|
|
+
|
|
+ // Encode BlockPos and Direction into a long (x: 26 bits, z: 26 bits, dir: 4 bits)
|
|
+ private static long encodeVisited(BlockPos pos, Direction dir) {
|
|
+ return ((long) (pos.getX() & 0x3FFFFFF) << 38)
|
|
+ | ((long) (pos.getZ() & 0x3FFFFFF) << 12)
|
|
+ | (dir.ordinal() & 0xF);
|
|
+ }
|
|
+
|
|
+ private static class QueueEntry {
|
|
+ final BlockPos pos;
|
|
+ final int depth;
|
|
+ final Direction excludeDir;
|
|
+
|
|
+ QueueEntry(BlockPos pos, int depth, Direction excludeDir) {
|
|
+ this.pos = pos.immutable();
|
|
+ this.depth = depth;
|
|
+ this.excludeDir = excludeDir;
|
|
+ }
|
|
}
|
|
|
|
boolean isWaterHole(BlockGetter level, BlockPos pos, BlockState state, BlockPos belowPos, BlockState belowState) {
|
|
@@ -612,12 +651,30 @@ public abstract class FlowingFluid extends Fluid {
|
|
}
|
|
|
|
public boolean isHole(BlockPos pos) {
|
|
- return this.holeCache.computeIfAbsent(this.getCacheKey(pos), s -> {
|
|
- BlockState blockState = this.getBlockState(pos, s);
|
|
- BlockPos blockPos = pos.below();
|
|
- BlockState blockState1 = this.level.getBlockState(blockPos);
|
|
- return FlowingFluid.this.isWaterHole(this.level, pos, blockState, blockPos, blockState1);
|
|
- });
|
|
+ short key = this.getCacheKey(pos);
|
|
+ // Fast path - check if we already have the result
|
|
+ if (this.holeCache.containsKey(key)) {
|
|
+ return this.holeCache.get(key);
|
|
+ }
|
|
+ // Get cached block state for current position
|
|
+ BlockState blockState = this.stateCache.get(key);
|
|
+ if (blockState == null) {
|
|
+ blockState = this.level.getBlockState(pos);
|
|
+ this.stateCache.put(key, blockState);
|
|
+ }
|
|
+ // Get position below and its key
|
|
+ BlockPos belowPos = pos.below();
|
|
+ short belowKey = this.getCacheKey(belowPos);
|
|
+ // Get cached block state for position below
|
|
+ BlockState belowState = this.stateCache.get(belowKey);
|
|
+ if (belowState == null) {
|
|
+ belowState = this.level.getBlockState(belowPos);
|
|
+ this.stateCache.put(belowKey, belowState);
|
|
+ }
|
|
+ // Compute result and cache it
|
|
+ boolean result = FlowingFluid.this.isWaterHole(this.level, pos, blockState, belowPos, belowState);
|
|
+ this.holeCache.put(key, result);
|
|
+ return result;
|
|
}
|
|
|
|
private short getCacheKey(BlockPos pos) {
|