Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd3db4ae8c | |||
| 11e9760eb3 | |||
| 13c5bd7331 | |||
| bbcc103643 |
@@ -45,7 +45,7 @@ git clone https://github.com/LuminolMC/Lophine.git
|
||||
cd Lophine
|
||||
|
||||
# 应用补丁并构建 Paperclip JAR
|
||||
./gradlew applyAllPatches && ./gradlew createMojmapPaperclipJar
|
||||
./gradlew applyAllPatches && ./gradlew createPaperclipJar
|
||||
```
|
||||
|
||||
构建完成后,您可以在 `lophine-server/build/libs` 目录中找到生成的 JAR 文件。
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ git clone https://github.com/LuminolMC/Lophine.git
|
||||
cd Lophine
|
||||
|
||||
# Apply patches and build Paperclip JAR
|
||||
./gradlew applyAllPatches && ./gradlew createMojmapPaperclipJar
|
||||
./gradlew applyAllPatches && ./gradlew createPaperclipJar
|
||||
```
|
||||
|
||||
After building, you can find the generated JAR file in the `lophine-server/build/libs` directory.
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ release=true
|
||||
# true for push to repo, false for skip push repo, auto for detect by release value
|
||||
pushRepo=auto
|
||||
|
||||
luminolRef=69a4456ca298c89f3624a6efa8bc2c459c2d3ba0
|
||||
luminolRef=80b2a6c27bd06f252c7c797867f8d8cb77391063
|
||||
|
||||
org.gradle.configuration-cache=true
|
||||
org.gradle.caching=true
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to disable some check for operators
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index aa9e99358e5f3a5d07d9902708bcfa6255d26b97..47beff71ed33e7fbd6fe6cd47aa955233af41f04 100644
|
||||
index b2dc29f75259eca66f5dfe4456845b6dd70b0baf..15470867ed0f668fd3ba9c1fa24f84b3de8cb756 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -399,7 +399,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ index 0c0775bbb0c0ba0c37d1b884bb106b5250e94750..0dfb25ad032429a2aea7aa441dd5fd18
|
||||
double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1);
|
||||
if (rangeY != -1) {
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 694c2c4c48bde264fb2436fdf02750fcc20f7fac..5bb8481341a0f2ced987bee478b306b8ac80684f 100644
|
||||
index 552fd994ee30deb6e9f4228b17a2883cf26b164c..6f7e5d62901733df08c6beafbda2e54bc1c5f917 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -167,7 +167,7 @@ public abstract class Entity
|
||||
@@ -30,7 +30,7 @@ index 694c2c4c48bde264fb2436fdf02750fcc20f7fac..5bb8481341a0f2ced987bee478b306b8
|
||||
// CraftBukkit start
|
||||
private static final int CURRENT_LEVEL = 2;
|
||||
static boolean isLevelAtLeast(ValueInput input, int level) {
|
||||
@@ -6421,4 +6421,46 @@ public abstract class Entity
|
||||
@@ -6432,4 +6432,46 @@ public abstract class Entity
|
||||
// Paper end - Expose entity id counter
|
||||
|
||||
public boolean shouldTickHot() { return this.tickCount > 20 * 10 && this.isAlive(); } // KioCG
|
||||
|
||||
@@ -24,7 +24,7 @@ index 981f63b75584dbcb4bb0d5672e8c8bb140c52f9d..0a7a23b996d1380ea7ff4a28422fab82
|
||||
this.tickConnections();
|
||||
|
||||
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
index eb5c0e77537056a13f445ec5d96b1c92de8f25af..7a01fb6073867be17958407d4d2f6eb84621cf99 100644
|
||||
index f60b3b40c7dc5820abc726abc8d094ed873edf6c..6be8f4862e62a021602f7fc4ba5bdd6d3759d71e 100644
|
||||
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
@@ -40,8 +40,8 @@ public final class TickRegionScheduler {
|
||||
|
||||
@@ -38,7 +38,7 @@ index c147a1acd4fd9f94c73bee69febf651ca00c28ce..f8004bf74edeabce871515fb73fa00f3
|
||||
if (count > maxAllowedCount) {
|
||||
source.sendFailure(Component.translatable("commands.give.failed.toomanyitems", maxAllowedCount, prototypeItemStack.getDisplayName()));
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 47beff71ed33e7fbd6fe6cd47aa955233af41f04..8e5b79db12882432de575f2a76aa36eac6fc8f51 100644
|
||||
index 15470867ed0f668fd3ba9c1fa24f84b3de8cb756..4f243a4d3143bae799619e2ec76366c961c62da6 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3229,7 +3229,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
@@ -9,7 +9,7 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 8e5b79db12882432de575f2a76aa36eac6fc8f51..977a4ac391b8cf8b59c5c77becf9a5951d513526 100644
|
||||
index 4f243a4d3143bae799619e2ec76366c961c62da6..e6c09a4b780dafbf55793fabf864f66aa6e5604d 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -346,9 +346,12 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
@@ -8,7 +8,7 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index e54479b88cd02e7ef73b5c234b6baa479241c51c..244db62e425064563eb98c4ac6328222c74dc38f 100644
|
||||
index da9706f866aabee6939cacbfbcc9def01fde0326..3708f9ffc46a5b1c038c0e7b2ce84802e2b22397 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -772,6 +772,11 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
|
||||
@@ -9,7 +9,7 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 977a4ac391b8cf8b59c5c77becf9a5951d513526..bc38b16dd296cca9bc5556b95117794e633a9c27 100644
|
||||
index e6c09a4b780dafbf55793fabf864f66aa6e5604d..57e3180dc4568f58d5b69d2b9656d7cf9bbae81f 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3902,7 +3902,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ MasaGadget(https://github.com/plusls/MasaGadget)
|
||||
litematica(https://github.com/maruohon/litematica)
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index bc38b16dd296cca9bc5556b95117794e633a9c27..57aff87cc7be0cb7136689412490cd399eff15eb 100644
|
||||
index 57e3180dc4568f58d5b69d2b9656d7cf9bbae81f..96088ba53f043c8bc6971bc62e5dcccd98523698 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2183,7 +2183,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
@@ -33,7 +33,7 @@ index efbbc1a40d203a2818eeda2a4e938b9a6117f1c3..6b85a5ad9af0c57a0d4d5b55f62b82c5
|
||||
private boolean encrypted;
|
||||
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
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88504bc46d 100644
|
||||
index 9e290fa626caffac148920c54479a75ad0919e70..75d93d7d8bc6077dd80e499cd43327a4afe58f51 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -297,6 +297,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -45,15 +45,24 @@ index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88
|
||||
public static <S extends MinecraftServer> S spin(final Function<Thread, S> factory) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
AtomicReference<S> serverReference = new AtomicReference<>();
|
||||
@@ -1120,6 +1122,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
LOGGER.info("Stopping server");
|
||||
Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
|
||||
+ this.getBotList().removeAll(); // Leaves - save or remove bot
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
||||
if (false) this.server.spark.disable(); // Paper - spark // Luminol - Force disable builtin spark
|
||||
@@ -1695,7 +1698,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1226,6 +1228,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.safeShutdown(wait, false);
|
||||
}
|
||||
public void safeShutdown(final boolean wait, final boolean isRestarting) {
|
||||
+ // Lophine start - Folia changes
|
||||
+ safeShutdown(wait, isRestarting, false);
|
||||
+ }
|
||||
+
|
||||
+ public void safeShutdown(final boolean wait, final boolean isRestarting, boolean force) {
|
||||
+ if (!force && !this.getBotList().forceShutdown && !this.getBotList().removeAll()) { // Leaves - save or remove bot
|
||||
+ this.getPlayerList().broadcastSystemMessage(Component.literal("Bot Still need to save, please wait! If you want to shuntdown without bot data saving, please use /stop force"), false);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Lophine end - Folia changes
|
||||
this.isRestarting = isRestarting;
|
||||
this.hasLoggedStop = true; // Paper - Debugging
|
||||
if (this.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
|
||||
@@ -1695,7 +1707,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
int emptyTickThreshold = this.pauseWhenEmptySeconds() * 20;
|
||||
this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping
|
||||
if (false && emptyTickThreshold > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy
|
||||
@@ -62,7 +71,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88
|
||||
this.emptyTicks++;
|
||||
} else {
|
||||
this.emptyTicks = 0;
|
||||
@@ -1827,6 +1830,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1827,6 +1839,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.isSaving = true;
|
||||
if (playerSaveInterval > 0) {
|
||||
this.playerList.saveAll(playerSaveInterval);
|
||||
@@ -70,7 +79,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88
|
||||
}
|
||||
if (region == null && fullSave) { // Folia - region threading - don't auto save level data
|
||||
this.saveGlobalData(false);
|
||||
@@ -2065,6 +2069,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2065,6 +2078,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
protected void tickConnection() {
|
||||
this.getConnection().tick();
|
||||
@@ -78,7 +87,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88
|
||||
}
|
||||
|
||||
public void forceGameTimeSynchronization() {
|
||||
@@ -3270,6 +3275,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -3270,6 +3284,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
return this.debugSubscribers;
|
||||
}
|
||||
|
||||
@@ -213,6 +222,22 @@ index 636f56bfc0e9075b257e2eb14e858975bdedd801..20cbc0e65fea3fc2d0033259c2f35e15
|
||||
if (!list.isOp(player)) {
|
||||
list.op(player);
|
||||
count++;
|
||||
diff --git a/net/minecraft/server/commands/StopCommand.java b/net/minecraft/server/commands/StopCommand.java
|
||||
index e9c9a468f046832e8eaa999bb57da261b4633604..2efe24c0378a80dd2750b10a54c1887816236c1a 100644
|
||||
--- a/net/minecraft/server/commands/StopCommand.java
|
||||
+++ b/net/minecraft/server/commands/StopCommand.java
|
||||
@@ -11,6 +11,10 @@ public class StopCommand {
|
||||
c.getSource().sendSuccess(() -> Component.translatable("commands.stop.stopping"), true);
|
||||
c.getSource().getServer().halt(false);
|
||||
return 1;
|
||||
- }));
|
||||
+ }).then(Commands.literal("force").requires(Commands.hasPermission(Commands.LEVEL_OWNERS)).executes(c -> {
|
||||
+ c.getSource().sendSuccess(() -> Component.translatable("commands.stop.stopping"), true);
|
||||
+ c.getSource().getServer().safeShutdown(false, false, true);
|
||||
+ return 1;
|
||||
+ })));
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 1bc1e9a77dca7acfe5f989f6439f185d0d2e20a6..1790e8c141a8d3f7ccf4b11f9a28b3582325e317 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -504,7 +529,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
|
||||
|
||||
public @Nullable ServerPlayer getPlayer(final String playerName) {
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 5bb8481341a0f2ced987bee478b306b8ac80684f..1b998686108254c63d33a19e725ada2abececd8a 100644
|
||||
index 6f7e5d62901733df08c6beafbda2e54bc1c5f917..07c5fed7b0bf3ecefb54ccb0bfb922c2f11f7939 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1257,7 +1257,7 @@ public abstract class Entity
|
||||
|
||||
@@ -84,10 +84,10 @@ index 7e3912b8b29e40eb3347f1451b0fd3ebee2af4f1..0834e402e6af7028e08851378e15390e
|
||||
result.add(player);
|
||||
if (result.size() >= limit) {
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e359bcdd7e 100644
|
||||
index 75d93d7d8bc6077dd80e499cd43327a4afe58f51..3b9a4f4b5794faa4955018858c94fd5c2d6ada3d 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1921,7 +1921,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1930,7 +1930,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
private ServerStatus.Players buildPlayerStatus() {
|
||||
@@ -96,7 +96,7 @@ index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e3
|
||||
int maxPlayers = this.getMaxPlayers();
|
||||
if (this.hidesOnlinePlayers()) {
|
||||
return new ServerStatus.Players(maxPlayers, players.size(), List.of());
|
||||
@@ -2142,7 +2142,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2151,7 +2151,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
@Override
|
||||
public int getPlayerCount() {
|
||||
@@ -105,7 +105,7 @@ index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e3
|
||||
}
|
||||
|
||||
public String[] getPlayerNames() {
|
||||
@@ -2354,7 +2354,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2363,7 +2363,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
} else {
|
||||
int count = 0;
|
||||
|
||||
@@ -114,7 +114,7 @@ index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e3
|
||||
player.getBukkitEntity().taskScheduler.schedule((ServerPlayer updatedPlayer) -> { // Folia - region threading
|
||||
// Paper start - Expand PlayerGameModeChangeEvent
|
||||
org.bukkit.event.player.PlayerGameModeChangeEvent event = updatedPlayer.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); // Folia - region threading
|
||||
@@ -2541,7 +2541,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2550,7 +2550,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (Thread.currentThread() != this.serverThread) return; // Paper
|
||||
// Paper start - we don't need to save everything, just advancements
|
||||
// this.getPlayerList().saveAll();
|
||||
@@ -123,7 +123,7 @@ index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e3
|
||||
player.getAdvancements().save();
|
||||
}
|
||||
// Paper end - we don't need to save everything, just advancements
|
||||
@@ -2677,7 +2677,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2686,7 +2686,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
PlayerList playerList = this.getPlayerList();
|
||||
UserWhiteList whiteList = playerList.getWhiteList();
|
||||
|
||||
|
||||
+4
-4
@@ -32,10 +32,10 @@ index 24f5b890b0126fc817863f99b676da1a548f7608..78bea975c15130c91c90f48c868ac32e
|
||||
throw PacketUtils.makeReportedException(var3, this.packet, this.listener);
|
||||
}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 269b884ff30d908f772d1c0cf05076e359bcdd7e..fe5f6eb98aaa29b2745f4db51b9daad2666ec8f1 100644
|
||||
index 3b9a4f4b5794faa4955018858c94fd5c2d6ada3d..19bef18e606d873308d08987d90e298703efb574 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -2010,11 +2010,26 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2019,11 +2019,26 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
try {
|
||||
foliaProfiler.startTimer(level.tickTimerId); try { // Folia - profiler
|
||||
level.tick(haveTime, region); // Folia - region threading
|
||||
@@ -103,7 +103,7 @@ index 423652d0ccef5c6a3b93480401c3d0f672bbf8a5..65965089d184695588c74294afb2f5c0
|
||||
CrashReport report = CrashReport.forThrowable(var4, "Ticking player");
|
||||
CrashReportCategory category = report.addCategory("Player being ticked");
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 1b998686108254c63d33a19e725ada2abececd8a..366813b9c8ae0d9e86da33c10e3f3bf7aeecc4b0 100644
|
||||
index 07c5fed7b0bf3ecefb54ccb0bfb922c2f11f7939..8a92d1748464ef8d1d33e51163a3e0d74120e5a7 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1459,7 +1459,15 @@ public abstract class Entity
|
||||
@@ -164,7 +164,7 @@ index b72861c0164ebb13b6fc3e78cd7ce0a2c484f22d..a359d9ce555b9c8ec01ed71b305ab8ef
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 244db62e425064563eb98c4ac6328222c74dc38f..b9a93eff68fb9a7960439741d7cea30249fae92a 100644
|
||||
index 3708f9ffc46a5b1c038c0e7b2ce84802e2b22397..7760a711f4c49fc3499bf71fabb59ee8b4c85083 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -400,6 +400,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ index 06160c24f1ffbe1445284bc81598cabb3ad20477..ca3f31a72060f797115787302d32a019
|
||||
// CraftBukkit start - special case for handling block placement with water lilies, frog spawn and snow buckets
|
||||
if (player != null && (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem)) {
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index b9a93eff68fb9a7960439741d7cea30249fae92a..c4a0e388fff7ee62ff57bc400df5b0a200028d21 100644
|
||||
index 7760a711f4c49fc3499bf71fabb59ee8b4c85083..ef3508dc4c8b3a9c8a6c7ff520cf51a68d6a13d9 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -1015,12 +1015,6 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
|
||||
+1
-1
@@ -797,7 +797,7 @@ index 0fbdf810c785c8a596d461e7651361fdedbb6217..ff1471f40b73582df68efbf2996a854c
|
||||
this.getBlock().affectNeighborsAfterRemoval(this.asState(), level, pos, movedByPiston);
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index c4a0e388fff7ee62ff57bc400df5b0a200028d21..eae282928d24a8303b7cdfe151d6e1c58ee9fce1 100644
|
||||
index ef3508dc4c8b3a9c8a6c7ff520cf51a68d6a13d9..11f0f5e1b8ee9ce7e6833d46ccb557d896674431 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -423,22 +423,28 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
|
||||
@@ -150,7 +150,7 @@ index 65965089d184695588c74294afb2f5c0b28bbf17..5ebff729bb7e75e1c84449c0e3021b97
|
||||
|
||||
public ClientInformation clientInformation() {
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 57aff87cc7be0cb7136689412490cd399eff15eb..5a902f36f9157694be4ee65b7687c43f215ae041 100644
|
||||
index 96088ba53f043c8bc6971bc62e5dcccd98523698..749ba2e7fa6f7bb9c6e8916a25f04fb63f88aac3 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2099,7 +2099,13 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1037,7 +1037,7 @@ index ff1471f40b73582df68efbf2996a854c6aa37d65..668f59f94efb34490bdd7d6aac62fb37
|
||||
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 eae282928d24a8303b7cdfe151d6e1c58ee9fce1..1f0d59e7b682b3d022533b20a11658a99a8e6f7b 100644
|
||||
index 11f0f5e1b8ee9ce7e6833d46ccb557d896674431..5a0271b29589db3e02f87b935a787d180b3696f0 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -423,10 +423,11 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
|
||||
@@ -50,10 +50,12 @@ import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.event.bot.*;
|
||||
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
@@ -190,7 +192,11 @@ public class BotList {
|
||||
bot.isRealPlayer = true;
|
||||
bot.loginTime = System.currentTimeMillis();
|
||||
bot.connection = new ServerBotPacketListenerImpl(this.server, bot);
|
||||
if (bot.connection.connection.getPlayer() != bot) {
|
||||
throw new IllegalStateException("Bot connection is not bound to its bot player");
|
||||
}
|
||||
bot.connection.markClientLoaded();
|
||||
bot.getBukkitEntity().setMetadata("NPC", new FixedMetadataValue(MinecraftInternalPlugin.INSTANCE, true));
|
||||
bot.setServerLevel(world);
|
||||
|
||||
BotSpawnLocationEvent event = new BotSpawnLocationEvent(bot.getBukkitEntity(), location);
|
||||
@@ -315,7 +321,7 @@ public class BotList {
|
||||
}
|
||||
}
|
||||
|
||||
if (!TickThread.isShutdownThread()) bot.level().getCurrentWorldData().connections.remove(bot.connection.connection);
|
||||
bot.level().getCurrentWorldData().connections.remove(bot.connection.connection);
|
||||
bot.level().removePlayerImmediately(bot, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
|
||||
bot.retireScheduler();
|
||||
|
||||
|
||||
@@ -417,23 +417,31 @@ public class ServerBot extends ServerPlayer {
|
||||
super.readAdditionalSaveData(nbt);
|
||||
this.setShiftKeyDown(nbt.getBooleanOr("isShiftKeyDown", false));
|
||||
|
||||
CompoundTag createNbt = nbt.read("createStatus", CompoundTag.CODEC).orElseThrow();
|
||||
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);
|
||||
BotCreateState.Builder createBuilder = BotCreateState
|
||||
.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());
|
||||
.builder(rawName, null) // Convert from legacy version, consider to use ca.spottedleaf.dataconverter.minecraft.MCDataConverter instead for release version
|
||||
.name(name);
|
||||
|
||||
String[] skin = null;
|
||||
if (createNbt.contains("skin")) {
|
||||
ListTag skinTag = createNbt.getList("skin").orElseThrow();
|
||||
ListTag skinTag = createNbt.getList("skin")
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid bot skin list"));
|
||||
skin = new String[skinTag.size()];
|
||||
for (int i = 0; i < skinTag.size(); i++) {
|
||||
skin[i] = skinTag.getString(i).orElseThrow();
|
||||
final int skinIndex = i;
|
||||
skin[i] = skinTag.getString(i)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid bot skin entry at index " + skinIndex));
|
||||
}
|
||||
}
|
||||
|
||||
createBuilder.skinName(createNbt.getString("skinName").orElseThrow()).skin(skin);
|
||||
createBuilder.skinName(skinName).skin(skin);
|
||||
createBuilder.createReason(BotCreateEvent.CreateReason.INTERNAL).creator(null);
|
||||
|
||||
this.createState = createBuilder.build();
|
||||
@@ -443,11 +451,17 @@ 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 -> {
|
||||
AbstractBotAction<?> action = Actions.getForName(actionTag.getString("actionName").orElseThrow());
|
||||
if (action != null) {
|
||||
AbstractBotAction<?> newAction = action.create();
|
||||
newAction.load(actionTag);
|
||||
this.actions.add(newAction);
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -455,10 +469,16 @@ 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) {
|
||||
AbstractBotConfig<?, ?> config = Configs.getConfig(configTag.getString("configName").orElseThrow());
|
||||
if (config != null) {
|
||||
config.setBot(this);
|
||||
config.load(configTag);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-3
@@ -31,7 +31,12 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class ServerBotPacketListenerImpl extends ServerGamePacketListenerImpl {
|
||||
|
||||
public ServerBotPacketListenerImpl(MinecraftServer server, ServerBot bot) {
|
||||
super(server, BotConnection.INSTANCE, bot, CommonListenerCookie.createInitial(bot.gameProfile, false));
|
||||
this(server, bot, new BotConnection());
|
||||
}
|
||||
|
||||
private ServerBotPacketListenerImpl(MinecraftServer server, ServerBot bot, BotConnection connection) {
|
||||
super(server, connection, bot, CommonListenerCookie.createInitial(bot.gameProfile, false));
|
||||
connection.bind(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,12 +58,14 @@ public class ServerBotPacketListenerImpl extends ServerGamePacketListenerImpl {
|
||||
|
||||
public static class BotConnection extends Connection {
|
||||
|
||||
private static final BotConnection INSTANCE = new BotConnection();
|
||||
|
||||
public BotConnection() {
|
||||
super(PacketFlow.SERVERBOUND);
|
||||
}
|
||||
|
||||
private void bind(ServerBotPacketListenerImpl listener) {
|
||||
this.packetListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
}
|
||||
|
||||
+37
-7
@@ -45,6 +45,7 @@ import java.util.jar.JarFile;
|
||||
public class LeavesProtocolManager {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
private static final LeavesCustomPayload INVALID_PAYLOAD = new InvalidPayload();
|
||||
|
||||
private static final Map<Class<? extends LeavesCustomPayload>, PayloadReceiverInvokerHolder> PAYLOAD_RECEIVERS = new HashMap<>();
|
||||
private static final Map<Class<? extends LeavesCustomPayload>, Identifier> IDS = new HashMap<>();
|
||||
@@ -217,8 +218,8 @@ public class LeavesProtocolManager {
|
||||
try {
|
||||
return codec.decode(ProtocolUtils.decorate(buf));
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to decode payload {}", location, e);
|
||||
throw e;
|
||||
LOGGER.warn("Rejected malformed Leaves payload {}", location, e);
|
||||
return INVALID_PAYLOAD;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,9 +239,16 @@ public class LeavesProtocolManager {
|
||||
}
|
||||
|
||||
public static void handlePayload(IdentifierSelector selector, LeavesCustomPayload payload) {
|
||||
if (payload == INVALID_PAYLOAD) {
|
||||
return;
|
||||
}
|
||||
PayloadReceiverInvokerHolder holder;
|
||||
if ((holder = PAYLOAD_RECEIVERS.get(payload.getClass())) != null) {
|
||||
holder.invoke(selector, payload);
|
||||
try {
|
||||
holder.invoke(selector, payload);
|
||||
} catch (RuntimeException exception) {
|
||||
LOGGER.warn("Rejected malformed Leaves payload {} from {}", payload.getClass().getName(), describeSelector(selector), exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,22 +256,44 @@ public class LeavesProtocolManager {
|
||||
RegistryFriendlyByteBuf buf1 = ProtocolUtils.decorate(buf);
|
||||
BytebufReceiverInvokerHolder holder;
|
||||
if ((holder = STRICT_BYTEBUF_RECEIVERS.get(location.toString())) != null) {
|
||||
holder.invoke(selector, buf1);
|
||||
safeInvokeBytebuf(holder, selector, location, buf1);
|
||||
return true;
|
||||
}
|
||||
if ((holder = NAMESPACED_BYTEBUF_RECEIVERS.get(location.getNamespace())) != null) {
|
||||
if (holder.invoke(selector, buf1)) {
|
||||
if (safeInvokeBytebuf(holder, selector, location, buf1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (var holder1 : GENERIC_BYTEBUF_RECEIVERS) {
|
||||
if (holder1.invoke(selector, buf1)) {
|
||||
if (safeInvokeBytebuf(holder1, selector, location, buf1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean safeInvokeBytebuf(BytebufReceiverInvokerHolder holder, IdentifierSelector selector, Identifier location, RegistryFriendlyByteBuf buf) {
|
||||
try {
|
||||
return holder.invoke(selector, buf);
|
||||
} catch (RuntimeException exception) {
|
||||
LOGGER.warn("Rejected malformed bytebuf payload {} from {}", location, describeSelector(selector), exception);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static String describeSelector(IdentifierSelector selector) {
|
||||
if (selector.player() != null) {
|
||||
return selector.player().getScoreboardName();
|
||||
}
|
||||
if (selector.context() != null) {
|
||||
return selector.context().profile().name();
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
private record InvalidPayload() implements LeavesCustomPayload {
|
||||
}
|
||||
|
||||
public static void handleTick() {
|
||||
long currentTime = System.currentTimeMillis() / MinecraftServer.getServer().tickRateManager().nanosecondsPerTick();
|
||||
if (currentTime == lastAcceptTime) return;
|
||||
@@ -414,4 +444,4 @@ public class LeavesProtocolManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-9
@@ -400,15 +400,25 @@ public class REIServerProtocol implements LeavesProtocol {
|
||||
private static List<List<ItemStack>> readInputs(RegistryAccess registryAccess, ListTag tag) {
|
||||
List<List<ItemStack>> items = new ArrayList<>();
|
||||
for (Tag t : tag) {
|
||||
CompoundTag compoundTag = (CompoundTag) t;
|
||||
compoundTag.getInt("Index").orElseThrow();
|
||||
if (!(t instanceof CompoundTag compoundTag)) {
|
||||
throw new IllegalStateException("Invalid REI input entry");
|
||||
}
|
||||
if (compoundTag.getInt("Index").isEmpty()) {
|
||||
throw new IllegalStateException("Missing REI input index");
|
||||
}
|
||||
ListTag ingredientList = compoundTag.getListOrEmpty("Ingredient");
|
||||
List<ItemStack> slotItems = new ArrayList<>();
|
||||
for (Tag ingredient : ingredientList) {
|
||||
CompoundTag ingredientTag = (CompoundTag) ingredient;
|
||||
if (!(ingredient instanceof CompoundTag ingredientTag)) {
|
||||
throw new IllegalStateException("Invalid REI ingredient entry");
|
||||
}
|
||||
Tag value = ingredientTag.get("value");
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Missing REI ingredient value");
|
||||
}
|
||||
ItemStack stack = ItemStack.OPTIONAL_CODEC.parse(
|
||||
registryAccess.createSerializationContext(NbtOps.INSTANCE),
|
||||
ingredientTag.get("value")
|
||||
value
|
||||
).getOrThrow();
|
||||
slotItems.add(stack);
|
||||
}
|
||||
@@ -420,16 +430,28 @@ public class REIServerProtocol implements LeavesProtocol {
|
||||
private static List<SlotAccessor> readSlots(AbstractContainerMenu menu, ServerPlayer player, ListTag tag) {
|
||||
List<SlotAccessor> slots = new ArrayList<>();
|
||||
for (Tag t : tag) {
|
||||
CompoundTag compoundTag = (CompoundTag) t;
|
||||
String id = compoundTag.getString("id").orElseThrow();
|
||||
if (!(t instanceof CompoundTag compoundTag)) {
|
||||
throw new IllegalStateException("Invalid REI slot entry");
|
||||
}
|
||||
String id = compoundTag.getString("id").orElseThrow(() -> new IllegalStateException("Missing REI slot id"));
|
||||
if (!id.startsWith(PROTOCOL_ID + ":")) {
|
||||
throw new IllegalStateException("Invalid slot id: " + id + ", expected to start with '" + PROTOCOL_ID + ":'");
|
||||
}
|
||||
id = id.substring((PROTOCOL_ID + ":").length());
|
||||
int slot = compoundTag.getInt("Slot").orElseThrow();
|
||||
int slot = compoundTag.getInt("Slot").orElseThrow(() -> new IllegalStateException("Missing REI slot index"));
|
||||
SlotAccessor accessor = switch (id) {
|
||||
case "vanilla" -> new VanillaSlotAccessor(menu.slots.get(slot));
|
||||
case "player" -> new PlayerInventorySlotAccessor(player, slot);
|
||||
case "vanilla" -> {
|
||||
if (slot < 0 || slot >= menu.slots.size()) {
|
||||
throw new IllegalStateException("Invalid vanilla slot index: " + slot);
|
||||
}
|
||||
yield new VanillaSlotAccessor(menu.slots.get(slot));
|
||||
}
|
||||
case "player" -> {
|
||||
if (slot < 0 || slot >= player.getInventory().getContainerSize()) {
|
||||
throw new IllegalStateException("Invalid player slot index: " + slot);
|
||||
}
|
||||
yield new PlayerInventorySlotAccessor(player, slot);
|
||||
}
|
||||
default -> throw new IllegalStateException("Unknown container id: " + id);
|
||||
};
|
||||
slots.add(accessor);
|
||||
|
||||
+23
-2
@@ -51,17 +51,21 @@ public record LitematicaSchematic(Map<String, SubRegion> subRegions, SchematicMe
|
||||
|
||||
public static final int MINECRAFT_DATA_VERSION = SharedConstants.getProtocolVersion();
|
||||
public static final int SCHEMATIC_VERSION = 7;
|
||||
private static final long MAX_REGION_VOLUME = 16_777_216L;
|
||||
|
||||
@NotNull
|
||||
@Contract("_ -> new")
|
||||
public static LitematicaSchematic readFromNBT(@NotNull CompoundTag nbt) {
|
||||
if (nbt.contains("Version")) {
|
||||
final int version = nbt.getIntOr("Version", -1);
|
||||
final int minecraftDataVersion = nbt.contains("MinecraftDataVersion") ? nbt.getInt("MinecraftDataVersion").orElseThrow() : SharedConstants.getProtocolVersion();
|
||||
final int minecraftDataVersion = nbt.getIntOr("MinecraftDataVersion", SharedConstants.getProtocolVersion());
|
||||
|
||||
if (version >= 1 && version <= SCHEMATIC_VERSION) {
|
||||
SchematicMetadata metadata = SchematicMetadata.readFromNBT(nbt.getCompoundOrEmpty("Metadata"), version, minecraftDataVersion, FileType.LITEMATICA_SCHEMATIC);
|
||||
Map<String, SubRegion> subRegions = readSubRegionsFromNBT(nbt.getCompoundOrEmpty("Regions"), version, minecraftDataVersion);
|
||||
if (subRegions.isEmpty()) {
|
||||
throw new IllegalArgumentException("Schematic has no regions");
|
||||
}
|
||||
return new LitematicaSchematic(subRegions, metadata);
|
||||
} else {
|
||||
throw new RuntimeException("Unsupported or future schematic version");
|
||||
@@ -116,6 +120,7 @@ public record LitematicaSchematic(Map<String, SubRegion> subRegions, SchematicMe
|
||||
if (position == null || size == null) {
|
||||
throw new IllegalArgumentException("Invalid region");
|
||||
}
|
||||
validateRegionSize(size);
|
||||
|
||||
Map<BlockPos, CompoundTag> tileEntities;
|
||||
List<EntityInfo> entities;
|
||||
@@ -141,6 +146,9 @@ public record LitematicaSchematic(Map<String, SubRegion> subRegions, SchematicMe
|
||||
Tag blockState = regionTag.get("BlockStates");
|
||||
if (blockState != null && blockState.getId() == Tag.TAG_LONG_ARRAY) {
|
||||
ListTag palette = regionTag.getListOrEmpty("BlockStatePalette");
|
||||
if (palette.isEmpty()) {
|
||||
throw new IllegalArgumentException("Missing block state palette");
|
||||
}
|
||||
long[] blockStateArr = ((LongArrayTag) blockState).getAsLongArray();
|
||||
BlockPos posEndRel = PositionUtils.getRelativeEndPositionFromAreaSize(size).offset(position);
|
||||
BlockPos posMin = PositionUtils.getMinCorner(position, posEndRel);
|
||||
@@ -155,6 +163,19 @@ public record LitematicaSchematic(Map<String, SubRegion> subRegions, SchematicMe
|
||||
return new SubRegion(blockContainers, tileEntities, pendingBlockTicks, pendingFluidTicks, entities, position, size);
|
||||
}
|
||||
|
||||
private static void validateRegionSize(BlockPos size) {
|
||||
long x = Math.abs((long) size.getX());
|
||||
long y = Math.abs((long) size.getY());
|
||||
long z = Math.abs((long) size.getZ());
|
||||
if (x == 0 || y == 0 || z == 0) {
|
||||
throw new IllegalArgumentException("Region has zero size");
|
||||
}
|
||||
long volume = Math.multiplyExact(Math.multiplyExact(x, y), z);
|
||||
if (volume > MAX_REGION_VOLUME) {
|
||||
throw new IllegalArgumentException("Region volume too large: " + volume);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<EntityInfo> readEntitiesFromNBT(ListTag tagList) {
|
||||
List<EntityInfo> entityList = new ArrayList<>();
|
||||
final int size = tagList.size();
|
||||
@@ -278,4 +299,4 @@ public record LitematicaSchematic(Map<String, SubRegion> subRegions, SchematicMe
|
||||
this.nbt = nbt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-7
@@ -264,12 +264,17 @@ public class ServuxLitematicsProtocol implements LeavesProtocol {
|
||||
}
|
||||
|
||||
if (tags.getStringOr("Task", "").equals("LitematicaPaste")) {
|
||||
ServuxProtocol.LOGGER.debug("litematic_data: Servux Paste request from player {}", player.getName().getString());
|
||||
ServerLevel serverLevel = player.level();
|
||||
long timeStart = System.currentTimeMillis();
|
||||
SchematicPlacement placement = SchematicPlacement.createFromNbt(tags);
|
||||
ReplaceBehavior replaceMode = ReplaceBehavior.fromStringStatic(tags.getStringOr("ReplaceMode", ReplaceBehavior.NONE.name()));
|
||||
placement.pasteTo(serverLevel, replaceMode, player, timeStart);
|
||||
try {
|
||||
ServuxProtocol.LOGGER.debug("litematic_data: Servux Paste request from player {}", player.getName().getString());
|
||||
ServerLevel serverLevel = player.level();
|
||||
long timeStart = System.currentTimeMillis();
|
||||
SchematicPlacement placement = SchematicPlacement.createFromNbt(tags);
|
||||
ReplaceBehavior replaceMode = ReplaceBehavior.fromStringStatic(tags.getStringOr("ReplaceMode", ReplaceBehavior.NONE.name()));
|
||||
placement.pasteTo(serverLevel, replaceMode, player, timeStart);
|
||||
} catch (RuntimeException exception) {
|
||||
player.getBukkitEntity().sendActionBar(Component.text("Invalid Litematica paste data", NamedTextColor.RED));
|
||||
ServuxProtocol.LOGGER.warn("Rejected invalid Litematica paste request from {}", player.getScoreboardName(), exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,4 +443,4 @@ public class ServuxLitematicsProtocol implements LeavesProtocol {
|
||||
return !this.hasBuffer() && !this.hasNbt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-2
@@ -47,11 +47,19 @@ public class LitematicaBitArray {
|
||||
|
||||
public LitematicaBitArray(int bitsPerEntryIn, long arraySizeIn, @Nullable long[] longArrayIn) {
|
||||
Validate.inclusiveBetween(1L, 32L, bitsPerEntryIn);
|
||||
Validate.isTrue(arraySizeIn >= 0L, "arraySize must not be negative");
|
||||
this.arraySize = arraySizeIn;
|
||||
this.bitsPerEntry = bitsPerEntryIn;
|
||||
this.maxEntryValue = (1L << bitsPerEntryIn) - 1L;
|
||||
|
||||
this.longArray = Objects.requireNonNullElseGet(longArrayIn, () -> new long[(int) (roundUp(arraySizeIn * bitsPerEntryIn, 64L) / 64L)]);
|
||||
long backingLength = roundUp(Math.multiplyExact(arraySizeIn, bitsPerEntryIn), 64L) / 64L;
|
||||
Validate.isTrue(backingLength <= Integer.MAX_VALUE, "BitArray backing storage is too large");
|
||||
if (longArrayIn != null) {
|
||||
Validate.isTrue(longArrayIn.length >= backingLength, "BitArray backing storage is too small");
|
||||
this.longArray = longArrayIn;
|
||||
} else {
|
||||
this.longArray = new long[(int) backingLength];
|
||||
}
|
||||
}
|
||||
|
||||
public static long roundUp(long value, long interval) {
|
||||
@@ -71,6 +79,7 @@ public class LitematicaBitArray {
|
||||
}
|
||||
|
||||
public void setAt(long index, int value) {
|
||||
this.checkIndex(index);
|
||||
long startOffset = index * (long) this.bitsPerEntry;
|
||||
int startArrIndex = (int) (startOffset >> 6); // startOffset / 64
|
||||
int endArrIndex = (int) (((index + 1L) * (long) this.bitsPerEntry - 1L) >> 6);
|
||||
@@ -85,6 +94,7 @@ public class LitematicaBitArray {
|
||||
}
|
||||
|
||||
public int getAt(long index) {
|
||||
this.checkIndex(index);
|
||||
long startOffset = index * (long) this.bitsPerEntry;
|
||||
int startArrIndex = (int) (startOffset >> 6); // startOffset / 64
|
||||
int endArrIndex = (int) (((index + 1L) * (long) this.bitsPerEntry - 1L) >> 6);
|
||||
@@ -101,4 +111,10 @@ public class LitematicaBitArray {
|
||||
public long size() {
|
||||
return this.arraySize;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIndex(long index) {
|
||||
if (index < 0L || index >= this.arraySize) {
|
||||
throw new IndexOutOfBoundsException("BitArray index " + index + " out of bounds for length " + this.arraySize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -49,7 +49,9 @@ public interface LitematicaBlockStatePalette {
|
||||
final int size = tagList.size();
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
CompoundTag tag = tagList.getCompound(i).orElseThrow();
|
||||
final int paletteIndex = i;
|
||||
CompoundTag tag = tagList.getCompound(i)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid block state palette entry at index " + paletteIndex));
|
||||
BlockState state = NbtUtils.readBlockState(lookup, tag);
|
||||
|
||||
if (i > 0 || state != LitematicaBlockStateContainer.AIR_BLOCK_STATE) {
|
||||
@@ -59,4 +61,4 @@ public interface LitematicaBlockStatePalette {
|
||||
}
|
||||
|
||||
ListTag writeToNBT();
|
||||
}
|
||||
}
|
||||
|
||||
+31
-7
@@ -62,20 +62,31 @@ public class SchematicPlacement {
|
||||
}
|
||||
|
||||
public static SchematicPlacement createFromNbt(CompoundTag tags) {
|
||||
if (!tags.contains("Schematics")) {
|
||||
throw new IllegalArgumentException("Missing Schematics tag");
|
||||
}
|
||||
BlockPos origin = NbtUtils.readBlockPosFromArrayTag(tags, "Origin");
|
||||
if (origin == null) {
|
||||
throw new IllegalArgumentException("Missing or invalid Origin tag");
|
||||
}
|
||||
SchematicPlacement placement = new SchematicPlacement(
|
||||
LitematicaSchematic.readFromNBT(tags.getCompoundOrEmpty("Schematics")),
|
||||
NbtUtils.readBlockPosFromArrayTag(tags, "Origin"),
|
||||
origin,
|
||||
tags.getStringOr("Name", "")
|
||||
);
|
||||
placement.mirror = Mirror.values()[tags.getIntOr("Mirror", 0)];
|
||||
placement.rotation = Rotation.values()[tags.getIntOr("Rotation", 0)];
|
||||
placement.mirror = enumByOrdinal(Mirror.values(), tags.getIntOr("Mirror", 0), "Mirror");
|
||||
placement.rotation = enumByOrdinal(Rotation.values(), tags.getIntOr("Rotation", 0), "Rotation");
|
||||
for (String name : tags.getCompoundOrEmpty("SubRegions").keySet()) {
|
||||
CompoundTag compound = tags.getCompoundOrEmpty("SubRegions").getCompoundOrEmpty(name);
|
||||
BlockPos pos = NbtUtils.readBlockPosFromArrayTag(compound, "Pos");
|
||||
if (pos == null) {
|
||||
throw new IllegalArgumentException("Missing or invalid Pos tag for sub-region " + name);
|
||||
}
|
||||
var sub = new SubRegionPlacement(
|
||||
compound.getStringOr("Name", "?"),
|
||||
NbtUtils.readBlockPosFromArrayTag(compound, "Pos"),
|
||||
Rotation.values()[compound.getIntOr("Rotation", 0)],
|
||||
Mirror.values()[compound.getIntOr("Mirror", 0)],
|
||||
pos,
|
||||
enumByOrdinal(Rotation.values(), compound.getIntOr("Rotation", 0), "SubRegions." + name + ".Rotation"),
|
||||
enumByOrdinal(Mirror.values(), compound.getIntOr("Mirror", 0), "SubRegions." + name + ".Mirror"),
|
||||
compound.getBooleanOr("Enabled", true),
|
||||
compound.getBooleanOr("IgnoreEntities", false)
|
||||
);
|
||||
@@ -84,6 +95,13 @@ public class SchematicPlacement {
|
||||
return placement;
|
||||
}
|
||||
|
||||
private static <T> T enumByOrdinal(T[] values, int ordinal, String tagName) {
|
||||
if (ordinal < 0 || ordinal >= values.length) {
|
||||
throw new IllegalArgumentException("Invalid " + tagName + " ordinal: " + ordinal);
|
||||
}
|
||||
return values[ordinal];
|
||||
}
|
||||
|
||||
public static IntBoundingBox getBoundsWithinChunkForBox(Box box, int chunkX, int chunkZ) {
|
||||
final int chunkXMin = chunkX << 4;
|
||||
final int chunkZMin = chunkZ << 4;
|
||||
@@ -302,7 +320,13 @@ public class SchematicPlacement {
|
||||
AtomicInteger count_full = new AtomicInteger();
|
||||
AtomicInteger count = new AtomicInteger();
|
||||
|
||||
streamChunkPos(Objects.requireNonNull(enclosingBox.toVanilla())).forEach(chunkPos -> {
|
||||
BlockBox vanillaBox = enclosingBox.toVanilla();
|
||||
if (vanillaBox == null) {
|
||||
ServuxProtocol.LOGGER.error("receiver a null vanilla enclosing box");
|
||||
return;
|
||||
}
|
||||
|
||||
streamChunkPos(vanillaBox).forEach(chunkPos -> {
|
||||
RegionizedServer.getInstance().taskQueue.queueTickTaskQueue(
|
||||
serverWorld,
|
||||
chunkPos.x(),
|
||||
|
||||
+19
-4
@@ -51,6 +51,7 @@ public class CommunicationManager implements LeavesProtocol {
|
||||
protected static final Map<UUID, Exchange> modifyState = new ConcurrentHashMap<>();
|
||||
protected static final Rotation[] rotOrdinals = Rotation.values();
|
||||
protected static final Mirror[] mirOrdinals = Mirror.values();
|
||||
private static final int MAX_SUB_REGION_MODIFICATIONS = 4096;
|
||||
private static final Map<UUID, List<ServerPlacement>> downloadingFile = new ConcurrentHashMap<>();
|
||||
private static final Map<ExchangeTarget, ServerPlayer> playerMap = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -87,7 +88,11 @@ public class CommunicationManager implements LeavesProtocol {
|
||||
|
||||
@ProtocolHandler.PayloadReceiver(payload = SyncmaticaPayload.class)
|
||||
public static void onPacketGet(ServerPlayer player, SyncmaticaPayload payload) {
|
||||
onPacket(player.connection.exchangeTarget, payload.packetType(), payload.data());
|
||||
try {
|
||||
onPacket(player.connection.exchangeTarget, payload.packetType(), payload.data());
|
||||
} catch (IllegalArgumentException | IndexOutOfBoundsException exception) {
|
||||
LOGGER.warn("Rejected malformed Syncmatica packet {} from {}", payload.packetType(), player.getScoreboardName(), exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onPacket(final @NotNull ExchangeTarget source, final Identifier id, final FriendlyByteBuf packetBuf) {
|
||||
@@ -326,20 +331,30 @@ public class CommunicationManager implements LeavesProtocol {
|
||||
public static void receivePositionData(final @NotNull ServerPlacement placement, final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) {
|
||||
final BlockPos pos = buf.readBlockPos();
|
||||
final String dimensionId = buf.readUtf(32767);
|
||||
final Rotation rot = rotOrdinals[buf.readInt()];
|
||||
final Mirror mir = mirOrdinals[buf.readInt()];
|
||||
final Rotation rot = readOrdinal(rotOrdinals, buf.readInt(), "rotation");
|
||||
final Mirror mir = readOrdinal(mirOrdinals, buf.readInt(), "mirror");
|
||||
placement.move(dimensionId, pos, rot, mir);
|
||||
|
||||
if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) {
|
||||
final SubRegionData subRegionData = placement.getSubRegionData();
|
||||
subRegionData.reset();
|
||||
final int limit = buf.readInt();
|
||||
if (limit < 0 || limit > MAX_SUB_REGION_MODIFICATIONS) {
|
||||
throw new IllegalArgumentException("Invalid sub-region modification count: " + limit);
|
||||
}
|
||||
for (int i = 0; i < limit; i++) {
|
||||
subRegionData.modify(buf.readUtf(32767), buf.readBlockPos(), rotOrdinals[buf.readInt()], mirOrdinals[buf.readInt()]);
|
||||
subRegionData.modify(buf.readUtf(32767), buf.readBlockPos(), readOrdinal(rotOrdinals, buf.readInt(), "sub-region rotation"), readOrdinal(mirOrdinals, buf.readInt(), "sub-region mirror"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T readOrdinal(T[] values, int ordinal, String name) {
|
||||
if (ordinal < 0 || ordinal >= values.length) {
|
||||
throw new IllegalArgumentException("Invalid " + name + " ordinal: " + ordinal);
|
||||
}
|
||||
return values[ordinal];
|
||||
}
|
||||
|
||||
public static void download(final ServerPlacement syncmatic, final ExchangeTarget source) throws NoSuchAlgorithmException, IOException {
|
||||
if (!SyncmaticaProtocol.getFileStorage().getLocalState(syncmatic).isReadyForDownload()) {
|
||||
throw new IllegalArgumentException(syncmatic.toString() + " is not ready for download local state is: " + SyncmaticaProtocol.getFileStorage().getLocalState(syncmatic).toString());
|
||||
|
||||
Reference in New Issue
Block a user