9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-26 18:39:23 +00:00

Update changes from ver/1.21.4 branch

This commit is contained in:
Dreeam
2025-05-02 22:45:26 -04:00
84 changed files with 6041 additions and 1028 deletions

View File

@@ -0,0 +1,87 @@
package org.dreeam.leaf.async.ai;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dreeam.leaf.config.modules.async.AsyncTargetFinding;
import org.dreeam.leaf.util.queue.SpscIntQueue;
import java.util.concurrent.locks.LockSupport;
public class AsyncGoalExecutor {
public static final Logger LOGGER = LogManager.getLogger("Leaf Async Goal");
protected final SpscIntQueue queue;
protected final SpscIntQueue wake;
private final AsyncGoalThread thread;
private final ServerLevel serverLevel;
private boolean dirty = false;
private long tickCount = 0L;
private static final int SPIN_LIMIT = 100;
public AsyncGoalExecutor(AsyncGoalThread thread, ServerLevel serverLevel) {
this.serverLevel = serverLevel;
this.queue = new SpscIntQueue(AsyncTargetFinding.queueSize);
this.wake = new SpscIntQueue(AsyncTargetFinding.queueSize);
this.thread = thread;
}
boolean wake(int id) {
Entity entity = this.serverLevel.getEntities().get(id);
if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) {
return false;
}
mob.goalSelector.wake();
mob.targetSelector.wake();
return true;
}
public final void submit(int entityId) {
if (!this.queue.send(entityId)) {
int spinCount = 0;
while (!this.queue.send(entityId)) {
spinCount++;
// Unpark the thread after some spinning to help clear the queue
if (spinCount > SPIN_LIMIT) {
unpark();
spinCount = 0;
}
Thread.onSpinWait();
}
}
dirty = true;
}
public final void unpark() {
if (dirty) LockSupport.unpark(thread);
dirty = false;
}
public final void midTick() {
boolean didWork = false;
while (true) {
int id = this.wake.recv();
if (id == Integer.MAX_VALUE) {
break;
}
didWork = true;
Entity entity = this.serverLevel.getEntities().get(id);
if (entity == null || !entity.isAlive() || !(entity instanceof Mob mob)) {
continue;
}
mob.tickingTarget = true;
boolean a = mob.targetSelector.poll();
mob.tickingTarget = false;
boolean b = mob.goalSelector.poll();
if (a || b) {
submit(id);
}
}
if (didWork || (tickCount & 15L) == 0L) unpark();
tickCount += 1;
}
}

View File

