Compare commits

...

19 Commits

Author SHA1 Message Date
Helvetica Volubi 132ee404d4 refactor: rename compatibility helper classes for clarity 2026-08-05 00:56:21 +08:00
Helvetica Volubi 0e10a8e8b0 merge patches 2026-08-05 00:49:01 +08:00
Helvetica Volubi 24e68fb203 fix typo 2026-08-05 00:42:33 +08:00
Helvetica Volubi 141c226294 Replace fast compressor with high compressor in buffered linear format 2026-08-05 00:26:22 +08:00
Helvetica Volubi 1049012aff chore: simplify code 2026-08-03 02:25:33 +08:00
Helvetica Volubi 302825cc7e feat: optimize RegionizedTaskQueue TTL and reduce ticket operations in nether portal searching 2026-08-01 16:38:23 +08:00
dependabot[bot] d806e4a423 [ci skip]Bump actions/setup-java from 5 to 5.6.0 (#168)
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 5 to 5.6.0.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v5...v5.6.0)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: 5.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-01 16:13:12 +08:00
Helvetica Volubi 952c4321d9 fix: fix up BotList 2026-07-31 01:07:56 +08:00
Helvetica Volubi dd7ef6701a feat: update fakeplayer code from Leaves 2026-07-30 02:13:08 +08:00
Helvetica Volubi 43036f971c feat: update Entity tick and removal limiter 2026-07-30 00:58:37 +08:00
Helvetica Volubi 25ce58c40d fix: fix folia nether portal ticket placement 2026-07-28 21:23:43 +08:00
Helvetica Volubi 106f1edb09 set release to stable cannel 2026-07-28 15:38:35 +08:00
Helvetica Volubi eea830188f update some optimizations from upstream 2026-07-28 15:37:41 +08:00
Helvetica Volubi f517cc0b8a feat: update b_linear format from upstream
Because of some reasons, this patch will be anonymous and hide the original commit address.
2026-07-28 02:03:00 +08:00
Helvetica Volubi d90c8567d3 [ci skip] simplify code 2026-07-28 01:29:59 +08:00
Helvetica Volubi 78b3a8a6e7 [ci skip] Use ComfreyWeight instead of HyacinthusWeight 2026-07-27 03:43:02 +08:00
Helvetica Volubi 2f93769135 [ci skip] Use ComfreyWeight instead of HyacinthusWeight 2026-07-27 03:32:49 +08:00
Helvetica Volubi 4e277ad91e [ci skip] Update clip version 2026-07-27 01:17:13 +08:00
Helvetica Volubi 1620687dba [ci skip] fix typo 2026-07-26 19:09:05 +08:00
129 changed files with 4414 additions and 2170 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
uses: actions/checkout@v7
- name: Set Up JDK
uses: actions/setup-java@v5
uses: actions/setup-java@v5.6.0
with:
distribution: zulu
java-version: 25
+1 -2
View File
@@ -34,7 +34,6 @@
- morninggloryclip.useMojangSource 强制服务端使用mojang源下载文件
- morninggloryclip.enable.mixin 启用服务器插件的mixin支持
## 📥 下载
### 稳定版本
@@ -90,7 +89,7 @@ java {
<dependency>
<groupId>fun.bm.lophine</groupId>
<artifactId>lophine-api</artifactId>
<version>[26.1.2.build,)</version>
<version>[26.2.build,)</version>
</dependency>
</dependencies>
```
+1 -1
View File
@@ -89,7 +89,7 @@ java {
<dependency>
<groupId>fun.bm.lophine</groupId>
<artifactId>lophine-api</artifactId>
<version>[26.1.2.build,)</version>
<version>[26.2.build,)</version>
<scope>provided</scope>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent
plugins {
java // TODO java launcher tasks
id("moe.luminolmc.hyacinthusweight.patcher")
id("fun.bm.comfreyweight.patcher")
}
paperweight {
+4 -4
View File
@@ -1,11 +1,11 @@
group=fun.bm.lophine
mcVersion=26.2
apiVersion=26.2
channel=BETA
clipVersion=1.0.0
weightVersion=2.0.15
channel=STABLE
clipVersion=1.0.1
weightVersion=1.0.0
# true for release, false for skip release, pre for pre-release
release=pre
release=true
# true for push to repo, false for skip push repo, auto for detect by release value
pushRepo=auto
+2 -2
View File
@@ -5,7 +5,7 @@
`maven-publish`
idea
- id("io.papermc.paperweight.core")
+ id("moe.luminolmc.hyacinthusweight.core") // TODO Later - rebrand
+ id("fun.bm.comfreyweight.core")
id("io.papermc.fill.gradle") version "1.0.12"
}
@@ -15,7 +15,7 @@
dependencies {
mache("io.papermc:mache:26.2+build.1")
- paperclip("io.papermc:paperclip:3.0.4")
+ hyacinthusclip("fun.bm:morninggloryclip:${providers.gradleProperty("clipVersion").get()}") // TODO Later - rebrand
+ morninggloryclip("fun.bm:morninggloryclip:${providers.gradleProperty("clipVersion").get()}")
}
paperweight {
@@ -5,7 +5,7 @@ Subject: [PATCH] Correct player respawn place
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 57f93d978fe48fdf6e77b7bfb9f1de060e1a8524..924d5f3236d9ba9836f39fc844392099df9cd25c 100644
index 57f93d978fe48fdf6e77b7bfb9f1de060e1a8524..c0e4ddbcf2b1f61fd4a5a6f10882fc1fb4176960 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -511,8 +511,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -43,12 +43,3 @@ index 57f93d978fe48fdf6e77b7bfb9f1de060e1a8524..924d5f3236d9ba9836f39fc844392099
if (inChunk == null) {
continue;
}
@@ -1997,7 +2009,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
if (newLevel.dimension() == lastDimension) {
- this.connection.internalTeleport(PositionMoveRotation.of(transition), transition.relatives()); // CraftBukkit
+ this.connection.internalTeleport(PositionMoveRotation.of(transition), transition.relatives()); // CraftBukkit // Luminol - Correct player respawn place
this.connection.resetPosition();
transition.postTeleportTransition().onTransition(this);
return this;
@@ -1,11 +1,14 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 28 Jun 2026 18:54:50 +0800
Subject: [PATCH] Configurable region format framework
Subject: [PATCH] Anonymous Object: Configurable region format framework
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
index a814512fcfb85312474ae2c2c21443843bf57831..2e084a5b28cbe4737f48c25e10af589213525362 100644
index a814512fcfb85312474ae2c2c21443843bf57831..9d69a022872e06b320bee46329cd8889f74fbbaa 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
@@ -8,9 +8,9 @@ public interface ChunkSystemRegionFileStorage {
@@ -13,15 +16,15 @@ index a814512fcfb85312474ae2c2c21443843bf57831..2e084a5b28cbe4737f48c25e10af5892
public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ);
- public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ);
+ public abomination.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // Luminol - Configurable region file format
+ public io.anonymous.anonymous.data.RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // Anonymous - Configurable region file format
- public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException;
+ public abomination.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // Luminol - Configurable region file format
+ public io.anonymous.anonymous.data.RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // Anonymous - Configurable region file format
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(
final int chunkX, final int chunkZ, final CompoundTag compound
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
index 3bb9b58ee97464687e348e23b99159226415c267..fc264727141c3897e6c06819b9713d4f6395baf0 100644
index 3bb9b58ee97464687e348e23b99159226415c267..4c3ad63f17bb4a04f982b36ad3f53d3c0f58bdb5 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
@@ -1273,7 +1273,7 @@ public final class MoonriseRegionFileIO {
@@ -29,7 +32,7 @@ index 3bb9b58ee97464687e348e23b99159226415c267..fc264727141c3897e6c06819b9713d4f
// Paper start - flush regionfiles on save
if (this.world.paperConfig().chunks.flushRegionsOnSave) {
- final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ);
+ final abomination.IRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // Luminol - Add configurable region file
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // Anonymous - Configurable region file format
if (regionFile != null) {
regionFile.flush();
} // else: evicted from cache, which should have called flush
@@ -38,12 +41,12 @@ index 3bb9b58ee97464687e348e23b99159226415c267..fc264727141c3897e6c06819b9713d4f
public static interface IORunnable {
- public void run(final RegionFile regionFile) throws IOException;
+ public void run(final abomination.IRegionFile regionFile) throws IOException; // Luminol - Configurable region file format
+ public void run(final io.anonymous.anonymous.data.RegionFile regionFile) throws IOException; // Anonymous - Configurable region file format
}
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
index 51c126735ace8fdde89ad97b5cab62f244212db0..c7d4d944eb198ac53a3eeae717a25c7d5815c8c1 100644
index 51c126735ace8fdde89ad97b5cab62f244212db0..ea2f45964fb8c617f90938597c230b50d83744aa 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
@@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer {
@@ -51,10 +54,10 @@ index 51c126735ace8fdde89ad97b5cab62f244212db0..c7d4d944eb198ac53a3eeae717a25c7d
public void moonrise$setWriteOnClose(final boolean value);
- public void moonrise$write(final RegionFile regionFile) throws IOException;
+ public void moonrise$write(final abomination.IRegionFile regionFile) throws IOException; // Luminol - Configurable region file format
+ public void moonrise$write(final io.anonymous.anonymous.data.RegionFile regionFile) throws IOException; // Anonymous - Configurable region file format
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index a49c46eb7df50fc3c5587a2c3668ab6edc887107..83b9aab16124ddcc416f7b4cd95084e1c64fe5b7 100644
index a49c46eb7df50fc3c5587a2c3668ab6edc887107..c74f76b46259204b33b69ad08bb03c81b8b36961 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -986,10 +986,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -62,16 +65,16 @@ index a49c46eb7df50fc3c5587a2c3668ab6edc887107..83b9aab16124ddcc416f7b4cd95084e1
for (ServerLevel level : this.getAllLevels()) {
String storageName = level.getChunkSource().chunkMap.getStorageName();
- LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", LEGACY_WORLD_NAMES_FOR_REALMS_LOG.getOrDefault(storageName, storageName));
+ LOGGER.info("ThreadedChunkStorage ({}): All chunks are saved", LEGACY_WORLD_NAMES_FOR_REALMS_LOG.getOrDefault(storageName, storageName)); // Luminol - configurable region format
+ LOGGER.info("ThreadedChunkStorage ({}): All chunks are saved", LEGACY_WORLD_NAMES_FOR_REALMS_LOG.getOrDefault(storageName, storageName)); // Anonymous - Configurable region format
}
- LOGGER.info("ThreadedAnvilChunkStorage: All dimensions are saved");
+ LOGGER.info("ThreadedChunkStorage: All dimensions are saved"); // Luminol - configurable region format
+ LOGGER.info("ThreadedChunkStorage: All dimensions are saved"); // Anonymous - configurable region format
}
return result;
diff --git a/net/minecraft/util/worldupdate/FileToUpgrade.java b/net/minecraft/util/worldupdate/FileToUpgrade.java
index a7f2cfa9277c898038f6b9e0a3401db51012b64c..db4dba8849eb27f8f84acc3297e342da4700d839 100644
index a7f2cfa9277c898038f6b9e0a3401db51012b64c..7b96f3ec2738875a3ed7aa34347c0f174b6579c5 100644
--- a/net/minecraft/util/worldupdate/FileToUpgrade.java
+++ b/net/minecraft/util/worldupdate/FileToUpgrade.java
@@ -4,5 +4,5 @@ import java.util.List;
@@ -79,10 +82,10 @@ index a7f2cfa9277c898038f6b9e0a3401db51012b64c..db4dba8849eb27f8f84acc3297e342da
import net.minecraft.world.level.chunk.storage.RegionFile;
-public record FileToUpgrade(RegionFile file, List<ChunkPos> chunksToUpgrade) {
+public record FileToUpgrade(abomination.IRegionFile file, List<ChunkPos> chunksToUpgrade) { // Luminol - Configurable region file format
+public record FileToUpgrade(io.anonymous.anonymous.data.RegionFile file, List<ChunkPos> chunksToUpgrade) { // Anonymous - Configurable region file format
}
diff --git a/net/minecraft/util/worldupdate/RegionStorageUpgrader.java b/net/minecraft/util/worldupdate/RegionStorageUpgrader.java
index b228cd6c54e8c8998923ab332882d99092769c67..140ef4959fa2fe5b9cd251955c93683e8e69d5ba 100644
index b228cd6c54e8c8998923ab332882d99092769c67..2dd3d0afd8f58e5e68a361dd38c95da06b4d133b 100644
--- a/net/minecraft/util/worldupdate/RegionStorageUpgrader.java
+++ b/net/minecraft/util/worldupdate/RegionStorageUpgrader.java
@@ -36,7 +36,7 @@ import org.slf4j.Logger;
@@ -90,7 +93,7 @@ index b228cd6c54e8c8998923ab332882d99092769c67..140ef4959fa2fe5b9cd251955c93683e
private static final Logger LOGGER = LogUtils.getLogger();
private static final String NEW_DIRECTORY_PREFIX = "new_";
- private static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
+ private static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\." + me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat.getArgument() + "$"); // Luminol - Configurable region file format
+ private static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\." + me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat.getArgument() + "$"); // Anonymous - Configurable region file format
private final DataFixer dataFixer;
private final UpgradeProgress upgradeProgress;
private final String type;
@@ -99,8 +102,8 @@ index b228cd6c54e8c8998923ab332882d99092769c67..140ef4959fa2fe5b9cd251955c93683e
List<ChunkPos> chunkPositions = Lists.newArrayList();
- try (RegionFile regionSource = new RegionFile(info, regionFile.toPath(), regionFolder, true)) {
+ var regionFileInfo = new me.earthme.luminol.utils.RegionCreatorInfo(info, regionFile.toPath(), regionFolder, true); // Luminol - Configurable region file format
+ try (abomination.IRegionFile regionSource = me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat.getCreator().create(regionFileInfo)) { // Luminol - Configurable region file format
+ var regionFileInfo = new io.anonymous.anonymous.utils.RegionCreatorInfo(info, regionFile.toPath(), regionFolder, true); // Anonymous - Configurable region file format
+ try (io.anonymous.anonymous.data.RegionFile regionSource = me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat.getCreator().newFile(regionFileInfo)) { // Anonymous - Configurable region file format
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
ChunkPos pos = new ChunkPos(x + xOffset, z + zOffset);
@@ -109,12 +112,12 @@ index b228cd6c54e8c8998923ab332882d99092769c67..140ef4959fa2fe5b9cd251955c93683e
}
- private void onFileFinished(final RegionFile regionFile) {
+ private void onFileFinished(final abomination.IRegionFile regionFile) { // Luminol - Configurable region file format
+ private void onFileFinished(final io.anonymous.anonymous.data.RegionFile regionFile) { // Anonymous - Configurable region file format
if (this.recreateRegionFiles) {
if (this.previousWriteFuture != null) {
this.previousWriteFuture.join();
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..d3350dee1d6d5bc15dcdfba3611f93addb767392 100644
index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..821924f85a507589a039832be8657e1dc3c0ce0c 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -22,7 +22,7 @@ import net.minecraft.world.level.ChunkPos;
@@ -122,7 +125,7 @@ index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..d3350dee1d6d5bc15dcdfba3611f93ad
import org.slf4j.Logger;
-public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system
+public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile , abomination.IRegionFile{ // Paper - rewrite chunk system // Luminol - Configurable region file format
+public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile , io.anonymous.anonymous.data.RegionFile{ // Paper - rewrite chunk system // Anonymous - Configurable region file format
private static final Logger LOGGER = LogUtils.getLogger();
public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
private static final int SECTOR_BYTES = 4096;
@@ -131,7 +134,7 @@ index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..d3350dee1d6d5bc15dcdfba3611f93ad
}
- boolean recalculateHeader() throws IOException {
+ public boolean recalculateHeader() throws IOException { // Luminol - Configurable region file format
+ public boolean recalculateHeader() throws IOException { // Anonymous - Configurable region file format
if (!this.canRecalcHeader) {
return false;
}
@@ -140,7 +143,7 @@ index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..d3350dee1d6d5bc15dcdfba3611f93ad
}
- protected synchronized void write(final ChunkPos pos, final ByteBuffer data) throws IOException {
+ public synchronized void write(final ChunkPos pos, final ByteBuffer data) throws IOException { // Luminol - Configurable region file format
+ public synchronized void write(final ChunkPos pos, final ByteBuffer data) throws IOException { // Anonymous - Configurable region file format
int offsetIndex = getOffsetIndex(pos);
int offset = this.offsets.get(offsetIndex);
int sectorNumber = getSectorNumber(offset);
@@ -149,7 +152,7 @@ index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..d3350dee1d6d5bc15dcdfba3611f93ad
@Override
- public final void moonrise$write(final RegionFile regionFile) throws IOException {
+ public final void moonrise$write(final abomination.IRegionFile regionFile) throws IOException { // Luminol - Configurable region file format
+ public final void moonrise$write(final io.anonymous.anonymous.data.RegionFile regionFile) throws IOException { // Anonymous - Configurable region file format
regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count));
}
// Paper end - rewrite chunk system
@@ -158,12 +161,12 @@ index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..d3350dee1d6d5bc15dcdfba3611f93ad
}
- synchronized boolean isOversized(int x, int z) {
+ public synchronized boolean isOversized(int x, int z) { // Luminol - Configurable region file format
+ public synchronized boolean isOversized(int x, int z) { // Anonymous - Configurable region file format
return this.oversized[getChunkIndex(x, z)] == 1;
}
- synchronized void setOversized(int x, int z, boolean oversized) throws IOException {
+ public synchronized void setOversized(int x, int z, boolean oversized) throws IOException { // Luminol - Configurable region file format
+ public synchronized void setOversized(int x, int z, boolean oversized) throws IOException { // Anonymous - Configurable region file format
final int offset = getChunkIndex(x, z);
boolean previous = this.oversized[offset] == 1;
this.oversized[offset] = (byte) (oversized ? 1 : 0);
@@ -172,12 +175,12 @@ index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..d3350dee1d6d5bc15dcdfba3611f93ad
}
- synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException {
+ public synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException { // Luminol - Configurable region file format
+ public synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException { // Anonymous - Configurable region file format
Path file = getOversizedFile(x, z);
try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new java.util.zip.InflaterInputStream(Files.newInputStream(file))))) {
return net.minecraft.nbt.NbtIo.read((java.io.DataInput) out);
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977ebfb18517 100644
index 63b40c420030d935bb81a219fb33defe0946e21f..e0e19f091f6b85d7788259cfcc53cc3db848b68e 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -19,7 +19,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
@@ -185,7 +188,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
public static final String ANVIL_EXTENSION = ".mca";
private static final int MAX_CACHE_SIZE = 256;
- private final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
+ private final Long2ObjectLinkedOpenHashMap<abomination.IRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); // Luminol - Configurable region file format
+ private final Long2ObjectLinkedOpenHashMap<io.anonymous.anonymous.data.RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); // Anonymous - Configurable region file format
private final RegionStorageInfo info;
private final Path folder;
private final boolean sync;
@@ -194,7 +197,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
public static ChunkPos getRegionFileCoordinates(Path file) {
String fileName = file.getFileName().toString();
- if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) {
+ if (!fileName.startsWith("r.") || !fileName.endsWith(getExtensionName())) { // Luminol - Configurable region file format
+ if (!fileName.startsWith("r.") || !fileName.endsWith(getExtensionName())) { // Anonymous - Configurable region file format
return null;
}
@@ -203,32 +206,32 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet();
private static String getRegionFileName(final int chunkX, final int chunkZ) {
- return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".mca";
+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + getExtensionName(); // Luminol - Configurable region file format
+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + getExtensionName(); // Anonymous - Configurable region file format
}
+ // Luminol start - Configurable region file format
+ public static abomination.IRegionFile createNew(RegionStorageInfo info, Path filePath, Path folder, boolean sync) throws IOException{
+ final me.earthme.luminol.enums.EnumRegionFormat regionFormat = me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat;
+ // Anonymous start - Configurable region file format
+ public static io.anonymous.anonymous.data.RegionFile createNew(RegionStorageInfo info, Path filePath, Path folder, boolean sync) throws IOException{
+ final io.anonymous.anonymous.enums.EnumRegionFormat regionFormat = me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat;
+ final String fullFileName = filePath.getFileName().toString();
+ final String[] fullNameSplit = fullFileName.split("\\.");
+ final String extensionName = fullNameSplit[fullNameSplit.length - 1];
+
+ if (!regionFormat.getArgument().equalsIgnoreCase(extensionName)) {
+ // delayed crash
+ // raise a delayed crash
+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> {
+ new RuntimeException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument());
+ throw new RuntimeException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument());
+ });
+
+
+ throw new IOException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument());
+ }
+
+ return regionFormat.getCreator().create(new me.earthme.luminol.utils.RegionCreatorInfo(info, filePath, folder, sync));
+ return regionFormat.getCreator().newFile(new io.anonymous.anonymous.utils.RegionCreatorInfo(info, filePath, folder, sync));
+ }
+
+ public static String getExtensionName() {
+ return "." + me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat.getArgument();
+ }
+ // Luminol end
+ // Anonymous end
private boolean doesRegionFilePossiblyExist(final long position) {
synchronized (this.nonExistingRegionFiles) {
@@ -237,17 +240,17 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
@Override
- public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) {
+ public synchronized final abomination.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // Luminol - Configurable region file format
+ public synchronized final io.anonymous.anonymous.data.RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // Anonymous - Configurable region file format
return this.regionCache.getAndMoveToFirst(ChunkPos.pack(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT));
}
@Override
- public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException {
+ public synchronized final abomination.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // Luminol - Configurable region file format
+ public synchronized final io.anonymous.anonymous.data.RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // Anonymous - Configurable region file format
final long key = ChunkPos.pack(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT);
- RegionFile ret = this.regionCache.getAndMoveToFirst(key);
+ abomination.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // Luminol - Configurable region file format
+ io.anonymous.anonymous.data.RegionFile ret = this.regionCache.getAndMoveToFirst(key); // Anonymous - Configurable region file format
if (ret != null) {
return ret;
}
@@ -256,7 +259,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
FileUtil.createDirectoriesSafe(this.folder);
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
+ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // Luminol - Configurable region file format
+ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // Anonymous - Configurable region file format
this.regionCache.putAndMoveToFirst(key, ret);
@@ -265,7 +268,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
- final RegionFile regionFile = this.getRegionFile(pos);
+ final abomination.IRegionFile regionFile = this.getRegionFile(pos); // Luminol - Configurable region file format
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.getRegionFile(pos); // Anonymous - Configurable region file format
// note: not required to keep regionfile loaded after this call, as the write param takes a regionfile as input
// (and, the regionfile parameter is unused for writing until the write call)
@@ -274,7 +277,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) {
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
+ final abomination.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // Luminol - Configurable region file format
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // Anonymous - Configurable region file format
if (regionFile != null) {
regionFile.clear(pos);
} // else: didn't exist
@@ -283,7 +286,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
final int chunkX, final int chunkZ
) throws IOException {
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
+ final abomination.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // Luminol - Configurable region file format
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // Anonymous - Configurable region file format
final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ));
@@ -292,7 +295,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
final ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(ret);
- final RegionFile regionFile = this.getRegionFile(pos);
+ final abomination.IRegionFile regionFile = this.getRegionFile(pos); // Luminol - Configurable region file format
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.getRegionFile(pos); // Anonymous - Configurable region file format
if (regionFile.getRecalculateCount() != readData.recalculateCount()) {
return null;
@@ -301,7 +304,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
// Paper end - rewrite chunk system
// Paper start - rewrite chunk system
- public RegionFile getRegionFile(ChunkPos pos) throws IOException {
+ public abomination.IRegionFile getRegionFile(ChunkPos pos) throws IOException { // Luminol - Configurable region file format
+ public io.anonymous.anonymous.data.RegionFile getRegionFile(ChunkPos pos) throws IOException { // Anonymous - Configurable region file format
return this.getRegionFile(pos, false);
}
// Paper end - rewrite chunk system
@@ -310,7 +313,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
}
- @org.jetbrains.annotations.Contract("_, false -> !null") private @Nullable RegionFile getRegionFile(final ChunkPos pos, boolean existingOnly) throws IOException { // CraftBukkit
+ @org.jetbrains.annotations.Contract("_, false -> !null") private abomination.@Nullable IRegionFile getRegionFile(final ChunkPos pos, boolean existingOnly) throws IOException { // CraftBukkit // Luminol - Configurable region file format
+ @org.jetbrains.annotations.Contract("_, false -> !null") private io.anonymous.anonymous.data.RegionFile getRegionFile(final ChunkPos pos, boolean existingOnly) throws IOException { // CraftBukkit // Anonymous - Configurable region file format
// Paper start - rewrite chunk system
if (existingOnly) {
return this.moonrise$getRegionFileIfExists(pos.x(), pos.z());
@@ -319,7 +322,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
final long key = ChunkPos.pack(pos.x() >> REGION_SHIFT, pos.z() >> REGION_SHIFT);
- RegionFile ret = this.regionCache.getAndMoveToFirst(key);
+ abomination.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // Luminol - Configurable region file format
+ io.anonymous.anonymous.data.RegionFile ret = this.regionCache.getAndMoveToFirst(key); // Anonymous - Configurable region file format
if (ret != null) {
return ret;
}
@@ -328,7 +331,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
FileUtil.createDirectoriesSafe(this.folder);
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
+ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // Luminol - Configurable region file format
+ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // Anonymous - Configurable region file format
this.regionCache.putAndMoveToFirst(key, ret);
@@ -337,7 +340,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
}
- private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException {
+ private static CompoundTag readOversizedChunk(abomination.IRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // Luminol - Configurable region file format
+ private static CompoundTag readOversizedChunk(io.anonymous.anonymous.data.RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // Anonymous - Configurable region file format
synchronized (regionfile) {
try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x(), chunkCoordinate.z());
@@ -346,7 +349,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
public @Nullable CompoundTag read(final ChunkPos pos) throws IOException {
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
- RegionFile region = this.getRegionFile(pos, true);
+ abomination.IRegionFile region = this.getRegionFile(pos, true); // Luminol - Configurable region file format
+ io.anonymous.anonymous.data.RegionFile region = this.getRegionFile(pos, true); // Anonymous - Configurable region file format
if (region == null) {
return null;
}
@@ -355,7 +358,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
public void scanChunk(final ChunkPos pos, final StreamTagVisitor scanner) throws IOException {
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
- RegionFile region = this.getRegionFile(pos, true);
+ abomination.IRegionFile region = this.getRegionFile(pos, true); // Luminol - Configurable region file format
+ io.anonymous.anonymous.data.RegionFile region = this.getRegionFile(pos, true); // Anonymous - Configurable region file format
if (region == null) {
return;
}
@@ -364,7 +367,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
public void write(final ChunkPos pos, final @Nullable CompoundTag value) throws IOException {
if (!SharedConstants.DEBUG_DONT_SAVE_WORLD) {
- RegionFile region = this.getRegionFile(pos, value == null); // CraftBukkit // Paper - rewrite chunk system
+ abomination.IRegionFile region = this.getRegionFile(pos, value == null); // CraftBukkit // Paper - rewrite chunk system // Luminol - Configurable region file format
+ io.anonymous.anonymous.data.RegionFile region = this.getRegionFile(pos, value == null); // CraftBukkit // Paper - rewrite chunk system // Anonymous - Configurable region file format
// Paper start - rewrite chunk system
if (region == null) {
// if the RegionFile doesn't exist, no point in deleting from it
@@ -373,7 +376,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
synchronized (this) {
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
- for (final RegionFile regionFile : this.regionCache.values()) {
+ for (final abomination.IRegionFile regionFile : this.regionCache.values()) { // Luminol - Configurable region file format
+ for (final io.anonymous.anonymous.data.RegionFile regionFile : this.regionCache.values()) { // Anonymous - Configurable region file format
try {
regionFile.close();
} catch (final IOException ex) {
@@ -382,7 +385,7 @@ index 63b40c420030d935bb81a219fb33defe0946e21f..2e67e69862cbf5d804de50193442977e
synchronized (this) {
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
- for (final RegionFile regionFile : this.regionCache.values()) {
+ for (final abomination.IRegionFile regionFile : this.regionCache.values()) { // Luminol - Configurable region file format
+ for (final io.anonymous.anonymous.data.RegionFile regionFile : this.regionCache.values()) { // Anonymous - Configurable region file format
try {
regionFile.flush();
} catch (final IOException ex) {
@@ -6,7 +6,7 @@ Subject: [PATCH] Do not enable any debug subscriptions
Really this would really crash the server by accident when the operators used F3 + J or toggled the debug synchronizer
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 924d5f3236d9ba9836f39fc844392099df9cd25c..fe34f2e648df9fd1174522baa5913976104b8d04 100644
index c0e4ddbcf2b1f61fd4a5a6f10882fc1fb4176960..4e1346777c0664547f73f8672ed02918392b591f 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -3483,7 +3483,8 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -6,7 +6,7 @@ Subject: [PATCH] Fix riding statistics desync
Referred to: https://github.com/CraftCanvasMC/Canvas/commit/057175b0c10d5a4d1d9059fd9d077750c32633b2
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index fe34f2e648df9fd1174522baa5913976104b8d04..fee4749c7938779f63155297bf9c7aeb0ca21709 100644
index 4e1346777c0664547f73f8672ed02918392b591f..bc390caff901a3b37a5a4ca3619dd9339fa4cb07 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2516,7 +2516,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -5,7 +5,7 @@ Subject: [PATCH] Fix player auto saving ignores interval
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index fee4749c7938779f63155297bf9c7aeb0ca21709..5668906866917f7bb6088ae16146d917d2b840b0 100644
index bc390caff901a3b37a5a4ca3619dd9339fa4cb07..6e39d752aef322fc1cc12bf221cff057cad18578 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -208,7 +208,7 @@ import org.slf4j.Logger;
@@ -6,7 +6,7 @@ Subject: [PATCH] Force disable builtin spark plugin
The spark passed down from paper has some memory leaking issue, so we fully removed it from the code to prevent that memory leaking issue.
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 83b9aab16124ddcc416f7b4cd95084e1c64fe5b7..7683c12d48d23dd43bce3d3b5633029c596930a5 100644
index c74f76b46259204b33b69ad08bb03c81b8b36961..cc8364891a5d2196e8809479db984b67b5bcb079 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -672,8 +672,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -228,7 +228,7 @@ index 5a72fa0d72bfdb927293abe921c57f6ae964a6ec..f8344f640f119e3865f2718d1abd0ede
private void uncaughtException(final Thread thread, final Throwable thr) {
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 7683c12d48d23dd43bce3d3b5633029c596930a5..ab61d18845827ac835edf92651d0b510358106ff 100644
index cc8364891a5d2196e8809479db984b67b5bcb079..7c67a8a6cf83ab80d3a8b37c5ff03e7a56497bc9 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -236,7 +236,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -275,7 +275,7 @@ index 534f103234eb92571c664cbcfea4ce4e990d3ea8..c4d9d890db784d376b876d70f0468df6
// CraftBukkit start
private final ResourceKey<LevelStem> typeKey;
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 5668906866917f7bb6088ae16146d917d2b840b0..4efbd0f840d74a3d96b28d38e48cba72d5c6fb9b 100644
index 6e39d752aef322fc1cc12bf221cff057cad18578..00dfc496f4e437393f0fc5707f50783418f263f4 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1694,7 +1694,30 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -53,3 +53,15 @@ index c4d9d890db784d376b876d70f0468df6edb75168..0641b98ef3298eb682ceae83f60b730f
} finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ENTITY_TICK); } // Folia - profiler
if (this.paperConfig().unsupportedSettings.ticking.blockEntities) { // Paper - option to disable ticking
profiler.popPush("blockEntities");
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
index 6efaa78faca15c7a48bdffb24480d1bac29f3ba8..31619890f1bd4f458b6f9a31fac8cefaafe09e8e 100644
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
@@ -73,6 +73,7 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
private final float spawnDimensionsScale;
private final FeatureFlagSet requiredFeatures;
private final boolean allowedInPeaceful;
+ public volatile dev.kaiijumc.kaiiju.KaiijuEntityLimits.EntityLimit entityLimit;
public static Identifier getKey(final EntityType<?> type) {
return BuiltInRegistries.ENTITY_TYPE.getKey(type);
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config for server mod name
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index ab61d18845827ac835edf92651d0b510358106ff..d4e31bb829451a687bf567fd0357f46fd7d46902 100644
index 7c67a8a6cf83ab80d3a8b37c5ff03e7a56497bc9..b2823c71ecb5e1f7a3c4c5b9f691d4cdb5419db3 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2072,7 +2072,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -19,7 +19,7 @@ index 9b1dcfadd6d5ae868b087a18983d03e8bb86b56a..21f2b9866e1cf36421e10a945fb6fbaa
DefaultGameModeCommands.register(this.dispatcher);
//DialogCommand.register(this.dispatcher, context); // Folia - region threading - TODO
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index d4e31bb829451a687bf567fd0357f46fd7d46902..4f292468194baae343eeb077362e51dcfb6c0df1 100644
index b2823c71ecb5e1f7a3c4c5b9f691d4cdb5419db3..a82cafadf2136d30ae7bca172062713a651373ac 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2415,6 +2415,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -17,7 +17,7 @@ index 52dcbcf64c3a510d4a4524b7d0ee226d9a73511d..051d601e7e809518e8d82ae4ae325905
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 4f292468194baae343eeb077362e51dcfb6c0df1..f0a3fdaf7e9d342b472b3db42f5b59b0f6691b49 100644
index a82cafadf2136d30ae7bca172062713a651373ac..e43aa6daa8d4465764348be5b82be5f163ef0819 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1743,7 +1743,46 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -106,7 +106,7 @@ index 0641b98ef3298eb682ceae83f60b730f3bf90103..cea4bc7036dfd8777c151a0dd811fc13
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 4efbd0f840d74a3d96b28d38e48cba72d5c6fb9b..8e4bbb224d036cf9f33667aec57bbc339c9e8377 100644
index 00dfc496f4e437393f0fc5707f50783418f263f4..f4fb1f36527e7d29b2b4733bbc7309a162d6949d 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -441,7 +441,9 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -6,7 +6,7 @@ Subject: [PATCH] Add config to enable tick command
only freeze/unfreeze/step/query/rate can run when enabled
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index ff90abb47203c03636d3175f2b3efcf43517b3b0..a2db29aa47a4b7213d4956f02f6e83122ccfdbd1 100644
index ff90abb47203c03636d3175f2b3efcf43517b3b0..a96da8ab0d8ca8241df79fbfca33f3e6072db367 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -239,6 +239,11 @@ public final class RegionizedServer {
@@ -14,7 +14,7 @@ index ff90abb47203c03636d3175f2b3efcf43517b3b0..a2db29aa47a4b7213d4956f02f6e8312
private void globalTick(final long tickCount) {
++this.tickCount;
+ // Luminol start - Add a config to enable tick command
+ if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
+ MinecraftServer.getServer().tickRateManager().tick();
+ }
+ // Luminol end - Add a config to enable tick command
@@ -41,12 +41,12 @@ index ff90abb47203c03636d3175f2b3efcf43517b3b0..a2db29aa47a4b7213d4956f02f6e8312
private void tickTime(final ServerLevel world, final long tickCount) {
- if (world.tickTime) {
+ if ((!me.earthme.luminol.config.modules.experiment.CommandConfig.tick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command
+ if ((!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command // Lophine - redirect
world.serverLevelData.setGameTime(world.serverLevelData.getGameTime() + tickCount);
}
}
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
index 58e557923dfe6cee39ec45e7f5aa43a5ded9f107..57a35d7a801621fc461e896eb2bba533d9d5bc1b 100644
index 58e557923dfe6cee39ec45e7f5aa43a5ded9f107..ae424c8931a2f82c6c8d4ddd8422a2c142a77a95 100644
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
@@ -40,8 +40,8 @@ public final class TickRegionScheduler {
@@ -92,7 +92,7 @@ index 58e557923dfe6cee39ec45e7f5aa43a5ded9f107..57a35d7a801621fc461e896eb2bba533
// next start isn't updated until the end of this tick
this.tickRegion(tickCount, tickStart, scheduledEnd);
+ // Luminol start - Add a config to enable tick command
+ if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
+ MinecraftServer.getServer().tickRateManager().endTickWork();
+ }
+ // Luminol end - Add a config to enable tick command
@@ -100,7 +100,7 @@ index 58e557923dfe6cee39ec45e7f5aa43a5ded9f107..57a35d7a801621fc461e896eb2bba533
this.scheduler.regionFailed(this, false, thr);
// regionFailed will schedule a shutdown, so we should avoid letting this region tick further
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 21f2b9866e1cf36421e10a945fb6fbaa251009ed..aa7931c9b6dc3bba2c8dfecff8df2db302ad905b 100644
index 21f2b9866e1cf36421e10a945fb6fbaa251009ed..409fcc5e95ca453fee7d3bd0375c910d79b507e6 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -259,7 +259,11 @@ public class Commands {
@@ -109,7 +109,7 @@ index 21f2b9866e1cf36421e10a945fb6fbaa251009ed..aa7931c9b6dc3bba2c8dfecff8df2db3
//TestCommand.register(this.dispatcher, context); // Folia - region threading
- //TickCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ // Luminol start - Add a config to enable tick command
+ if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
+ TickCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ }
+ // Luminol end - Add a config to enable tick command
@@ -5,7 +5,7 @@ Subject: [PATCH] Add missing teleportation event APIs for folia
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 8e4bbb224d036cf9f33667aec57bbc339c9e8377..4397f77d0169a3eefd347d3097657de4f6d37ef8 100644
index f4fb1f36527e7d29b2b4733bbc7309a162d6949d..75a36bbd5671992e78fe36a9b3d946ba465919d5 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1803,6 +1803,9 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -69,7 +69,7 @@ index f32d118e1e925b2155cef3fcdcb1e194c541e242..2d5d4170e1f45ae9113c37623b406686
// this is copy on write to allow packet processing to iterate safely
private final CopyOnWriteArrayList<ServerPlayer> localPlayers = new CopyOnWriteArrayList<>();
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index f0a3fdaf7e9d342b472b3db42f5b59b0f6691b49..ac49bcc53951c025de0160fd8afd319b1f3d1347 100644
index e43aa6daa8d4465764348be5b82be5f163ef0819..f4274e844018992bba7c32d2146198efc034631e 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1973,6 +1973,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config for waypoint restoration
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index aa7931c9b6dc3bba2c8dfecff8df2db302ad905b..c67ea715f02086e5a39cc5832ccdc0b32199db93 100644
index 409fcc5e95ca453fee7d3bd0375c910d79b507e6..5a5f7f7fefacaa0d77ec389d6eb332eff519496a 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -267,7 +267,7 @@ public class Commands {
@@ -18,7 +18,7 @@ index aa7931c9b6dc3bba2c8dfecff8df2db302ad905b..c67ea715f02086e5a39cc5832ccdc0b3
WorldBorderCommand.register(this.dispatcher);
if (JvmProfiler.INSTANCE.isAvailable()) {
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index ac49bcc53951c025de0160fd8afd319b1f3d1347..c91902632d0e97b814e387454b119edb62b67413 100644
index f4274e844018992bba7c32d2146198efc034631e..42ee15c813761702031d5a63f0d080b135be2e0f 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -3127,8 +3127,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -8,7 +8,7 @@ A part of Leaf(https://github.com/Winds-Studio/Leaf/blob/edb0504069139beaa6f39ef
License: https://github.com/Winds-Studio/Leaf/blob/edb0504069139beaa6f39efa4702370c2576b3fc/LICENSE.md
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index c91902632d0e97b814e387454b119edb62b67413..4b6f961e695155db1d6cc86496491017bf3a6383 100644
index 42ee15c813761702031d5a63f0d080b135be2e0f..1736816e26c255645d62696814cd539ee1ffed8d 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -217,7 +217,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -8,7 +8,7 @@ As part of: Leaves (https://github.com/LeavesMC/Leaves/blob/4ade1001e4dd19c47d95
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/level/dimension/end/EnderDragonFight.java b/net/minecraft/world/level/dimension/end/EnderDragonFight.java
index 824ef3f458505569fe5b8efb2055ecea7ba6cc56..3388bf5d2cff00b397af1dd7b9ab93669985b35c 100644
index 824ef3f458505569fe5b8efb2055ecea7ba6cc56..7c68effb78bcb17ca64e043f87d6449f90b1b0a7 100644
--- a/net/minecraft/world/level/dimension/end/EnderDragonFight.java
+++ b/net/minecraft/world/level/dimension/end/EnderDragonFight.java
@@ -317,7 +317,67 @@ public class EnderDragonFight extends SavedData {
@@ -21,7 +21,7 @@ index 824ef3f458505569fe5b8efb2055ecea7ba6cc56..3388bf5d2cff00b397af1dd7b9ab9366
+ private int cachePortalOriginIteratorY = -1;
+
public BlockPattern.@Nullable BlockPatternMatch findExitPortal() {
+ if (me.earthme.luminol.config.modules.optimizations.OptimizedDragonRespawnConfig.optimizedRespawn) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.optimizedDragonRespawn) { // Lophine - redirect
+ int i, j;
+ for (i = cachePortalChunkIteratorX; i <= 8; ++i) {
+ for (j = cachePortalChunkIteratorZ; j <= 8; ++j) {
@@ -137,7 +137,7 @@ index 2e71a1cbabf3405e3e4fd5349a1784d895e7e60c..42de919064680b1a464d813976ca5e69
if (!itemStack.isEmpty()) {
slots.add(Pair.of(slot, itemStack.copy()));
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 4397f77d0169a3eefd347d3097657de4f6d37ef8..42e09148519596f95fc9c9c63df9c87e6ece3102 100644
index 75a36bbd5671992e78fe36a9b3d946ba465919d5..e029278822f264bd0c66060cd0031a515d43e98f 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1424,7 +1424,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to enable cross region damage trace
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 42e09148519596f95fc9c9c63df9c87e6ece3102..444753590d3bc96ce68e25a3834d7abb86e20f94 100644
index e029278822f264bd0c66060cd0031a515d43e98f..0a6c85ff078df07f80faf7cfb39d301d5788584e 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1448,6 +1448,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to enable save-all command
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index a2db29aa47a4b7213d4956f02f6e83122ccfdbd1..6fb3c88463ff69bddb7d8dcde0e5339567d3e1c6 100644
index a96da8ab0d8ca8241df79fbfca33f3e6072db367..f881d10d63a665a73aefe03ba1305ca9ae956513 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -265,6 +265,8 @@ public final class RegionizedServer {
@@ -31,7 +31,7 @@ index 97c514673a454b752ab86b944fd143725ca8090d..ba91d40d6d91588a4b39abfefcb17a36
private final Reference2ReferenceOpenHashMap<RegionizedData<?>, Object> regionizedData = new Reference2ReferenceOpenHashMap<>();
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index c67ea715f02086e5a39cc5832ccdc0b32199db93..946094713bdb294d7d8beb03967b2a2488f5359b 100644
index 5a5f7f7fefacaa0d77ec389d6eb332eff519496a..f0f6175569100589102d9d76b3ff8f5546030060 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -299,7 +299,11 @@ public class Commands {
@@ -48,7 +48,7 @@ index c67ea715f02086e5a39cc5832ccdc0b32199db93..946094713bdb294d7d8beb03967b2a24
SaveOnCommand.register(this.dispatcher);
SetPlayerIdleTimeoutCommand.register(this.dispatcher);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 4b6f961e695155db1d6cc86496491017bf3a6383..e7f7f7927fc1e2ce45ea5dbf7cc9ec19197c599f 100644
index 1736816e26c255645d62696814cd539ee1ffed8d..a0c285d2cb666d0f9bd0e859e0dac414254325c3 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1652,6 +1652,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to enable function command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 946094713bdb294d7d8beb03967b2a2488f5359b..3d9e8c5ba567efd363e0ed54059f67fbfe25e361 100644
index f0f6175569100589102d9d76b3ff8f5546030060..ddd656e147cdaeb8f91865117e6f9c268b0fd9bc 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -217,7 +217,11 @@ public class Commands {
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to enable scoreboard command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 3d9e8c5ba567efd363e0ed54059f67fbfe25e361..6642288dde528899d9bce7ccd8d92a199e8975c8 100644
index ddd656e147cdaeb8f91865117e6f9c268b0fd9bc..5fda3083f73744b0df3aab47b3c378dba41b904c 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -246,7 +246,11 @@ public class Commands {
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to enable trigger command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 6642288dde528899d9bce7ccd8d92a199e8975c8..77d7d83cc781baf19593227d20b827bf0be6ed28 100644
index 5fda3083f73744b0df3aab47b3c378dba41b904c..82af03649c7537274aa54ed942e4aae589b97888 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -274,7 +274,11 @@ public class Commands {
@@ -80,10 +80,10 @@ index 43e07a3c98e80f874f55411beac39e215ffdc3cf..cddf44f5da5cba5603dcff4913b4658d
+ // Lophine end - Add config to enable raytracing tracker
}
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
index 6efaa78faca15c7a48bdffb24480d1bac29f3ba8..8a328a41673a3d720f0b1a5de8ce049e360fac1b 100644
index 31619890f1bd4f458b6f9a31fac8cefaafe09e8e..50643bd0b546a1ff70031ea39e2610f219ef8a79 100644
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
@@ -84,6 +84,11 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
@@ -85,6 +85,11 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
public final int passengerTickTimerId;
public final int passengerInactiveTickTimerId;
// Folia end - profiler
@@ -5,7 +5,7 @@ Subject: [PATCH] Spawn invulnerable time
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 444753590d3bc96ce68e25a3834d7abb86e20f94..e64db3045ebf08600283a47960005827c1920f94 100644
index 0a6c85ff078df07f80faf7cfb39d301d5788584e..729fc979fb313ddf2a5c6a04a9a0790440d15830 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -245,6 +245,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -36,7 +36,7 @@ index 08e253662a2c183c0ab53a51cc07485cff33bf2c..1bd678d668a1febc129f4cb4d0d95ea2
};
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index e7f7f7927fc1e2ce45ea5dbf7cc9ec19197c599f..1f13f7b016b4256e92989d83003a983d6ba1c750 100644
index a0c285d2cb666d0f9bd0e859e0dac414254325c3..9614a22c4b67e5e3a46e46fa69d22c136d4beb4b 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2016,6 +2016,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -33,7 +33,7 @@ index d2e9d46bbd9ee4ce45419b11499d7a7bc50f0219..848967dbe41694411603ef369cfdc3a0
private final java.util.concurrent.atomic.AtomicBoolean disconnectionHandled = new java.util.concurrent.atomic.AtomicBoolean(false); // Folia - region threading - may be called concurrently during configuration stage
private int receivedPackets;
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 1f13f7b016b4256e92989d83003a983d6ba1c750..f76e40f8bbea076ad620f7525d4d8666603a5175 100644
index 9614a22c4b67e5e3a46e46fa69d22c136d4beb4b..5bc6baf2a13b78f65e5851a22ca79dbcaed957b2 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -296,6 +296,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -240,7 +240,7 @@ index 3021b70b941ed09c5c58b98d30830a2279b8339c..d289f59475b617ae527d123239297f69
}
}
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 2dae0f4249eade60ac55c9fa289dd146dc3675e1..239cad02f85f0d14d4abfa746ecdc4dd82b04657 100644
index 2dae0f4249eade60ac55c9fa289dd146dc3675e1..f70f6501254b40cf76dc7f9bcd621a1f68e39ea9 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -230,6 +230,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -251,16 +251,17 @@ index 2dae0f4249eade60ac55c9fa289dd146dc3675e1..239cad02f85f0d14d4abfa746ecdc4dd
this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage));
org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings"));
org.spigotmc.SpigotConfig.registerCommands();
@@ -251,6 +252,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
consoleThread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
if (false) this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark // Luminol - Force disable builtin spark
+ this.getBotList().loadResumeBotInfo(); // Leaves - load resident bot info
@@ -254,6 +255,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
+ this.getBotList().loadResumeBotInfo(); // Leaves - load resident bot info
+
// this.worldData.setGameType(properties.gameMode.get()); // CraftBukkit - moved to world loading
LOGGER.info("Default game type: {}", properties.gameMode.get());
// Paper start - Unix domain socket support
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 5196431f52e81608a5575f8a262cd5c855b06182..6d43ca34f38192faf5bb4254d849c5ac51197f48 100644
index 5196431f52e81608a5575f8a262cd5c855b06182..84c047ed0242778a9e6bca5e41561bd1bdcf633c 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -972,7 +972,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
@@ -272,7 +273,21 @@ index 5196431f52e81608a5575f8a262cd5c855b06182..6d43ca34f38192faf5bb4254d849c5ac
org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot
// Paper start - ignore and warn about illegal addEntity calls instead of crashing server
if (!entity.valid || entity.level() != this.level || entity.moonrise$getTrackedEntity() != null) { // Folia - region threading
@@ -1389,6 +1389,13 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
@@ -1258,6 +1258,13 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
ServerPlayer player = conn.getPlayer();
if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player)) {
this.removePlayer(player);
+ // Leaves start - render bot
+ if (entity instanceof org.leavesmc.leaves.bot.ServerBot bot) {
+ if (bot.needSendFakeData(player)) {
+ bot.sendFakeData(player.connection, false);
+ }
+ }
+ // Leaves end - render bot
}
}
}
@@ -1389,6 +1396,13 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
}
} else {
this.removePlayer(player);
@@ -344,7 +359,7 @@ index cb11830c2f399c9706b20f8104686dc0d9b686f9..1c4c67410849f844946e4883585910fc
ServerLevel.this.updateSleepingPlayerList();
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index e64db3045ebf08600283a47960005827c1920f94..a3d3a602ab86e27ae0c6e6207384dc0043279d47 100644
index 729fc979fb313ddf2a5c6a04a9a0790440d15830..a2e83ca70606a00f36f5b5cbac9f08baf8c5494a 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -232,7 +232,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -564,9 +579,18 @@ index cddf44f5da5cba5603dcff4913b4658dcfcc48db..9eaed81a330a22e7fd6585cd286ec613
final boolean xZero = movement.x == 0.0;
final boolean yZero = movement.y == 0.0;
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index cb1589e3aa663ca058fb5c3a24da700d4482cf35..d64c68651b7142869a06ce0200fb625cd45ae235 100644
index cb1589e3aa663ca058fb5c3a24da700d4482cf35..1de8eac336e2dd6335c433b7708ce6b6684553c9 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -2001,7 +2001,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
return 0; // CraftBukkit
}
- protected void dropExperience(ServerLevel level, @Nullable Entity entity) {
+ public void dropExperience(ServerLevel level, @Nullable Entity entity) {
// CraftBukkit start - Update getExpReward() above if the removed if() changes!
if (!(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time
ExperienceOrb.awardWithDirection(level, this.position(), Vec3.ZERO, this.expToDrop, this instanceof ServerPlayer ? org.bukkit.entity.ExperienceOrb.SpawnReason.PLAYER_DEATH : org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, entity, this); // Paper
@@ -3348,7 +3348,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
private void travelRidden(final Player controller, final Vec3 selfInput) {
Vec3 riddenInput = this.getRiddenInput(controller, selfInput);
@@ -88,7 +88,7 @@ index 6c05b9276bdc267a36376f6c64592a50e4b2b36e..21d2c97b3d1e1d29c9de02b6acd58985
result.add(player);
if (result.size() >= limit) {
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index f76e40f8bbea076ad620f7525d4d8666603a5175..77bbc527b017c2ac42ebe4638457caf32868e3f6 100644
index 5bc6baf2a13b78f65e5851a22ca79dbcaed957b2..803faa6b80a42d16687ea8b109973938d02f4a36 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1909,7 +1909,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -551,7 +551,7 @@ index ed50484ca24ef24b1e5bef9f6369dfa4b30c359c..575b4eabcaac48ae87b69dd037493ebf
// Leaves end - fakeplayer support
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index d64c68651b7142869a06ce0200fb625cd45ae235..1fe317cf3251bff7bb3e0335452a5714d4d31017 100644
index 1de8eac336e2dd6335c433b7708ce6b6684553c9..dae262a073acb3bb3464d169dd5a0b6d67f27846 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -276,7 +276,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -36,7 +36,7 @@ index 20fa23988efbfb50c664fa48cc823adbe8e6ce58..1a95ccd745f4789225d711ab6fe497c6
throw PacketUtils.makeReportedException(e, this.packet, this.listener);
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 77bbc527b017c2ac42ebe4638457caf32868e3f6..6ba62c5c6af4fc060442de8dfb069d5fe8ac0c69 100644
index 803faa6b80a42d16687ea8b109973938d02f4a36..6c5cdfebb3a362c51b3b940397e10536dc67afc8 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1998,11 +1998,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -98,7 +98,7 @@ index ae88e57974f631ff2494c35d6e02049ba5d38014..6b8073023833fc9e99684944802dc594
}
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index a3d3a602ab86e27ae0c6e6207384dc0043279d47..70f7cb6b38a90ca337bd52c18fa7bfd4016b552c 100644
index a2e83ca70606a00f36f5b5cbac9f08baf8c5494a..2c15275066923cb488be8e1d7777785466768332 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1111,6 +1111,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -5,7 +5,7 @@ Subject: [PATCH] Carpet features
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index 6fb3c88463ff69bddb7d8dcde0e5339567d3e1c6..7ee9eb8439330724c537f9b1451be78dd3a107ad 100644
index f881d10d63a665a73aefe03ba1305ca9ae956513..7577533f82688304f06c445fd5a1c3fa3c4575fc 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -238,6 +238,7 @@ public final class RegionizedServer {
@@ -15,7 +15,7 @@ index 6fb3c88463ff69bddb7d8dcde0e5339567d3e1c6..7ee9eb8439330724c537f9b1451be78d
+ final long tickStartNanos = System.nanoTime(); // Lophine - Carpet features
++this.tickCount;
// Luminol start - Add a config to enable tick command
if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
@@ -280,6 +281,10 @@ public final class RegionizedServer {
}
// Lophine end - Add a config to enable tick command
@@ -28,7 +28,7 @@ index 6fb3c88463ff69bddb7d8dcde0e5339567d3e1c6..7ee9eb8439330724c537f9b1451be78d
this.tickConnections();
diff --git a/net/minecraft/commands/arguments/blocks/BlockInput.java b/net/minecraft/commands/arguments/blocks/BlockInput.java
index 29dcaa5b33e4f6c649b0918721cfaafe9c74eb01..c7e4f2345c8d48b263eeb537d5fcce3ac43bb59e 100644
index 29dcaa5b33e4f6c649b0918721cfaafe9c74eb01..804f7d9d5b71ccff3c16f4c743081c38b658dd3c 100644
--- a/net/minecraft/commands/arguments/blocks/BlockInput.java
+++ b/net/minecraft/commands/arguments/blocks/BlockInput.java
@@ -65,7 +65,11 @@ public class BlockInput implements Predicate<BlockInWorld> {
@@ -37,7 +37,7 @@ index 29dcaa5b33e4f6c649b0918721cfaafe9c74eb01..c7e4f2345c8d48b263eeb537d5fcce3a
public boolean place(final ServerLevel level, final BlockPos pos, final @Block.UpdateFlags int update) {
- BlockState state = (update & Block.UPDATE_KNOWN_SHAPE) != 0 ? this.state : Block.updateFromNeighbourShapes(this.state, level, pos);
+ // Lophine start - Carpet features
+ BlockState state = (update & Block.UPDATE_KNOWN_SHAPE) != 0 || fun.bm.lophine.carpet.InteractionUpdateCompatHelper.shouldSkipUpdates()
+ BlockState state = (update & Block.UPDATE_KNOWN_SHAPE) != 0 || fun.bm.lophine.carpet.InteractionUpdateHelper.shouldSkipUpdates()
+ ? this.state
+ : Block.updateFromNeighbourShapes(this.state, level, pos);
+ // Lophine end - Carpet features
@@ -128,7 +128,7 @@ index 8cc4fe9feb57902a4b9a6a26e6175ac00a2cef65..9ab1a812e43145120859734075e2ac99
// Paper start - fix converting txt to json file; moved from constructor
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 70f7cb6b38a90ca337bd52c18fa7bfd4016b552c..9a6f18fd0eb7e2aef174b25d14cfd0f5a3ade6af 100644
index 2c15275066923cb488be8e1d7777785466768332..9e8157e6a6df32d00fd1f689a6005ce0f7e0dfbd 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -260,6 +260,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -173,7 +173,7 @@ index 70f7cb6b38a90ca337bd52c18fa7bfd4016b552c..9a6f18fd0eb7e2aef174b25d14cfd0f5
public ClientInformation clientInformation() {
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 77b9cd3d14eddc735d9131597916405fde4230ec..b23a47380fb1178696dc49e35d2c3d7dacb4fd1e 100644
index 77b9cd3d14eddc735d9131597916405fde4230ec..52187fe9d2c907e31cf961a93f599231a70ac08c 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2091,7 +2091,15 @@ public class ServerGamePacketListenerImpl
@@ -185,7 +185,7 @@ index 77b9cd3d14eddc735d9131597916405fde4230ec..b23a47380fb1178696dc49e35d2c3d7d
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.interactionUpdates) {
+ this.player.gameMode.handleBlockBreakAction(pos, action, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence());
+ } else {
+ fun.bm.lophine.carpet.InteractionUpdateCompatHelper.runWithSuppressedUpdates(
+ fun.bm.lophine.carpet.InteractionUpdateHelper.runWithSuppressedUpdates(
+ () -> this.player.gameMode.handleBlockBreakAction(pos, action, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence())
+ );
+ }
@@ -226,7 +226,7 @@ index 77b9cd3d14eddc735d9131597916405fde4230ec..b23a47380fb1178696dc49e35d2c3d7d
+ return action.get();
+ }
+
+ return fun.bm.lophine.carpet.InteractionUpdateCompatHelper.supplyWithSuppressedUpdates(action);
+ return fun.bm.lophine.carpet.InteractionUpdateHelper.supplyWithSuppressedUpdates(action);
+ }
+
+ // Lophine end - Carpet features
@@ -238,7 +238,7 @@ index 77b9cd3d14eddc735d9131597916405fde4230ec..b23a47380fb1178696dc49e35d2c3d7d
final String conversationInput = rawMessage;
this.server.processQueue.add(() -> ServerGamePacketListenerImpl.this.getCraftPlayer().acceptConversationInput(conversationInput));
+ // Lophine start - Carpet features
+ } else if (fun.bm.lophine.carpet.CarpetCalculatorCompatHelper.handleChat(this.player, rawMessage)) {
+ } else if (fun.bm.lophine.carpet.CarpetCalculatorHelper.handleChat(this.player, rawMessage)) {
+ return;
+ // Lophine end - Carpet features
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) { // Re-add "Command Only" flag check
@@ -424,7 +424,7 @@ index b95c56e0699fbe16e65efcf010cd514f0ac0962f..0125d59551accd9005aa33a5c7cc8ec2
return this.entityData.get(DATA_VALUE);
}
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 1fe317cf3251bff7bb3e0335452a5714d4d31017..14a79e8ef5a98b1eef2f2d3e0c63f21cb5bb4dbf 100644
index dae262a073acb3bb3464d169dd5a0b6d67f27846..0990e393c8695b17571d9a7646d895ab07ec30ba 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -623,7 +623,10 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -716,7 +716,7 @@ index 6812ade4d9de26d507234b8357b109ec7e5cbb50..071d2cd7e0c2e5bba0732590ba804a5c
public void addRecipe(RecipeHolder<?> holder) {
org.spigotmc.AsyncCatcher.catchOp("Recipe Add"); // Spigot
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 000e4924e8e338728715a3946002903a3118a98a..55d83a1a97077033191f0f0c220e99095f2a314d 100644
index 000e4924e8e338728715a3946002903a3118a98a..ca92bb3a8b739c0da3f48a2dd16c5fb4fa7e8453 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1179,7 +1179,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -725,7 +725,7 @@ index 000e4924e8e338728715a3946002903a3118a98a..55d83a1a97077033191f0f0c220e9909
if (newState == blockState) {
- if (oldState != newState) {
+ // Lophine start - Carpet features
+ boolean skipInteractionUpdates = fun.bm.lophine.carpet.InteractionUpdateCompatHelper.shouldSkipUpdates();
+ boolean skipInteractionUpdates = fun.bm.lophine.carpet.InteractionUpdateHelper.shouldSkipUpdates();
+ if (skipInteractionUpdates) {
+ updateFlags &= ~Block.UPDATE_NEIGHBORS;
+ }
@@ -744,7 +744,7 @@ index 000e4924e8e338728715a3946002903a3118a98a..55d83a1a97077033191f0f0c220e9909
// CraftBukkit start
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index 0d8d2459457167d78a9a9ea43765980240416947..717cd4b18da2c637fc070c738741f926649b097f 100644
index 0d8d2459457167d78a9a9ea43765980240416947..6da302e1dd755217b82dbc10051324bc8b5d10c1 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -289,6 +289,12 @@ public final class NaturalSpawner {
@@ -753,7 +753,7 @@ index 0d8d2459457167d78a9a9ea43765980240416947..717cd4b18da2c637fc070c738741f926
double nearestPlayerDistanceSqr = nearestPlayer.distanceToSqr(xx, yStart, zz);
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ nearestPlayerDistanceSqr = fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.limitDistanceSq(mobCategory, nearestPlayerDistanceSqr);
+ nearestPlayerDistanceSqr = fun.bm.lophine.carpet.LagFreeSpawningHelper.limitDistanceSq(mobCategory, nearestPlayerDistanceSqr);
+ }
+
+ // Lophine end - Carpet features
@@ -766,7 +766,7 @@ index 0d8d2459457167d78a9a9ea43765980240416947..717cd4b18da2c637fc070c738741f926
if (!mob.isRemoved()) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.markSpawned(level, mob.getType());
+ fun.bm.lophine.carpet.LagFreeSpawningHelper.markSpawned(level, mob.getType());
+ }
+
+ // Lophine end - Carpet features
@@ -780,7 +780,7 @@ index 0d8d2459457167d78a9a9ea43765980240416947..717cd4b18da2c637fc070c738741f926
- && level.noCollision(type.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5));
+ // Lophine start - Carpet features
+ && (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning
+ ? fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.hasNoCollision(level, type.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5))
+ ? fun.bm.lophine.carpet.LagFreeSpawningHelper.hasNoCollision(level, type.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5))
+ : level.noCollision(type.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5)));
+ // Lophine end - Carpet features
return success ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent
@@ -789,7 +789,7 @@ index 0d8d2459457167d78a9a9ea43765980240416947..717cd4b18da2c637fc070c738741f926
private static @Nullable Mob getMobForSpawn(final ServerLevel level, final EntityType<?> type) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ Mob cachedMob = fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.getOrCreateMob(level, type);
+ Mob cachedMob = fun.bm.lophine.carpet.LagFreeSpawningHelper.getOrCreateMob(level, type);
+ if (cachedMob != null) {
+ return cachedMob;
+ }
@@ -806,7 +806,7 @@ index 0d8d2459457167d78a9a9ea43765980240416947..717cd4b18da2c637fc070c738741f926
- if (!level.noCollision(spawnerData.type().getSpawnAABB(fx, pos.getY(), fz))
+ // Lophine start - Carpet features
+ if (!(fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning
+ ? fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.hasNoCollision(level.getLevel(), spawnerData.type().getSpawnAABB(fx, pos.getY(), fz))
+ ? fun.bm.lophine.carpet.LagFreeSpawningHelper.hasNoCollision(level.getLevel(), spawnerData.type().getSpawnAABB(fx, pos.getY(), fz))
+ : level.noCollision(spawnerData.type().getSpawnAABB(fx, pos.getY(), fz)))
+ // Lophine end - Carpet features
|| !SpawnPlacements.checkSpawnRules(
@@ -818,7 +818,7 @@ index 0d8d2459457167d78a9a9ea43765980240416947..717cd4b18da2c637fc070c738741f926
level.addFreshEntityWithPassengers(mob, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.markSpawned(level.getLevel(), mob.getType());
+ fun.bm.lophine.carpet.LagFreeSpawningHelper.markSpawned(level.getLevel(), mob.getType());
+ }
+ // Lophine end - Carpet features
success = true;
@@ -1182,7 +1182,7 @@ index 972b953a579120c1c05f2dc9bfc2b408d6071d26..a60bb8af6b6aa356193befa9d7e9cdfc
return function != null ? function.evaluate(this.asState(), pos) : Vec3.ZERO;
}
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index a4d5bf1773a9ce8184a940384696f0d38690a421..cd8ccc6de723bc01390b0439382ea69c775640ba 100644
index a4d5bf1773a9ce8184a940384696f0d38690a421..5b306cc2d4a3cdc3ce08595dc63975c87fca9d3f 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -425,10 +425,10 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
@@ -1190,7 +1190,7 @@ index a4d5bf1773a9ce8184a940384696f0d38690a421..cd8ccc6de723bc01390b0439382ea69c
boolean movedByPiston = (flags & Block.UPDATE_MOVE_BY_PISTON) != 0;
boolean sideEffects = (flags & Block.UPDATE_SKIP_BLOCK_ENTITY_SIDEEFFECTS) == 0;
- // Leaves start - behaviour 1.21.1-
+ boolean skipInteractionUpdates = fun.bm.lophine.carpet.InteractionUpdateCompatHelper.shouldSkipUpdates(); // Lophine - Carpet features// Leaves start - behaviour 1.21.1-
+ boolean skipInteractionUpdates = fun.bm.lophine.carpet.InteractionUpdateHelper.shouldSkipUpdates(); // Lophine - Carpet features// Leaves start - behaviour 1.21.1-
if (!fun.bm.lophine.config.modules.experiment.RedStoneConfig.oldBlockRemoveBehaviour) {
if (blockChanged && oldState.hasBlockEntity() && !state.shouldChangedStateKeepBlockEntity(oldState)) {
- if (!this.level.isClientSide() && sideEffects) {
@@ -1,67 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 21 Jan 2026 21:28:21 +0800
Subject: [PATCH] Carpet Features Compatible
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index 7ee9eb8439330724c537f9b1451be78dd3a107ad..7577533f82688304f06c445fd5a1c3fa3c4575fc 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -241,7 +241,7 @@ public final class RegionizedServer {
final long tickStartNanos = System.nanoTime(); // Lophine - Carpet features
++this.tickCount;
// Luminol start - Add a config to enable tick command
- if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
MinecraftServer.getServer().tickRateManager().tick();
}
// Luminol end - Add a config to enable tick command
@@ -435,7 +435,7 @@ public final class RegionizedServer {
}
private void tickTime(final ServerLevel world, final long tickCount) {
- if ((!me.earthme.luminol.config.modules.experiment.CommandConfig.tick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command
+ if ((!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command // Lophine - redirect
world.serverLevelData.setGameTime(world.serverLevelData.getGameTime() + tickCount);
}
}
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
index 57a35d7a801621fc461e896eb2bba533d9d5bc1b..ae424c8931a2f82c6c8d4ddd8422a2c142a77a95 100644
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
@@ -576,7 +576,7 @@ public final class TickRegionScheduler {
// next start isn't updated until the end of this tick
this.tickRegion(tickCount, tickStart, scheduledEnd);
// Luminol start - Add a config to enable tick command
- if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
MinecraftServer.getServer().tickRateManager().endTickWork();
}
// Luminol end - Add a config to enable tick command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 77d7d83cc781baf19593227d20b827bf0be6ed28..82af03649c7537274aa54ed942e4aae589b97888 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -268,7 +268,7 @@ public class Commands {
TellRawCommand.register(this.dispatcher, context);
//TestCommand.register(this.dispatcher, context); // Folia - region threading
// Luminol start - Add a config to enable tick command
- if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
TickCommand.register(this.dispatcher); // Folia - region threading - TODO later
}
// Luminol end - Add a config to enable tick command
diff --git a/net/minecraft/world/level/dimension/end/EnderDragonFight.java b/net/minecraft/world/level/dimension/end/EnderDragonFight.java
index 3388bf5d2cff00b397af1dd7b9ab93669985b35c..e70a6c295e8c26bdf56528826801f037ad0f93b0 100644
--- a/net/minecraft/world/level/dimension/end/EnderDragonFight.java
+++ b/net/minecraft/world/level/dimension/end/EnderDragonFight.java
@@ -323,7 +323,7 @@ public class EnderDragonFight extends SavedData {
private int cachePortalOriginIteratorY = -1;
public BlockPattern.@Nullable BlockPatternMatch findExitPortal() {
- if (me.earthme.luminol.config.modules.optimizations.OptimizedDragonRespawnConfig.optimizedRespawn) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.optimizedDragonRespawn) { // Lophine - Carpet Features Compatible
int i, j;
for (i = cachePortalChunkIteratorX; i <= 8; ++i) {
for (j = cachePortalChunkIteratorZ; j <= 8; ++j) {
@@ -21,7 +21,7 @@ index dd17339fe2f9d7660b20eed05b61d6231302aa82..d997e4f7ae6ee4e81f5fffe874f2895d
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 9a6f18fd0eb7e2aef174b25d14cfd0f5a3ade6af..b43bbe461500782a75a49c9238bd4d4d81448d09 100644
index 9e8157e6a6df32d00fd1f689a6005ce0f7e0dfbd..2da765eb74c4e84254857ad05b7af82eb8500fc3 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2339,7 +2339,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -34,7 +34,7 @@ index 9a6f18fd0eb7e2aef174b25d14cfd0f5a3ade6af..b43bbe461500782a75a49c9238bd4d4d
}
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 14a79e8ef5a98b1eef2f2d3e0c63f21cb5bb4dbf..429116ab6bac69054a30b0c766ea5d0186877fae 100644
index 0990e393c8695b17571d9a7646d895ab07ec30ba..386033fa4ba0fb705593e0c9f9cc6574c0ab55ac 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -4004,7 +4004,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -99,7 +99,7 @@ index 6130c477349096d5912dce859b616661e2f43b36..c8c433dcfef3442ff8385c9fc1f1ea47
return true;
} // Paper - Add phantom creative and insomniac controls
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index 717cd4b18da2c637fc070c738741f926649b097f..dfb85696affef368d85f93cb0b465abb88267aa1 100644
index 6da302e1dd755217b82dbc10051324bc8b5d10c1..e333abe5bcdd0c571682550d43c7e88d9f6f3296 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -90,7 +90,8 @@ public final class NaturalSpawner {
@@ -5,7 +5,7 @@ Subject: [PATCH] Restore vanilla ender pearl loading
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index b43bbe461500782a75a49c9238bd4d4d81448d09..68e36ad03325cd6348dc4bbab37409b70bee6023 100644
index 2da765eb74c4e84254857ad05b7af82eb8500fc3..d0b9f4140952d0d0416b257077a885d352b40bd1 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -277,7 +277,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 28 Jul 2026 15:08:10 +0800
Subject: [PATCH] Anonymous Object: Fix wrong variable passing in
RegionizedWorldData
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
index 3a50e625160d0dad6bd8fa534b719087dae7881d..20439c632044ae9b4358bfba309b378b3de98601 100644
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
@@ -841,7 +841,7 @@ public final class RegionizedWorldData {
}
public void setTickingBlockEntities(final boolean to) {
- this.tickingBlockEntities = true;
+ this.tickingBlockEntities = to; // Anonymous - Fix wrong variable passing in RegionizedWorldData
}
public List<TickingBlockEntity> getBlockEntityTickers() {
@@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 28 Jul 2026 15:08:28 +0800
Subject: [PATCH] Anonymous Object: Fix wrong variable passing in
ThreadedRegionizer
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/io/papermc/paper/threadedregions/ThreadedRegionizer.java b/io/papermc/paper/threadedregions/ThreadedRegionizer.java
index a346b96500ae859e9469c80e2ff6b39c4d3d0b52..73e0aeb5a5e9bdd1f275dd64d1fffa32c389052d 100644
--- a/io/papermc/paper/threadedregions/ThreadedRegionizer.java
+++ b/io/papermc/paper/threadedregions/ThreadedRegionizer.java
@@ -755,8 +755,8 @@ public final class ThreadedRegionizer<R extends ThreadedRegionizer.ThreadedRegio
final int x1 = CoordinateUtils.getChunkX(k1);
final int x2 = CoordinateUtils.getChunkX(k2);
- final int z1 = CoordinateUtils.getChunkZ(x1);
- final int z2 = CoordinateUtils.getChunkZ(x2);
+ final int z1 = CoordinateUtils.getChunkZ(k1); // Anonymous - Fix wrong variable passing in ThreadedRegionizer
+ final int z2 = CoordinateUtils.getChunkZ(k2); // Anonymous - Fix wrong variable passing in ThreadedRegionizer
final int zCompare = Integer.compare(z1, z2);
if (zCompare != 0) {
@@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 28 Jul 2026 15:08:42 +0800
Subject: [PATCH] Anonymous Object: Fix wrong ticket update determination in
RegionizedTaskQueue
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
index b264dbd13a392cde3f24ff75c0034985fda68ccc..fe0a6bd90cba4869a0ee11723832f2dee5039f62 100644
--- a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
+++ b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
@@ -289,14 +289,17 @@ public final class RegionizedTaskQueue {
boolean executeTickTasks = allowedTickTasks > 0;
boolean executeChunkTasks = allowedChunkTasks > 0;
boolean executeGlobalTasks = true;
+ boolean processedChunkTask = false; // Anonymous - Fix wrong ticket update determination in RegionizedTaskQueue
do {
executeTickTasks = executeTickTasks && allowedTickTasks-- > 0 && tickTaskQueue.executeTask();
executeChunkTasks = executeChunkTasks && allowedChunkTasks-- > 0 && chunkTaskQueue.executeTask();
executeGlobalTasks = executeGlobalTasks && this.worldRegionTaskData.executeGlobalChunkTask();
+
+ processedChunkTask |= (executeChunkTasks | executeGlobalTasks); // Anonymous - Fix wrong ticket update determination in RegionizedTaskQueue
} while (executeTickTasks | executeChunkTasks | executeGlobalTasks);
- if (allowedChunkTasks > 0) {
+ if (processedChunkTask) { // Anonymous - Fix wrong ticket update determination in RegionizedTaskQueue
// if we executed chunk tasks, we should try to process ticket updates for full status changes
this.worldRegionTaskData.world.moonrise$getChunkTaskScheduler().chunkHolderManager.processTicketUpdates();
}
@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 28 Jul 2026 15:09:06 +0800
Subject: [PATCH] Anonymous Object: Lithium optimized collections for
WeightedList
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/util/random/WeightedList.java b/net/minecraft/util/random/WeightedList.java
index a8481259e42aa116e29bccd1e30fdfd91f51a8cc..49a558d6021db2d57eb2596206ea459fd33485e0 100644
--- a/net/minecraft/util/random/WeightedList.java
+++ b/net/minecraft/util/random/WeightedList.java
@@ -23,7 +23,7 @@ public class WeightedList<E> { // Paper - non-final
private final WeightedList.@Nullable Selector<E> selector;
protected WeightedList(final List<? extends Weighted<E>> items) { // Paper - protected
- this.items = List.copyOf(items);
+ this.items = items.size() > 4 ? new net.caffeinemc.mods.lithium.common.util.collections.HashedReferenceList(items) : new it.unimi.dsi.fastutil.objects.ReferenceArrayList<>(items); // Anonymous - Lithium optimized collections for WeightedList
this.totalWeight = WeightedRandom.getTotalWeight(items, Weighted::weight);
if (this.totalWeight == 0) {
this.selector = null;
@@ -0,0 +1,282 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 28 Jul 2026 15:09:19 +0800
Subject: [PATCH] Anonymous Object: Lithium optimized non poi block searching
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
index c6e9b155c2341c13d569f28f54f0c1d2d7313676..927635518c51375315390877d582b32fc38748df 100644
--- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
+++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
@@ -5,7 +5,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.level.LevelReader;
-public abstract class MoveToBlockGoal extends Goal {
+public abstract class MoveToBlockGoal extends Goal implements net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.LithiumMoveToBlockGoal { // Anonymous - Lithium Optimizes move to block goal
private static final int GIVE_UP_TICKS = 1200;
private static final int STAY_TICKS = 1200;
private static final int INTERVAL_TICKS = 200;
@@ -133,4 +133,167 @@ public abstract class MoveToBlockGoal extends Goal {
}
protected abstract boolean isValidTarget(LevelReader level, BlockPos pos);
+ // Anonymous start - Lithium Optimizes move to block goal
+ /**
+ * Finds the nearest block matching the predicates.
+ * <p>
+ * Side effect: The matching block position is stored in the blockPos field.
+ *
+ * @return Whether a matching block was found.
+ */
+ @Override
+ public boolean lithium$findNearestBlock(java.util.function.Predicate<net.minecraft.world.level.block.state.BlockState> requiredBlock, java.util.function.BiPredicate<net.minecraft.world.level.chunk.ChunkAccess,
+ BlockPos.MutableBlockPos> lithium$isValidTarget, final boolean shouldChunkLoad) {
+ //Center of the search starts 1 block below the mob's block position
+ BlockPos center = this.mob.blockPosition().offset(0,-1,0);
+
+ //Range is +-(searchRange - 1), +-verticalSearchRange, +-(searchRange - 1)
+ //Cache ChunkAccesses - getting them is surprisingly expensive - and track whether subchunks have the block
+ final LevelReader levelReader = this.mob.level();
+ net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.CheckAndCacheBlockChecker checker = new net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.CheckAndCacheBlockChecker(center,
+ this.searchRange-1, this.verticalSearchRange,
+ levelReader, requiredBlock, shouldChunkLoad);
+ it.unimi.dsi.fastutil.longs.LongArrayList sortedChunksMaybeWithBlock = new it.unimi.dsi.fastutil.longs.LongArrayList(checker.getChunkSize());
+ checker.initializeChunks(sortedChunksMaybeWithBlock::addLast);
+
+ if (checker.shouldStop()) {
+ return false; //No chunks with the target block - return early
+ }
+
+ final int minY = net.caffeinemc.mods.lithium.common.util.Pos.BlockCoord.getMinY(levelReader);
+ final int maxY = net.caffeinemc.mods.lithium.common.util.Pos.BlockCoord.getMaxYInclusive(levelReader);
+
+ // Prefer chunk aware search because it also cuts iterations inside "empty" chunk sections
+ if(!checker.hasUnloadedPossibleChunks()){
+ return this.lithium$chunkAwareSearch(center, lithium$isValidTarget, checker, sortedChunksMaybeWithBlock, minY, maxY);
+ }
+
+ // Use vanilla search because unordered search may observably alter chunk-loading behavior
+ return this.lithium$vanillaOrderSearch(center, lithium$isValidTarget, checker, minY, maxY);
+ }
+
+ private boolean lithium$vanillaOrderSearch(BlockPos center,
+ java.util.function.BiPredicate<net.minecraft.world.level.chunk.ChunkAccess, BlockPos.MutableBlockPos> lithium$isValidTarget,
+ net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.CheckAndCacheBlockChecker checker, final int minY, final int maxY) {
+ BlockPos.MutableBlockPos currentPos = new BlockPos.MutableBlockPos();
+ final int centerY = center.getY();
+
+ for (int layer = this.verticalSearchStart; layer <= this.verticalSearchRange; layer = layer > 0 ? -layer : 1 - layer) {
+ final int y = centerY + layer;
+
+ // Layer outside of build limit - skip
+ // Note: this is likely to be hit because farms where this lags tend to be built at world floor
+ if (y < minY || y > maxY) {
+ continue;
+ }
+
+ for (int ring = 0; ring < this.searchRange; ring++) {
+ for (int dX = 0; dX <= ring; dX = dX > 0 ? -dX : 1 - dX) {
+ for (int dZ = dX < ring && dX > -ring ? ring : 0; dZ <= ring; dZ = dZ > 0 ? -dZ : 1 - dZ) {
+ currentPos.setWithOffset(center, dX, layer, dZ);
+ if (this.mob.isWithinHome(currentPos) && checker.checkPosition(currentPos)) {
+ // ChunkAccess is always loaded at this point
+ net.minecraft.world.level.chunk.ChunkAccess chunkAccess = checker.getCachedChunkAccess(currentPos);
+ if (lithium$isValidTarget.test(chunkAccess, currentPos)){
+ this.blockPos = currentPos;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private boolean lithium$chunkAwareSearch(BlockPos center,
+ java.util.function.BiPredicate<net.minecraft.world.level.chunk.ChunkAccess, BlockPos.MutableBlockPos> lithium$isValidTarget,
+ net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.CheckAndCacheBlockChecker checker, it.unimi.dsi.fastutil.longs.LongArrayList sortedChunksMaybeWithBlock,
+ final int minY, final int maxY) {
+ // Sort chunks by lowest sort order - has the earliest searched position
+ // Note: In this search order, the closest point normally is also the closest point in the search
+ sortedChunksMaybeWithBlock.sort((chunkLong0, chunkLong1) ->
+ net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.NonPOISearchDistances.MoveToBlockGoalDistances.getMinimumSortOrderOfChunk(center, chunkLong0)
+ - net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.NonPOISearchDistances.MoveToBlockGoalDistances.getMinimumSortOrderOfChunk(center, chunkLong1)
+ );
+
+ java.util.function.Predicate<net.minecraft.world.level.block.state.BlockState> requiredBlock = checker.blockStatePredicate;
+ final int minSectionY = checker.minSectionY;
+
+ BlockPos.MutableBlockPos foundPos = new BlockPos.MutableBlockPos();
+ BlockPos.MutableBlockPos currentPos = new BlockPos.MutableBlockPos();
+
+ // Same layer order as vanilla - saves iterations if targets are found in the first layer
+ for (int layer = this.verticalSearchStart; layer <= this.verticalSearchRange; layer = layer > 0 ? -layer : 1 - layer) {
+ final int y = center.getY() + layer;
+
+ // Layer outside of build limit - skip
+ // Note: this is likely to be hit because farms where this lags tend to be built at world floor
+ if (y < minY || y > maxY) {
+ continue;
+ }
+
+ final int chunkY = net.minecraft.core.SectionPos.blockToSectionCoord(y);
+ final int ySectionIndex = chunkY - minSectionY;
+
+ int closestFound = Integer.MAX_VALUE;
+ int ringMax = this.searchRange - 1;
+
+ // Iterate through slices of chunks that may have the target blockState
+ for (long chunkPos: sortedChunksMaybeWithBlock) {
+ final int chunkX = net.minecraft.world.level.ChunkPos.getX(chunkPos);
+ final int chunkZ = net.minecraft.world.level.ChunkPos.getZ(chunkPos);
+
+ // Break since no subsequent chunks can be closer
+ if (closestFound < net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.NonPOISearchDistances.MoveToBlockGoalDistances.getMinimumSortOrderOfChunk(center, chunkX, chunkZ)) {
+ break;
+ }
+
+ // Skip if the current subchunk does not have the block
+ if (!checker.checkCachedSection(chunkX, chunkY, chunkZ)) {
+ continue;
+ }
+
+ net.minecraft.world.level.chunk.ChunkAccess chunkAccess = checker.getCachedChunkAccess(chunkPos);
+ // If ChunkSection may have close enough targets, iterate layer in Paletted Container (x then z) order
+ final int chunkBlockX = net.minecraft.core.SectionPos.sectionToBlockCoord(chunkX);
+ int xMin = Math.max(center.getX() - ringMax, chunkBlockX);
+ int xMax = Math.min(center.getX() + ringMax, chunkBlockX + 15);
+ final int chunkBlockZ = net.minecraft.core.SectionPos.sectionToBlockCoord(chunkZ);
+ int zMin = Math.max(center.getZ() - ringMax, chunkBlockZ);
+ int zMax = Math.min(center.getZ() + ringMax, chunkBlockZ + 15);
+ net.minecraft.world.level.chunk.LevelChunkSection levelChunkSection = chunkAccess.getSections()[ySectionIndex];
+ for (int z = zMin; z <= zMax; z++) {
+ for (int x = xMin; x <= xMax; x++) {
+ int dX = x - center.getX();
+ int dZ = z - center.getZ();
+ int ring = net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.NonPOISearchDistances.MoveToBlockGoalDistances.getRing(dX, dZ);
+ int currentDistance = net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.NonPOISearchDistances.MoveToBlockGoalDistances.getVanillaSortOrderInt(ring, dX, dZ);
+ if (currentDistance < closestFound
+ && this.mob.isWithinHome(currentPos.set(x, y, z))
+ && requiredBlock.test(levelChunkSection.getBlockState(x & 15, y & 15, z & 15))
+ && lithium$isValidTarget.test(chunkAccess, currentPos)) {
+ // Constrain search size when we find a valid target
+ ringMax = ring;
+ xMin = Math.max(center.getX() - ringMax, chunkBlockX);
+ xMax = Math.min(center.getX() + ringMax, chunkBlockX + 15);
+ zMax = Math.min(center.getZ() + ringMax, chunkBlockZ + 15);
+ foundPos.set(x, y, z);
+ closestFound = currentDistance;
+ }
+ }
+ }
+ }
+
+ if (closestFound < Integer.MAX_VALUE) {
+ // Vanilla uses the mutable pos, no need to create immutable copy
+ this.blockPos = foundPos;
+ return true;
+ }
+ }
+
+ return false;
+ }
+ // Anonymous end - Lithium Optimizes move to block goal
}
diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
index ff0f99d4b560a1c0721885b0eba5bd5ab2087bd7..99c076ee2fe0d8294398c5ef1f24a95da5eee89c 100644
--- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
+++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
@@ -25,6 +25,19 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
private final Mob removerMob;
private int ticksSinceReachedGoal;
private static final int WAIT_AFTER_BLOCK_FOUND = 20;
+ // Anonymous start - Lithium Optimize remove block goal
+ private static final java.util.function.BiPredicate<ChunkAccess, BlockPos.MutableBlockPos> IS_VALID_TARGET_ABOVE_BIPREDICATE =
+ RemoveBlockGoal::lithium$isValidTargetAbove;
+ //Split check condition in order to use maybeHas
+ private boolean lithium$isValidTargetBlock(net.minecraft.world.level.block.state.BlockState blockState){
+ return blockState.is(this.blockToRemove);
+ }
+
+ private static boolean lithium$isValidTargetAbove(ChunkAccess chunkAccess, BlockPos.MutableBlockPos mutable) {
+ return chunkAccess.getBlockState(mutable.move(0, 1, 0)).isAir()
+ && chunkAccess.getBlockState(mutable.move(0, 1, 0)).isAir();
+ }
+ // Anonymous end - Lithium Optimize remove block goal
public RemoveBlockGoal(final Block blockToRemove, final PathfinderMob mob, final double speedModifier, final int verticalSearchRange) {
super(mob, speedModifier, 24, verticalSearchRange);
@@ -39,7 +52,7 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
} else if (this.nextStartTick > 0) {
this.nextStartTick--;
return false;
- } else if (this.findNearestBlock()) {
+ } else if (((net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.LithiumMoveToBlockGoal) this).lithium$findNearestBlock(this::lithium$isValidTargetBlock, IS_VALID_TARGET_ABOVE_BIPREDICATE, false)) { // Anonymous - Lithium Optimize remove block goal
this.nextStartTick = reducedTickDelay(20);
return true;
} else {
diff --git a/net/minecraft/world/entity/ai/sensing/HoglinSpecificSensor.java b/net/minecraft/world/entity/ai/sensing/HoglinSpecificSensor.java
index 7022679c84e184999b416e06d1af2cc2500cb12b..78743515ff2afd1ea1f06432f33f41a03fc7988b 100644
--- a/net/minecraft/world/entity/ai/sensing/HoglinSpecificSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/HoglinSpecificSensor.java
@@ -16,6 +16,14 @@ import net.minecraft.world.entity.monster.hoglin.Hoglin;
import net.minecraft.world.entity.monster.piglin.Piglin;
public class HoglinSpecificSensor extends Sensor<Hoglin> {
+ // Anonymous start - Lithium Optimizes Hoglin repellent search.
+ private static final java.util.function.Predicate<net.minecraft.world.level.block.state.BlockState> IS_VALID_REPELLENT_PREDICATE =
+ HoglinSpecificSensor::lithium$isValidRepellent;
+
+ private static boolean lithium$isValidRepellent(net.minecraft.world.level.block.state.BlockState blockState) {
+ return blockState.is(BlockTags.HOGLIN_REPELLENTS);
+ }
+ // Anonymous end - Lithium Optimizes Hoglin repellent search.
@Override
public Set<MemoryModuleType<?>> requires() {
return ImmutableSet.of(
@@ -30,8 +38,8 @@ public class HoglinSpecificSensor extends Sensor<Hoglin> {
@Override
protected void doTick(final ServerLevel level, final Hoglin body) {
- Brain<?> brain = body.getBrain();
- brain.setMemory(MemoryModuleType.NEAREST_REPELLENT, this.findNearestRepellent(level, body));
+ Brain<?> brain = body.getBrain();;
+ brain.setMemory(MemoryModuleType.NEAREST_REPELLENT, net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.CommonBlockSearchesCheckAndCache.blockPosFindClosestMatch(level, body, 8, 4, IS_VALID_REPELLENT_PREDICATE, true)); // Anonymous - Lithium Optimizes Hoglin repellent search.
Optional<Piglin> adultPiglin = Optional.empty();
int adultPiglinCount = 0;
List<Hoglin> adultHoglins = Lists.newArrayList();
diff --git a/net/minecraft/world/entity/ai/sensing/PiglinSpecificSensor.java b/net/minecraft/world/entity/ai/sensing/PiglinSpecificSensor.java
index 060a53da799a3036a343cc6f1d73e3e5ca4b7af9..8594f559a5c8f5957348f7178464d5e9c5abc5ff 100644
--- a/net/minecraft/world/entity/ai/sensing/PiglinSpecificSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/PiglinSpecificSensor.java
@@ -26,6 +26,15 @@ import net.minecraft.world.level.block.CampfireBlock;
import net.minecraft.world.level.block.state.BlockState;
public class PiglinSpecificSensor extends Sensor<LivingEntity> {
+ // Anonymous start - Lithium Optimizes Piglin repellent search.
+ private static final java.util.function.Predicate<BlockState> IS_VALID_REPELLENT_PREDICATE =
+ PiglinSpecificSensor::lithium$isValidRepellent;
+ private static boolean lithium$isValidRepellent(BlockState blockState){
+ final boolean isPiglinRepellent = blockState.is(BlockTags.PIGLIN_REPELLENTS);
+ return isPiglinRepellent && blockState.is(Blocks.SOUL_CAMPFIRE) ?
+ CampfireBlock.isLitCampfire(blockState) : isPiglinRepellent;
+ }
+ // Anonymous end - Lithium Optimizes Piglin repellent search.
@Override
public Set<MemoryModuleType<?>> requires() {
return ImmutableSet.of(
@@ -47,7 +56,7 @@ public class PiglinSpecificSensor extends Sensor<LivingEntity> {
@Override
protected void doTick(final ServerLevel level, final LivingEntity body) {
Brain<?> brain = body.getBrain();
- brain.setMemory(MemoryModuleType.NEAREST_REPELLENT, findNearestRepellent(level, body));
+ brain.setMemory(MemoryModuleType.NEAREST_REPELLENT, net.caffeinemc.mods.lithium.common.ai.non_poi_block_search.CommonBlockSearchesCheckAndCache.blockPosFindClosestMatch(level, body, 8, 4, IS_VALID_REPELLENT_PREDICATE, true)); // Anonymous - Lithium Optimizes Piglin repellent search.
Optional<Mob> nemesis = Optional.empty();
Optional<Hoglin> huntableHoglin = Optional.empty();
Optional<Hoglin> babyHoglin = Optional.empty();
@@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 28 Jul 2026 20:40:01 +0800
Subject: [PATCH] Anonymous Object: Fix folia nether portal ticket placement
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/util/BlockUtil.java b/net/minecraft/util/BlockUtil.java
index ea93ac07ec6d4e83d1d0904daf721132e2bbecc3..4252672ad2aaf03d50e5ea6a681e9964fd9a6137 100644
--- a/net/minecraft/util/BlockUtil.java
+++ b/net/minecraft/util/BlockUtil.java
@@ -138,12 +138,20 @@ public class BlockUtil {
public final BlockPos minCorner;
public final int axis1Size;
public final int axis2Size;
+ public BlockPos foundOrigin; // Anonymous - Fix folia nether portal ticket placement
public FoundRectangle(final BlockPos minCorner, final int axis1Size, final int axis2Size) {
this.minCorner = minCorner;
this.axis1Size = axis1Size;
this.axis2Size = axis2Size;
+ this.foundOrigin = minCorner; // Anonymous - Fix folia nether portal ticket placement - prevent edge conditions(idk if someone would do this so just prevent it)
}
+ // Anonymous start - Fix folia nether portal ticket placement
+ public FoundRectangle withFoundOrigin(BlockPos origin) {
+ this.foundOrigin = origin;
+ return this;
+ }
+ // Anonymous end
}
public static class IntBounds {
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index acc9caf8559cd341ea17d3b58f13cdac7de18564..489011f9af49fa3407038bd2f00439443307d179 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -4851,7 +4851,7 @@ public abstract class Entity
portalInfoCompletable.complete(
new TeleportTransition(destination, Vec3.atCenterOf(targetPos), Vec3.ZERO,
90.0f, 0.0f,
- TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET))
+ TeleportTransition.PLAY_PORTAL_SOUND.then(ent -> ent.placePortalTicket(targetPos))) // Anonymous - Fix folia nether portal ticket placement
);
return;
}
@@ -4863,7 +4863,7 @@ public abstract class Entity
portalInfoCompletable.complete(
net.minecraft.world.level.block.NetherPortalBlock.createDimensionTransition(
destination, portal, originalPortalDirection, relativePos,
- Entity.this, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET)
+ Entity.this, TeleportTransition.PLAY_PORTAL_SOUND.then(ent -> ent.placePortalTicket(portal.foundOrigin)) // Anonymous - Fix folia nether portal ticket placement
)
);
}
diff --git a/net/minecraft/world/level/block/NetherPortalBlock.java b/net/minecraft/world/level/block/NetherPortalBlock.java
index 29fc9521c2c8333c999647dd833899393a838064..e8d2b52a3948755c8d3912a4ad1204cea5f78674 100644
--- a/net/minecraft/world/level/block/NetherPortalBlock.java
+++ b/net/minecraft/world/level/block/NetherPortalBlock.java
@@ -204,7 +204,7 @@ public class NetherPortalBlock extends Block implements Portal {
return BlockUtil.getLargestRectangleAround(found, portalState.getValue(BlockStateProperties.HORIZONTAL_AXIS), 21, Direction.Axis.Y, 21, (pos) -> {
return world.getBlockStateFromEmptyChunk(pos) == portalState;
- });
+ }).withFoundOrigin(found); // Anonymous - Fix folia nether portal ticket placement
}
// Folia end - region threading
@@ -0,0 +1,146 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sat, 1 Aug 2026 16:30:53 +0800
Subject: [PATCH] Anonymous Object: RegionizedTaskQueue queue TTL optimization
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
index fe0a6bd90cba4869a0ee11723832f2dee5039f62..53579b6faa9d55485088d59ec2fd1e4251c2fb01 100644
--- a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
+++ b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
@@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicLong;
public final class RegionizedTaskQueue {
private static final TicketType<Long> TASK_QUEUE_TICKET = ChunkSystemTicketType.create("task_queue_ticket", Long::compareTo);
+ private static final long QUEUE_MAX_TTL_TICKS = 5L; // Anonymous - RegionizedTaskQueue queue TTL optimization
public PrioritisedExecutor.PrioritisedTask createChunkTask(final ServerLevel world, final int chunkX, final int chunkZ,
final Runnable run) {
@@ -155,6 +156,58 @@ public final class RegionizedTaskQueue {
}
}
+ // Anonymous start - RegionizedTaskQueue queue TTL optimization
+ public void tickQueueReferenceTTL() {
+ final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> currentRegion
+ = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegion();
+ if (currentRegion == null) {
+ return;
+ }
+
+ final ReferenceCountData[] toRemoveTicket = new ReferenceCountData[1];
+
+ for (ConcurrentChainedLong2ReferenceHashTable.TableEntry<ReferenceCountData> counterEntry : this.referenceCounters.entrySet()) {
+ final long coord = counterEntry.getKey();
+ final ReferenceCountData counterData = counterEntry.getValue();
+
+ // only tick for our region
+ if (currentRegion == this.world.regioniser.getRegionAtUnsynchronised(CoordinateUtils.getChunkX(coord), CoordinateUtils.getChunkZ(coord))) {
+ long curr = counterData.referenceTTL.get();
+ // successfully decreased ttl
+ if (curr == (curr = counterData.referenceTTL.compareAndExchange(curr, curr - 1))) {
+ if (counterData.referenceCount.get() != 0L) {
+ // still has reference, pump back
+ counterData.referenceTTL.set(QUEUE_MAX_TTL_TICKS);
+ continue;
+ }
+
+ // dead
+ if (curr <= 0) {
+ // parsed from decrementReference
+ this.referenceCounters.computeIfPresent(coord, (final long keyInMap, final ReferenceCountData valueInMap) -> {
+ // might be increased again
+ if (valueInMap.referenceCount.get() != 0L) {
+ valueInMap.referenceTTL.set(QUEUE_MAX_TTL_TICKS); // still has reference, pump back
+ return valueInMap; // directly, the ttl was already charged in add logic
+ }
+
+ // note: valueInMap may not be referenceCountData
+ toRemoveTicket[0] = valueInMap;
+
+ return null;
+ });
+
+ if (toRemoveTicket[0] != null) {
+ this.removeTicket(coord, toRemoveTicket[0].id);
+ toRemoveTicket[0] = null;
+ }
+ }
+ }
+ }
+ }
+ }
+ // Anonymous end - RegionizedTaskQueue queue TTL optimization
+
private void decrementReference(final ReferenceCountData referenceCountData, final long coord) {
if (!referenceCountData.decreaseReferenceCount()) {
return;
@@ -212,9 +265,10 @@ public final class RegionizedTaskQueue {
private final long id = ID_GENERATOR.getAndIncrement();
public final AtomicLong referenceCount = new AtomicLong(1L);
+ public final AtomicLong referenceTTL = new AtomicLong(QUEUE_MAX_TTL_TICKS); // Anonymous - RegionizedTaskQueue queue TTL optimization
public volatile boolean addedTicket;
- // returns false if reference count is 0, otherwise increments ref count
+ // returns false if reference count or ttl is 0, otherwise increments ref count // Anonymous - RegionizedTaskQueue queue TTL optimization
public boolean addCount() {
int failures = 0;
for (long curr = this.referenceCount.get();;) {
@@ -227,6 +281,27 @@ public final class RegionizedTaskQueue {
}
if (curr == (curr = this.referenceCount.compareAndExchange(curr, curr + 1L))) {
+ // Anonymous start - RegionizedTaskQueue queue TTL optimization
+ // now force charge back the ttl to max
+ int ttlFailures = 0;
+ for (long currTTL = this.referenceTTL.get();;) {
+ for (int i = 0; i < ttlFailures; i++) {
+ Thread.onSpinWait();
+ }
+
+ // add failed, rollback (ttl reached)
+ if (currTTL <= 0) {
+ this.referenceCount.decrementAndGet(); // revert the addition
+ return false;
+ }
+
+ if (currTTL == (currTTL = this.referenceTTL.compareAndExchange(currTTL, QUEUE_MAX_TTL_TICKS))) {
+ break;
+ }
+
+ ++ttlFailures;
+ }
+ // Anonymous end - RegionizedTaskQueue queue TTL optimization
return true;
}
@@ -234,11 +309,11 @@ public final class RegionizedTaskQueue {
}
}
- // returns true if new reference count is 0
+ // returns true if new reference count and ttl is 0 // Anonymous - RegionizedTaskQueue queue TTL optimization
public boolean decreaseReferenceCount() {
final long res = this.referenceCount.decrementAndGet();
if (res >= 0L) {
- return res == 0L;
+ return res == 0L && this.referenceTTL.get() <= 0L; // Anonymous - RegionizedTaskQueue queue TTL optimization
} else {
throw new IllegalStateException("Negative reference count");
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 6c5cdfebb3a362c51b3b940397e10536dc67afc8..4a00b2399a190b609f7b0944e407f3b087e617b5 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1756,6 +1756,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.PASSENGER_DESYNC_CHECK);
}
// Folia end - fix passenger desync
+ region.world.taskQueueRegionData.tickQueueReferenceTTL(); // Anonymous - RegionizedTaskQueue queue TTL optimization
}
// Folia end - region threading
//this.tickCount++; // Folia - region threading
@@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sat, 1 Aug 2026 16:31:57 +0800
Subject: [PATCH] Anonymous Object: Reduce ticket operations in nether portal
searching
As requested by the original author, this patch will be anonymous and hide the original commit address.
This patch is used with permission from the original author.
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 132122f23a697109696852cf383fa1b0186e0210..619521d8ff74c92a822bde9c160931cdfdb7da43 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -221,6 +221,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
private final StructureCheck structureCheck;
public final boolean tickTime; // Folia - region threading
private final LevelDebugSynchronizers debugSynchronizers = new LevelDebugSynchronizers(this);
+ public final io.anonymous.anonymous.utils.ReferenceCountingChunkLoader portalSearchingChunkLoader = new io.anonymous.anonymous.utils.ReferenceCountingChunkLoader(this, net.minecraft.world.level.chunk.status.ChunkStatus.EMPTY); // Anonymous - Reduce ticket operations in nether portal searching
// Luminol start - Level schedulers
private static final java.util.concurrent.atomic.AtomicInteger UNLOADER_ID_GEN = new java.util.concurrent.atomic.AtomicInteger(0);
public final me.earthme.luminol.utils.thread.LevelAwareRegionScheduler levelScheduler = new me.earthme.luminol.utils.thread.LevelAwareRegionScheduler(io.papermc.paper.threadedregions.TickRegions.getScheduler().scheduler);
@@ -1004,6 +1005,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
this.debugSynchronizers.tick(this.server.debugSubscribers());
profiler.pop();
+ this.portalSearchingChunkLoader.tickChunkReferenceTTL(); // Anonymous - Reduce ticket operations in nether portal searching
}
// Folia start - region threading
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 489011f9af49fa3407038bd2f00439443307d179..340e6ad83ba93f3927a08a107e3c8dbafa546112 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -4870,10 +4870,10 @@ public abstract class Entity
);
// kick off search for existing portal or creation
- destination.moonrise$loadChunksAsync(
+ destination.portalSearchingChunkLoader.loadChunksAsync( // Anonymous - Reduce ticket operations in nether portal searching
// add 32 so that the final search for a portal frame doesn't load any chunks
targetPos, portalSearchRadius + 32,
- net.minecraft.world.level.chunk.status.ChunkStatus.EMPTY,
+ //net.minecraft.world.level.chunk.status.ChunkStatus.EMPTY, // Anonymous - Reduce ticket operations in nether portal searching
ca.spottedleaf.concurrentutil.util.Priority.HIGH,
(chunks) -> {
BlockUtil.FoundRectangle portal =
@@ -4,6 +4,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import com.github.luben.zstd.ZstdInputStream;
import com.github.luben.zstd.ZstdOutputStream;
import com.mojang.logging.LogUtils;
import io.anonymous.anonymous.data.RegionFile;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
@@ -26,7 +27,7 @@ import java.util.concurrent.locks.ReentrantLock;
// LinearRegionFile_implementation_version_0_5byXymb
// Just gonna use this string to inform other forks about updates ;-)
public class LinearRegionFile implements IRegionFile {
public class LinearRegionFile implements RegionFile {
private static final long SUPERBLOCK = 0xc3ff13183cca9d9aL;
private static final byte VERSION = 3;
private static final int HEADER_SIZE = 27;
@@ -489,15 +490,15 @@ public class LinearRegionFile implements IRegionFile {
public DataOutputStream getChunkDataOutputStream(ChunkPos pos) {
openRegionFile();
openBucket(pos.x(), pos.z());
return new DataOutputStream(new BufferedOutputStream(new LinearRegionFile.ChunkBuffer(pos)));
return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos)));
}
@Override
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) throws IOException {
final DataOutputStream out = this.getChunkDataOutputStream(pos);
return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData(
data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE,
return new MoonriseRegionFileIO.RegionDataController.WriteData(
data, MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE,
out, regionFile -> out.close()
);
}
@@ -21,5 +21,4 @@ public final class MathUtilities {
int i = (int) d;
return d > (double) i ? i + 1 : i;
}
}
@@ -19,20 +19,19 @@ package dev.kaiijumc.kaiiju;
import com.google.common.base.Throwables;
import com.mojang.logging.LogUtils;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ScanResult;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.world.entity.Entity;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.EntityType;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jspecify.annotations.NonNull;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
@SuppressWarnings("unused")
@@ -44,26 +43,11 @@ public class KaiijuEntityLimits {
"Per region entity limits for Kaiiju.\n"
+ "If there are more of particular entity type in a region than limit, entity ticking will be throttled.\n"
+ "Example: for Wither limit 100 & 300 Withers in a region -> 100 Withers tick every tick & every Wither ticks every 3 ticks.\n"
+ "Available entities: GlowSquid, Ambient, Bat, Animal, Bee, Cat, Chicken, Cod, Cow, Dolphin, Fish, FishSchool, Fox, Golem, IronGolem, "
+ "MushroomCow, Ocelot, Panda, Parrot, Perchable, Pig, PolarBear, PufferFish, Rabbit, Salmon, Sheep, Snowman, Squid, TropicalFish, Turtle, "
+ "WaterAnimal, Wolf, Allay, Axolotl, Camel, Frog, Tadpole, Goat, Horse, HorseAbstract, HorseChestedAbstract, HorseDonkey, HorseMule, "
+ "HorseSkeleton, HorseZombie, Llama, LlamaTrader, Sniffer, EnderCrystal, EnderDragon, Wither, ArmorStand, Hanging, ItemFrame, Leash, "
+ "Painting, GlowItemFrame, FallingBlock, Item, TNTPrimed, Blaze, CaveSpider, Creeper, Drowned, Enderman, Endermite, Evoker, Ghast, "
+ "GiantZombie, Guardian, GuardianElder, IllagerAbstract, IllagerIllusioner, IllagerWizard, MagmaCube, Monster, MonsterPatrolling, Phantom, "
+ "ZombifiedPiglin, Pillager, Ravager, Shulker, Silverfish, Skeleton, SkeletonAbstract, SkeletonStray, SkeletonWither, Slime, Spider, Strider, Vex, "
+ "Vindicator, Witch, Zoglin, Zombie, ZombieHusk, ZombieVillager, Hoglin, Piglin, PiglinAbstract, PiglinBrute, Warden, Villager, "
+ "VillagerTrader, Arrow, DragonFireball, Egg, EnderPearl, EnderSignal, EvokerFangs, Fireball, FireballFireball, Fireworks, FishingHook, "
+ "LargeFireball, LlamaSpit, Potion, Projectile, ProjectileThrowable, ShulkerBullet, SmallFireball, Snowball, SpectralArrow, ThrownExpBottle, "
+ "ThrownTrident, TippedArrow, WitherSkull, Raider, ChestBoat, Boat, MinecartAbstract, MinecartChest, MinecartCommandBlock, MinecartContainer, "
+ "MinecartFurnace, MinecartHopper, MinecartMobSpawner, MinecartRideable, MinecartTNT\n";
+ "Entity names are named under the registry of minecraft's entity type";
protected static final File ENTITY_LIMITS_FILE = new File(CONFIG_FOLDER, "kaiiju_entity_limits.yml");
public static YamlConfiguration entityLimitsConfig;
public static boolean enabled = false;
protected static Map<Class<? extends Entity>, EntityLimit> entityLimits;
static final String ENTITY_PREFIX = "Entity";
public static void init() {
init(true);
}
@@ -84,8 +68,9 @@ public class KaiijuEntityLimits {
entityLimitsConfig.options().header(HEADER);
entityLimitsConfig.options().copyDefaults(true);
entityLimitsConfig.set("enabled", enabled);
entityLimitsConfig.set("Axolotl.limit", 1000);
entityLimitsConfig.set("Axolotl.removal", 2000);
entityLimitsConfig.set("axolotl.limit", 1000);
entityLimitsConfig.set("axolotl.removal", 2000);
try {
entityLimitsConfig.save(ENTITY_LIMITS_FILE);
} catch (IOException ex) {
@@ -96,62 +81,42 @@ public class KaiijuEntityLimits {
enabled = entityLimitsConfig.getBoolean("enabled");
entityLimits = new Object2ObjectOpenHashMap<>();
try (ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages("net.minecraft.world.entity").scan()) {
Map<String, ClassInfo> entityClasses = new HashMap<>();
for (ClassInfo classInfo : scanResult.getAllClasses()) {
Class<?> entityClass = Class.forName(classInfo.getName());
if (Entity.class.isAssignableFrom(entityClass)) {
String entityName = extractEntityName(entityClass.getSimpleName());
entityClasses.put(entityName, classInfo);
}
}
for (String key : entityLimitsConfig.getKeys(false)) {
if (key.equals("enabled")) {
continue;
}
if (!entityClasses.containsKey(key)) {
LOGGER.error("Unknown entity '" + key + "' in kaiiju-entity-limits.yml, skipping");
continue;
}
int limit = entityLimitsConfig.getInt(key + ".limit");
int removal = entityLimitsConfig.getInt(key + ".removal");
if (limit < 1) {
LOGGER.error(key + " has a limit less than the minimum of 1, ignoring");
continue;
}
if (removal <= limit && removal != -1) {
LOGGER.error(key + " has a removal limit that is less than or equal to its limit, setting removal to limit * 10");
removal = limit * 10;
}
entityLimits.put((Class<? extends Entity>) Class.forName(entityClasses.get(key).getName()), new EntityLimit(limit, removal));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
if (!enabled) {
return;
}
}
public static EntityLimit getEntityLimit(Entity entity) {
return entityLimits.get(entity.getClass());
}
for (String key : entityLimitsConfig.getKeys(false)) {
if (key.equals("enabled")) {
continue;
}
private static String extractEntityName(String input) {
int prefixLength = ENTITY_PREFIX.length();
final Optional<Holder.Reference<EntityType<?>>> lookup = BuiltInRegistries.ENTITY_TYPE.get(Identifier.fromNamespaceAndPath(Identifier.DEFAULT_NAMESPACE, key));
if (lookup.isEmpty()) {
LOGGER.error("Unknown entity '{}' in kaiiju-entity-limits.yml, skipping", key);
continue;
}
if (input.length() <= prefixLength || !input.startsWith(ENTITY_PREFIX)) {
return input;
} else {
return input.substring(prefixLength);
final EntityType<?> value = lookup.get().value();
int limit = entityLimitsConfig.getInt(key + ".limit");
int removal = entityLimitsConfig.getInt(key + ".removal");
if (limit < 1) {
LOGGER.error("{} has a limit less than the minimum of 1, ignoring", key);
continue;
}
if (removal <= limit && removal != -1) {
LOGGER.error("{} has a removal limit that is less than or equal to its limit, setting removal to limit * 10", key);
removal = limit * 10;
}
value.entityLimit = new EntityLimit(limit, removal);
}
}
public record EntityLimit(int limit, int removal) {
@Override
public String toString() {
public @NonNull String toString() {
return "EntityLimit{limit=" + limit + ", removal=" + removal + "}";
}
}
@@ -45,7 +45,8 @@ public class KaiijuEntityThrottler {
public EntityThrottlerReturn tickLimiterShouldSkip(Entity entity) {
EntityThrottlerReturn retVal = new EntityThrottlerReturn();
if (entity.isRemoved()) return retVal;
KaiijuEntityLimits.EntityLimit entityLimit = KaiijuEntityLimits.getEntityLimit(entity);
KaiijuEntityLimits.EntityLimit entityLimit = entity.getType().entityLimit;
if (entityLimit != null) {
TickInfo tickInfo = entityLimitTickInfoMap.computeIfAbsent(entityLimit, el -> {
@@ -8,7 +8,7 @@ import net.objecthunter.exp4j.ExpressionBuilder;
import java.math.BigDecimal;
public final class CarpetCalculatorCompatHelper {
public final class CarpetCalculatorHelper {
public static boolean handleChat(ServerPlayer player, String rawMessage) {
if (!GeneralCompatConfig.simpleInGameCalculator || !rawMessage.startsWith("=")) {
@@ -10,8 +10,7 @@ import org.leavesmc.leaves.protocol.CarpetServerProtocol;
import java.util.List;
// WARNING: THIS FILE NEED TO FULLY REWRITTEN
public final class CarpetCompatSync {
public final class CarpetProtocalDataBase {
private static boolean init = false;
public static void apply() {
@@ -24,6 +23,7 @@ public final class CarpetCompatSync {
return configuredLoggers == null ? List.of() : List.copyOf(configuredLoggers);
}
// Rules may be need update because we redirected many config path & the carpet version updated
private static void registerProtocolRules() {
CarpetServerProtocol.CarpetRules.beginBatch();
try {
@@ -2,7 +2,7 @@ package fun.bm.lophine.carpet;
import java.util.function.Supplier;
public final class InteractionUpdateCompatHelper {
public final class InteractionUpdateHelper {
private static final ThreadLocal<Integer> SUPPRESSED_DEPTH = ThreadLocal.withInitial(() -> 0);
public static boolean shouldSkipUpdates() {
@@ -24,7 +24,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
public final class LagFreeSpawningCompatHelper {
public final class LagFreeSpawningHelper {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Map<RegionizedWorldData, Map<EntityType<?>, Mob>> PRECOOKED_MOBS = new WeakHashMap<>();
@@ -1,6 +1,6 @@
package fun.bm.lophine.carpet.config.modules;
import fun.bm.lophine.carpet.CarpetCompatSync;
import fun.bm.lophine.carpet.CarpetProtocalDataBase;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigClassInfo;
import me.earthme.luminol.config.flags.ConfigInfo;
@@ -193,6 +193,6 @@ public class GeneralCompatConfig implements IConfigModule {
@Override
public void beforeFinalLoad() {
// send changes to client
CarpetCompatSync.apply();
CarpetProtocalDataBase.apply();
}
}
@@ -1,12 +1,9 @@
package fun.bm.lophine.config.modules.experiment;
import fun.bm.lophine.enums.GlobalEntitiesCounterType;
import me.earthme.luminol.config.ConfigManager;
import me.earthme.luminol.config.ConfigsInstance;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigClassInfo;
import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.config.flags.DoNotLoad;
import me.earthme.luminol.config.flags.HotReloadUnsupported;
import me.earthme.luminol.enums.EnumConfigCategory;
@@ -16,46 +13,15 @@ public class GlobalEntitiesCounter implements IConfigModule {
@ConfigInfo(name = "version")
public static GlobalEntitiesCounterType type = GlobalEntitiesCounterType.DISABLED;
@DoNotLoad
private static boolean enabled;
@DoNotLoad
private static boolean async;
@DoNotLoad
private static boolean defaultModule;
public static boolean isEnabled() {
return enabled;
return type.isEnabled();
}
public static boolean isAsync() {
return async;
return type.isAsync();
}
public static boolean isDefaultModule() {
return defaultModule;
}
@Override
public void beforeFinalLoad() {
ConfigsInstance configsInstance = ConfigManager.getConfigs("lophine");
try {
Boolean enabled0 = configsInstance.getConfigOrigin("experiment.global_entities_counter.enabled");
Boolean async0 = configsInstance.getConfigOrigin("experiment.global_entities_counter.async");
if (enabled0 != null) {
if (enabled0) {
if (async0 != null && async0) {
type = GlobalEntitiesCounterType.DEFAULT_ASYNC;
} else {
type = GlobalEntitiesCounterType.DEFAULT_SYNC;
}
}
}
configsInstance.removeConfig("experiment.global_entities_counter.enabled");
configsInstance.removeConfig("experiment.global_entities_counter.async");
} catch (Exception ignored) {
}
enabled = type != GlobalEntitiesCounterType.DISABLED;
async = type == GlobalEntitiesCounterType.DEFAULT_ASYNC;
defaultModule = type == GlobalEntitiesCounterType.DEFAULT_SYNC || type == GlobalEntitiesCounterType.DEFAULT_ASYNC;
return type.isDefaultModule();
}
}
@@ -1,8 +1,30 @@
package fun.bm.lophine.enums;
public enum GlobalEntitiesCounterType {
DISABLED,
DEFAULT_SYNC,
DEFAULT_ASYNC,
PRECISE
DISABLED(false, false, false),
DEFAULT_SYNC(true, false, true),
DEFAULT_ASYNC(true, true, true),
PRECISE(true, false, false);
private final boolean enabled;
private final boolean async;
private final boolean defaultModule;
private GlobalEntitiesCounterType(boolean enabled, boolean async, boolean defaultModule) {
this.enabled = enabled;
this.async = async;
this.defaultModule = defaultModule;
}
public boolean isEnabled() {
return enabled;
}
public boolean isAsync() {
return async;
}
public boolean isDefaultModule() {
return defaultModule;
}
}
@@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Function;
import java.util.function.Predicate;
public class ConcurrentTable<X, Y, Z> implements AbstractConcurrentTable<X, Y, Z> {
@@ -150,7 +151,7 @@ public class ConcurrentTable<X, Y, Z> implements AbstractConcurrentTable<X, Y, Z
}
private <T> List<T> filterAndCollect(Predicate<TableEntry<X, Y, Z>> filter,
java.util.function.Function<TableEntry<X, Y, Z>, T> mapper) {
Function<TableEntry<X, Y, Z>, T> mapper) {
List<T> result = new ArrayList<>();
for (TableEntry<X, Y, Z> entry : data) {
if (filter.test(entry)) {
@@ -161,8 +162,8 @@ public class ConcurrentTable<X, Y, Z> implements AbstractConcurrentTable<X, Y, Z
}
private <K, V> Map<K, V> filterAndMap(Predicate<TableEntry<X, Y, Z>> filter,
java.util.function.Function<TableEntry<X, Y, Z>, K> keyMapper,
java.util.function.Function<TableEntry<X, Y, Z>, V> valueMapper) {
Function<TableEntry<X, Y, Z>, K> keyMapper,
Function<TableEntry<X, Y, Z>, V> valueMapper) {
Map<K, V> map = new HashMap<>();
for (TableEntry<X, Y, Z> entry : data) {
if (filter.test(entry)) {
@@ -172,7 +173,7 @@ public class ConcurrentTable<X, Y, Z> implements AbstractConcurrentTable<X, Y, Z
return map;
}
private <T> List<T> collectAll(java.util.function.Function<TableEntry<X, Y, Z>, T> mapper) {
private <T> List<T> collectAll(Function<TableEntry<X, Y, Z>, T> mapper) {
List<T> result = new ArrayList<>();
for (TableEntry<X, Y, Z> entry : data) {
result.add(mapper.apply(entry));
@@ -173,7 +173,7 @@ public class OptimizedConcurrentTable<X, Y, Z> extends ConcurrentTable<X, Y, Z>
}
private <K, V, R, S> Map<R, S> buildMapFromIndex(ConcurrentHashMap<K, Set<V>> indexMap, java.util.function.Function<K, R> keyMapper, java.util.function.Function<V, S> valueMapper) {
private <K, V, R, S> Map<R, S> buildMapFromIndex(ConcurrentHashMap<K, Set<V>> indexMap, Function<K, R> keyMapper, Function<V, S> valueMapper) {
Map<R, S> result = new HashMap<>();
if (indexMap != null) {
for (Map.Entry<K, Set<V>> entry : indexMap.entrySet()) {
@@ -23,7 +23,6 @@ import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.SentryEvent;
import io.sentry.SentryLevel;
import io.sentry.protocol.Message;
import io.sentry.protocol.User;
import me.earthme.luminol.config.modules.misc.SentryConfig;
import org.apache.logging.log4j.Level;
@@ -67,9 +66,6 @@ public class PufferfishSentryAppender extends AbstractAppender {
private void logException(LogEvent e) {
SentryEvent event = new SentryEvent(e.getThrown());
Message sentryMessage = new Message();
sentryMessage.setMessage(e.getMessage().getFormattedMessage());
event.setThrowable(e.getThrown());
event.setLevel(getLevel(e.getLevel()));
event.setLogger(e.getLoggerName());
@@ -26,10 +26,6 @@ public class SentryManager {
private static final Logger logger = LogManager.getLogger(SentryManager.class);
private SentryManager() {
}
private static boolean initialized = false;
public static synchronized void init(Level logLevel) {
@@ -1,10 +1,9 @@
package me.earthme.luminol.utils;
package io.anonymous.anonymous.data;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
import me.earthme.luminol.data.BufferedLinearRegionFile;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
@@ -1,4 +1,5 @@
package abomination;
package io.anonymous.anonymous.data;
import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile;
import net.minecraft.nbt.CompoundTag;
@@ -10,7 +11,7 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Path;
public interface IRegionFile extends ChunkSystemRegionFile, AutoCloseable {
public interface RegionFile extends ChunkSystemRegionFile, AutoCloseable {
Path getPath();
DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException;
@@ -39,5 +40,5 @@ public interface IRegionFile extends ChunkSystemRegionFile, AutoCloseable {
default int getRecalculateCount() {
return 0;
} // Luminol - Configurable region file format
} // Anonymous - Configurable region file format
}
@@ -1,9 +1,9 @@
package me.earthme.luminol.enums;
package io.anonymous.anonymous.enums;
import abomination.LinearRegionFile;
import io.anonymous.anonymous.data.BufferedLinearRegionFile;
import io.anonymous.anonymous.utils.RegionFileFactory;
import me.earthme.luminol.config.modules.function.RegionFormatConfig;
import me.earthme.luminol.data.BufferedLinearRegionFile;
import me.earthme.luminol.utils.IRegionCreateFunction;
import net.minecraft.world.level.chunk.storage.RegionFile;
public enum EnumRegionFormat {
@@ -12,14 +12,14 @@ public enum EnumRegionFormat {
B_LINEAR("b_linear", (info) -> new BufferedLinearRegionFile(info.filePath(), RegionFormatConfig.linearCompressionLevel, RegionFormatConfig.blinearFlusher));
private final String argument;
private final IRegionCreateFunction creator;
private final RegionFileFactory creator;
EnumRegionFormat(String argument, IRegionCreateFunction creator) {
EnumRegionFormat(String argument, RegionFileFactory creator) {
this.argument = argument;
this.creator = creator;
}
public IRegionCreateFunction getCreator() {
public RegionFileFactory getCreator() {
return this.creator;
}
@@ -0,0 +1,312 @@
package io.anonymous.anonymous.utils;
import ca.spottedleaf.concurrentutil.completable.CallbackCompletable;
import ca.spottedleaf.concurrentutil.map.concurrent.longs.ConcurrentChainedLong2ReferenceHashTable;
import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
import io.papermc.paper.threadedregions.RegionizedServer;
import io.papermc.paper.threadedregions.ThreadedRegionizer;
import io.papermc.paper.threadedregions.TickRegions;
import it.unimi.dsi.fastutil.Pair;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import org.jspecify.annotations.NonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
/**
* 一个简单的基于folia的RegionizedTaskQueue引用计数的轻量ticket区块加载器
* 用于在folia传送门搜索的高频率scheduleChunkLoad的调用下减少ticket操作从而减轻锁负载
* 大部分内容物均取自folia的RegionizedTaskQueue(引用计数), ttl机制取自我的优化
*
* @see io.papermc.paper.threadedregions.RegionizedTaskQueue
* @see Entity#findOrCreatePortalAsync(ServerLevel, BlockPos, ServerLevel, Entity.PortalType, CallbackCompletable)
*/
public class ReferenceCountingChunkLoader {
private static final long MAX_CHUNK_TTL_TICKS = 2L;
private final ServerLevel world;
private final ChunkStatus targetStatus;
private final ConcurrentChainedLong2ReferenceHashTable<ReferenceCountData> referenceCounters = new ConcurrentChainedLong2ReferenceHashTable<>();
public ReferenceCountingChunkLoader(ServerLevel world, ChunkStatus targetStatus) {
this.world = world;
this.targetStatus = targetStatus;
}
private void decrementReference(final @NonNull ReferenceCountData referenceCountData, final long coord) {
if (!referenceCountData.decreaseReferenceCount()) {
return;
}
final ReferenceCountData[] toRemoveTicket = new ReferenceCountData[1];
this.referenceCounters.computeIfPresent(coord, (final long keyInMap, final ReferenceCountData valueInMap) -> {
if (valueInMap.referenceCount.get() != 0L) {
return valueInMap;
}
toRemoveTicket[0] = valueInMap;
return null;
});
if (toRemoveTicket[0] != null) {
this.removeTicket(coord, toRemoveTicket[0].id);
}
}
private void removeTicket(final long coord, final long id) {
this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(
ChunkTaskScheduler.CHUNK_LOAD, coord, ChunkTaskScheduler.getTicketLevel(this.targetStatus), Long.valueOf(id)
);
}
private void addTicket(final long coord, final long id) {
this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAtLevel(
ChunkTaskScheduler.CHUNK_LOAD, coord, ChunkTaskScheduler.getTicketLevel(this.targetStatus), Long.valueOf(id)
);
}
private void processTicketUpdates(final long coord) {
this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.processTicketUpdates(CoordinateUtils.getChunkX(coord), CoordinateUtils.getChunkZ(coord));
}
private void ensureTicketAdded(final long coord, final @NonNull ReferenceCountData referenceCountData) {
if (!referenceCountData.addedTicket) {
this.addTicket(coord, referenceCountData.id);
this.processTicketUpdates(coord);
referenceCountData.addedTicket = true;
}
}
public final void loadChunksAsync(final @NonNull BlockPos pos, final int radiusBlocks,
final Priority priority,
final Consumer<List<ChunkAccess>> onLoad) {
this.loadChunksAsync(
(pos.getX() - radiusBlocks) >> 4,
(pos.getX() + radiusBlocks) >> 4,
(pos.getZ() - radiusBlocks) >> 4,
(pos.getZ() + radiusBlocks) >> 4,
priority, onLoad
);
}
public final void loadChunksAsync(final int minChunkX, final int maxChunkX, final int minChunkZ, final int maxChunkZ,
final Priority priority,
final Consumer<List<ChunkAccess>> onLoad) {
this.loadChunksAsync(minChunkX, maxChunkX, minChunkZ, maxChunkZ, priority, onLoad, null);
}
public final void loadChunksAsync(final int minChunkX, final int maxChunkX, final int minChunkZ, final int maxChunkZ,
final Priority priority,
final Consumer<List<ChunkAccess>> onLoad, final Consumer<ChunkAccess> onEachLoad) {
final int requiredChunks = (maxChunkX - minChunkX + 1) * (maxChunkZ - minChunkZ + 1);
final AtomicInteger loadedChunks = new AtomicInteger();
final List<Pair<ReferenceCountData, ChunkAccess>> ret = new ArrayList<>(requiredChunks);
final Consumer<ChunkAccess> consumer = (final ChunkAccess chunk) -> {
if (chunk != null) {
final long pos = chunk.getPos().longKey();
synchronized (ret) {
ret.add(Pair.of(this.incrementReference(pos), chunk));
}
}
if (onEachLoad != null) {
onEachLoad.accept(chunk);
}
if (loadedChunks.incrementAndGet() == requiredChunks) {
try {
if (onLoad != null) {
final List<ChunkAccess> processed = new ArrayList<>(ret.size());
for (Pair<ReferenceCountData, ChunkAccess> result : ret) {
processed.add(result.right());
}
onLoad.accept(processed);
}
} finally {
for (Pair<ReferenceCountData, ChunkAccess> extraRefEntry : ret) {
this.decrementReference(extraRefEntry.left(), extraRefEntry.right().getPos().longKey());
}
}
}
};
for (int cx = minChunkX; cx <= maxChunkX; ++cx) {
for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) {
this.loadAsync(cx, cz, consumer, priority);
}
}
}
public void loadAsync(int chunkX, int chunkZ, Consumer<ChunkAccess> callback, Priority priority) {
final long coord = CoordinateUtils.getChunkKey(chunkX, chunkZ);
final ReferenceCountData increased = this.incrementReference(coord);
final ChunkAccess cached = increased.cached;
if (cached != null) {
RegionizedServer.getInstance().taskQueue.queueChunkTask(this.world, chunkX, chunkZ, () -> {
try {
callback.accept(cached);
} finally {
this.decrementReference(increased, coord);
}
}, priority);
return;
}
this.world.moonrise$getChunkTaskScheduler().scheduleChunkLoad(
chunkX, chunkZ, this.targetStatus, true, priority,
chunk -> {
try {
increased.cached = chunk;
callback.accept(chunk);
} finally {
this.decrementReference(increased, coord);
}
}
);
}
private ReferenceCountData incrementReference(final long coord) {
ReferenceCountData referenceCountData = this.referenceCounters.get(coord);
if (referenceCountData != null && referenceCountData.addCount()) {
this.ensureTicketAdded(coord, referenceCountData);
return referenceCountData;
}
referenceCountData = this.referenceCounters.compute(coord, (final long keyInMap, final ReferenceCountData valueInMap) -> {
if (valueInMap == null) {
return new ReferenceCountData();
}
valueInMap.referenceCount.getAndIncrement();
return valueInMap;
});
this.ensureTicketAdded(coord, referenceCountData);
return referenceCountData;
}
public void tickChunkReferenceTTL() {
final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> currentRegion
= io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegion();
if (currentRegion == null) {
return;
}
final ReferenceCountData[] toRemoveTicket = new ReferenceCountData[1];
for (ConcurrentChainedLong2ReferenceHashTable.TableEntry<ReferenceCountData> counterEntry : this.referenceCounters.entrySet()) {
final long coord = counterEntry.getKey();
final ReferenceCountData counterData = counterEntry.getValue();
if (currentRegion == this.world.regioniser.getRegionAtUnsynchronised(CoordinateUtils.getChunkX(coord), CoordinateUtils.getChunkZ(coord))) {
long curr = counterData.referenceTTL.get();
if (curr == (curr = counterData.referenceTTL.compareAndExchange(curr, curr - 1))) {
if (counterData.referenceCount.get() != 0L) {
counterData.referenceTTL.set(MAX_CHUNK_TTL_TICKS);
continue;
}
if (curr <= 0) {
this.referenceCounters.computeIfPresent(coord, (final long keyInMap, final ReferenceCountData valueInMap) -> {
if (valueInMap.referenceCount.get() != 0L) {
valueInMap.referenceTTL.set(MAX_CHUNK_TTL_TICKS);
return valueInMap;
}
toRemoveTicket[0] = valueInMap;
return null;
});
if (toRemoveTicket[0] != null) {
this.removeTicket(coord, toRemoveTicket[0].id);
toRemoveTicket[0] = null;
}
}
}
}
}
}
private static final class ReferenceCountData {
private static final AtomicLong ID_GENERATOR = new AtomicLong();
private final long id = ID_GENERATOR.getAndIncrement();
public final AtomicLong referenceCount = new AtomicLong(1L);
public final AtomicLong referenceTTL = new AtomicLong(MAX_CHUNK_TTL_TICKS);
public volatile ChunkAccess cached;
public volatile boolean addedTicket;
public boolean addCount() {
int failures = 0;
for (long curr = this.referenceCount.get(); ; ) {
for (int i = 0; i < failures; ++i) {
Thread.onSpinWait();
}
if (curr == 0L) {
return false;
}
if (curr == (curr = this.referenceCount.compareAndExchange(curr, curr + 1L))) {
int ttlFailures = 0;
for (long currTTL = this.referenceTTL.get(); ; ) {
for (int i = 0; i < ttlFailures; i++) {
Thread.onSpinWait();
}
if (currTTL <= 0) {
this.referenceCount.decrementAndGet();
return false;
}
if (currTTL == (currTTL = this.referenceTTL.compareAndExchange(currTTL, MAX_CHUNK_TTL_TICKS))) {
break;
}
++ttlFailures;
}
return true;
}
++failures;
}
}
public boolean decreaseReferenceCount() {
final long res = this.referenceCount.decrementAndGet();
if (res >= 0L) {
return res == 0L && this.referenceTTL.get() <= 0L;
} else {
throw new IllegalStateException("Negative reference count");
}
}
}
}
@@ -1,4 +1,4 @@
package me.earthme.luminol.utils;
package io.anonymous.anonymous.utils;
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
@@ -0,0 +1,10 @@
package io.anonymous.anonymous.utils;
import io.anonymous.anonymous.data.RegionFile;
import java.io.IOException;
@FunctionalInterface
public interface RegionFileFactory {
RegionFile newFile(RegionCreatorInfo info) throws IOException;
}
@@ -2,6 +2,8 @@ package me.earthme.luminol.config.modules.function;
import abomination.LinearRegionFile;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import io.anonymous.anonymous.data.BufferedLinearRegionFileFlusher;
import io.anonymous.anonymous.enums.EnumRegionFormat;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.IllegalFormatConversionExceptionWithOrigin;
import me.earthme.luminol.config.flags.ConfigClassInfo;
@@ -9,8 +11,6 @@ import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.config.flags.DoNotLoad;
import me.earthme.luminol.config.flags.HotReloadUnsupported;
import me.earthme.luminol.enums.EnumConfigCategory;
import me.earthme.luminol.enums.EnumRegionFormat;
import me.earthme.luminol.utils.BufferedLinearRegionFileFlusher;
import net.minecraft.server.MinecraftServer;
import org.jetbrains.annotations.Nullable;
@@ -1,10 +0,0 @@
package me.earthme.luminol.utils;
import abomination.IRegionFile;
import java.io.IOException;
@FunctionalInterface
public interface IRegionCreateFunction {
IRegionFile create(RegionCreatorInfo info) throws IOException;
}
@@ -0,0 +1,159 @@
/*
* This file is part of Lithium
*
* Lithium is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Lithium is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Lithium. If not, see <https://www.gnu.org/licenses/>.
*/
package net.caffeinemc.mods.lithium.common.ai.non_poi_block_search;
import net.caffeinemc.mods.lithium.common.util.collections.FixedChunkAccessSectionBitBuffer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* This is intended to be used to optimize Non-POI block searches by pre-checking the ChunkSections, getting the
* ChunkAccesses which then allows for returning early or only calling getBlockState in possible ChunkSections.
* <p>
* Note: Please correctly specify shouldChunkLoad based on whether the getBlockState in vanilla can chunk load or not.
* The default in game is that it can. Setting it to true will mean that the search will assume that unloaded chunks
* may have the target and will chunk load then search them if and when it reaches it.
*
* @author jcw780
*/
public class CheckAndCacheBlockChecker {
private final FixedChunkAccessSectionBitBuffer chunkSections2MaybeContainsMatchingBlock;
private final LevelReader levelReader;
public final boolean shouldChunkLoad;
public final Predicate<BlockState> blockStatePredicate;
private int unloadedPossibleChunkSections = 0;
public final int minSectionY;
public CheckAndCacheBlockChecker(BlockPos origin, int horizontalRangeInclusive, int verticalRangeInclusive, LevelReader levelReader,
Predicate<BlockState> blockStatePredicate, boolean shouldChunkLoad) {
this.chunkSections2MaybeContainsMatchingBlock = new FixedChunkAccessSectionBitBuffer(origin, horizontalRangeInclusive, verticalRangeInclusive);
this.levelReader = levelReader;
this.shouldChunkLoad = shouldChunkLoad;
this.blockStatePredicate = blockStatePredicate;
this.minSectionY = levelReader.getMinSectionY();
}
public void initializeChunks() {
this.initializeChunks(null);
}
public void initializeChunks(Consumer<Long> chunkCollector) {
final boolean nullChunkCollector = chunkCollector == null;
for (long chunkPos : this.chunkSections2MaybeContainsMatchingBlock.getChunkPosInRange()) {
int x = ChunkPos.getX(chunkPos);
int z = ChunkPos.getZ(chunkPos);
boolean chunkMaybeHas = false;
//Never load chunks in the first pass to avoid observably altering chunk loading behavior
//Otherwise full region will be loaded vs partial region if the search finds the block early.
ChunkAccess chunkAccess = levelReader.getChunk(x, z, ChunkStatus.FULL, false);
if (chunkAccess != null) {
this.chunkSections2MaybeContainsMatchingBlock.setChunkAccess(chunkPos, chunkAccess);
for (int y : this.chunkSections2MaybeContainsMatchingBlock.getSectionYInRange()) {
chunkMaybeHas = this.checkChunkSection(chunkAccess, x, y, z) || chunkMaybeHas;
}
} else if (this.shouldChunkLoad) {
/* If the search may chunk load then it is possible that target blocks may be revealed when the search
* reaches it. Since we cannot load the chunks and check now, we cannot definitively exclude subchunks
* inside the chunk. This means that we must flag subchunks that are within build limit - otherwise air
* anyway - for the search.
*/
for (int y : this.chunkSections2MaybeContainsMatchingBlock.getSectionYInRange()) {
this.chunkSections2MaybeContainsMatchingBlock.setChunkSectionStatus(SectionPos.asLong(x, y, z),
!levelReader.isOutsideBuildHeight(SectionPos.sectionToBlockCoord(y)));
++this.unloadedPossibleChunkSections;
}
chunkMaybeHas = true;
}
if (!nullChunkCollector && chunkMaybeHas) {
chunkCollector.accept(chunkPos);
}
}
}
public int getChunkSize() {
return this.chunkSections2MaybeContainsMatchingBlock.numChunks;
}
public boolean hasUnloadedPossibleChunks() {
return this.unloadedPossibleChunkSections > 0;
}
private boolean checkChunkSection(ChunkAccess chunkAccess, int chunkX, int chunkY, int chunkZ) {
final int chunkSectionYIndex = chunkY - this.minSectionY;
LevelChunkSection[] chunkSections = chunkAccess.getSections();
if (chunkSectionYIndex >= 0
&& chunkSectionYIndex < chunkSections.length
&& chunkSections[chunkSectionYIndex].maybeHas(blockStatePredicate)) {
this.chunkSections2MaybeContainsMatchingBlock.setChunkSectionStatus(
SectionPos.asLong(chunkX, chunkY, chunkZ), true);
return true;
}
return false;
}
public boolean checkCachedSection(int chunkX, int chunkY, int chunkZ) {
return this.chunkSections2MaybeContainsMatchingBlock.getChunkSectionBit(chunkX, chunkY, chunkZ);
}
public ChunkAccess getCachedChunkAccess(long chunkPos) {
return this.chunkSections2MaybeContainsMatchingBlock.getChunkAccess(chunkPos);
}
public ChunkAccess getCachedChunkAccess(BlockPos blockPos) {
return this.chunkSections2MaybeContainsMatchingBlock.getChunkAccess(blockPos);
}
public boolean shouldStop() {
return this.chunkSections2MaybeContainsMatchingBlock.hasNoTrueChunkSections();
}
public boolean checkPosition(BlockPos blockPos) {
if (!this.chunkSections2MaybeContainsMatchingBlock.getChunkSectionBit(blockPos)) return false;
ChunkAccess chunkAccess = this.chunkSections2MaybeContainsMatchingBlock.getChunkAccess(blockPos);
if (chunkAccess == null) {
if (!this.shouldChunkLoad) {
return false;
}
final int chunkX = SectionPos.blockToSectionCoord(blockPos.getX());
final int chunkY = SectionPos.blockToSectionCoord(blockPos.getY());
final int chunkZ = SectionPos.blockToSectionCoord(blockPos.getZ());
chunkAccess = levelReader.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true);
//this chunkAccess cannot be null and reach here because it should throw earlier
assert chunkAccess != null;
this.chunkSections2MaybeContainsMatchingBlock.setChunkAccess(blockPos, chunkAccess);
if (!checkChunkSection(chunkAccess, chunkX, chunkY, chunkZ)) {
--this.unloadedPossibleChunkSections;
return false;
}
}
return blockStatePredicate.test(chunkAccess.getBlockState(blockPos));
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of Lithium
*
* Lithium is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Lithium is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Lithium. If not, see <https://www.gnu.org/licenses/>.
*/
package net.caffeinemc.mods.lithium.common.ai.non_poi_block_search;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.state.BlockState;
import java.util.Optional;
import java.util.function.Predicate;
/**
* Uses CheckAndCacheBlockChecker to improve common block searches
*/
public class CommonBlockSearchesCheckAndCache {
/**
* Optimizes BlockPos::findClosestMatch
* [Vanilla Copy] search order and chunk-loading - even though the latter is unlikely to be observable in vanilla.
*/
public static Optional<BlockPos> blockPosFindClosestMatch(LevelReader levelReader, LivingEntity livingEntity,
int horizontalRange, int verticalRange,
Predicate<BlockState> blockStatePredicate,
boolean shouldChunkLoad) {
BlockPos mobPos = livingEntity.blockPosition();
CheckAndCacheBlockChecker checker = new CheckAndCacheBlockChecker(
mobPos, horizontalRange, verticalRange, levelReader, blockStatePredicate, shouldChunkLoad);
checker.initializeChunks();
if (checker.shouldStop()) {
return Optional.empty();
}
return BlockPos.findClosestMatch(mobPos, horizontalRange, verticalRange, checker::checkPosition);
}
}
@@ -0,0 +1,30 @@
/*
* This file is part of Lithium
*
* Lithium is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Lithium is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Lithium. If not, see <https://www.gnu.org/licenses/>.
*/
package net.caffeinemc.mods.lithium.common.ai.non_poi_block_search;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
public interface LithiumMoveToBlockGoal {
boolean lithium$findNearestBlock(Predicate<BlockState> requiredBlock,
BiPredicate<ChunkAccess, BlockPos.MutableBlockPos> lithium$isValidTarget,
final boolean shouldChunkLoad);
}
@@ -0,0 +1,68 @@
/*
* This file is part of Lithium
*
* Lithium is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Lithium is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Lithium. If not, see <https://www.gnu.org/licenses/>.
*/
package net.caffeinemc.mods.lithium.common.ai.non_poi_block_search;
import net.caffeinemc.mods.lithium.common.util.Distances;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
public class NonPOISearchDistances {
public static class MoveToBlockGoalDistances {
public static int getMinimumSortOrderOfChunk(BlockPos center, final long chunkPos) {
return getMinimumSortOrderOfChunk(center, ChunkPos.getX(chunkPos), ChunkPos.getZ(chunkPos));
}
public static int getMinimumSortOrderOfChunk(BlockPos center, final int chunkX, final int chunkZ) {
final int dX = Distances.getClosestBlockCoordInSection(center.getX(), chunkX) - center.getX();
final int dZ = Distances.getClosestBlockCoordInSection(center.getZ(), chunkZ) - center.getZ();
//This will always get the closest one due to the nature of the search
return getVanillaSortOrderInt(getRing(dX, dZ), dX, dZ);
}
public static int getRing(final int dX, final int dZ) {
return Math.max(Math.abs(dX), Math.abs(dZ));
}
/**
* Sort order function for 1 layer of MoveToBlockGoal findNearestBlock
* This is equivalent to:
* int withinRingX = Math.abs(dX) * 2 - (dX > 0 ? 1 : 0);
* int withinRingZ = Math.abs(dZ) * 2 - (dZ > 0 ? 1 : 0);
* return ring << 16 | withinRingX << 8 | withinRingZ;
* <p>
* This works because the search prioritizes in order of:
* 1. The distance of y from the center - Not used
* 2. Whether y is - or + (+ is closer) - Not used
* 3. The square ring that the block is in (outer is further)
* 4. The distance of x from the center
* 5. Whether x is - or + (+ is closer)
* 6. The distance of z from the center
* 7. Whether z is - or + (+ is closer)
* <p>
* Note: The bit-packing only works for horizontal search ranges of <=128.
* You can convert to longs if you somehow exceed that, but also seriously consider POIs instead.
*
* @param ring Which square ring the block is at relative to the center
* @param dX Relative x position of the block to the center
* @param dZ Relative z position of the block to the center
*/
public static int getVanillaSortOrderInt(final int ring, final int dX, final int dZ) {
return (ring << 16 | Math.abs(dX) << 9 | Math.abs(dZ) << 1) - ((dX > 0 ? 1 : 0) << 8 | (dZ > 0 ? 1 : 0));
}
}
}
@@ -0,0 +1,83 @@
/*
* This file is part of Lithium
*
* Lithium is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Lithium is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Lithium. If not, see <https://www.gnu.org/licenses/>.
*/
package net.caffeinemc.mods.lithium.common.util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
public class Distances {
public static long getMinChunkToBlockDistanceL2Sq(BlockPos origin, int chunkX, int chunkZ) {
int chunkMinX = SectionPos.sectionToBlockCoord(chunkX);
int chunkMinZ = SectionPos.sectionToBlockCoord(chunkZ);
int xDistance = origin.getX() - chunkMinX;
if (xDistance > 0) {
xDistance = Math.max(0, xDistance - 15);
}
int zDistance = origin.getZ() - chunkMinZ;
if (zDistance > 0) {
zDistance = Math.max(0, zDistance - 15);
}
return (long) xDistance * (long) xDistance + (long) zDistance * (long) zDistance;
}
public static BlockPos getClosestPosInChunk(BlockPos origin, int chunkX, int chunkZ) {
int closestX = getClosestBlockCoordInSection(origin.getX(), chunkX);
int closestZ = getClosestBlockCoordInSection(origin.getZ(), chunkZ);
return new BlockPos(closestX, origin.getY(), closestZ);
}
public static boolean isWithinCubeRadius(BlockPos origin, int radius, BlockPos pos) {
return Math.abs(pos.getX() - origin.getX()) <= radius &&
Math.abs(pos.getZ() - origin.getZ()) <= radius;
}
public static boolean isWithinSphereRadius(BlockPos origin, long radiusSq, BlockPos pos) {
return distanceSq(origin, pos) <= radiusSq;
}
public static int getClosestBlockCoordInSection(int blockCoord, int sectionCoord) {
final int minBlockInSection = SectionPos.sectionToBlockCoord(sectionCoord);
return Math.min(Math.max(blockCoord, minBlockInSection), minBlockInSection + 15);
}
public static long getMinSectionDistanceSq(BlockPos origin, int chunkX, int chunkY, int chunkZ) {
int originX = origin.getX(), originY = origin.getY(), originZ = origin.getZ();
long distX = getClosestBlockCoordInSection(originX, chunkX) - originX;
long distY = getClosestBlockCoordInSection(originY, chunkY) - originY;
long distZ = getClosestBlockCoordInSection(originZ, chunkZ) - originZ;
return distX * distX + distY * distY + distZ * distZ;
}
public static long distanceSq(BlockPos a, BlockPos b) {
long dx = a.getX() - b.getX();
long dy = a.getY() - b.getY();
long dz = a.getZ() - b.getZ();
return dx * dx + dy * dy + dz * dz;
}
public static int distanceSqInt(BlockPos a, BlockPos b) {
int dx = a.getX() - b.getX();
int dy = a.getY() - b.getY();
int dz = a.getZ() - b.getZ();
// Check overflows to avoid silent incorrect results
return Math.addExact(Math.addExact(Math.multiplyExact(dx, dx), Math.multiplyExact(dy, dy)), Math.multiplyExact(dz, dz));
}
}
@@ -0,0 +1,120 @@
/*
* This file is part of Lithium
*
* Lithium is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Lithium is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Lithium. If not, see <https://www.gnu.org/licenses/>.
*/
package net.caffeinemc.mods.lithium.common.util;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.LevelHeightAccessor;
public class Pos {
public static class BlockCoord {
public static int getYSize(LevelHeightAccessor view) {
return view.getHeight();
}
public static int getMinY(LevelHeightAccessor view) {
return view.getMinY();
}
public static int getMaxYInclusive(LevelHeightAccessor view) {
return view.getMaxY();
}
public static int getMaxYExclusive(LevelHeightAccessor view) {
return view.getMaxY() + 1;
}
public static int getMaxInSectionCoord(int sectionCoord) {
return 15 + getMinInSectionCoord(sectionCoord);
}
public static int getMaxYInSectionIndex(LevelHeightAccessor view, int sectionIndex) {
return getMaxInSectionCoord(SectionYCoord.fromSectionIndex(view, sectionIndex));
}
public static int getMinInSectionCoord(int sectionCoord) {
return SectionPos.sectionToBlockCoord(sectionCoord);
}
public static int getMinYInSectionIndex(LevelHeightAccessor view, int sectionIndex) {
return getMinInSectionCoord(SectionYCoord.fromSectionIndex(view, sectionIndex));
}
}
public static class ChunkCoord {
public static int fromBlockCoord(int blockCoord) {
return SectionPos.blockToSectionCoord(blockCoord);
}
public static int fromBlockSize(int i) {
return i >> 4; //same method as fromBlockCoord, just be clear about coord/size semantic difference
}
}
public static class SectionYCoord {
public static int getNumYSections(LevelHeightAccessor view) {
return view.getSectionsCount();
}
public static int getMinYSection(LevelHeightAccessor view) {
return view.getMinSectionY();
}
public static int getMaxYSectionInclusive(LevelHeightAccessor view) {
return view.getMaxSectionY();
}
public static int getMaxYSectionExclusive(LevelHeightAccessor view) {
return view.getMaxSectionY() + 1;
}
public static int fromSectionIndex(LevelHeightAccessor view, int sectionCoord) {
return sectionCoord + SectionYCoord.getMinYSection(view);
}
public static int fromBlockCoord(int blockCoord) {
return SectionPos.blockToSectionCoord(blockCoord);
}
}
public static class SectionYIndex {
public static int getNumYSections(LevelHeightAccessor view) {
return view.getSectionsCount();
}
public static int getMinYSectionIndex(LevelHeightAccessor view) {
return 0;
}
public static int getMaxYSectionIndexInclusive(LevelHeightAccessor view) {
return view.getSectionsCount() - 1;
}
public static int getMaxYSectionIndexExclusive(LevelHeightAccessor view) {
return view.getSectionsCount();
}
public static int fromSectionCoord(LevelHeightAccessor view, int sectionCoord) {
return sectionCoord - SectionYCoord.getMinYSection(view);
}
public static int fromBlockCoord(LevelHeightAccessor view, int blockCoord) {
return fromSectionCoord(view, SectionPos.blockToSectionCoord(blockCoord));
}
}
}
@@ -0,0 +1,189 @@
/*
* This file is part of Lithium
*
* Lithium is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Lithium is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Lithium. If not, see <https://www.gnu.org/licenses/>.
*/
package net.caffeinemc.mods.lithium.common.util.collections;
import it.unimi.dsi.fastutil.ints.IntIterable;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.longs.LongIterable;
import it.unimi.dsi.fastutil.longs.LongIterator;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
public class FixedChunkAccessSectionBitBuffer {
public final int xMin, yMin, zMin;
public final int xLength, yLength, zLength, numChunks, numSections;
public final BitSet chunkSectionBits;
public final ArrayList<ChunkAccess> chunkAccesses;
public FixedChunkAccessSectionBitBuffer(int x0, int x1, int y0, int y1, int z0, int z1) {
this.xMin = Math.min(x0, x1);
this.yMin = Math.min(y0, y1);
this.zMin = Math.min(z0, z1);
this.xLength = Math.max(x0, x1) - this.xMin + 1;
this.yLength = Math.max(y0, y1) - this.yMin + 1;
this.zLength = Math.max(z0, z1) - this.zMin + 1;
this.numChunks = xLength * zLength;
this.numSections = yLength * xLength * zLength;
this.chunkSectionBits = new BitSet(numSections);
this.chunkAccesses = new ArrayList<>(Collections.nCopies(xLength * zLength, null));
}
public FixedChunkAccessSectionBitBuffer(BlockPos center, int horizontalRangeInclusive, int verticalRangeInclusive) {
this(SectionPos.blockToSectionCoord(center.getX() - horizontalRangeInclusive),
SectionPos.blockToSectionCoord(center.getX() + horizontalRangeInclusive),
SectionPos.blockToSectionCoord(center.getY() - verticalRangeInclusive),
SectionPos.blockToSectionCoord(center.getY() + verticalRangeInclusive),
SectionPos.blockToSectionCoord(center.getZ() - horizontalRangeInclusive),
SectionPos.blockToSectionCoord(center.getZ() + horizontalRangeInclusive)
);
}
public int getSectionIndex(int x, int y, int z) {
int dx = x - this.xMin;
int dy = y - this.yMin;
int dz = z - this.zMin;
return (dx * this.zLength + dz) * this.yLength + dy;
}
public int getSectionIndex(long sectionPos) {
return this.getSectionIndex(
SectionPos.x(sectionPos),
SectionPos.y(sectionPos),
SectionPos.z(sectionPos)
);
}
public boolean getChunkSectionBit(BlockPos blockPos) {
return this.getChunkSectionBit(SectionPos.blockToSectionCoord(blockPos.getX()), SectionPos.blockToSectionCoord(blockPos.getY()), SectionPos.blockToSectionCoord(blockPos.getZ()));
}
public boolean getChunkSectionBit(int chunkX, int chunkY, int chunkZ) {
return this.chunkSectionBits.get(this.getSectionIndex(chunkX, chunkY, chunkZ));
}
public void setChunkSectionStatus(long sectionPos, boolean value) {
this.chunkSectionBits.set(this.getSectionIndex(sectionPos), value);
}
public int getChunkIndex(int x, int z) {
int dx = x - this.xMin;
int dz = z - this.zMin;
return dx * this.zLength + dz;
}
public int getChunkIndex(long chunkPos) {
return this.getChunkIndex(ChunkPos.getX(chunkPos), ChunkPos.getZ(chunkPos));
}
public ChunkAccess getChunkAccess(long chunkPos) {
return this.chunkAccesses.get(this.getChunkIndex(chunkPos));
}
public ChunkAccess getChunkAccess(BlockPos blockPos) {
return this.getChunkAccess(ChunkPos.pack(blockPos));
}
public void setChunkAccess(long chunkPos, ChunkAccess chunkAccess) {
this.chunkAccesses.set(this.getChunkIndex(chunkPos), chunkAccess);
}
public void setChunkAccess(BlockPos blockPos, ChunkAccess chunkAccess) {
this.setChunkAccess(ChunkPos.pack(blockPos), chunkAccess);
}
public boolean hasNoTrueChunkSections() {
return this.chunkSectionBits.nextSetBit(0) == -1;
}
public LongIterable getChunkPosInRange() {
return new LongIterable() {
@Override
public @NotNull LongIterator iterator() {
return getChunkPosInRangeIterator();
}
};
}
public LongIterator getChunkPosInRangeIterator() {
final int xMin = this.xMin;
final int xMax = this.xMin + this.xLength - 1;
final int zMin = this.zMin;
final int zMax = this.zMin + this.zLength - 1;
return new LongIterator() {
int x = xMin;
int z = zMin;
@Override
public long nextLong() {
long result = ChunkPos.pack(x, z);
if (z < zMax) {
z++;
} else {
z = zMin;
x++;
}
return result;
}
@Override
public boolean hasNext() {
return x <= xMax;
}
};
}
public IntIterable getSectionYInRange() {
return new IntIterable() {
@Override
public @NotNull IntIterator iterator() {
return getSectionYInRangeIterator();
}
};
}
public IntIterator getSectionYInRangeIterator() {
final int yMin = this.yMin;
final int yLimit = yMin + this.yLength;
return new IntIterator() {
int y = yMin;
@Override
public int nextInt() {
return y++;
}
@Override
public boolean hasNext() {
return y < yLimit;
}
};
}
}
@@ -0,0 +1,293 @@
/*
* This file is part of Lithium
*
* Lithium is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Lithium is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Lithium. If not, see <https://www.gnu.org/licenses/>.
*/
package net.caffeinemc.mods.lithium.common.util.collections;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import org.jetbrains.annotations.NotNull;
import java.util.*;
/**
* Wraps a {@link List} with a hash table which provides O(1) lookups for {@link Collection#contains(Object)}. The type
* contained by this list must use reference-equality semantics.
*/
@SuppressWarnings("SuspiciousMethodCalls")
public class HashedReferenceList<T> implements List<T> {
private final ReferenceArrayList<T> list;
private final Reference2IntOpenHashMap<T> counter;
public HashedReferenceList(Collection<T> list) {
this.list = new ReferenceArrayList<>();
this.list.addAll(list);
this.counter = new Reference2IntOpenHashMap<>();
this.counter.defaultReturnValue(0);
for (T obj : this.list) {
this.counter.addTo(obj, 1);
}
}
@Override
public int size() {
return this.list.size();
}
@Override
public boolean isEmpty() {
return this.list.isEmpty();
}
@Override
public boolean contains(Object o) {
return this.counter.containsKey(o);
}
@Override
public Iterator<T> iterator() {
return this.listIterator();
}
@Override
public Object[] toArray() {
return this.list.toArray();
}
@Override
public <T1> T1[] toArray(T1 @NotNull [] a) {
return this.list.toArray(a);
}
@Override
public boolean add(T t) {
this.trackReferenceAdded(t);
return this.list.add(t);
}
@Override
public boolean remove(Object o) {
this.trackReferenceRemoved(o);
return this.list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object obj : c) {
if (!this.counter.containsKey(obj)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends T> c) {
for (T obj : c) {
this.trackReferenceAdded(obj);
}
return this.list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
for (T obj : c) {
this.trackReferenceAdded(obj);
}
return this.list.addAll(index, c);
}
@Override
public boolean removeAll(@NotNull Collection<?> c) {
if (this.size() >= 2 && c.size() > 4 && c instanceof List) {
//HashReferenceList uses reference equality, so using ReferenceOpenHashSet is fine
c = new ReferenceOpenHashSet<>(c);
}
this.counter.keySet().removeAll(c);
return this.list.removeAll(c);
}
@Override
public boolean retainAll(@NotNull Collection<?> c) {
this.counter.keySet().retainAll(c);
return this.list.retainAll(c);
}
@Override
public void clear() {
this.counter.clear();
this.list.clear();
}
@Override
public T get(int index) {
return this.list.get(index);
}
@Override
public T set(int index, T element) {
T prev = this.list.set(index, element);
if (prev != element) {
if (prev != null) {
this.trackReferenceRemoved(prev);
}
this.trackReferenceAdded(element);
}
return prev;
}
@Override
public void add(int index, T element) {
this.trackReferenceAdded(element);
this.list.add(index, element);
}
@Override
public T remove(int index) {
T prev = this.list.remove(index);
if (prev != null) {
this.trackReferenceRemoved(prev);
}
return prev;
}
@Override
public int indexOf(Object o) {
return this.list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return this.list.lastIndexOf(o);
}
@Override
public ListIterator<T> listIterator() {
return this.listIterator(0);
}
@Override
public ListIterator<T> listIterator(int index) {
return new ListIterator<>() {
private final ListIterator<T> inner = HashedReferenceList.this.list.listIterator(index);
@Override
public boolean hasNext() {
return this.inner.hasNext();
}
@Override
public T next() {
return this.inner.next();
}
@Override
public boolean hasPrevious() {
return this.inner.hasPrevious();
}
@Override
public T previous() {
return this.inner.previous();
}
@Override
public int nextIndex() {
return this.inner.nextIndex();
}
@Override
public int previousIndex() {
return this.inner.previousIndex();
}
@Override
public void remove() {
int last = this.previousIndex();
if (last == -1) {
throw new NoSuchElementException();
}
T prev = HashedReferenceList.this.get(last);
if (prev != null) {
HashedReferenceList.this.trackReferenceRemoved(prev);
}
this.inner.remove();
}
@Override
public void set(T t) {
int last = this.previousIndex();
if (last == -1) {
throw new NoSuchElementException();
}
T prev = HashedReferenceList.this.get(last);
if (prev != t) {
if (prev != null) {
HashedReferenceList.this.trackReferenceRemoved(prev);
}
HashedReferenceList.this.trackReferenceAdded(t);
}
this.inner.remove();
}
@Override
public void add(T t) {
HashedReferenceList.this.trackReferenceAdded(t);
this.inner.add(t);
}
};
}
@Override
public List<T> subList(int fromIndex, int toIndex) {
return this.list.subList(fromIndex, toIndex);
}
private void trackReferenceAdded(T t) {
this.counter.addTo(t, 1);
}
@SuppressWarnings("unchecked")
private void trackReferenceRemoved(Object o) {
if (this.counter.addTo((T) o, -1) <= 1) {
this.counter.removeInt(o);
}
}
}
@@ -116,7 +116,7 @@ public record BotCreateState(String rawName, String fullName, String skinName, S
}
public void spawnWithSkin(Consumer<Bot> consumer) {
Bukkit.getAsyncScheduler().runNow(MinecraftInternalPlugin.INSTANCE, (task0) -> {
Bukkit.getAsyncScheduler().runNow(MinecraftInternalPlugin.INSTANCE, (_) -> {
this.mojangAPISkin();
Bukkit.getRegionScheduler().execute(
MinecraftInternalPlugin.INSTANCE,
@@ -22,6 +22,7 @@ import net.minecraft.core.UUIDUtil;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtAccounter;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.Tag;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.storage.LevelResource;
@@ -34,7 +35,10 @@ import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class BotDataStorage {
@@ -42,7 +46,7 @@ public class BotDataStorage {
private final File botDir;
private final File botListFile;
private CompoundTag savedBotList;
private final CompoundTag savedBotList;
public BotDataStorage(LevelStorageSource.@NotNull LevelStorageAccess session, String dataDir, String listFileName) {
this.botDir = session.getLevelPath(new LevelResource(dataDir)).toFile();
@@ -52,7 +56,11 @@ public class BotDataStorage {
this.savedBotList = new CompoundTag();
if (this.botListFile.exists() && this.botListFile.isFile()) {
try {
Optional.of(NbtIo.readCompressed(this.botListFile.toPath(), NbtAccounter.unlimitedHeap())).ifPresent(tag -> this.savedBotList = tag);
Optional.of(NbtIo.readCompressed(this.botListFile.toPath(), NbtAccounter.unlimitedHeap())).ifPresent(tag -> {
for (Map.Entry<String, Tag> entry : tag.entrySet()) {
savedBotList.put(entry.getKey().toLowerCase(Locale.ROOT), entry.getValue());
}
});
} catch (Exception exception) {
BotDataStorage.LOGGER.warn("Failed to load player data list");
}
@@ -60,7 +68,6 @@ public class BotDataStorage {
}
public void save(Player player) {
boolean flag = true;
try {
CompoundTag nbt = TagUtil.saveEntityWithoutId(player);
File file = new File(this.botDir, player.getStringUUID() + ".dat");
@@ -76,20 +83,19 @@ public class BotDataStorage {
NbtIo.writeCompressed(nbt, file.toPath());
} catch (Exception exception) {
BotDataStorage.LOGGER.warn("Failed to save fakeplayer data for {}", player.getScoreboardName(), exception);
flag = false;
return;
}
if (flag && player instanceof ServerBot bot) {
if (player instanceof ServerBot bot) {
CompoundTag nbt = new CompoundTag();
nbt.putString("name", bot.createState.fullName());
nbt.store("uuid", UUIDUtil.CODEC, bot.getUUID());
nbt.putBoolean("resume", bot.resume);
this.savedBotList.put(bot.createState.fullName(), nbt);
this.savedBotList.put(bot.createState.fullName().toLowerCase(Locale.ROOT), nbt);
this.saveBotList();
}
}
public Optional<ValueInput> load(@NotNull ServerBot bot, ProblemReporter reporter) {
return this.load(bot.nameAndId().name(), bot.nameAndId().id().toString()).map(nbt -> {
ValueInput valueInput = TagValueInput.create(reporter, bot.registryAccess(), nbt);
@@ -98,27 +104,27 @@ public class BotDataStorage {
});
}
public void removeSavedData(@NotNull ServerBot bot) {
this.load(bot.nameAndId().name(), bot.nameAndId().id().toString());
public void removeSavedData(String name) {
this.savedBotList.remove(name.toLowerCase(Locale.ROOT));
this.saveBotList();
}
private Optional<CompoundTag> load(String name, String uuid) {
File file = new File(this.botDir, uuid + ".dat");
if (file.exists() && file.isFile()) {
try {
Optional<CompoundTag> optional = Optional.of(NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap()));
if (!file.delete()) {
throw new IOException("Failed to delete fakeplayer data");
}
this.savedBotList.remove(name);
this.saveBotList();
return optional;
} catch (Exception exception) {
BotDataStorage.LOGGER.warn("Failed to load fakeplayer data for {}", name);
}
if (!file.exists() || !file.isFile()) {
LOGGER.warn("Failed to load bot {}, the file {} DOES NOT EXIST!", name, file);
return Optional.empty();
}
try {
Optional<CompoundTag> optional = Optional.of(NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap()));
if (!file.delete()) {
throw new IOException("Failed to delete fakeplayer data");
}
this.removeSavedData(name);
return optional;
} catch (Exception exception) {
BotDataStorage.LOGGER.warn("Failed to load fakeplayer data for {}", name);
}
return Optional.empty();
}
@@ -153,4 +159,12 @@ public class BotDataStorage {
public CompoundTag getSavedBotList() {
return savedBotList;
}
public UUID getUUIDFromLower(String lowerName) {
return savedBotList.getCompoundOrEmpty(lowerName).read("uuid", UUIDUtil.CODEC).orElseThrow();
}
public String getNameFromLower(String lowerName) {
return savedBotList.getCompoundOrEmpty(lowerName).getString("name").orElseThrow();
}
}
@@ -28,11 +28,11 @@ import fun.bm.lophine.config.modules.function.OldFeatureConfig;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.profile.MutablePropertyMap;
import io.papermc.paper.threadedregions.RegionizedServer;
import io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler;
import io.papermc.paper.util.MCUtil;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
import net.minecraft.resources.ResourceKey;
@@ -76,7 +76,7 @@ public class BotList {
private final BotDataStorage resumeDataStorage;
private final Map<UUID, ServerBot> botsByUUID = Maps.newHashMap();
private final Map<String, ServerBot> botsByName = Maps.newHashMap();
private final Map<String, ServerBot> botsByLowerName = Maps.newHashMap();
private final Map<String, Set<String>> botsNameByWorldUuid = Maps.newHashMap();
private final Map<String, Set<String>> legacyBotsNameByWorldUuid = Maps.newHashMap();
@@ -141,20 +141,24 @@ public class BotList {
return this.loadNewBot(fullName, this.resumeDataStorage);
}
public ServerBot loadNewBot(String fullName, BotDataStorage storage) {
if (botsByName.containsKey(fullName)) {
public ServerBot loadNewBot(String inputName, BotDataStorage storage) {
String lowerName = inputName.toLowerCase(Locale.ROOT);
if (botsByLowerName.containsKey(lowerName)) {
return null;
}
try {
UUID uuid = BotUtil.getBotUUID(fullName);
BotLoadEvent event = new BotLoadEvent(fullName, uuid);
if (!storage.getSavedBotList().contains(lowerName)) {
return null;
}
String name = storage.getNameFromLower(lowerName);
UUID uuid = storage.getUUIDFromLower(lowerName);
BotLoadEvent event = new BotLoadEvent(name, uuid);
this.server.server.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return null;
}
ServerBot bot = new ServerBot(this.server, this.server.getLevel(Level.OVERWORLD), new GameProfile(uuid, fullName));
ServerBot bot = new ServerBot(this.server, this.server.getLevel(Level.OVERWORLD), new GameProfile(uuid, name));
bot.connection = new ServerBotPacketListenerImpl(this.server, bot);
Optional<ValueInput> optional;
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(bot.problemPath(), LOGGER)) {
@@ -182,7 +186,7 @@ public class BotList {
ServerLevel world = this.server.getLevel(resourcekey);
return this.placeNewBot(bot, world, bot.getLocation(), nbt);
} catch (Exception e) {
LOGGER.error("Failed to load bot {}", fullName, e);
LOGGER.error("Failed to load bot {}", inputName, e);
return null;
}
}
@@ -213,18 +217,20 @@ public class BotList {
bot.connection.teleport(bot.getX(), bot.getY(), bot.getZ(), bot.getYRot(), bot.getXRot());
this.bots.add(bot);
this.botsByName.put(bot.getScoreboardName().toLowerCase(Locale.ROOT), bot);
this.botsByLowerName.put(bot.getScoreboardName().toLowerCase(Locale.ROOT), bot);
this.botsByUUID.put(bot.getUUID(), bot);
bot.suppressTrackerForLogin = true;
Runnable task = () -> {
world.addNewPlayer(bot);
optional.ifPresent(nbt -> {
bot.loadAndSpawnEnderPearls(nbt);
bot.loadAndSpawnParentVehicle(nbt);
});
world.getCurrentWorldData().connections.add(bot.connection.connection);
world.addNewPlayer(bot);
BotJoinEvent event1 = new BotJoinEvent(bot.getBukkitEntity(), PaperAdventure.asAdventure(Component.translatable("multiplayer.player.joined", bot.getDisplayName())).style(Style.style(NamedTextColor.YELLOW)));
this.server.server.getPluginManager().callEvent(event1);
@@ -279,13 +285,13 @@ public class BotList {
}
if (bot.removeTaskId != -1) {
((FoliaGlobalRegionScheduler) Bukkit.getGlobalRegionScheduler()).cancelTask(bot.removeTaskId);
Bukkit.getGlobalRegionScheduler().cancelTask(bot.removeTaskId);
bot.removeTaskId = -1;
}
bot.disconnect();
this.resumeDataStorage.removeSavedData(bot);
this.resumeDataStorage.removeSavedData(bot.nameAndId().name());
if (event.shouldSave()) {
if (resume) {
this.resumeDataStorage.save(bot);
@@ -293,6 +299,7 @@ public class BotList {
this.manualSaveDataStorage.save(bot);
}
} else {
bot.dropExperience(bot.level(), null);
bot.dropAll(true);
botsNameByWorldUuid.getOrDefault(bot.level().uuid.toString(), new HashSet<>()).remove(bot.getBukkitEntity().getName());
}
@@ -327,7 +334,7 @@ public class BotList {
bot.retireScheduler();
this.bots.remove(bot);
this.botsByName.remove(bot.getScoreboardName().toLowerCase(Locale.ROOT));
this.botsByLowerName.remove(bot.getScoreboardName().toLowerCase(Locale.ROOT));
UUID uuid = bot.getUUID();
ServerBot bot1 = this.botsByUUID.get(uuid);
@@ -400,7 +407,9 @@ public class BotList {
return;
}
CompoundTag savedBotList = this.getResumeBotList().copy();
for (String fullName : savedBotList.keySet()) {
for (Map.Entry<String, Tag> entry : savedBotList.entrySet()) {
String lowerName = entry.getKey();
String fullName = ((CompoundTag) entry.getValue()).getStringOr("name", lowerName);
UUID levelUuid = BotUtil.getBotLevel(fullName, this.resumeDataStorage);
if (levelUuid == null) {
LOGGER.warn("Bot {} has no world UUID, skipping loading.", fullName);
@@ -416,6 +425,7 @@ public class BotList {
private void loadLegacyResumeBotInfo() {
CompoundTag savedBotList = this.getManualSavedBotList().copy();
for (String fullName : savedBotList.keySet()) {
// Legacy format saved fullName as the key
CompoundTag nbt = savedBotList.getCompound(fullName).orElseThrow();
if (!nbt.getBoolean("resume").orElse(false)) {
continue;
@@ -461,7 +471,7 @@ public class BotList {
@Nullable
public ServerBot getBotByName(@NotNull String name) {
return this.botsByName.get(name.toLowerCase(Locale.ROOT));
return this.botsByLowerName.get(name.toLowerCase(Locale.ROOT));
}
public CompoundTag getManualSavedBotList() {
@@ -24,7 +24,6 @@ import net.minecraft.stats.ServerStatsCounter;
import net.minecraft.stats.Stat;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NonNull;
import java.io.File;
@@ -45,7 +44,7 @@ public class BotStatsCounter extends ServerStatsCounter {
}
@Override
public void parse(@NonNull DataFixer fixerUpper, @NonNull JsonElement json) {
public void parse(DataFixer fixerUpper, JsonElement json) {
}
@Override
@@ -18,15 +18,11 @@
package org.leavesmc.leaves.bot;
import com.google.common.base.Charsets;
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
import net.minecraft.core.NonNullList;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.ItemContainerContents;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
@@ -38,66 +34,23 @@ public class BotUtil {
public static void replenishment(@NotNull ItemStack itemStack, NonNullList<ItemStack> itemStackList) {
int count = itemStack.getMaxStackSize() / 2;
if (itemStack.getCount() <= 8 && count > 8) {
if (pullMatchingStack(itemStack, itemStackList, count)) {
return;
}
if (FakePlayerCompatConfig.fakePlayerAutoReplenishmentFormShulkerBox) {
pullMatchingStackFromShulkerBox(itemStack, itemStackList, count);
}
}
}
private static boolean pullMatchingStack(@NotNull ItemStack targetStack, NonNullList<ItemStack> itemStackList, int transferLimit) {
for (ItemStack inventoryStack : itemStackList) {
if (inventoryStack == ItemStack.EMPTY || inventoryStack == targetStack) {
continue;
}
if (ItemStack.isSameItemSameComponents(inventoryStack, targetStack)) {
if (inventoryStack.getCount() > transferLimit) {
targetStack.setCount(targetStack.getCount() + transferLimit);
inventoryStack.setCount(inventoryStack.getCount() - transferLimit);
} else {
targetStack.setCount(targetStack.getCount() + inventoryStack.getCount());
inventoryStack.setCount(0);
}
return true;
}
}
return false;
}
private static boolean pullMatchingStackFromShulkerBox(@NotNull ItemStack targetStack, NonNullList<ItemStack> itemStackList, int transferLimit) {
for (ItemStack containerStack : itemStackList) {
if (containerStack == ItemStack.EMPTY || !containerStack.is(ItemTags.SHULKER_BOXES)) {
continue;
}
ItemContainerContents contents = containerStack.getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY);
NonNullList<ItemStack> shulkerItems = NonNullList.withSize(contents.items.size(), ItemStack.EMPTY);
contents.copyInto(shulkerItems);
for (int slot = 0; slot < shulkerItems.size(); slot++) {
ItemStack shulkerStack = shulkerItems.get(slot);
if (shulkerStack.isEmpty() || !ItemStack.isSameItemSameComponents(shulkerStack, targetStack)) {
for (ItemStack itemStack1 : itemStackList) {
if (itemStack1 == ItemStack.EMPTY || itemStack1 == itemStack) {
continue;
}
int moved = Math.min(Math.min(transferLimit, shulkerStack.getCount()), targetStack.getMaxStackSize() - targetStack.getCount());
if (moved <= 0) {
return false;
if (ItemStack.isSameItemSameComponents(itemStack1, itemStack)) {
if (itemStack1.getCount() > count) {
itemStack.setCount(itemStack.getCount() + count);
itemStack1.setCount(itemStack1.getCount() - count);
} else {
itemStack.setCount(itemStack.getCount() + itemStack1.getCount());
itemStack1.setCount(0);
}
break;
}
targetStack.grow(moved);
shulkerStack.shrink(moved);
shulkerItems.set(slot, shulkerStack.isEmpty() ? ItemStack.EMPTY : shulkerStack);
containerStack.set(DataComponents.CONTAINER, ItemContainerContents.fromItems(shulkerItems));
return true;
}
}
return false;
}
public static void replaceTool(@NotNull EquipmentSlot slot, @NotNull ServerBot bot) {
@@ -93,7 +93,7 @@ public class ServerBot extends ServerPlayer {
private static final int AUTO_FISH_ENTITY_DELAY = 20;
private final List<AbstractBotAction<?>> actions;
private final Map<String, AbstractBotConfig<?, ?>> configs;
private final Map<String, AbstractBotConfig<?>> configs;
public boolean resume = false;
public BotCreateState createState;
@@ -116,9 +116,10 @@ public class ServerBot extends ServerPlayer {
this.gameMode = new ServerBotGameMode(this);
this.actions = new ArrayList<>();
ImmutableMap.Builder<String, AbstractBotConfig<?, ?>> configBuilder = ImmutableMap.builder();
for (AbstractBotConfig<?, ?> config : Configs.getConfigs()) {
configBuilder.put(config.getName(), config.create().setBot(this));
ImmutableMap.Builder<String, AbstractBotConfig<?>> configBuilder = ImmutableMap.builder();
for (Configs<?> config : Configs.getConfigs()) {
configBuilder.put(config.getName(), config.create(this));
}
this.configs = configBuilder.build();
@@ -147,7 +148,7 @@ public class ServerBot extends ServerPlayer {
this.joining = false;
}
// this.resetOperationCountPerTick(); // Leaves - player operation limiter
//this.resetOperationCountPerTick(); // Leaves - player operation limiter // Lophine
this.wardenSpawnTracker.tick();
if (this.invulnerableTime > 0) {
this.invulnerableTime--;
@@ -303,19 +304,6 @@ public class ServerBot extends ServerPlayer {
this.stopUsingItem();
teleportTransition.postTeleportTransition().onTransition(this);
this.isChangingDimension = false;
// Lophine - We don't have this
/* if (LeavesConfig.modify.netherPortalFix) {
final ResourceKey<Level> fromDim = fromLevel.dimension();
final ResourceKey<Level> toDim = level().dimension();
if (!((fromDim != Level.OVERWORLD || toDim != Level.NETHER) && (fromDim != Level.NETHER || toDim != Level.OVERWORLD))) {
BlockPos fromPortal = org.leavesmc.leaves.util.ReturnPortalManager.findPortalAt(this, fromDim, lastPos);
BlockPos toPos = this.blockPosition();
if (fromPortal != null) {
org.leavesmc.leaves.util.ReturnPortalManager.storeReturnPortal(this, toDim, toPos, fromPortal);
}
}
}*/
if (this.isBlocking()) {
this.stopUsingItem();
}
@@ -348,10 +336,8 @@ public class ServerBot extends ServerPlayer {
ItemStack item = this.getItemInHand(hand);
if (!item.isEmpty()) {
if (FakePlayerCompatConfig.fakePlayerAutoReplenishment) {
BotUtil.replenishment(item, getInventory().getNonEquipmentItems());
}
if (FakePlayerCompatConfig.fakePlayerAutoReplaceTool && BotUtil.isDamage(item, 10)) {
BotUtil.replenishment(item, getInventory().getNonEquipmentItems());
if (BotUtil.isDamage(item, 10)) {
BotUtil.replaceTool(hand == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND, this);
}
}
@@ -421,7 +407,7 @@ public class ServerBot extends ServerPlayer {
if (!this.configs.isEmpty()) {
ValueOutput.TypedOutputList<CompoundTag> configNbt = nbt.list("configs", CompoundTag.CODEC);
for (AbstractBotConfig<?, ?> config : this.configs.values()) {
for (AbstractBotConfig<?> config : this.configs.values()) {
configNbt.add(config.save(new CompoundTag()));
}
}
@@ -432,31 +418,23 @@ public class ServerBot extends ServerPlayer {
super.readAdditionalSaveData(nbt);
this.setShiftKeyDown(nbt.getBooleanOr("isShiftKeyDown", false));
CompoundTag createNbt = nbt.read("createStatus", CompoundTag.CODEC)
.orElseThrow(() -> new IllegalArgumentException("Missing bot createStatus"));
String rawName = createNbt.getString("rawName")
.orElseGet(() -> createNbt.getString("realName")
.orElseThrow(() -> new IllegalArgumentException("Missing bot rawName")));
String name = createNbt.getString("name")
.orElseThrow(() -> new IllegalArgumentException("Missing bot name"));
String skinName = createNbt.getStringOr("skinName", rawName);
CompoundTag createNbt = nbt.read("createStatus", CompoundTag.CODEC).orElseThrow();
BotCreateState.Builder createBuilder = BotCreateState
.builder(rawName, null) // Convert from legacy version, consider to use ca.spottedleaf.dataconverter.minecraft.MCDataConverter instead for release version
.name(name);
.builder(createNbt.getString("rawName")
.orElseGet(() -> createNbt.getString("realName")
.orElseThrow()), null) // Convert from legacy version, consider to use ca.spottedleaf.dataconverter.minecraft.MCDataConverter instead for release version
.name(createNbt.getString("name").orElseThrow());
String[] skin = null;
if (createNbt.contains("skin")) {
ListTag skinTag = createNbt.getList("skin")
.orElseThrow(() -> new IllegalArgumentException("Invalid bot skin list"));
ListTag skinTag = createNbt.getList("skin").orElseThrow();
skin = new String[skinTag.size()];
for (int i = 0; i < skinTag.size(); i++) {
final int skinIndex = i;
skin[i] = skinTag.getString(i)
.orElseThrow(() -> new IllegalArgumentException("Invalid bot skin entry at index " + skinIndex));
skin[i] = skinTag.getString(i).orElseThrow();
}
}
createBuilder.skinName(skinName).skin(skin);
createBuilder.skinName(createNbt.getString("skinName").orElseThrow()).skin(skin);
createBuilder.createReason(BotCreateEvent.CreateReason.INTERNAL).creator(null);
this.createState = createBuilder.build();
@@ -466,17 +444,11 @@ public class ServerBot extends ServerPlayer {
if (FakePlayerCompatConfig.fakePlayerReloadAction && nbt.list("actions", CompoundTag.CODEC).isPresent()) {
ValueInput.TypedInputList<CompoundTag> actionNbt = nbt.list("actions", CompoundTag.CODEC).orElseThrow();
actionNbt.forEach(actionTag -> {
try {
String actionName = actionTag.getString("actionName")
.orElseThrow(() -> new IllegalArgumentException("Missing actionName"));
AbstractBotAction<?> action = Actions.getForName(actionName);
if (action != null) {
AbstractBotAction<?> newAction = action.create();
newAction.load(actionTag);
this.actions.add(newAction);
}
} catch (RuntimeException exception) {
LophineLogger.LOGGER.warn("Skipped invalid saved action for bot {}", this.getScoreboardName(), exception);
Actions<?> holder = Actions.getByName(actionTag.getString("actionName").orElseThrow());
if (holder != null) {
AbstractBotAction<?> newAction = holder.create();
newAction.load(actionTag);
this.actions.add(newAction);
}
});
}
@@ -484,17 +456,12 @@ public class ServerBot extends ServerPlayer {
if (nbt.list("configs", CompoundTag.CODEC).isPresent()) {
ValueInput.TypedInputList<CompoundTag> configNbt = nbt.list("configs", CompoundTag.CODEC).orElseThrow();
for (CompoundTag configTag : configNbt) {
try {
String configName = configTag.getString("configName")
.orElseThrow(() -> new IllegalArgumentException("Missing configName"));
AbstractBotConfig<?, ?> config = Configs.getConfig(configName);
if (config != null) {
config.setBot(this);
config.load(configTag);
}
} catch (RuntimeException exception) {
LophineLogger.LOGGER.warn("Skipped invalid saved config for bot {}", this.getScoreboardName(), exception);
String key = configTag.getString("configName").orElseThrow();
if (!this.configs.containsKey(key)) {
LophineLogger.LOGGER.warn("Trying to load a unknown config \"{}\", discard.", key);
continue;
}
this.configs.get(key).load(configTag);
}
}
}
@@ -523,7 +490,7 @@ public class ServerBot extends ServerPlayer {
playerConnection.send(this.getAddEntityPacket(entityTracker.serverEntity));
if (login) {
Bukkit.getGlobalRegionScheduler().runDelayed(MinecraftInternalPlugin.INSTANCE, (task) -> playerConnection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))), 10);
Bukkit.getGlobalRegionScheduler().runDelayed(MinecraftInternalPlugin.INSTANCE, (_) -> playerConnection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))), 10);
} else {
playerConnection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f)));
}
@@ -573,6 +540,11 @@ public class ServerBot extends ServerPlayer {
getServer().getBotList().removeBot(this, BotRemoveEvent.RemoveReason.DEATH, null, false, false);
}
@Override
protected int getBaseExperienceReward(@NotNull ServerLevel level) {
return this.isSpectator() ? 0 : Math.min(this.experienceLevel * 7, 100);
}
@Override
public boolean startRiding(@NotNull Entity vehicle, boolean force, boolean sendGameEvent) {
if (super.startRiding(vehicle, force, sendGameEvent)) {
@@ -764,15 +736,15 @@ public class ServerBot extends ServerPlayer {
}
@SuppressWarnings("unchecked")
public <T, E extends AbstractBotConfig<T, E>> AbstractBotConfig<T, E> getConfig(@NotNull AbstractBotConfig<T, E> config) {
return (AbstractBotConfig<T, E>) Objects.requireNonNull(this.configs.get(config.getName()));
public <T> AbstractBotConfig<T> getConfig(@NotNull Configs<? extends AbstractBotConfig<T>> config) {
return (AbstractBotConfig<T>) Objects.requireNonNull(this.configs.get(config.getName()));
}
public Collection<AbstractBotConfig<?, ?>> getAllConfigs() {
public Collection<AbstractBotConfig<?>> getAllConfigs() {
return configs.values();
}
public <T, E extends AbstractBotConfig<T, E>> T getConfigValue(@NotNull AbstractBotConfig<T, E> config) {
public <T> T getConfigValue(@NotNull Configs<? extends AbstractBotConfig<T>> config) {
return this.getConfig(config).getValue();
}
@@ -81,7 +81,7 @@ public class ServerBotGameMode extends ServerPlayerGameMode {
this.level.sendBlockUpdated(pos, blockState, blockState, 3);
return false;
} else {
BlockState blockState1 = /*isNoBlockUpdate() ? blockState : */block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update
BlockState blockState1 = /*isNoBlockUpdate() ? blockState : */block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update // Lophine
boolean flag = this.level.removeBlock(pos, false);
if (flag) {
block.destroy(this.level, pos, blockState1);
@@ -56,6 +56,11 @@ public class ServerBotPacketListenerImpl extends ServerGamePacketListenerImpl {
public void tick() {
}
@Override
public boolean hasClientLoaded() {
return true; // Don't kick me out!
}
public static class BotConnection extends Connection {
public BotConnection() {
@@ -17,49 +17,54 @@
package org.leavesmc.leaves.bot.agent;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import fun.bm.lophine.bot.BotActionGuiContainer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.agent.actions.*;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.entity.bot.action.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
public class Actions {
public class Actions<T extends AbstractBotAction<T>> {
private static final Map<String, AbstractBotAction<?>> actionsByName = new HashMap<>();
private static final Map<Class<?>, AbstractBotAction<?>> actionsByClass = new HashMap<>();
private static final Map<String, Actions<? extends AbstractBotAction<?>>> actionsByName = new HashMap<>();
private static final Map<Class<? extends BotAction<?>>, Actions<? extends AbstractBotAction<?>>> actionsByClass = new HashMap<>();
static {
register(new ServerAttackAction(), AttackAction.class);
register(new ServerBreakBlockAction(), BreakBlockAction.class);
register(new ServerDropAction(), DropAction.class);
register(new ServerJumpAction(), JumpAction.class);
register(new ServerSneakAction(), SneakAction.class);
register(new ServerUseItemAutoAction(), UseItemAutoAction.class);
register(new ServerUseItemAction(), UseItemAction.class);
register(new ServerUseItemOnAction(), UseItemOnAction.class);
register(new ServerUseItemToAction(), UseItemToAction.class);
register(new ServerUseItemOffhandAction(), UseItemOffhandAction.class);
register(new ServerUseItemOnOffhandAction(), UseItemOnOffhandAction.class);
register(new ServerUseItemToOffhandAction(), UseItemToOffhandAction.class);
register(new ServerLookAction(), LookAction.class);
register(new ServerFishAction(), FishAction.class);
register(new ServerSwimAction(), SwimAction.class);
register(new ServerRotationAction(), RotationAction.class);
register(new ServerMoveAction(), MoveAction.class);
register(new ServerMountAction(), MountAction.class);
register(new ServerSwapAction(), SwapAction.class);
register(AttackAction.class, ServerAttackAction::new);
register(BreakBlockAction.class, ServerBreakBlockAction::new);
register(DropAction.class, ServerDropAction::new);
register(JumpAction.class, ServerJumpAction::new);
register(SneakAction.class, ServerSneakAction::new);
register(UseItemAutoAction.class, ServerUseItemAutoAction::new);
register(UseItemAction.class, ServerUseItemAction::new);
register(UseItemOnAction.class, ServerUseItemOnAction::new);
register(UseItemToAction.class, ServerUseItemToAction::new);
register(UseItemOffhandAction.class, ServerUseItemOffhandAction::new);
register(UseItemOnOffhandAction.class, ServerUseItemOnOffhandAction::new);
register(UseItemToOffhandAction.class, ServerUseItemToOffhandAction::new);
register(LookAction.class, ServerLookAction::new);
register(FishAction.class, ServerFishAction::new);
register(SwimAction.class, ServerSwimAction::new);
register(RotationAction.class, ServerRotationAction::new);
register(MoveAction.class, ServerMoveAction::new);
register(MountAction.class, ServerMountAction::new);
register(SwapAction.class, ServerSwapAction::new);
}
public static boolean register(@NotNull AbstractBotAction<?> action, Class<?> type) {
public static <T extends AbstractBotAction<T>> boolean register(Class<? extends BotAction<?>> apiType, @NotNull Supplier<T> creator) {
AbstractBotAction<T> action = creator.get();
if (!actionsByName.containsKey(action.getName())) {
actionsByName.put(action.getName(), action);
actionsByClass.put(type, action);
Actions<?> actions = new Actions<>(creator.get().getName(), apiType, creator);
actionsByName.put(action.getName(), actions);
actionsByClass.put(apiType, actions);
if (action.getGuiData() != null) {
BotActionGuiContainer.registerGuiRootNode(action.getGuiData());
}
@@ -68,14 +73,37 @@ public class Actions {
return false;
}
public static boolean register(@NotNull AbstractBotAction<?> action) {
return register(action, action.getClass());
private final String name;
private final Class<?> apiType;
private final Supplier<T> creator;
private Actions(String name, Class<? extends BotAction<?>> apiType, Supplier<T> creator) {
this.name = name;
this.apiType = apiType;
this.creator = creator;
}
public String getName() {
return name;
}
public Class<?> getType() {
return apiType;
}
public T create() {
return creator.get();
}
public T createByCommand(CommandContext context) throws CommandSyntaxException {
T action = create();
action.loadCommand(context);
return action;
}
public static boolean unregister(@NotNull String name) {
AbstractBotAction<?> action = actionsByName.remove(name);
Actions<?> action = actionsByName.remove(name);
BotActionGuiContainer.unregisterGuiRootNode(name);
if (action != null) {
actionsByClass.remove(action.getClass());
return true;
@@ -85,7 +113,7 @@ public class Actions {
@NotNull
@Contract(pure = true)
public static Collection<AbstractBotAction<?>> getAll() {
public static Collection<Actions<? extends AbstractBotAction<?>>> getAll() {
return actionsByName.values();
}
@@ -95,12 +123,12 @@ public class Actions {
}
@Nullable
public static AbstractBotAction<?> getForName(String name) {
public static Actions<?> getByName(String name) {
return actionsByName.get(name);
}
@Nullable
public static AbstractBotAction<?> getForClass(@NotNull Class<?> type) {
public static Actions<?> getByClass(@NotNull Class<?> type) {
return actionsByClass.get(type);
}
}
@@ -19,41 +19,76 @@ package org.leavesmc.leaves.bot.agent;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.configs.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
@SuppressWarnings({"unused"})
public class Configs {
private static final Map<Class<?>, AbstractBotConfig<?, ?>> configs = new HashMap<>();
public class Configs<E extends AbstractBotConfig<?>> {
public static final SkipSleepConfig SKIP_SLEEP = register(new SkipSleepConfig());
public static final AlwaysSendDataConfig ALWAYS_SEND_DATA = register(new AlwaysSendDataConfig());
public static final SpawnPhantomConfig SPAWN_PHANTOM = register(new SpawnPhantomConfig());
public static final SimulationDistanceConfig SIMULATION_DISTANCE = register(new SimulationDistanceConfig());
public static final TickTypeConfig TICK_TYPE = register(new TickTypeConfig());
public static final LocatorBarConfig ENABLE_LOCATOR_BAR = register(new LocatorBarConfig());
private static final Map<String, Configs<? extends AbstractBotConfig<?>>> configs = new HashMap<>();
@Nullable
public static AbstractBotConfig<?, ?> getConfig(String name) {
public static final Configs<SkipSleepConfig> SKIP_SLEEP = register(SkipSleepConfig.class, SkipSleepConfig::new);
public static final Configs<AlwaysSendDataConfig> ALWAYS_SEND_DATA = register(AlwaysSendDataConfig.class, AlwaysSendDataConfig::new);
public static final Configs<SpawnPhantomConfig> SPAWN_PHANTOM = register(SpawnPhantomConfig.class, SpawnPhantomConfig::new);
public static final Configs<SimulationDistanceConfig> SIMULATION_DISTANCE = register(SimulationDistanceConfig.class, SimulationDistanceConfig::new);
public static final Configs<TickTypeConfig> TICK_TYPE = register(TickTypeConfig.class, TickTypeConfig::new);
public static final Configs<LocatorBarConfig> ENABLE_LOCATOR_BAR = register(LocatorBarConfig.class, LocatorBarConfig::new);
private final Class<? extends AbstractBotConfig<?>> configClass;
private final Supplier<? extends AbstractBotConfig<?>> configCreator;
private final String name;
private Configs(Class<? extends AbstractBotConfig<?>> configClass, Supplier<? extends AbstractBotConfig<?>> configCreator, String name) {
this.configClass = configClass;
this.configCreator = configCreator;
this.name = name;
}
public String getName() {
return name;
}
@SuppressWarnings("unchecked")
public E create() {
return (E) configCreator.get();
}
@SuppressWarnings("unchecked")
public E create(ServerBot bot) {
E config = (E) configCreator.get();
config.setBot(bot);
return config;
}
@NotNull
public static Optional<Configs<?>> getConfig(String name) {
return configs.values().stream()
.filter(config -> config.getName().equals(name))
.findFirst()
.orElse(null);
.filter(config -> config.name.equals(name))
.findFirst();
}
@NotNull
public static <T> Optional<Configs<?>> getConfig(Class<? extends AbstractBotConfig<T>> configClass) {
return configs.values().stream()
.filter(config -> config.configClass.equals(configClass))
.findFirst();
}
@NotNull
@Contract(pure = true)
public static Collection<AbstractBotConfig<?, ?>> getConfigs() {
public static Collection<Configs<? extends AbstractBotConfig<?>>> getConfigs() {
return configs.values();
}
@SuppressWarnings("unchecked")
private static <T, E extends AbstractBotConfig<T, E>> @NotNull E register(AbstractBotConfig<T, E> instance) {
configs.put(instance.getClass(), instance);
return (E) instance;
private static <T, E extends AbstractBotConfig<T>> @NotNull Configs<E> register(Class<? extends AbstractBotConfig<T>> configClass, Supplier<AbstractBotConfig<T>> configCreator) {
String name = configCreator.get().getName();
Configs<E> config = new Configs<>(configClass, configCreator, name);
configs.put(name, config);
return config;
}
}
@@ -1,3 +1,19 @@
/*
* This file is part of Leaves (https://github.com/LeavesMC/Leaves)
*
* Leaves is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Leaves is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Leaves. If not, see <https://www.gnu.org/licenses/>.
*/
package org.leavesmc.leaves.bot.agent;
import org.apache.commons.lang3.tuple.Pair;
@@ -30,20 +30,19 @@ import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.ExtraData;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.WrappedArgument;
import org.leavesmc.leaves.entity.bot.actions.CraftBotAction;
import org.leavesmc.leaves.event.bot.BotActionExecuteEvent;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.util.UpdateSuppressionException;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
@SuppressWarnings("unchecked")
public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
private final String name;
private final Map<Integer, List<Pair<String, WrappedArgument<?>>>> arguments;
private final Supplier<E> creator;
private UUID uuid;
private int currentFork = 0;
@@ -61,10 +60,9 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
protected GuiRootNode guiData;
public AbstractBotAction(String name, Supplier<E> creator) {
public AbstractBotAction(String name) {
this.name = name;
this.uuid = UUID.randomUUID();
this.creator = creator;
this.arguments = new HashMap<>();
this.cancel = false;
@@ -75,7 +73,7 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
public abstract boolean doTick(@NotNull ServerBot bot);
public abstract Object asCraft();
public abstract CraftBotAction<?, E> asCraft();
public String getActionDataString() {
return getActionDataString(new ExtraData(new ArrayList<>()));
@@ -201,11 +199,6 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
public void loadCommand(@NotNull CommandContext context) throws CommandSyntaxException {
}
@NotNull
public E create() {
return this.creator.get();
}
public String getName() {
return this.name;
}
@@ -17,11 +17,9 @@
package org.leavesmc.leaves.bot.agent.actions;
import java.util.function.Supplier;
public abstract class AbstractStateBotAction<E extends AbstractStateBotAction<E>> extends AbstractBotAction<E> {
public AbstractStateBotAction(String name, Supplier<E> creator) {
super(name, creator);
public AbstractStateBotAction(String name) {
super(name);
this.setDoNumber(-1);
}
}
@@ -24,15 +24,13 @@ import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.agent.ExtraData;
import org.leavesmc.leaves.command.CommandContext;
import java.util.function.Supplier;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static org.leavesmc.leaves.command.ArgumentNode.ArgumentSuggestions.strings;
public abstract class AbstractTimerBotAction<E extends AbstractTimerBotAction<E>> extends AbstractBotAction<E> {
public AbstractTimerBotAction(String name, Supplier<E> creator, GuiRootNode guiData) {
super(name, creator);
public AbstractTimerBotAction(String name, GuiRootNode guiData) {
super(name);
String[] delaySuggestions = {"0", "5", "10", "20"};
String[] intervalSuggestions = {"20", "0", "5", "10"};
this.addArgument("delay", integer(0)).suggests(strings(delaySuggestions)).setOptional(true);
@@ -29,8 +29,6 @@ import org.leavesmc.leaves.bot.agent.ExtraData;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import java.util.function.Supplier;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
public abstract class AbstractUseBotAction<T extends AbstractUseBotAction<T>> extends AbstractTimerBotAction<T> {
@@ -38,8 +36,8 @@ public abstract class AbstractUseBotAction<T extends AbstractUseBotAction<T>> ex
private int alreadyUsedTick = 0;
private int useItemRemainingTicks = 0;
public AbstractUseBotAction(String name, Supplier<T> supplier, GuiRootNode guiData) {
super(name, supplier, guiData);
public AbstractUseBotAction(String name, GuiRootNode guiData) {
super(name, guiData);
this.addArgument("use_timeout", integer(-1))
.suggests((context, builder) -> {
builder.suggest("-1", Component.literal("no use timeout"));
@@ -47,7 +45,6 @@ public abstract class AbstractUseBotAction<T extends AbstractUseBotAction<T>> ex
builder.suggest("10", Component.literal("minimum trident shoot time"));
})
.setOptional(true);
if (guiData == null) return;
for (GuiNode node : guiData.getAllFurthestChildren()) {
@@ -23,12 +23,13 @@ import net.minecraft.world.phys.EntityHitResult;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftAttackAction;
import org.leavesmc.leaves.entity.bot.actions.CraftBotAction;
public class ServerAttackAction extends AbstractTimerBotAction<ServerAttackAction> {
public ServerAttackAction() {
GuiRootNode guiData = new GuiRootNode("Attack", "Attack an entity", Items.DIAMOND_SWORD, "attack");
super("attack", ServerAttackAction::new, guiData);
super("attack", guiData);
}
@Override
@@ -43,7 +44,7 @@ public class ServerAttackAction extends AbstractTimerBotAction<ServerAttackActio
}
@Override
public Object asCraft() {
public CraftBotAction<?, ServerAttackAction> asCraft() {
return new CraftAttackAction(this);
}
}
@@ -30,13 +30,14 @@ import org.bukkit.block.Block;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftBotAction;
import org.leavesmc.leaves.entity.bot.actions.CraftBreakBlockAction;
public class ServerBreakBlockAction extends AbstractTimerBotAction<ServerBreakBlockAction> {
public ServerBreakBlockAction() {
GuiRootNode guiRootNode = new GuiRootNode("Break", "Break a block", Items.DIAMOND_PICKAXE, "break");
super("break", ServerBreakBlockAction::new, guiRootNode);
super("break", guiRootNode);
}
private ItemStack lastItem = null;
@@ -122,7 +123,7 @@ public class ServerBreakBlockAction extends AbstractTimerBotAction<ServerBreakBl
}
@Override
public Object asCraft() {
public CraftBotAction<?, ServerBreakBlockAction> asCraft() {
return new CraftBreakBlockAction(this);
}
}
@@ -21,13 +21,14 @@ import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftBotAction;
import org.leavesmc.leaves.entity.bot.actions.CraftDropAction;
public class ServerDropAction extends AbstractTimerBotAction<ServerDropAction> {
public ServerDropAction() {
GuiRootNode guiRootNode = new GuiRootNode("Drop", "Drop all items", Items.BARRIER, "drop");
super("drop", ServerDropAction::new, guiRootNode);
super("drop", guiRootNode);
}
@Override
@@ -37,7 +38,7 @@ public class ServerDropAction extends AbstractTimerBotAction<ServerDropAction> {
}
@Override
public Object asCraft() {
public CraftBotAction<?, ServerDropAction> asCraft() {
return new CraftDropAction(this);
}
}
@@ -26,13 +26,14 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftBotAction;
import org.leavesmc.leaves.entity.bot.actions.CraftFishAction;
public class ServerFishAction extends AbstractTimerBotAction<ServerFishAction> {
public ServerFishAction() {
GuiRootNode guiRootNode = new GuiRootNode("Fish", "Fish", Items.FISHING_ROD, "fish");
super("fish", ServerFishAction::new, guiRootNode);
super("fish", guiRootNode);
}
private static final int CATCH_ENTITY_DELAY = 20;
@@ -94,7 +95,7 @@ public class ServerFishAction extends AbstractTimerBotAction<ServerFishAction> {
}
@Override
public Object asCraft() {
public CraftBotAction<?, ServerFishAction> asCraft() {
return new CraftFishAction(this);
}
}

Some files were not shown because too many files have changed in this diff Show More