9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-26 18:39:23 +00:00
Files
Leaf/leaf-server/minecraft-patches/features/0216-Use-BFS-on-getSlopeDistance.patch
Dreeam 3c25377465 Drop some unused patches
ClassInstanceMultiMap belongs to Minecraft vanilla entity storage.
And is unused, since replaced by spottedleaf's entity storage (rewrite chunk system).
However these patches might be useful for vanilla entity storage if is used.
2025-07-09 04:20:02 +08:00

174 lines
8.0 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Taiyou06 <kaandindar21@gmail.com>
Date: Wed, 19 Mar 2025 18:41:56 +0100
Subject: [PATCH] Use BFS on getSlopeDistance
Uses Breadth First Search (BFS) to optimize getSlopeDistance
Paper: ~75ms
Leaf: ~48ms (-36%)
This should help drastically on the farms that use actively changing fluids.
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 56e6691f4fc425f13fe5f1fd40de16f4c54a3195..f77bd9472300aec6958ebfa69469fb4e1ee36484 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1438,6 +1438,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.emptyTime = 0;
}
+ // Leaf start - Use BFS on getSlopeDistance
+ public it.unimi.dsi.fastutil.longs.LongSet slopeDistanceCacheVisited = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(512);
+ public net.minecraft.world.level.material.FlowingFluid.SlopeDistanceNodeDeque slopeDistanceCacheQueue = new net.minecraft.world.level.material.FlowingFluid.SlopeDistanceNodeDeque();
+ // Leaf end - Use BFS on getSlopeDistance
private void tickFluid(BlockPos pos, Fluid fluid) {
BlockState blockState = this.getBlockState(pos);
FluidState fluidState = blockState.getFluidState();
diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java
index 4fe1b3fc6304a2a404fd0f62f52fc792bcd5dfaf..a00c38b0d6b6d32af4ab3e926705b0f2594157dd 100644
--- a/net/minecraft/world/level/material/FlowingFluid.java
+++ b/net/minecraft/world/level/material/FlowingFluid.java
@@ -342,32 +342,124 @@ 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;
+ // Leaf start - Use BFS on getSlopeDistance
+ protected int getSlopeDistance(LevelReader level, BlockPos startPos, int initialDepth, Direction excludedDirection, BlockState startState, FlowingFluid.SpreadContext spreadContext) {
+ it.unimi.dsi.fastutil.longs.LongSet visited = ((ServerLevel) level).slopeDistanceCacheVisited;
+ SlopeDistanceNodeDeque queue = ((ServerLevel) level).slopeDistanceCacheQueue;
+ visited.clear();
+ queue.clear();
+
+ for (Direction dir : Direction.Plane.HORIZONTAL) {
+ if (dir == excludedDirection) continue;
+
+ BlockPos neighborPos = startPos.relative(dir); // immutable
+ BlockState neighborState = spreadContext.getBlockStateIfLoaded(neighborPos);
+ if (neighborState == null) continue;
+
+ // Check if the fluid can actually pass through to this first neighbor before adding
+ FluidState neighborFluidState = neighborState.getFluidState();
+ if (!this.canPassThrough(level, this.getFlowing(), startPos, startState, dir, neighborPos, neighborState, neighborFluidState)) {
+ continue;
+ }
+ long visitKey = encodeSlopeNode(neighborPos, dir.getOpposite());
+ if (visited.add(visitKey)) {
+ queue.add(new FlowingFluid.SlopeDistanceNode(neighborPos, initialDepth, dir.getOpposite(), neighborState));
+ }
+ }
- 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;
- }
+ int slopeFindDistance = this.getSlopeFindDistance(level);
+ int minDistance = 1000;
- if (depth < this.getSlopeFindDistance(level)) {
- int slopeDistance = this.getSlopeDistance(level, blockPos, depth + 1, direction1.getOpposite(), blockState, spreadContext);
- if (slopeDistance < i) {
- i = slopeDistance;
- }
- }
+ // Process the queue
+ while (!queue.isEmpty()) {
+ FlowingFluid.SlopeDistanceNode current = queue.poll();
+ if (spreadContext.isHole(current.pos)) {
+ return current.depth;
+ }
+
+ if (current.depth >= slopeFindDistance) continue;
+
+ for (Direction dir : Direction.Plane.HORIZONTAL) {
+ if (dir == current.excludedDir) continue;
+
+ BlockPos nextPos = current.pos.relative(dir); // immutable
+ BlockState nextState = spreadContext.getBlockStateIfLoaded(nextPos);
+ if (nextState == null) continue;
+
+ FluidState nextFluidState = nextState.getFluidState();
+ if (!this.canPassThrough(level, this.getFlowing(), current.pos, current.state, dir, nextPos, nextState, nextFluidState)) {
+ continue;
+ }
+
+ long visitKey = encodeSlopeNode(nextPos, dir.getOpposite());
+ if (visited.add(visitKey)) {
+ queue.add(new FlowingFluid.SlopeDistanceNode(nextPos, current.depth + 1, dir.getOpposite(), nextState));
}
}
}
- return i;
+ return minDistance;
+ }
+
+ private static long encodeSlopeNode(BlockPos pos, Direction excludedDir) {
+ return ((long) pos.getX() & 0xFFFFFFFFL) << 32 | ((long) pos.getZ() & 0xFFFFFFFFL) << 4 | (excludedDir.ordinal() & 0x0F);
+ }
+
+ public static class SlopeDistanceNodeDeque {
+ private SlopeDistanceNode[] array;
+ private int length;
+ private int start;
+ private int end;
+
+ public SlopeDistanceNodeDeque() {
+ array = new SlopeDistanceNode[256];
+ length = array.length;
+ }
+
+ /*
+ private int size() {
+ int apparent = end - start;
+ return apparent >= 0 ? apparent : length + apparent;
+ }
+ */
+
+ private void clear() {
+ start = 0;
+ end = 0;
+ }
+
+ private boolean isEmpty() {
+ return end == start || (end <= start && length == start - end);
+ }
+
+ private SlopeDistanceNode poll() {
+ final SlopeDistanceNode t = array[start];
+ if (++start == length) start = 0;
+ return t;
+ }
+
+ private void add(final SlopeDistanceNode node) {
+ array[end++] = node;
+ if (end == length) end = 0;
+ if (end == start) resize(length, 2 * length);
+ }
+
+ private void resize(final int size, final int newLength) {
+ final SlopeDistanceNode[] newArray = new SlopeDistanceNode[newLength];
+ if (size != 0) {
+ System.arraycopy(array, start, newArray, 0, length - start);
+ System.arraycopy(array, 0, newArray, length - start, end);
+ }
+ start = 0;
+ end = size;
+ array = newArray;
+ length = newLength;
+ }
+ }
+
+ private record SlopeDistanceNode(BlockPos pos, int depth, Direction excludedDir, BlockState state) {
}
+ // Leaf end - Use BFS on getSlopeDistance
boolean isWaterHole(BlockGetter level, BlockPos pos, BlockState state, BlockPos belowPos, BlockState belowState) {
return canPassThroughWall(Direction.DOWN, level, pos, state, belowPos, belowState)