@@ -0,0 +1,57 @@
package org.dreeam.leaf.async.ai;
import net.minecraft.Util;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import java.util.concurrent.locks.LockSupport;
public class AsyncGoalThread extends Thread {
private static final int SPIN_TRIES = 1000;
public AsyncGoalThread(final MinecraftServer server) {
super(() -> run(server), "Leaf Async Goal Thread");
this.setDaemon(false);
this.setUncaughtExceptionHandler(Util::onThreadException);
this.setPriority(Thread.NORM_PRIORITY - 1);
this.start();
}
private static void run(MinecraftServer server) {
int emptySpins = 0;
while (server.isRunning()) {
boolean didWork = false;
for (ServerLevel level : server.getAllLevels()) {
var exec = level.asyncGoalExecutor;
boolean levelWork = false;
while (true) {
int id = exec.queue.recv();
if (id == Integer.MAX_VALUE) {
break;
}
levelWork = true;
if (exec.wake(id)) {
while (!exec.wake.send(id)) {
Thread.onSpinWait();
}
}
}
didWork |= levelWork;
}
// Adaptive parking
if (didWork) {
emptySpins = 0; // Reset counter when work was done
} else {
emptySpins++;
if (emptySpins > SPIN_TRIES) {
LockSupport.park(); // Only park after several empty spins
emptySpins = 0;
} else {
Thread.onSpinWait(); // Yield to other threads but don't park
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
package org.dreeam.leaf.async.ai;
import org.jetbrains.annotations.Nullable;
public class Waker {
@Nullable
public volatile Runnable wake = null;
@Nullable
public volatile Object result = null;
public volatile boolean state = true;
public final @Nullable Object result() {
Object result = this.result;
this.result = null;
return result;
}
}

View File

@@ -6,7 +6,8 @@ import java.util.Locale;
public enum PathfindTaskRejectPolicy {
FLUSH_ALL,
CALLER_RUNS;
CALLER_RUNS,
DISCARD;
public static PathfindTaskRejectPolicy fromString(String policy) {
try {

View File

@@ -46,6 +46,13 @@ public abstract class ConfigModules extends LeafConfig {
for (ConfigModules module : MODULES) {
module.onPostLoaded();
}
// Save config to disk
try {
LeafConfig.config().saveConfig();
} catch (Exception e) {
LeafConfig.LOGGER.error("Failed to save config file!", e);
}
}
private static List<Field> getAnnotatedStaticFields(Class<?> clazz, Class<? extends Annotation> annotation) {

View File

@@ -58,6 +58,7 @@ public class LeafConfig {
/* Load & Reload */
// Reload config (async)
public static @NotNull CompletableFuture<Void> reloadAsync(CommandSender sender) {
return CompletableFuture.runAsync(() -> {
try {
@@ -76,6 +77,7 @@ public class LeafConfig {
}, Util.ioPool());
}
// Init config
public static void loadConfig() {
try {
long begin = System.nanoTime();
@@ -100,9 +102,6 @@ public class LeafConfig {
// Load config modules
ConfigModules.initModules();
// Save config to disk
leafGlobalConfig.saveConfig();
}
public static LeafGlobalConfig config() {

View File

@@ -1,28 +0,0 @@
package org.dreeam.leaf.config.modules.async;
import org.dreeam.leaf.config.ConfigModules;
import org.dreeam.leaf.config.EnumConfigCategory;
public class AsyncBlockFinding extends ConfigModules {
public String getBasePath() {
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".async-block-finding";
}
public static boolean enabled = false;
public static boolean asyncBlockFindingInitialized;
@Override
public void onLoaded() {
config.addCommentRegionBased(getBasePath(), """
This moves the expensive search calculations to a background thread while
keeping the actual block validation on the main thread.""",
"""
这会将昂贵的搜索计算移至后台线程, 同时在主线程上保持实际的方块验证.""");
if (!asyncBlockFindingInitialized) {
asyncBlockFindingInitialized = true;
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
}
}
}

View File

@@ -13,8 +13,7 @@ public class AsyncChunkSend extends ConfigModules {
@Override
public void onLoaded() {
config.addCommentRegionBased(getBasePath(),
"""
config.addCommentRegionBased(getBasePath(), """
Makes chunk packet preparation and sending asynchronous to improve server performance.
This can significantly reduce main thread load when many players are loading chunks.""",
"""

View File

@@ -10,7 +10,7 @@ public class AsyncMobSpawning extends ConfigModules {
}
public static boolean enabled = true;
public static boolean asyncMobSpawningInitialized;
private static boolean asyncMobSpawningInitialized;
@Override
public void onLoaded() {
@@ -22,13 +22,16 @@ public class AsyncMobSpawning extends ConfigModules {
This just offloads some expensive calculations that are required for mob spawning.""",
"""
是否异步化生物生成.
在实体较多的服务器上, 异步生成可最高带来15%的性能提升.
在实体较多的服务器上, 异步生成可最高带来 15% 的性能提升.
须在Paper配置文件中打开 per-player-mob-spawns 才能生效.""");
// This prevents us from changing the value during a reload.
if (!asyncMobSpawningInitialized) {
asyncMobSpawningInitialized = true;
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
if (asyncMobSpawningInitialized) {
config.getConfigSection(getBasePath());
return;
}
asyncMobSpawningInitialized = true;
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
}
}

View File

@@ -16,9 +16,27 @@ public class AsyncPathfinding extends ConfigModules {
public static int asyncPathfindingKeepalive = 60;
public static int asyncPathfindingQueueSize = 0;
public static PathfindTaskRejectPolicy asyncPathfindingRejectPolicy = PathfindTaskRejectPolicy.FLUSH_ALL;
private static boolean asyncPathfindingInitialized;
@Override
public void onLoaded() {
config.addCommentRegionBased(getBasePath() + ".reject-policy", """
The policy to use when the queue is full and a new task is submitted.
FLUSH_ALL: All pending tasks will be run on server thread.
CALLER_RUNS: Newly submitted task will be run on server thread.
DISCARD: Newly submitted task will be dropped directly.""",
"""
当队列满时, 新提交的任务将使用以下策略处理.
FLUSH_ALL: 所有等待中的任务都将在主线程上运行.
CALLER_RUNS: 新提交的任务将在主线程上运行.
DISCARD: 新提交的任务会被直接丢弃."""
);
if (asyncPathfindingInitialized) {
config.getConfigSection(getBasePath());
return;
}
asyncPathfindingInitialized = true;
final int availableProcessors = Runtime.getRuntime().availableProcessors();
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
asyncPathfindingMaxThreads = config.getInt(getBasePath() + ".max-threads", asyncPathfindingMaxThreads);
@@ -37,15 +55,10 @@ public class AsyncPathfinding extends ConfigModules {
if (asyncPathfindingQueueSize <= 0)
asyncPathfindingQueueSize = asyncPathfindingMaxThreads * 256;
asyncPathfindingRejectPolicy = PathfindTaskRejectPolicy.fromString(config.getString(getBasePath() + ".reject-policy", availableProcessors >= 12 && asyncPathfindingQueueSize < 512 ? PathfindTaskRejectPolicy.FLUSH_ALL.toString() : PathfindTaskRejectPolicy.CALLER_RUNS.toString(), config.pickStringRegionBased(
"""
The policy to use when the queue is full and a new task is submitted.
FLUSH_ALL: All pending tasks will be run on server thread.
CALLER_RUNS: Newly submitted task will be run on server thread.""",
"""
当队列满时, 新提交的任务将使用以下策略处理.
FLUSH_ALL: 所有等待中的任务都将在主线程上运行.
CALLER_RUNS: 新提交的任务将在主线程上运行."""
)));
asyncPathfindingRejectPolicy = PathfindTaskRejectPolicy.fromString(config.getString(getBasePath() + ".reject-policy",
availableProcessors >= 12 && asyncPathfindingQueueSize < 512
? PathfindTaskRejectPolicy.FLUSH_ALL.toString()
: PathfindTaskRejectPolicy.CALLER_RUNS.toString())
);
}
}

View File

@@ -10,17 +10,13 @@ public class AsyncPlayerDataSave extends ConfigModules {
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".async-playerdata-save";
}
@Experimental
public static boolean enabled = false;
@Override
public void onLoaded() {
config.addCommentRegionBased(getBasePath(),
"""
**Experimental feature, may have data lost in some circumstances!**
config.addCommentRegionBased(getBasePath(), """
Make PlayerData saving asynchronously.""",
"""
**实验性功能, 在部分场景下可能丢失玩家数据!**
异步保存玩家数据.""");
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);

View File

@@ -11,22 +11,40 @@ public class AsyncTargetFinding extends ConfigModules {
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".async-target-finding";
}
@Experimental
public static boolean enabled = false;
public static boolean asyncTargetFindingInitialized;
public static boolean alertOther = true;
public static boolean searchBlock = true;
public static boolean searchEntity = true;
public static int queueSize = 4096;
private static boolean asyncTargetFindingInitialized;
@Override
public void onLoaded() {
config.addCommentRegionBased(getBasePath(), """
**Experimental feature**
This moves the expensive entity target search calculations to a background thread while
keeping the actual entity validation on the main thread.""",
This moves the expensive entity and block search calculations to background thread while
keeping the actual validation on the main thread.""",
"""
这会将昂贵的实体目标搜索计算移至后台线程, 同时在主线程上保持实际的实体验证.""");
if (!asyncTargetFindingInitialized) {
asyncTargetFindingInitialized = true;
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
if (asyncTargetFindingInitialized) {
config.getConfigSection(getBasePath());
return;
}
asyncTargetFindingInitialized = true;
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
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", 4096);
if (queueSize <= 0) {
queueSize = 4096;
}
if (!enabled) {
alertOther = false;
searchEntity = false;
searchBlock = false;
}
}
}

View File

@@ -15,6 +15,7 @@ public class MultithreadedTracker extends ConfigModules {
public static int asyncEntityTrackerMaxThreads = 0;
public static int asyncEntityTrackerKeepalive = 60;
public static int asyncEntityTrackerQueueSize = 0;
private static boolean asyncMultithreadedTrackerInitialized;
@Override
public void onLoaded() {
@@ -24,15 +25,22 @@ public class MultithreadedTracker extends ConfigModules {
"""
异步实体跟踪,
在实体数量多且密集的情况下效果明显.""");
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
compatModeEnabled = config.getBoolean(getBasePath() + ".compat-mode", compatModeEnabled, config.pickStringRegionBased("""
config.addCommentRegionBased(getBasePath() + ".compat-mode", """
Enable compat mode ONLY if Citizens or NPC plugins using real entity has installed,
Compat mode fixed visible issue with player type NPCs of Citizens,
But still recommend to use packet based / virtual entity NPC plugin, e.g. ZNPC Plus, Adyeshach, Fancy NPC or else.""",
"""
是否启用兼容模式,
如果你的服务器安装了 Citizens 或其他类似非发包 NPC 插件, 请开启此项."""));
如果你的服务器安装了 Citizens 或其他类似非发包 NPC 插件, 请开启此项.""");
if (asyncMultithreadedTrackerInitialized) {
config.getConfigSection(getBasePath());
return;
}
asyncMultithreadedTrackerInitialized = true;
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
compatModeEnabled = config.getBoolean(getBasePath() + ".compat-mode", compatModeEnabled);
asyncEntityTrackerMaxThreads = config.getInt(getBasePath() + ".max-threads", asyncEntityTrackerMaxThreads);
asyncEntityTrackerKeepalive = config.getInt(getBasePath() + ".keepalive", asyncEntityTrackerKeepalive);
asyncEntityTrackerQueueSize = config.getInt(getBasePath() + ".queue-size", asyncEntityTrackerQueueSize);

View File

@@ -2,6 +2,7 @@ package org.dreeam.leaf.config.modules.async;
import org.dreeam.leaf.config.ConfigModules;
import org.dreeam.leaf.config.EnumConfigCategory;
import org.dreeam.leaf.config.LeafConfig;
import org.dreeam.leaf.config.annotations.Experimental;
public class SparklyPaperParallelWorldTicking extends ConfigModules {
@@ -19,22 +20,29 @@ public class SparklyPaperParallelWorldTicking extends ConfigModules {
@Override
public void onLoaded() {
config.addCommentRegionBased(getBasePath(),
"""
config.addCommentRegionBased(getBasePath(), """
**Experimental feature**
Enables parallel world ticking to improve performance on multi-core systems..""",
Enables parallel world ticking to improve performance on multi-core systems.""",
"""
**实验性功能**
启用并行世界处理以提高多核系统的性能.""");
启用并行世界处理以提高多核 CPU 使用率.""");
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
threads = config.getInt(getBasePath() + ".threads", threads);
threads = enabled ? threads : 0;
if (enabled) {
if (threads <= 0) threads = 8;
} else {
threads = 0;
}
logContainerCreationStacktraces = config.getBoolean(getBasePath() + ".log-container-creation-stacktraces", logContainerCreationStacktraces);
logContainerCreationStacktraces = enabled && logContainerCreationStacktraces;
disableHardThrow = config.getBoolean(getBasePath() + ".disable-hard-throw", disableHardThrow);
disableHardThrow = enabled && disableHardThrow;
runAsyncTasksSync = config.getBoolean(getBasePath() + ".run-async-tasks-sync", runAsyncTasksSync);
runAsyncTasksSync = enabled && runAsyncTasksSync;
if (enabled) {
LeafConfig.LOGGER.info("Using {} threads for Parallel World Ticking", threads);
}
}
}

View File

@@ -0,0 +1,32 @@
package org.dreeam.leaf.config.modules.gameplay;
import org.dreeam.leaf.config.ConfigModules;
import org.dreeam.leaf.config.EnumConfigCategory;
public class ConfigurableInventoryOverflowEvent extends ConfigModules {
public String getBasePath() {
return EnumConfigCategory.GAMEPLAY.getBaseKeyName() + ".inventory-overflow-event";
}
public static boolean enabled = false;
public static String listenerClass = "com.example.package.PlayerInventoryOverflowEvent" ;
@Override
public void onLoaded() {
enabled = config.getBoolean(getBasePath() + ".enabled", enabled, config.pickStringRegionBased("""
The event called when used plugin to Inventory#addItem
into player's inventory, and the inventory is full.
This is not recommended to use, please re-design to use the
returned map of Inventory#addItem method as soon as possible!""",
"""
此事件将在插件使用 Inventory#addItem 方法
添加物品到玩家背包, 但是背包已满时调用.
不建议使用此事件,请尽快迁移至使用 Inventory#addItem 方法
返回的 map"""));
listenerClass = config.getString(getBasePath() + ".listener-class", listenerClass, config.pickStringRegionBased("""
The full class name of the listener which listens to this inventory overflow event.""",
"""
监听此物品栏物品溢出事件的完整类名."""));
}
}

View File

@@ -15,8 +15,7 @@ public class SmoothTeleport extends ConfigModules {
@Override
public void onLoaded() {
enabled = config.getBoolean(getBasePath(), enabled, config.pickStringRegionBased(
"""
enabled = config.getBoolean(getBasePath(), enabled, config.pickStringRegionBased("""
**Experimental feature**
Whether to make a "smooth teleport" when players changing dimension.
This requires original world and target world have same logical height to work.""",

View File

@@ -10,7 +10,7 @@ public class ServerBrand extends ConfigModules {
}
public static String serverModName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName();
public static String serverGUIName = "Leaf Console";
public static String serverGUIName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName() + " Console";
@Override
public void onLoaded() {

View File

@@ -17,8 +17,7 @@ public class ChatMessageSignature extends ConfigModules {
Whether or not enable chat message signature,
disable will prevent players to report chat messages.
And also disables the popup when joining a server without
'secure chat', such as offline-mode servers.
""",
'secure chat', such as offline-mode servers.""",
"""
是否启用聊天签名, 禁用后玩家无法进行聊天举报."""));
}

View File

@@ -20,8 +20,7 @@ public class OptimizeNonFlushPacketSending extends ConfigModules {
Optimizes non-flush packet sending by using Netty's lazyExecute method to avoid
expensive thread wakeup calls when scheduling packet operations.
Requires server restart to take effect.
""",
Requires server restart to take effect.""",
"""
警告: 此选项与 ProtocolLib 不兼容, 并可能导致与其他修改数据包
处理的插件出现问题.
@@ -29,7 +28,6 @@ public class OptimizeNonFlushPacketSending extends ConfigModules {
通过使用 Netty 的 lazyExecute 方法来优化非刷新数据包的发送,
避免在调度数据包操作时进行昂贵的线程唤醒调用.
需要重启服务器才能生效.
"""));
需要重启服务器才能生效."""));
}
}

View File

@@ -15,8 +15,7 @@ public class DontSaveEntity extends ConfigModules {
@Override
public void onLoaded() {
dontSavePrimedTNT = config.getBoolean(getBasePath() + ".dont-save-primed-tnt", dontSavePrimedTNT,
config.pickStringRegionBased(
"""
config.pickStringRegionBased("""
Disable save primed tnt on chunk unloads.
Useful for redstone/technical servers, can prevent machines from being exploded by TNT,
when player disconnected caused by Internet issue.""",

View File

@@ -67,8 +67,8 @@ public class FastRNG extends ConfigModules {
Use direct random implementation instead of delegating to Java's RandomGenerator.
This may improve performance but potentially changes RNG behavior.""",
"""
使用直接随机实现而不是委托给Java的RandomGenerator.
这可能会提高性能但可能会改变RNG行为"""));
使用直接随机实现而不是委派给 RandomGenerator.
这可能会提高性能, 但可能会改变 RNG 行为."""));
if (enabled) {
try {

View File

@@ -10,7 +10,7 @@ public class ThrottleHopperWhenFull extends ConfigModules {
}
public static boolean enabled = false;
public static int skipTicks = 0;
public static int skipTicks = 8;
@Override
public void onLoaded() {

View File

@@ -0,0 +1,70 @@
package org.dreeam.leaf.util.map;
import com.google.common.collect.AbstractIterator;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public final class BlockPosIterator extends AbstractIterator<BlockPos> {
private final int startX;
private final int startY;
private final int startZ;
private final int endX;
private final int endY;
private final int endZ;
private @Nullable MutableBlockPos pos = null;
public static Iterable<BlockPos> iterable(AABB bb) {
return () -> new BlockPosIterator(bb);
}
public static Iterable<BlockPos> traverseArea(Vec3 vec, AABB boundingBox) {
double toTravel = Math.min(16.0 / vec.length(), 1.0);
Vec3 movement = vec.scale(toTravel);
AABB fromBB = boundingBox.move(-vec.x, -vec.y, -vec.z);
AABB searchArea = fromBB.expandTowards(movement);
return BlockPosIterator.iterable(searchArea);
}
public BlockPosIterator(AABB bb) {
this.startX = Mth.floor(bb.minX);
this.startY = Mth.floor(bb.minY);
this.startZ = Mth.floor(bb.minZ);
this.endX = Mth.floor(bb.maxX);
this.endY = Mth.floor(bb.maxY);
this.endZ = Mth.floor(bb.maxZ);
}
@Override
protected BlockPos computeNext() {
MutableBlockPos pos = this.pos;
if (pos == null) {
return this.pos = new MutableBlockPos(this.startX, this.startY, this.startZ);
} else {
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
if (y < this.endY) {
y += 1;
} else if (x < this.endX) {
x += 1;
y = this.startY;
} else if (z < this.endZ) {
z += 1;
x = this.startX;
} else {
return this.endOfData();
}
pos.set(x, y, z);
return pos;
}
}
}

View File

@@ -1,6 +1,9 @@
package org.dreeam.leaf.util.map;
import it.unimi.dsi.fastutil.longs.*;
import it.unimi.dsi.fastutil.longs.LongCollection;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;

View File

@@ -20,20 +20,18 @@ public class FasterRandomSource implements BitRandomSource {
private static final RandomGeneratorFactory<RandomGenerator> RANDOM_GENERATOR_FACTORY = RandomGeneratorFactory.of(FastRNG.randomGenerator);
private static final boolean isSplittableGenerator = RANDOM_GENERATOR_FACTORY.isSplittable();
private long seed;
private boolean useDirectImpl;
private static final boolean useDirectImpl = FastRNG.useDirectImpl;
private RandomGenerator randomGenerator;
public static final FasterRandomSource SHARED_INSTANCE = new FasterRandomSource(ThreadLocalRandom.current().nextLong());
public FasterRandomSource(long seed) {
this.seed = seed;
this.randomGenerator = RANDOM_GENERATOR_FACTORY.create(seed);
this.useDirectImpl = FastRNG.useDirectImpl; // Get the value from config
}
private FasterRandomSource(long seed, RandomGenerator.SplittableGenerator randomGenerator) {
this.seed = seed;
this.randomGenerator = randomGenerator;
this.useDirectImpl = FastRNG.useDirectImpl;
}
@Override
@@ -59,7 +57,6 @@ public class FasterRandomSource implements BitRandomSource {
@Override
public final int next(int bits) {
if (useDirectImpl) {
// Direct
return (int) ((seed = seed * MULTIPLIER + INCREMENT & SEED_MASK) >>> (INT_BITS - bits));
}

View File

@@ -0,0 +1,64 @@
package org.dreeam.leaf.util.queue;
/// Lock-free Single Producer Single Consumer Queue
public class SpscIntQueue {
private final int[] data;
private final PaddedAtomicInteger producerIdx = new PaddedAtomicInteger();
private final PaddedAtomicInteger producerCachedIdx = new PaddedAtomicInteger();
private final PaddedAtomicInteger consumerIdx = new PaddedAtomicInteger();
private final PaddedAtomicInteger consumerCachedIdx = new PaddedAtomicInteger();
public SpscIntQueue(int size) {
this.data = new int[size + 1];
}
public final boolean send(int e) {
final int idx = producerIdx.getOpaque();
int nextIdx = idx + 1;
if (nextIdx == data.length) {
nextIdx = 0;
}
int cachedIdx = consumerCachedIdx.getPlain();
if (nextIdx == cachedIdx) {
cachedIdx = consumerIdx.getAcquire();
consumerCachedIdx.setPlain(cachedIdx);
if (nextIdx == cachedIdx) {
return false;
}
}
data[idx] = e;
producerIdx.setRelease(nextIdx);
return true;
}
public final int recv() {
final int idx = consumerIdx.getOpaque();
int cachedIdx = producerCachedIdx.getPlain();
if (idx == cachedIdx) {
cachedIdx = producerIdx.getAcquire();
producerCachedIdx.setPlain(cachedIdx);
if (idx == cachedIdx) {
return Integer.MAX_VALUE;
}
}
int e = data[idx];
int nextIdx = idx + 1;
if (nextIdx == data.length) {
nextIdx = 0;
}
consumerIdx.setRelease(nextIdx);
return e;
}
public final int size() {
return this.data.length;
}
static class PaddedAtomicInteger extends java.util.concurrent.atomic.AtomicInteger {
@SuppressWarnings("unused")
private int i1, i2, i3, i4, i5, i6, i7, i8,
i9, i10, i11, i12, i13, i14, i15;
}
}