mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-27 10:59:16 +00:00
Update changes from ver/1.21.4 branch
This commit is contained in:
@@ -7,48 +7,78 @@ Original license: MIT
|
||||
Original project: https://github.com/thebrightspark/AsyncLocator
|
||||
|
||||
diff --git a/net/minecraft/server/commands/LocateCommand.java b/net/minecraft/server/commands/LocateCommand.java
|
||||
index a734b2597c3491db35d9660e169f8e8b6320900b..8a79a339757d6ac49713bf6db0fb675d9893fd1b 100644
|
||||
index a734b2597c3491db35d9660e169f8e8b6320900b..5274f09b0abf148aea1c0baa39edbfdac1acc4f5 100644
|
||||
--- a/net/minecraft/server/commands/LocateCommand.java
|
||||
+++ b/net/minecraft/server/commands/LocateCommand.java
|
||||
@@ -106,6 +106,38 @@ public class LocateCommand {
|
||||
@@ -106,6 +106,34 @@ public class LocateCommand {
|
||||
BlockPos blockPos = BlockPos.containing(source.getPosition());
|
||||
ServerLevel level = source.getLevel();
|
||||
Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER);
|
||||
+ // Leaf start - Asynchronous locator
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncLocator.enabled) {
|
||||
+ net.minecraft.commands.CommandSource locatorSource = source.source;
|
||||
+ if (locatorSource instanceof net.minecraft.server.level.ServerPlayer || locatorSource instanceof net.minecraft.server.MinecraftServer) {
|
||||
+ BlockPos originPos = BlockPos.containing(source.getPosition());
|
||||
+ BlockPos originPos = BlockPos.containing(source.getPosition());
|
||||
+ org.dreeam.leaf.async.locate.AsyncLocator.locate(source.getLevel(), holderSet, originPos, 100, false)
|
||||
+ .thenOnServerThread(pair -> {
|
||||
+ stopwatch.stop();
|
||||
+ if (pair != null) {
|
||||
+ showLocateResult(
|
||||
+ source,
|
||||
+ structure,
|
||||
+ originPos,
|
||||
+ pair,
|
||||
+ "commands.locate.structure.success",
|
||||
+ false,
|
||||
+ stopwatch.elapsed()
|
||||
+ );
|
||||
+ } else {
|
||||
+ source.sendFailure(
|
||||
+ Component.literal(
|
||||
+ ERROR_STRUCTURE_NOT_FOUND.create(structure.asPrintable()).getMessage()
|
||||
+ )
|
||||
+ );
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ org.dreeam.leaf.async.locate.AsyncLocator.locate(source.getLevel(), holderSet, originPos, 100, false)
|
||||
+ .thenOnServerThread(pair -> {
|
||||
+ stopwatch.stop();
|
||||
+ if (pair != null) {
|
||||
+ showLocateResult(
|
||||
+ source,
|
||||
+ structure,
|
||||
+ originPos,
|
||||
+ pair,
|
||||
+ "commands.locate.structure.success",
|
||||
+ false,
|
||||
+ stopwatch.elapsed()
|
||||
+ );
|
||||
+ } else {
|
||||
+ source.sendFailure(
|
||||
+ Component.literal(
|
||||
+ ERROR_STRUCTURE_NOT_FOUND.create(structure.asPrintable()).getMessage()
|
||||
+ )
|
||||
+ );
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 0;
|
||||
+ }
|
||||
+ // Leaf end - Asynchronous locator
|
||||
Pair<BlockPos, Holder<Structure>> pair = level.getChunkSource().getGenerator().findNearestMapStructure(level, holderSet, blockPos, 100, false);
|
||||
stopwatch.stop();
|
||||
if (pair == null) {
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index eaaa66c4d86d4ebda0acf8f1dbe8ecb55aa28285..8f41326fda8c5f9f6926038508be6c6529b051bc 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -852,14 +852,25 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
|
||||
@Override
|
||||
public boolean pollTask() {
|
||||
+ // Leaf start - Async Locator
|
||||
// Paper start - rewrite chunk system
|
||||
- final ServerChunkCache serverChunkCache = ServerChunkCache.this;
|
||||
- if (serverChunkCache.runDistanceManagerUpdates()) {
|
||||
- return true;
|
||||
+ java.util.function.Supplier<Boolean> supplier = () -> {
|
||||
+ final ServerChunkCache serverChunkCache = ServerChunkCache.this;
|
||||
+ if (serverChunkCache.runDistanceManagerUpdates()) {
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) serverChunkCache.level).moonrise$getChunkTaskScheduler().executeMainThreadTask();
|
||||
+ }
|
||||
+ };
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncLocator.enabled && Thread.currentThread() instanceof org.dreeam.leaf.async.locate.AsyncLocator.AsyncLocatorThread) {
|
||||
+ return MinecraftServer.getServer().scheduleWithResult((java.util.concurrent.CompletableFuture<Boolean> future) -> {
|
||||
+ future.complete(supplier.get());
|
||||
+ }).join();
|
||||
} else {
|
||||
- return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)serverChunkCache.level).moonrise$getChunkTaskScheduler().executeMainThreadTask();
|
||||
+ return supplier.get();
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ // Leaf end - Async Locator
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java
|
||||
index 23696a5e2871ea07f34d4b4f6a20e2896ac3f5bd..c4fda92e078c9ba745b2548ecaaffffff97fb0fd 100644
|
||||
--- a/net/minecraft/world/entity/animal/Dolphin.java
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Leymooo <Vjatseslav.Maspanov@gmail.com>
|
||||
Date: Wed, 11 Jun 2025 05:30:39 +0300
|
||||
Subject: [PATCH] PaperPR: Fix excess slot updates / inventory state id desync
|
||||
|
||||
Original license: GPLv3
|
||||
Original project: https://github.com/SparklyPower/SparklyPaper
|
||||
Paper pull request: https://github.com/PaperMC/Paper/pull/12654
|
||||
|
||||
Fixes inventory state id desync with high ping causing inventory to be "buggy" (ghost items, items jumping to/from cursor, etc)
|
||||
|
||||
Without patch: https://youtu.be/hOXt3Rpkgtg
|
||||
With patch: https://youtu.be/MtOYD7uieS4
|
||||
|
||||
https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/df01cf867a2255024aacf9ac2ff6a56b2ffb7ce5#nms-patches/net/minecraft/world/inventory/Container.patch
|
||||
|
||||
https://discord.com/channels/289587909051416579/555462289851940864/1382165293308182699
|
||||
|
||||
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
index 9dd3187fd968ab95e9d55b4c8cc74e782cc0f241..c5ede24d00f444d04c835af3a7f0154227492be4 100644
|
||||
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
@@ -559,7 +559,7 @@ public abstract class AbstractContainerMenu {
|
||||
|
||||
slot.setChanged();
|
||||
// CraftBukkit start - Make sure the client has the right slot contents
|
||||
- if (player instanceof ServerPlayer serverPlayer && slot.getMaxStackSize() != 64) {
|
||||
+ if (player instanceof ServerPlayer serverPlayer && slot.getMaxStackSize() != net.minecraft.world.Container.MAX_STACK) { // Paper - Fix excess slot updates / inventory state id desync
|
||||
serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), slot.index, slot.getItem()));
|
||||
// Updating a crafting inventory makes the client reset the result slot, have to send it again
|
||||
if (this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.WORKBENCH || this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.CRAFTING) {
|
||||
@@ -0,0 +1,105 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Fri, 6 Jun 2025 20:46:10 +0900
|
||||
Subject: [PATCH] optimize random tick
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 46e171ca454253c32e22c0c18587e9a7ba19f331..36e592ff42eba050829f9c4d055c3d49a78ba813 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -633,6 +633,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
} finally {
|
||||
list.clear();
|
||||
}
|
||||
+ this.level.randomTickSystem.tick(this.level); // Leaf - optimize random tick
|
||||
|
||||
this.iterateTickingChunksFaster(); // Paper - chunk tick iteration optimisations
|
||||
if (_boolean) {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 27da552e2542153a58d6177f592cf30d858c41a9..a180612fea46ec9f7dcfe1781e985dd2e98ed513 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1114,6 +1114,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.simpleRandom.nextInt(16); } // Gale - Airplane - optimize random calls in chunk ticking
|
||||
|
||||
+ public org.dreeam.leaf.world.RandomTickSystem randomTickSystem = new org.dreeam.leaf.world.RandomTickSystem(); // Leaf - optimize random tick
|
||||
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
||||
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
|
||||
ChunkPos pos = chunk.getPos();
|
||||
@@ -1129,7 +1130,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
} // Paper - Option to disable ice and snow
|
||||
|
||||
if (randomTickSpeed > 0) {
|
||||
- this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking
|
||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizeRandomTick.enabled) randomTickSystem.tickChunk(this.simpleRandom, chunk, randomTickSpeed); // Leaf - optimize random tick
|
||||
+ else this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking // Leaf - optimize random tick
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index a3674ddb883eecb255279375a5e2eece7e016c0f..634bf0c15eb63aeb5ff06dd9b43ecbab627b0128 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -152,6 +152,48 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
}
|
||||
// Gale end - Airplane - optimize random calls in chunk ticking - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively
|
||||
|
||||
+ // Leaf start - optimize random tick
|
||||
+ private boolean leaf$tickingBlocksDirty = true;
|
||||
+ private int leaf$tickingBlocksCount;
|
||||
+ private int leaf$firstTickingSectionIndex = -1;
|
||||
+ public final int leaf$tickingBlocksCount() {
|
||||
+ if (!leaf$tickingBlocksDirty) {
|
||||
+ return leaf$tickingBlocksCount;
|
||||
+ }
|
||||
+ leaf$tickingBlocksDirty = false;
|
||||
+ int sum = 0;
|
||||
+ leaf$firstTickingSectionIndex = -1;
|
||||
+ for (int i = 0; i < sections.length; i++) {
|
||||
+ LevelChunkSection section = sections[i];
|
||||
+ int size = section.moonrise$getTickingBlockList().size();
|
||||
+ if (size != 0 && leaf$firstTickingSectionIndex == -1) {
|
||||
+ leaf$firstTickingSectionIndex = i;
|
||||
+ }
|
||||
+ sum += size;
|
||||
+ }
|
||||
+ leaf$tickingBlocksCount = sum;
|
||||
+ return sum;
|
||||
+ }
|
||||
+ public final java.util.OptionalLong leaf$getTickingPos(int idx) {
|
||||
+ if (leaf$firstTickingSectionIndex != -1) {
|
||||
+ for (int i = leaf$firstTickingSectionIndex; i < sections.length; i++) {
|
||||
+ LevelChunkSection section = sections[i];
|
||||
+ var l = section.moonrise$getTickingBlockList();
|
||||
+ int size = l.size();
|
||||
+ if (idx < size) {
|
||||
+ short loc = l.getRaw(idx);
|
||||
+ int x = (loc & 15) | (chunkPos.x << 4);
|
||||
+ int y = (loc >>> 8) | ((getMinSectionY() + i) << 4);
|
||||
+ int z = ((loc >>> 4) & 15) | (chunkPos.z << 4);
|
||||
+ return java.util.OptionalLong.of(BlockPos.asLong(x, y, z));
|
||||
+ }
|
||||
+ idx -= size;
|
||||
+ }
|
||||
+ }
|
||||
+ leaf$tickingBlocksDirty = true;
|
||||
+ return java.util.OptionalLong.empty();
|
||||
+ }
|
||||
+ // Leaf end - optimize random tick
|
||||
public LevelChunk(Level level, ChunkPos pos) {
|
||||
this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null);
|
||||
}
|
||||
@@ -416,6 +458,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
if (blockState == state) {
|
||||
return null;
|
||||
} else {
|
||||
+ // Leaf start - optimize random tick
|
||||
+ if (blockState.isRandomlyTicking() != state.isRandomlyTicking()) {
|
||||
+ leaf$tickingBlocksDirty = true;
|
||||
+ }
|
||||
+ // Leaf end - optimize random tick
|
||||
Block block = state.getBlock();
|
||||
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(i, y, i2, state);
|
||||
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(i, y, i2, state);
|
||||
@@ -100,7 +100,7 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194
|
||||
- // Paper end - detailed watchdog information
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 12cf6dc9bac109a4feeeeede5f3762b20ea582bb..b450ac5e19d42765c739311de1566b7b0c11c88b 100644
|
||||
index 36e592ff42eba050829f9c4d055c3d49a78ba813..b32cb1c85a9f7a7a96a257c4546ee7e21cd91a6d 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -623,8 +623,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -117,10 +117,10 @@ index 12cf6dc9bac109a4feeeeede5f3762b20ea582bb..b450ac5e19d42765c739311de1566b7b
|
||||
|
||||
for (LevelChunk levelChunk : list) {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 117a8ef98c369bf0919e44fe823d6af0758816b5..47357e1d54563e30b4281c410a1ab70ccd672ad0 100644
|
||||
index a180612fea46ec9f7dcfe1781e985dd2e98ed513..7cb8329fc787aa6a9f877afb43dc9cd655cb0e90 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1526,13 +1526,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1518,13 +1518,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// Paper end - log detailed entity tick information
|
||||
|
||||
public void tickNonPassenger(Entity entity) {
|
||||
@@ -134,7 +134,7 @@ index 117a8ef98c369bf0919e44fe823d6af0758816b5..47357e1d54563e30b4281c410a1ab70c
|
||||
entity.setOldPosAndRot();
|
||||
entity.tickCount++;
|
||||
entity.totalEntityAge++; // Paper - age-like counter for all entities
|
||||
@@ -1545,13 +1539,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1537,13 +1531,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
for (Entity entity1 : entity.getPassengers()) {
|
||||
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
|
||||
}
|
||||
@@ -149,7 +149,7 @@ index 117a8ef98c369bf0919e44fe823d6af0758816b5..47357e1d54563e30b4281c410a1ab70c
|
||||
|
||||
private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 7573c566aace4b7661c5aed6d96653472bab81bb..84808bf3311067409aad99817d3f1df2c098d83c 100644
|
||||
index fc39af434b59054260d763b994fb50bcf92b4ff3..ddc2a7fbca414b8e3c044cfe7076d2cac182b63e 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1166,16 +1166,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.dreeam.leaf.async.ai;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
@@ -10,85 +9,54 @@ import org.dreeam.leaf.config.modules.async.AsyncTargetFinding;
|
||||
import org.dreeam.leaf.util.queue.SpscIntQueue;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
public class AsyncGoalExecutor {
|
||||
|
||||
protected static final Logger LOGGER = LogManager.getLogger("Leaf Async Goal");
|
||||
protected final SpscIntQueue queue;
|
||||
protected final SpscIntQueue wake;
|
||||
protected final IntArrayList submit;
|
||||
private final ServerLevel world;
|
||||
private long midTickCount = 0L;
|
||||
|
||||
public AsyncGoalExecutor(AsyncGoalThread thread, ServerLevel world) {
|
||||
public AsyncGoalExecutor(ServerLevel world) {
|
||||
this.world = world;
|
||||
this.queue = new SpscIntQueue(AsyncTargetFinding.queueSize);
|
||||
this.wake = new SpscIntQueue(AsyncTargetFinding.queueSize);
|
||||
this.submit = new IntArrayList();
|
||||
}
|
||||
|
||||
boolean wake(int id) {
|
||||
Entity entity = this.world.getEntities().get(id);
|
||||
if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) {
|
||||
return false;
|
||||
}
|
||||
mob.goalSelector.ctx.wake();
|
||||
mob.targetSelector.ctx.wake();
|
||||
return true;
|
||||
}
|
||||
|
||||
public final void submit(int entityId) {
|
||||
this.submit.add(entityId);
|
||||
}
|
||||
|
||||
public final void tick() {
|
||||
batchSubmit();
|
||||
boolean wakeAll() {
|
||||
boolean success = false;
|
||||
while (true) {
|
||||
OptionalInt result = this.wake.recv();
|
||||
OptionalInt result = queue.recv();
|
||||
if (result.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
int id = result.getAsInt();
|
||||
if (poll(id) && !this.queue.send(id)) {
|
||||
do {
|
||||
wake(id);
|
||||
} while (poll(id));
|
||||
}
|
||||
success = true;
|
||||
wake(id);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private void batchSubmit() {
|
||||
if (submit.isEmpty()) {
|
||||
public void tickMob(Mob mob) {
|
||||
if (!poll(mob)) {
|
||||
return;
|
||||
}
|
||||
int[] raw = submit.elements();
|
||||
int size = submit.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int id = raw[i];
|
||||
if (poll(id) && !this.queue.send(id)) {
|
||||
do {
|
||||
wake(id);
|
||||
} while (poll(id));
|
||||
}
|
||||
int entityId = mob.getId();
|
||||
if (!this.queue.send(entityId)) {
|
||||
do {
|
||||
wake(entityId);
|
||||
} while (poll(mob));
|
||||
}
|
||||
this.submit.clear();
|
||||
}
|
||||
|
||||
public final void midTick() {
|
||||
if (AsyncTargetFinding.threshold <= 0L || (midTickCount % AsyncTargetFinding.threshold) == 0L) {
|
||||
batchSubmit();
|
||||
}
|
||||
|
||||
midTickCount += 1;
|
||||
}
|
||||
|
||||
private boolean poll(int id) {
|
||||
private void wake(int id) {
|
||||
Entity entity = this.world.getEntities().get(id);
|
||||
if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
mob.goalSelector.ctx.wake();
|
||||
mob.targetSelector.ctx.wake();
|
||||
}
|
||||
|
||||
private boolean poll(Mob mob) {
|
||||
try {
|
||||
mob.tickingTarget = true;
|
||||
boolean a = mob.targetSelector.poll();
|
||||
@@ -97,8 +65,7 @@ public class AsyncGoalExecutor {
|
||||
return a || b;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Exception while polling", e);
|
||||
// retry
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,26 +22,11 @@ public class AsyncGoalThread extends Thread {
|
||||
while (RUNNING) {
|
||||
boolean retry = false;
|
||||
for (ServerLevel level : server.getAllLevels()) {
|
||||
var exec = level.asyncGoalExecutor;
|
||||
while (true) {
|
||||
OptionalInt result = exec.queue.recv();
|
||||
if (result.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
int id = result.getAsInt();
|
||||
retry = true;
|
||||
if (exec.wake(id)) {
|
||||
while (!exec.wake.send(id)) {
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Thread.yield();
|
||||
retry |= level.asyncGoalExecutor.wakeAll();
|
||||
}
|
||||
|
||||
if (!retry) {
|
||||
LockSupport.parkNanos(10_000L);
|
||||
LockSupport.parkNanos(1_000_000L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.minecraft.Util;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dreeam.leaf.config.modules.misc.SentryDSN;
|
||||
import org.dreeam.leaf.config.modules.opt.FastBiomeManagerSeedObfuscation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -243,6 +244,7 @@ public class LeafConfig {
|
||||
|
||||
List<String> extraHidden = existing != null ? new ArrayList<>(Arrays.asList(existing.split(","))) : new ArrayList<>();
|
||||
extraHidden.add(SentryDSN.sentryDsnConfigPath); // Hide Sentry DSN key
|
||||
extraHidden.add(FastBiomeManagerSeedObfuscation.seedObfKeyPath); // Hide FastBiomeManagerSeedObfuscation key
|
||||
|
||||
return extraHidden;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ public class AsyncTargetFinding extends ConfigModules {
|
||||
public static boolean searchBlock = true;
|
||||
public static boolean searchEntity = true;
|
||||
public static int queueSize = 4096;
|
||||
public static long threshold = 10L;
|
||||
private static boolean asyncTargetFindingInitialized;
|
||||
|
||||
@Override
|
||||
@@ -36,21 +35,17 @@ public class AsyncTargetFinding extends ConfigModules {
|
||||
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
|
||||
// Disable if parallel world ticking is enabled, as they are incompatible.
|
||||
if (enabled && SparklyPaperParallelWorldTicking.enabled) {
|
||||
LeafConfig.LOGGER.warn("Async Target Finding is incompatible with Parallel World Ticking. Disabling Async Target Finding automatically.");
|
||||
LeafConfig.LOGGER.warn("Async target finding is incompatible with Parallel World Ticking. Disabling Async target finding automatically.");
|
||||
enabled = false;
|
||||
}
|
||||
alertOther = config.getBoolean(getBasePath() + ".async-alert-other", true);
|
||||
searchBlock = config.getBoolean(getBasePath() + ".async-search-block", true);
|
||||
searchEntity = config.getBoolean(getBasePath() + ".async-search-entity", true);
|
||||
queueSize = config.getInt(getBasePath() + ".queue-size", 0);
|
||||
threshold = config.getLong(getBasePath() + ".threshold", 0);
|
||||
|
||||
if (queueSize <= 0) {
|
||||
queueSize = 4096;
|
||||
}
|
||||
if (threshold == 0L) {
|
||||
threshold = 10L;
|
||||
}
|
||||
if (!enabled) {
|
||||
alertOther = false;
|
||||
searchEntity = false;
|
||||
|
||||
@@ -15,6 +15,7 @@ public class FastBiomeManagerSeedObfuscation extends ConfigModules {
|
||||
@Experimental
|
||||
public static boolean enabled = false;
|
||||
public static long seedObfuscationKey = ThreadLocalRandom.current().nextLong();
|
||||
public static String seedObfKeyPath;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
@@ -26,7 +27,7 @@ public class FastBiomeManagerSeedObfuscation extends ConfigModules {
|
||||
"""
|
||||
**实验性功能**
|
||||
将原版 BiomeManager 的 SHA-256 种子混淆换成 XXHash."""));
|
||||
seedObfuscationKey = config.getLong(getBasePath() + ".seed-obfuscation-key", seedObfuscationKey,
|
||||
seedObfuscationKey = config.getLong(seedObfKeyPath = getBasePath() + ".seed-obfuscation-key", seedObfuscationKey,
|
||||
config.pickStringRegionBased(
|
||||
"Seed obfuscation key for XXHash.",
|
||||
"XXHash 的混淆种子."));
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.dreeam.leaf.config.modules.opt;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
import org.dreeam.leaf.config.annotations.Experimental;
|
||||
|
||||
public class OptimizeRandomTick extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.PERF.getBaseKeyName() + ".optimise-random-tick";
|
||||
}
|
||||
|
||||
@Experimental
|
||||
public static boolean enabled = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
enabled = config.getBoolean(getBasePath(), enabled);
|
||||
}
|
||||
}
|
||||
@@ -56,11 +56,7 @@ public class FasterRandomSource implements BitRandomSource {
|
||||
|
||||
@Override
|
||||
public final int next(int bits) {
|
||||
if (useDirectImpl) {
|
||||
return (int) ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits));
|
||||
}
|
||||
|
||||
return (int) ((seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits));
|
||||
return (int) ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits));
|
||||
}
|
||||
|
||||
public static class FasterRandomSourcePositionalRandomFactory implements PositionalRandomFactory {
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
package org.dreeam.leaf.world;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
|
||||
import java.util.OptionalLong;
|
||||
|
||||
public final class RandomTickSystem {
|
||||
private static final long SCALE = 0x100000L;
|
||||
private static final long CHUNK_BLOCKS = 4096L;
|
||||
|
||||
/// reduce unnecessary sampling and block counting
|
||||
private static final long TICK_MASK = 0b11L;
|
||||
private static final long TICK_MUL = 4L;
|
||||
private static final int BITS_STEP = 2;
|
||||
private static final int BITS_MAX = 60;
|
||||
|
||||
private final LongArrayList queue = new LongArrayList();
|
||||
private final LongArrayList samples = new LongArrayList();
|
||||
private final LongArrayList weights = new LongArrayList();
|
||||
private long weightsSum = 0L;
|
||||
|
||||
private int bits = 60;
|
||||
private long cacheRandom = 0L;
|
||||
|
||||
public void tick(ServerLevel world) {
|
||||
if (weights.isEmpty() || samples.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var random = world.simpleRandom;
|
||||
final long chosen;
|
||||
if (((weightsSum % SCALE) >= boundedNextLong(random, SCALE))) {
|
||||
chosen = weightsSum / SCALE + 1L;
|
||||
} else {
|
||||
chosen = weightsSum / SCALE;
|
||||
}
|
||||
if (chosen == 0L) {
|
||||
return;
|
||||
}
|
||||
|
||||
final long spoke = weightsSum / chosen;
|
||||
if (spoke == 0L) {
|
||||
return;
|
||||
}
|
||||
|
||||
final long[] weightsRaw = weights.elements();
|
||||
final long[] samplesRaw = samples.elements();
|
||||
|
||||
long accumulated = weightsRaw[0];
|
||||
long current = boundedNextLong(random, spoke);
|
||||
int i = 0;
|
||||
while (current < weightsSum) {
|
||||
while (accumulated < current) {
|
||||
i += 1;
|
||||
accumulated += weightsRaw[i];
|
||||
}
|
||||
queue.add(samplesRaw[i]);
|
||||
current += spoke;
|
||||
}
|
||||
while (queue.size() < chosen) {
|
||||
queue.add(samplesRaw[i]);
|
||||
}
|
||||
|
||||
long[] queueRaw = queue.elements();
|
||||
int j = 0;
|
||||
int k;
|
||||
for (k = queue.size() - 3; j < k; j += 4) {
|
||||
final long packed1 = queueRaw[j];
|
||||
final long packed2 = queueRaw[j + 1];
|
||||
final long packed3 = queueRaw[j + 2];
|
||||
final long packed4 = queueRaw[j + 3];
|
||||
final LevelChunk chunk1 = getChunk(world, packed1);
|
||||
final LevelChunk chunk2 = packed1 != packed2 ? getChunk(world, packed2) : chunk1;
|
||||
final LevelChunk chunk3 = packed2 != packed3 ? getChunk(world, packed3) : chunk2;
|
||||
final LevelChunk chunk4 = packed3 != packed4 ? getChunk(world, packed4) : chunk3;
|
||||
if (chunk1 != null) tickBlock(world, chunk1, random);
|
||||
if (chunk2 != null) tickBlock(world, chunk2, random);
|
||||
if (chunk3 != null) tickBlock(world, chunk3, random);
|
||||
if (chunk4 != null) tickBlock(world, chunk4, random);
|
||||
}
|
||||
for (k = queue.size(); j < k; j++) {
|
||||
final LevelChunk chunk = getChunk(world, queueRaw[j]);
|
||||
if (chunk != null) tickBlock(world, chunk, random);
|
||||
}
|
||||
|
||||
weightsSum = 0L;
|
||||
queue.clear();
|
||||
weights.clear();
|
||||
samples.clear();
|
||||
}
|
||||
|
||||
private static LevelChunk getChunk(ServerLevel world, long packed) {
|
||||
return world.chunkSource.getChunkAtIfLoadedImmediately((int) packed, (int) (packed >> 32));
|
||||
}
|
||||
|
||||
private static void tickBlock(ServerLevel world, LevelChunk chunk, RandomSource random) {
|
||||
int count = chunk.leaf$tickingBlocksCount();
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
OptionalLong optionalPos = chunk.leaf$getTickingPos(random.nextInt(count));
|
||||
if (optionalPos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
BlockPos pos = BlockPos.of(optionalPos.getAsLong());
|
||||
BlockState state = chunk.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
|
||||
state.randomTick(world, pos, random);
|
||||
|
||||
final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
|
||||
if (doubleTickFluids) {
|
||||
final FluidState fluidState = state.getFluidState();
|
||||
if (fluidState.isRandomlyTicking()) {
|
||||
fluidState.randomTick(world, pos, random);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void tickChunk(
|
||||
RandomSource random,
|
||||
LevelChunk chunk,
|
||||
long tickSpeed
|
||||
) {
|
||||
if (this.bits == BITS_MAX) {
|
||||
this.bits = 0;
|
||||
this.cacheRandom = random.nextLong();
|
||||
} else {
|
||||
this.bits += BITS_STEP;
|
||||
}
|
||||
if ((this.cacheRandom & (TICK_MASK << bits)) == 0L) {
|
||||
long count = chunk.leaf$tickingBlocksCount();
|
||||
if (count != 0L) {
|
||||
long weight = (TICK_MUL * tickSpeed * count * SCALE) / CHUNK_BLOCKS;
|
||||
samples.add(chunk.getPos().longKey);
|
||||
weights.add(weight);
|
||||
weightsSum += weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rng a random number generator to be used as a
|
||||
* source of pseudorandom {@code long} values
|
||||
* @param bound the upper bound (exclusive); must be greater than zero
|
||||
*
|
||||
* @return a pseudorandomly chosen {@code long} value
|
||||
*
|
||||
* @see java.util.random.RandomGenerator#nextLong(long) nextLong(bound)
|
||||
*/
|
||||
public static long boundedNextLong(RandomSource rng, long bound) {
|
||||
final long m = bound - 1;
|
||||
long r = rng.nextLong();
|
||||
if ((bound & m) == 0L) {
|
||||
r &= m;
|
||||
} else {
|
||||
for (long u = r >>> 1;
|
||||
u + m - (r = u % bound) < 0L;
|
||||
u = rng.nextLong() >>> 1)
|
||||
;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,6 @@ public class OptimizedPoweredRails {
|
||||
|
||||
private static final int UPDATE_FORCE_PLACE = UPDATE_MOVE_BY_PISTON | UPDATE_KNOWN_SHAPE | UPDATE_CLIENTS;
|
||||
|
||||
private static int RAIL_POWER_LIMIT = 8;
|
||||
|
||||
private static final Object2BooleanOpenHashMap<BlockPos> CHECKED_POS_POOL = new Object2BooleanOpenHashMap<>();
|
||||
|
||||
private static void giveShapeUpdate(Level level, BlockState state, BlockPos pos, BlockPos fromPos, Direction direction) {
|
||||
@@ -36,14 +34,6 @@ public class OptimizedPoweredRails {
|
||||
);
|
||||
}
|
||||
|
||||
public static int getRailPowerLimit() {
|
||||
return RAIL_POWER_LIMIT;
|
||||
}
|
||||
|
||||
public static void setRailPowerLimit(int powerLimit) {
|
||||
RAIL_POWER_LIMIT = powerLimit;
|
||||
}
|
||||
|
||||
public static void updateState(PoweredRailBlock self, BlockState state, Level level, BlockPos pos) {
|
||||
boolean shouldBePowered = level.hasNeighborSignal(pos) ||
|
||||
findPoweredRailSignalFaster(self, level, pos, state, true, 0, CHECKED_POS_POOL) ||
|
||||
@@ -97,7 +87,7 @@ public class OptimizedPoweredRails {
|
||||
private static boolean findPoweredRailSignalFaster(PoweredRailBlock self, Level level,
|
||||
BlockPos pos, BlockState state, boolean searchForward, int distance,
|
||||
Object2BooleanOpenHashMap<BlockPos> checkedPos) {
|
||||
if (distance >= RAIL_POWER_LIMIT - 1) return false;
|
||||
if (distance >= level.purpurConfig.railActivationRange) return false;
|
||||
int x = pos.getX();
|
||||
int y = pos.getY();
|
||||
int z = pos.getZ();
|
||||
@@ -203,7 +193,8 @@ public class OptimizedPoweredRails {
|
||||
|
||||
private static void setRailPositionsPower(PoweredRailBlock self, Level level, BlockPos pos,
|
||||
Object2BooleanOpenHashMap<BlockPos> checkedPos, int[] count, int i, Direction dir) {
|
||||
for (int z = 1; z < RAIL_POWER_LIMIT; z++) {
|
||||
final int railPowerLimit = level.purpurConfig.railActivationRange;
|
||||
for (int z = 1; z < railPowerLimit; z++) {
|
||||
BlockPos newPos = pos.relative(dir, z);
|
||||
BlockState state = level.getBlockState(newPos);
|
||||
if (checkedPos.containsKey(newPos)) {
|
||||
@@ -229,7 +220,8 @@ public class OptimizedPoweredRails {
|
||||
int[] count, int i, Direction dir) {
|
||||
Object2BooleanOpenHashMap<BlockPos> checkedPos = CHECKED_POS_POOL;
|
||||
checkedPos.clear();
|
||||
for (int z = 1; z < RAIL_POWER_LIMIT; z++) {
|
||||
final int railPowerLimit = level.purpurConfig.railActivationRange;
|
||||
for (int z = 1; z < railPowerLimit; z++) {
|
||||
BlockPos newPos = pos.relative(dir, z);
|
||||
BlockState state = level.getBlockState(newPos);
|
||||
if (!state.is(self) || !state.getValue(POWERED) || level.hasNeighborSignal(newPos) ||
|
||||
|
||||
Reference in New Issue
Block a user