Compare commits

..

11 Commits

Author SHA1 Message Date
Helvetica Volubi cefaa4a712 fix: some fix for bot action
fix stop command could stop all the same type of action when a stop action called

fix some typo in command reply
2026-07-11 01:03:01 +08:00
Helvetica Volubi 322bc18e9b [ci skip] because of tmp move to new org, rebrand 2026-07-10 00:17:39 +08:00
Helvetica Volubi fffb3115c0 fix bot command register 2026-07-06 20:23:43 +08:00
Helvetica Volubi a0da7e4b51 Update Luminol to fix some bugs 2026-07-06 01:37:36 +08:00
Helvetica Volubi 2763dc8336 [ci skip]Replace MenthaMC Maven repo with Bacteriawa
Update Maven repository URL from https://repo.menthamc.org/... to https://repo.bacteriawa.com/... across project files. Changes include README.md and README_EN.md (repository id changed to "repository" and URL updated), build.gradle.kts (rename menthaMavenPublicUrl to bacteriawaMavenPublicUrl and switch repository used for dependencies and publishing, update publishing repo name), luminol-server/build.gradle.kts.patch (use bacteriawaMavenPublicUrl), and settings.gradle.kts (add new Maven URL). This centralizes the project to use the Bacteriawa Maven host for dependency resolution and publishing.

Origin Commit: https://github.com/LuminolMC/Luminol/commit/ba28403ff6d15da3cf8b1af9828bbd1f997a7b9e

Co-authored-by: Bacteriawa <a3167717663@hotmail.com>
2026-07-05 21:34:52 +08:00
Helvetica Volubi 70bfb77edf Update Luminol 2026-07-03 06:22:54 +08:00
Helvetica Volubi aae432fc3c [ci skip]push repo 2026-07-02 20:02:09 +08:00
Helvetica Volubi f7ad2f93f1 feat: old leader zombie health logic
close https://github.com/LuminolMC/Lophine/issues/157
2026-07-02 18:52:09 +08:00
xiaoxijun 07073cb4a3 #154 (#155)
* Add PCA sync protocol support

Introduce PCA sync protocol and integrate it into Carpet/Leaves.

- Added org/leavesmc/leaves/protocol/PcaSyncProtocol.java: full implementation of the PCA sync protocol (handlers for sync requests, watcher maps, update payloads, player/block watch management, scheduling, and config-driven behavior).
- Added fun/bm/lophine/config/modules/function/protocol/PcaSyncProtocolConfig.java and enum PcaPlayerEntityType.java to drive enabling and player-entity sync policy.
- Integrated protocol into Carpet: register new carpet rules (pcaSyncProtocol, pcaSyncPlayerEntity) in CarpetCompatSync and added batching to avoid excessive updates when rules change.
- Enhanced CarpetServerProtocol to track active players, batch rule updates, and send server rule data safely on the server thread.
- Added a Minecraft patch (0046-PCA-sync-protocol.patch) to trigger syncs from setChanged() in containers, chest boats, minecarts and BlockEntity updates so watched clients receive entity/block-entity updates.

This enables PCA clients to watch and receive synchronized block-entity and entity state on demand, while keeping updates gated by config and player permissions and improving rule-update performance via batching.

* Add Vanilla-like experience config and updates

Introduce a new VanillaLikeExperienceConfig module and a patch (0047) that gates multiple Paper/Luminol behavior changes behind this toggle to restore more vanilla-like technical behavior when enabled. The patch injects conditional checks across many server classes (entity merging, phantoms, pistons, hoppers, TNT handling, explosions, portal/piston protections, item merging, teleportation, spawn counting, etc.). Also adjust PCA sync protocol references in the existing 0046 patch to use the updated fun.bm.lophine package path. Includes the new fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.java file.

* Restore vanilla ender pearl loading on Folia

Add patch (features/0048) that restores vanilla ender-pearl loading behavior on Folia. Reintroduces ender-pearl tracking and persistence: ServerPlayer now uses a thread-safe enderPearls set and saves pearl tags, ThrownEnderpearl maintains a lastSavedEnderPearlTag (updated on construction, owner changes, spawn and restore) and updates/clears it on tick/removal, and EnderpearlItem updates the saved tag when spawning a pearl. PlayerList and BotList now schedule pearl removal via the Bukkit taskScheduler when players/bots quit. The changes preserve Paper's legacyEnderPearlBehavior checks where applicable and add logging and safer tag handling to avoid saving invalid snapshots.

* Restore vanilla ender pearl loading

Restore vanilla ender-pearl loading behavior on Folia by preserving the last saved NBT for thrown pearls. ThrownEnderpearl.java: add a volatile CompoundTag lastSavedEnderPearlTag, provide a defensive-copying getter getLastSavedEnderPearlTag(), adjust @Nullable annotation placement, and update logger/comment. Minor index/format updates in ServerPlayer.java, PlayerList.java and EnderpearlItem.java.

* remove extra import

* Add Precise mob cap and adjust ender pearl patch

Introduce a Precise mob cap feature and integrate it into Paper/Folia world/region lifecycle. Adds new patch features/0049-Precise-mob-cap.patch which modifies RegionizedWorldData, ServerChunkCache and ServerLevel to support an incremental, event-driven mob counting system that can supersede the existing GlobalEntitiesCounter. Adds PreciseMobCapConfig (toggle and behavior flags) and PreciseMobCapCounter (unique id management, area map registration, per-level global counters, spawnable-chunk tracking, spawn state creation, and cleanup on unload). Also updates the existing 0048 ender-pearl loading patch file (minor import/index adjustments). The Precise mob cap counts only relevant mobs (configurable to match vanilla or Paper-optimized behavior), hooks into entity tracking start/end, and requires per-player-mob-spawns=false to be set in Paper world defaults when enabled.

* remove extra import

* pre merge config

* transform config

* merge config

* rebuild patches

* fix a bug in new counter

* simplify code

---------

Co-authored-by: Helvetica Volubi <suisuroru@blue-millennium.fun>
Co-authored-by: Helvetica Volubi <88063803+Suisuroru@users.noreply.github.com>
2026-07-02 18:11:12 +08:00
Helvetica Volubi 37c22202ab [ci skip] oops 2026-06-28 04:18:47 +08:00
Helvetica Volubi 2e67f978ec Update Luminol 2026-06-28 03:16:11 +08:00
72 changed files with 1719 additions and 315 deletions
+3 -3
View File
@@ -57,7 +57,7 @@ cd Lophine
```kotlin
repositories {
maven {
url = "https://repo.menthamc.org/repository/maven-public/"
url = "https://repo.bacteriawa.com/repository/maven-public/"
}
}
@@ -71,8 +71,8 @@ dependencies {
```xml
<repositories>
<repository>
<id>menthamc</id>
<url>https://repo.menthamc.org/repository/maven-public/</url>
<id>repository</id>
<url>https://repo.bacteriawa.com/repository/maven-public/</url>
</repository>
</repositories>
+3 -3
View File
@@ -57,7 +57,7 @@ After building, you can find the generated JAR file in the `lophine-server/build
```kotlin
repositories {
maven {
url = "https://repo.menthamc.org/repository/maven-public/"
url = "https://repo.bacteriawa.com/repository/maven-public/"
}
}
@@ -71,8 +71,8 @@ dependencies {
```xml
<repositories>
<repository>
<id>menthamc</id>
<url>https://repo.menthamc.org/repository/maven-public/</url>
<id>repository</id>
<url>https://repo.bacteriawa.com/repository/maven-public/</url>
</repository>
</repositories>
+4 -4
View File
@@ -44,7 +44,7 @@ paperweight {
}
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
val menthaMavenPublicUrl = "https://repo.menthamc.org/repository/maven-public/";
val bacteriawaMavenPublicUrl = "https://repo.bacteriawa.com/repository/maven-public/";
subprojects {
apply(plugin = "java-library")
@@ -59,7 +59,7 @@ subprojects {
repositories {
mavenCentral()
maven(paperMavenPublicUrl)
maven(menthaMavenPublicUrl)
maven(bacteriawaMavenPublicUrl)
}
dependencies {
@@ -91,8 +91,8 @@ subprojects {
extensions.configure<PublishingExtension> {
repositories {
maven("https://repo.menthamc.org/repository/maven-snapshots/") {
name = "MenthaMC"
maven("https://repo.bacteriawa.com/repository/maven-releases/") {
name = "Bacteriawa"
credentials(PasswordCredentials::class) {
username = System.getenv("PRIVATE_MAVEN_REPO_USERNAME")
password = System.getenv("PRIVATE_MAVEN_REPO_PASSWORD")
+1 -1
View File
@@ -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=2a3c21971bf030511823915c8b8d537f6d5963eb
luminolRef=b796645fdaae7d6b3d3c84fd79f9c090a6458a48
org.gradle.configuration-cache=true
org.gradle.caching=true
@@ -5,14 +5,14 @@ Subject: [PATCH] Rebrand to Lophine
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index a2f5a99ee45a0810fd338ccf6f71df3a077ca62b..05e1aa84586284ac0389e7023f975bfb08438535 100644
index 3b700b214ac6818cd75c34b207aa1436f52231e7..315c137cb9dbac51a8ac0d63f0ae0127e57c6c9f 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -24,6 +24,7 @@ public class ConfigManager {
@@ -25,6 +25,7 @@ public class ConfigManager {
public static void initConfigs() {
registerConfig("luminol", ConfigsInstance.of("luminol", "me.earthme.luminol.config.modules"));
+ registerConfig("lophine", ConfigsInstance.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
registerConfig("luminol", builder.of("luminol", "me.earthme.luminol.config.modules"));
+ registerConfig("lophine", builder.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
preLoad();
}
@@ -5,10 +5,10 @@ Subject: [PATCH] Leaves: Fakeplayer
diff --git a/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java b/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
index 389a31b14912a2dfc8e8b20c104505d211d7f8ad..04b9e3a432181c9698e1a4c147b420c230b66a36 100644
index a4c188f71564fc77a9fa22b4cae032e1919d06f2..019266803f1452cb1e76350da8edae10a77020ac 100644
--- a/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
+++ b/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
@@ -55,6 +55,12 @@ public class FoliaServerWaypointManager extends ServerWaypointManager {
@@ -54,6 +54,12 @@ public class FoliaServerWaypointManager extends ServerWaypointManager {
return;
}
@@ -21,16 +21,15 @@ index 389a31b14912a2dfc8e8b20c104505d211d7f8ad..04b9e3a432181c9698e1a4c147b420c2
this.waypoints.add(waypoint);
for (ServerPlayer toCreateFor : this.trackingPlayers) {
@@ -111,6 +117,12 @@ public class FoliaServerWaypointManager extends ServerWaypointManager {
scheduleIfOffTarget(player, () -> {
this.trackingPlayers.add(player);
@@ -110,6 +116,11 @@ public class FoliaServerWaypointManager extends ServerWaypointManager {
this.trackingPlayers.add(player);
scheduleIfOffTarget(player, () -> {
+ // Leaves start - fakeplayer
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ return;
+ }
+ // Leaves end - fakeplayer
+
for (WaypointTransmitter transmitter : this.waypoints) {
this.createConnection(player, transmitter);
}
@@ -5,15 +5,15 @@ Subject: [PATCH] Carpet features
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index 05e1aa84586284ac0389e7023f975bfb08438535..5a8c94337e42584ddaf25ef289327777e7ac675e 100644
index 315c137cb9dbac51a8ac0d63f0ae0127e57c6c9f..2a2d6aff636ad960638b357d224a631c89d23d33 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -25,6 +25,15 @@ public class ConfigManager {
@@ -26,6 +26,15 @@ public class ConfigManager {
public static void initConfigs() {
registerConfig("luminol", ConfigsInstance.of("luminol", "me.earthme.luminol.config.modules"));
registerConfig("lophine", ConfigsInstance.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
registerConfig("luminol", builder.of("luminol", "me.earthme.luminol.config.modules"));
registerConfig("lophine", builder.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
+ // Lophine start - add carpet config
+ registerConfig("lophine_carpet", ConfigsInstance.of(
+ registerConfig("lophine_carpet", builder.of(
+ new java.io.File("lophine_config"),
+ "lophine_carpet",
+ "lophine_carpet_config.toml",
@@ -7,10 +7,10 @@ Subject: [PATCH] TEMP: Temporarily transform config between different config
Should be removed in Minecraft 26.2 Update
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index 5a8c94337e42584ddaf25ef289327777e7ac675e..b652525f243c23e09c4e13f67617e99a3ce0db04 100644
index 2a2d6aff636ad960638b357d224a631c89d23d33..536e8d7df4ce9de1dbe587c1af6b2474a530a165 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -64,6 +64,12 @@ public class ConfigManager {
@@ -65,6 +65,12 @@ public class ConfigManager {
CompletableFuture.allOf(futures).join();
CommandRegister.register(); // register command after config loaded to enable some command didn't depend on config files
initialized = true;
@@ -39,7 +39,7 @@ index 143ad4e342b184aa02b6fbbe81508e244eebc7a2..89be42b8519522398920eb424c894fd2
String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck();
if (awtException != null) {
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 3707b03b6d7ebdf47a38f4feff5b738eb41f38e1..1bc1e9a77dca7acfe5f989f6439f185d0d2e20a6 100644
index dfac07850b02abba160f8f143eba4569172ab9e9..fcd4b4785f0d09f87fe214202468c75395157e14 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -283,6 +283,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -5,10 +5,10 @@ Subject: [PATCH] Fix datapack command save function
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 28384f9ebfcdbfbd07fc7fe3c929786eb9e2ccd3..d1cc2f956213add0e04d51db7b9da7076b521d8b 100644
index e7eec08a4d8943b35a76173e39529498c348140c..61983a80191e64942bfdac74c6d2f23cf781484d 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2472,6 +2472,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2475,6 +2475,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return this.reloadResources(packsToEnable, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN);
}
@@ -8,10 +8,10 @@ As part of: Purpur (https://github.com/PurpurMC/Purpur/blob/dc46f46d28dcdcaf33bb
Licensed under: MIT (https://github.com/PurpurMC/Purpur/blob/dc46f46d28dcdcaf33bb533f9571a107db98c1d7/LICENSE)
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 63b81f30b8d813a7986ae72842fdc2d3097fa103..527c495bb4f6007aee760b99cc0e9aa589931f4b 100644
index c9d3b000a328fe3583a7053a94c72dc003c1e10c..45e5ac1e8e2ec30935e96fa20d18e77bbd0e20bd 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -961,6 +961,10 @@ public abstract class PlayerList {
@@ -963,6 +963,10 @@ public abstract class PlayerList {
player.getBukkitEntity().recalculatePermissions(); // CraftBukkit
this.server.getCommands().sendCommands(player);
} // Paper - Add sendOpLevel API
@@ -23,10 +23,10 @@ index 63b81f30b8d813a7986ae72842fdc2d3097fa103..527c495bb4f6007aee760b99cc0e9aa5
// Paper start - whitelist verify event / login event
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 1413286ddc63c5978e745eb26f6012230e4b1cd6..234124cc64e5175c20f9e9f0f482c9c677bca563 100644
index 592ce8beb28ebe8aaac2ed167abb24148afb0bc3..ce8ab4b7eee5e0715e780d189d2f6554c5a9dc3c 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -174,6 +174,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -175,6 +175,7 @@ public abstract class Player extends Avatar implements ContainerUser {
public float hurtDir;
public boolean affectsSpawning = true; // Paper - Affects Spawning API
public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage
@@ -5,10 +5,10 @@ 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 fecab5bfbc35fbecef8c559369de70c198bfe1e7..338e0c7c09120c6e9617893dd074cbd5da40a093 100644
index ad50feba5cbc5fe904850e6da06a866eeb23b519..f7869f06ab29e4bbd003c807176345dec9e9e5ab 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1464,6 +1464,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1467,6 +1467,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.awardStat(Stats.ENTITY_KILLED_BY.get(killer.getType()));
killer.awardKillScore(this, source);
this.createWitherRose(killer);
@@ -22,7 +22,7 @@ index fecab5bfbc35fbecef8c559369de70c198bfe1e7..338e0c7c09120c6e9617893dd074cbd5
}
this.level().broadcastEntityEvent(this, EntityEvent.DEATH);
@@ -1487,6 +1494,24 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1490,6 +1497,24 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// Leaves end - exp fix
@@ -48,10 +48,10 @@ index 89f61f5715942d2b521e04b9fdc8b1b379c0c957..2c2487e1c1c65438119a13bd705a9e44
SaveOnCommand.register(this.dispatcher);
SetPlayerIdleTimeoutCommand.register(this.dispatcher);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index d1cc2f956213add0e04d51db7b9da7076b521d8b..82013a8f7cf07b6f0645ca6b51ee75fcb0a56298 100644
index 61983a80191e64942bfdac74c6d2f23cf781484d..99edebf474277e680df63930b51fef579b712def 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1683,6 +1683,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1686,6 +1686,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Folia start - region threading
public void tickServer(final long startTime, final long scheduledEnd, final long targetBuffer,
final io.papermc.paper.threadedregions.TickRegions.TickRegionData region) {
@@ -96,10 +96,10 @@ index cb0a52dc3795e1cf54069bcbe82abf7877a658b8..0d743a01ae70baa789cd0e0bb9abd4c4
public EntityType(
final EntityType.EntityFactory<T> factory,
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 234124cc64e5175c20f9e9f0f482c9c677bca563..b45481f781f3556001af89704b718d6291ba1f66 100644
index ce8ab4b7eee5e0715e780d189d2f6554c5a9dc3c..06c6d30f3aef605bc25c42db8a6d26bbde57f40b 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -185,6 +185,25 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -186,6 +186,25 @@ public abstract class Player extends Avatar implements ContainerUser {
return (org.bukkit.craftbukkit.entity.CraftHumanEntity) super.getBukkitEntity();
}
// CraftBukkit end
@@ -125,7 +125,7 @@ index 234124cc64e5175c20f9e9f0f482c9c677bca563..b45481f781f3556001af89704b718d62
public Player(final Level level, final GameProfile gameProfile) {
super(EntityType.PLAYER, level);
@@ -240,6 +259,26 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -241,6 +260,26 @@ public abstract class Player extends Avatar implements ContainerUser {
@Override
public void tick() {
@@ -152,7 +152,7 @@ index 234124cc64e5175c20f9e9f0f482c9c677bca563..b45481f781f3556001af89704b718d62
this.noPhysics = this.isSpectator();
if (this.isSpectator() || this.isPassenger()) {
this.setOnGround(false);
@@ -1352,6 +1391,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1355,6 +1394,7 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.hasContainerOpen()) {
this.doCloseContainer();
}
@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 2 Jul 2026 18:49:40 +0800
Subject: [PATCH] Old leader zombie health logic
diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
index 2734ffc103ee4760d3521609fdd090ab99df675b..a99683d341f52139003dfa5190ee118d5b06f59f 100644
--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
+++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
@@ -597,7 +597,7 @@ public class Zombie extends Monster {
.addOrReplacePermanentModifier(
new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)
);
- if (spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) {
+ if (!fun.bm.lophine.config.modules.function.OldFeatureConfig.oldLeaderZombieHealth && spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) { // Lophine - Configurable option to disable health boost for leader zombies
this.setHealth(this.getMaxHealth());
}
@@ -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 338e0c7c09120c6e9617893dd074cbd5da40a093..baab2435bac22aacff30ad52bde629b4093bfaba 100644
index f7869f06ab29e4bbd003c807176345dec9e9e5ab..295be200cb0696bd2ae2b655f89d96dd7723a541 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -242,6 +242,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -16,7 +16,7 @@ index 338e0c7c09120c6e9617893dd074cbd5da40a093..baab2435bac22aacff30ad52bde629b4
private ChatVisiblity chatVisibility = ChatVisiblity.FULL;
public ParticleStatus particleStatus = ParticleStatus.ALL;
private boolean canChatColor = true;
@@ -920,6 +921,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -923,6 +924,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.connection.tickClientLoadTimeout();
this.gameMode.tick();
this.wardenSpawnTracker.tick();
@@ -24,7 +24,7 @@ index 338e0c7c09120c6e9617893dd074cbd5da40a093..baab2435bac22aacff30ad52bde629b4
if (this.invulnerableTime > 0) {
this.invulnerableTime--;
}
@@ -1556,6 +1558,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1559,6 +1561,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
if (this.isInvulnerableTo(level, source)) {
return false;
} else {
@@ -36,10 +36,10 @@ index e9f86409bf9351e85ed31e747d9350dbf0cc441f..1f8f4d979d8766d6ba385f74cf8fcf8e
};
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 82013a8f7cf07b6f0645ca6b51ee75fcb0a56298..54ba8a2bc70f3a7f9754a872f6b9c22b40887d8e 100644
index 99edebf474277e680df63930b51fef579b712def..3cd1a0de188db35ac9c48996a4dbe6186b69e348 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2037,6 +2037,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2040,6 +2040,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
profiler.popPush("server gui refresh");
@@ -96,10 +96,10 @@ index cf4b5e436b8d81657d1deaa5b06645016d9dc3cc..f3af5660a377e2eb823f79ec274feaf3
bridge.removeChannel(channel);
}
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 527c495bb4f6007aee760b99cc0e9aa589931f4b..e6987eaf6e4d36d43cee4ece3ce22d31052a2a2a 100644
index 45e5ac1e8e2ec30935e96fa20d18e77bbd0e20bd..deb029c5621f793f63447d351526c31fab5ec12c 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -317,6 +317,8 @@ public abstract class PlayerList {
@@ -318,6 +318,8 @@ public abstract class PlayerList {
//return; // Folia - region threading - must still allow the player to connect, as we must add to chunk map before handling disconnect
}
@@ -108,7 +108,7 @@ index 527c495bb4f6007aee760b99cc0e9aa589931f4b..e6987eaf6e4d36d43cee4ece3ce22d31
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -517,6 +519,7 @@ public abstract class PlayerList {
@@ -518,6 +520,7 @@ public abstract class PlayerList {
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
}
public net.kyori.adventure.text.@Nullable Component remove(final ServerPlayer player, final net.kyori.adventure.text.Component leaveMessage) {
@@ -116,7 +116,7 @@ index 527c495bb4f6007aee760b99cc0e9aa589931f4b..e6987eaf6e4d36d43cee4ece3ce22d31
// Paper end - Fix kick event leave message not being sent
ServerLevel level = player.level();
player.awardStat(Stats.LEAVE_GAME);
@@ -1411,6 +1414,7 @@ public abstract class PlayerList {
@@ -1413,6 +1416,7 @@ public abstract class PlayerList {
player.connection.send(recipes);
player.getRecipeBook().sendInitialRecipeBook(player);
}
@@ -21,10 +21,10 @@ index 0f1bd15ea3b1400cc948883c92eceabcd4a4cda1..006844d6fda43f3b151899655f03b1de
}
// Paper end - Fix merchant inventory not closing on entity removal
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index e6987eaf6e4d36d43cee4ece3ce22d31052a2a2a..168702a5ae51a2bc42c5761e13cb14008a8162c4 100644
index deb029c5621f793f63447d351526c31fab5ec12c..6148e7e5978a9a5b7d7f90b58b86b0166fd16c9d 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -560,7 +560,7 @@ public abstract class PlayerList {
@@ -561,7 +561,7 @@ public abstract class PlayerList {
player.stopRiding();
vehicle.getPassengersAndSelf().forEach(e -> {
// Paper start - Fix villager boat exploit
@@ -8,10 +8,10 @@ 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/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 168702a5ae51a2bc42c5761e13cb14008a8162c4..ebd2f2887780d9c6c3c44983bac23eab732cf43f 100644
index 6148e7e5978a9a5b7d7f90b58b86b0166fd16c9d..16d01fcb97aa3dbd7554bd64b3608c6e80ce3dbd 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -1105,6 +1105,7 @@ public abstract class PlayerList {
@@ -1107,6 +1107,7 @@ public abstract class PlayerList {
//player.connection.send(new ClientboundSetChunkCacheRadiusPacket(io.papermc.paper.FeatureHooks.getViewDistance(level))); // Paper - rewrite chunk system
//player.connection.send(new ClientboundSetSimulationDistancePacket(io.papermc.paper.FeatureHooks.getSimulationDistance(level))); // Paper - rewrite chunk system
// Paper end - view distances
@@ -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 54ba8a2bc70f3a7f9754a872f6b9c22b40887d8e..c4685bb540e95d889dfbc107923876045be29848 100644
index 3cd1a0de188db35ac9c48996a4dbe6186b69e348..9837d8388e6fe73ef87d021c7370c2a7c236c634 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,7 +45,7 @@ index 54ba8a2bc70f3a7f9754a872f6b9c22b40887d8e..c4685bb540e95d889dfbc10792387604
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<>();
@@ -1226,6 +1228,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1229,6 +1231,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.safeShutdown(wait, false);
}
public void safeShutdown(final boolean wait, final boolean isRestarting) {
@@ -62,7 +62,7 @@ index 54ba8a2bc70f3a7f9754a872f6b9c22b40887d8e..c4685bb540e95d889dfbc10792387604
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
@@ -1698,7 +1710,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
@@ -71,7 +71,7 @@ index 54ba8a2bc70f3a7f9754a872f6b9c22b40887d8e..c4685bb540e95d889dfbc10792387604
this.emptyTicks++;
} else {
this.emptyTicks = 0;
@@ -1827,6 +1839,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1830,6 +1842,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.isSaving = true;
if (playerSaveInterval > 0) {
this.playerList.saveAll(playerSaveInterval);
@@ -79,7 +79,7 @@ index 54ba8a2bc70f3a7f9754a872f6b9c22b40887d8e..c4685bb540e95d889dfbc10792387604
}
if (region == null && fullSave) { // Folia - region threading - don't auto save level data
this.saveGlobalData(false);
@@ -2065,6 +2078,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2068,6 +2081,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
protected void tickConnection() {
this.getConnection().tick();
@@ -87,7 +87,7 @@ index 54ba8a2bc70f3a7f9754a872f6b9c22b40887d8e..c4685bb540e95d889dfbc10792387604
}
public void forceGameTimeSynchronization() {
@@ -3270,6 +3284,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -3273,6 +3287,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return this.debugSubscribers;
}
@@ -239,7 +239,7 @@ index e9c9a468f046832e8eaa999bb57da261b4633604..2efe24c0378a80dd2750b10a54c18878
}
}
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 1bc1e9a77dca7acfe5f989f6439f185d0d2e20a6..1790e8c141a8d3f7ccf4b11f9a28b3582325e317 100644
index fcd4b4785f0d09f87fe214202468c75395157e14..09e92f20f97b374582e057b0dc7d2edc82d6f431 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -274,6 +274,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -334,7 +334,7 @@ index 0befa4fc81e10a23c6ba824e559f2fb4886e68ee..2ddcf6ae90aaaf98e2fcd8ab9995b6f0
ServerLevel.this.updateSleepingPlayerList();
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index baab2435bac22aacff30ad52bde629b4093bfaba..cdb4a52cbd34322903144364c3686a4e1bf0fbb8 100644
index 295be200cb0696bd2ae2b655f89d96dd7723a541..4f6010285a5ff9cf939248c4d93043133680d383 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -229,7 +229,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -355,7 +355,7 @@ index baab2435bac22aacff30ad52bde629b4093bfaba..cdb4a52cbd34322903144364c3686a4e
private @Nullable Vec3 levitationStartPos;
private int levitationStartTime;
private boolean disconnected;
@@ -1514,7 +1514,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1517,7 +1517,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// Luminol End - Cross Region Damage trace
@@ -364,7 +364,7 @@ index baab2435bac22aacff30ad52bde629b4093bfaba..cdb4a52cbd34322903144364c3686a4e
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
this.level()
.getEntitiesOfClass(Mob.class, aabb, EntitySelector.NO_SPECTATORS)
@@ -2180,6 +2180,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -2183,6 +2183,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.lastSentHealth = -1.0F;
this.lastSentFood = -1;
this.teleportSpectators(transition, oldLevel);
@@ -377,7 +377,7 @@ index baab2435bac22aacff30ad52bde629b4093bfaba..cdb4a52cbd34322903144364c3686a4e
org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), oldLevel.getWorld());
this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
diff --git a/net/minecraft/server/players/CachedUserNameToIdResolver.java b/net/minecraft/server/players/CachedUserNameToIdResolver.java
index 50c64f4be138f08e8a57fb10888dbfbc364c91af..382fc20df48d7d554833715a9c9f62ea7464a25d 100644
index d2da9f3c5e53ceaeb85c6d3d7443e124a4d93bb8..8a96c07e6d5fd0826efc50e3fd585a42b2c9028c 100644
--- a/net/minecraft/server/players/CachedUserNameToIdResolver.java
+++ b/net/minecraft/server/players/CachedUserNameToIdResolver.java
@@ -122,6 +122,12 @@ public class CachedUserNameToIdResolver implements UserNameToIdResolver {
@@ -442,10 +442,10 @@ index 484714beb5f7cdf8178834c5edd4f847fb06ebb8..ba7a280aad07f36366c15cd158b36ca9
// Paper start - utility method for common conversion back to the game profile
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f0da2047c 100644
index 16d01fcb97aa3dbd7554bd64b3608c6e80ce3dbd..b77968e195d1f87c825c09b2a1622b3a3ed5f772 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -319,6 +319,19 @@ public abstract class PlayerList {
@@ -320,6 +320,19 @@ public abstract class PlayerList {
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
@@ -465,7 +465,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -791,6 +804,11 @@ public abstract class PlayerList {
@@ -793,6 +806,11 @@ public abstract class PlayerList {
respawnReason
).callEvent();
// Paper end
@@ -477,7 +477,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
return player;
}
@@ -893,11 +911,16 @@ public abstract class PlayerList {
@@ -895,11 +913,16 @@ public abstract class PlayerList {
public String[] getPlayerNamesArray() {
List<ServerPlayer> players = new java.util.ArrayList<>(this.players); // Folia - region threading
@@ -495,7 +495,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
return names;
}
@@ -1016,8 +1039,15 @@ public abstract class PlayerList {
@@ -1018,8 +1041,15 @@ public abstract class PlayerList {
|| this.allowCommandsForAllPlayers;
}
@@ -513,7 +513,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
}
public void broadcast(
@@ -1360,7 +1390,13 @@ public abstract class PlayerList {
@@ -1362,7 +1392,13 @@ public abstract class PlayerList {
}
public @Nullable ServerPlayer getPlayer(final UUID uuid) {
@@ -597,7 +597,7 @@ index 2bce20202b7c539bee3685741663a8ed225919ff..a2f44e4354f6aa1c0502cba40cadaad5
if (!this.level().isClientSide()) {
boolean wasUsingItem = this.isUsingItem();
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index b45481f781f3556001af89704b718d6291ba1f66..2135ea645131c27b9bec5534431199f9d55134d8 100644
index 06c6d30f3aef605bc25c42db8a6d26bbde57f40b..20a76138a8625663cf608e4ef97cc8ca4085b844 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -167,7 +167,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -608,8 +608,8 @@ index b45481f781f3556001af89704b718d6291ba1f66..2135ea645131c27b9bec5534431199f9
+ protected ItemStack lastItemInMainHand = ItemStack.EMPTY; // Leaves - fakeplayer
private final ItemCooldowns cooldowns = this.createItemCooldowns();
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
public @Nullable FishingHook fishing;
@@ -340,6 +340,12 @@ public abstract class Player extends Avatar implements ContainerUser {
public me.earthme.luminol.functions.bars.TickableStatusBarList statusBarList = new me.earthme.luminol.functions.bars.TickableStatusBarList(this); // Luminol status bars
@@ -341,6 +341,12 @@ public abstract class Player extends Avatar implements ContainerUser {
this.updatePlayerPose();
}
@@ -622,7 +622,7 @@ index b45481f781f3556001af89704b718d6291ba1f66..2135ea645131c27b9bec5534431199f9
@Override
protected float getMaxHeadRotationRelativeToBody() {
return this.isBlocking() ? 15.0F : super.getMaxHeadRotationRelativeToBody();
@@ -565,7 +571,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -566,7 +572,7 @@ public abstract class Player extends Avatar implements ContainerUser {
public void removeEntitiesOnShoulder() {
}
@@ -631,7 +631,7 @@ index b45481f781f3556001af89704b718d6291ba1f66..2135ea645131c27b9bec5534431199f9
entity.playerTouch(this);
}
@@ -1247,7 +1253,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1250,7 +1256,7 @@ public abstract class Player extends Avatar implements ContainerUser {
// Paper end - Configurable sprint interruption on attack
}
@@ -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 c4685bb540e95d889dfbc107923876045be29848..f99c02b4d88cea924e20ca8dced67873c83c093f 100644
index 9837d8388e6fe73ef87d021c7370c2a7c236c634..5889aa815ab02261f26048c5ef43f5bdfa2939fc 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1930,7 +1930,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1933,7 +1933,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
private ServerStatus.Players buildPlayerStatus() {
@@ -96,7 +96,7 @@ index c4685bb540e95d889dfbc107923876045be29848..f99c02b4d88cea924e20ca8dced67873
int maxPlayers = this.getMaxPlayers();
if (this.hidesOnlinePlayers()) {
return new ServerStatus.Players(maxPlayers, players.size(), List.of());
@@ -2151,7 +2151,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2154,7 +2154,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@Override
public int getPlayerCount() {
@@ -105,7 +105,7 @@ index c4685bb540e95d889dfbc107923876045be29848..f99c02b4d88cea924e20ca8dced67873
}
public String[] getPlayerNames() {
@@ -2363,7 +2363,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2366,7 +2366,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
} else {
int count = 0;
@@ -114,7 +114,7 @@ index c4685bb540e95d889dfbc107923876045be29848..f99c02b4d88cea924e20ca8dced67873
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
@@ -2550,7 +2550,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2553,7 +2553,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 c4685bb540e95d889dfbc107923876045be29848..f99c02b4d88cea924e20ca8dced67873
player.getAdvancements().save();
}
// Paper end - we don't need to save everything, just advancements
@@ -2686,7 +2686,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2689,7 +2689,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
PlayerList playerList = this.getPlayerList();
UserWhiteList whiteList = playerList.getWhiteList();
@@ -307,7 +307,7 @@ index 2ddcf6ae90aaaf98e2fcd8ab9995b6f0d7791856..a7cebb797973cde399dc30c696b064ef
}
// Leaves end - skip
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1f82c9279 100644
index b77968e195d1f87c825c09b2a1622b3a3ed5f772..c95c7b9a3968fc34a900a613b65b5d3e1abb24bf 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -130,6 +130,7 @@ public abstract class PlayerList {
@@ -318,7 +318,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
// CraftBukkit start
private org.bukkit.craftbukkit.CraftServer cserver;
@@ -191,6 +192,7 @@ public abstract class PlayerList {
@@ -192,6 +193,7 @@ public abstract class PlayerList {
private boolean countConnection(Connection conn, int limit) {
synchronized (this.connectionsStateLock) {
@@ -326,7 +326,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
int count = this.usersCountedAgainstLimit.size();
if (count >= limit) {
return false;
@@ -221,6 +223,124 @@ public abstract class PlayerList {
@@ -222,6 +224,124 @@ public abstract class PlayerList {
abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor
@@ -451,7 +451,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
public void placeNewPlayer(final Connection connection, final ServerPlayer player, final CommonListenerCookie cookie) {
player.isRealPlayer = true; // Paper
player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
@@ -294,6 +414,7 @@ public abstract class PlayerList {
@@ -295,6 +415,7 @@ public abstract class PlayerList {
// player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players)); // CraftBukkit - replaced with loop below
this.players.add(player);
@@ -459,7 +459,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); // Spigot
this.playersByUUID.put(player.getUUID(), player);
// this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player))); // CraftBukkit - replaced with loop below
@@ -513,6 +634,7 @@ public abstract class PlayerList {
@@ -514,6 +635,7 @@ public abstract class PlayerList {
}
protected void save(final ServerPlayer player) {
@@ -467,7 +467,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
player.lastSave = System.nanoTime(); // Folia - region threading - changed to nanoTime tracking
this.playerIo.save(player);
@@ -527,6 +649,47 @@ public abstract class PlayerList {
@@ -528,6 +650,47 @@ public abstract class PlayerList {
}
}
@@ -515,15 +515,15 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
public net.kyori.adventure.text.@Nullable Component remove(final ServerPlayer player) { // CraftBukkit - return string // Paper - return Component
// Paper start - Fix kick event leave message not being sent
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
@@ -600,6 +763,7 @@ public abstract class PlayerList {
@@ -601,6 +764,7 @@ public abstract class PlayerList {
player.getBukkitEntity().packetProcessor.close(); // Folia - region threading
player.getAdvancements().stopListening();
this.players.remove(player);
+ this.realPlayers.remove(player); // Leaves - replay api
this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
if (me.earthme.luminol.config.modules.misc.UsernameCheckConfig.allowOldPlayersJoin) this.playedPlayers.remove(player.getGameProfile().name()); // Leaf - Configurable vanilla username check
this.server.getCustomBossEvents().onPlayerDisconnect(player);
UUID uuid = player.getUUID();
@@ -910,15 +1074,15 @@ public abstract class PlayerList {
@@ -912,15 +1076,15 @@ public abstract class PlayerList {
}
public String[] getPlayerNamesArray() {
@@ -21,10 +21,10 @@ index e302c6198d71782b524391329aa5c89d2b3e0ccf..2312803297321f66c9057bc54ce56dd1
} else {
this.followingPlayer = null;
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 2135ea645131c27b9bec5534431199f9d55134d8..5e7e99410c7597ec5330cc82e441fa30c53c9532 100644
index 20a76138a8625663cf608e4ef97cc8ca4085b844..97057675369875ed71c228a87f5a4d3c3489dded 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -279,8 +279,8 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -280,8 +280,8 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.cullTask != null) this.cullTask.requestCullSignal(); // Luminol - Ray tracing entity tracker
// Luminol end
@@ -35,7 +35,7 @@ index 2135ea645131c27b9bec5534431199f9d55134d8..5e7e99410c7597ec5330cc82e441fa30
this.setOnGround(false);
}
@@ -406,7 +406,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -407,7 +407,7 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) {
Pose desiredPose = this.getDesiredPose();
Pose actualPose;
@@ -44,7 +44,7 @@ index 2135ea645131c27b9bec5534431199f9d55134d8..5e7e99410c7597ec5330cc82e441fa30
actualPose = desiredPose;
} else if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.CROUCHING)) {
actualPose = Pose.CROUCHING;
@@ -535,7 +535,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -536,7 +536,7 @@ public abstract class Player extends Avatar implements ContainerUser {
this.updateSwingTime();
this.yHeadRot = this.getYRot();
this.setSpeed((float)this.getAttributeValue(Attributes.MOVEMENT_SPEED));
@@ -53,7 +53,7 @@ index 2135ea645131c27b9bec5534431199f9d55134d8..5e7e99410c7597ec5330cc82e441fa30
AABB pickupArea;
if (this.isPassenger() && !this.getVehicle().isRemoved()) {
pickupArea = this.getBoundingBox().minmax(this.getVehicle().getBoundingBox()).inflate(1.0, 0.0, 1.0);
@@ -1846,6 +1846,26 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1849,6 +1849,26 @@ public abstract class Player extends Avatar implements ContainerUser {
return this.gameMode() == GameType.SPECTATOR;
}
@@ -5,7 +5,7 @@ Subject: [PATCH] Global Entities Counter
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
index 0cf5815672ac62d8caf7f18165be1f0f8e067aed..64d407c5a6140a7e5dc47a8e304b4c00602e2bdd 100644
index eedbeb005d3c8090333c36b9857c837dfb75dbd4..7ea91dbfb988aff3215a91cf62c9beae94461484 100644
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
@@ -558,6 +558,9 @@ public final class RegionizedWorldData {
@@ -23,10 +23,10 @@ index 0cf5815672ac62d8caf7f18165be1f0f8e067aed..64d407c5a6140a7e5dc47a8e304b4c00
this.regionData = regionData;
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ uniqueId = fun.bm.lophine.utils.EntitiesCounterUtil.generateUniqueId();
+ fun.bm.lophine.utils.EntitiesCounterUtil.reportAreaMap(world, spawnChunkTracker, uniqueId);
+ fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(world, loadedEntities, uniqueId);
+ if (!fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(world, loadedEntities, uniqueId);
+ underGlobalEntitiesCounter = true;
+ }
+ // Lophine end - Global Entities Counter
@@ -35,15 +35,15 @@ index 0cf5815672ac62d8caf7f18165be1f0f8e067aed..64d407c5a6140a7e5dc47a8e304b4c00
this.updateTickData();
}
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f824ad7df2 100644
index 27389ff98942e27c2a877ea5b671caa31353d18c..76fa17ce0afc7ff1c0b2b84aa2baddd2ba18c1a5 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -513,6 +513,25 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -513,6 +513,26 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
this.chunkMap.tick(haveTime);
profiler.pop();
this.clearCache();
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.level.getCurrentWorldData();
+ if (regionizedWorldData != null) {
+ if (regionizedWorldData.underGlobalEntitiesCounter) {
@@ -53,6 +53,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
+ }
+ } else {
+ if (!regionizedWorldData.getLocalPlayers().isEmpty()) {
+ regionizedWorldData.uniqueId = fun.bm.lophine.utils.EntitiesCounterUtil.generateUniqueId();
+ fun.bm.lophine.utils.EntitiesCounterUtil.reportAreaMap(level, regionizedWorldData.spawnChunkTracker, regionizedWorldData.uniqueId);
+ fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(level, (ca.spottedleaf.moonrise.common.list.ReferenceList<Entity>) regionizedWorldData.getLoadedEntities(), regionizedWorldData.uniqueId);
+ regionizedWorldData.underGlobalEntitiesCounter = true;
@@ -64,14 +65,14 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
}
private void tickChunks() {
@@ -577,7 +596,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -577,7 +597,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
}
spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, null, true); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
} else {
- spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ spawnCookie = fun.bm.lophine.utils.EntitiesCounterUtil.runRemainingTasks(level, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ spawnCookie = fun.bm.lophine.utils.EntitiesCounterUtil.createSpawnState(level, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
+ } else {
+ spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
+ }
@@ -79,7 +80,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
}
} finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.MOB_SPAWN_ENTITY_COUNT); } // Folia - profiler
// Paper end - Optional per player mob spawns
@@ -585,7 +610,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -585,7 +611,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
boolean doMobSpawning = this.level.getGameRules().get(GameRules.SPAWN_MOBS) && !this.level.getLocalPlayers().isEmpty(); // CraftBukkit // Folia - region threading
int tickSpeed = this.level.getGameRules().get(GameRules.RANDOM_TICK_SPEED);
List<MobCategory> spawningCategories;
@@ -88,7 +89,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
// Paper start - PlayerNaturallySpawnCreaturesEvent
for (ServerPlayer player : this.level.getLocalPlayers()) { // Folia - region threading
int chunkRange = Math.min(level.spigotConfig.mobSpawnRange, player.getBukkitEntity().getViewDistance());
@@ -645,7 +670,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -645,7 +671,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
this.level.tickThunder(chunk);
}
@@ -98,7 +99,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
NaturalSpawner.spawnForChunk(this.level, chunk, spawnCookie, spawningCategories);
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index a7cebb797973cde399dc30c696b064efd40874f2..c0e62a69bb5c9e777265b5474d76ba8d06ccec4b 100644
index a7cebb797973cde399dc30c696b064efd40874f2..1d60c20649b2a6469bfceb5b44c38bfd133e21eb 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -808,6 +808,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -106,15 +107,51 @@ index a7cebb797973cde399dc30c696b064efd40874f2..c0e62a69bb5c9e777265b5474d76ba8d
public void tick(BooleanSupplier haveTime, final io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ if (fun.bm.lophine.utils.EntitiesCounterUtil.canRunNewTask(this)) fun.bm.lophine.utils.EntitiesCounterUtil.tick(this);
+ }
+ // Lophine end - Global Entities Counter
final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - regionised ticking
final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle foliaProfiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler
ProfilerFiller profiler = Profiler.get();
@@ -2902,6 +2907,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public void close() throws IOException {
super.close();
//this.entityManager.close(); // Paper - rewrite chunk system
+ // Lophine start - Precise mob cap
+ if (!fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onWorldUnload(this);
+ }
+ // Lophine end - Precise mob cap
}
@Override
@@ -3136,6 +3146,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
entity.inWorld = true; // CraftBukkit - Mark entity as in world
entity.valid = true; // CraftBukkit
ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server
+ // Lophine start - Precise mob cap
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled() && !fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onEntityTrackingStart(ServerLevel.this, entity);
+ }
+ // Lophine end - Precise mob cap
// Paper start - Entity origin API
if (entity.origin == null) {
entity.origin = entity.position();
@@ -3151,6 +3166,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public void onTrackingEnd(final Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot
+ // Lophine start - Precise mob cap
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled() && !fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onEntityTrackingEnd(ServerLevel.this, entity);
+ }
+ // Lophine end - Precise mob cap
ServerLevel.this.getCurrentWorldData().removeLoadedEntity(entity); // Folia - region threading
// Spigot start // TODO I don't think this is needed anymore
if (entity instanceof Player player) {
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
index fc29654dd7ee3329edf1ccf705f45631d0ecc079..9b8ee2df5a0b6d76d9bfc747187f6cd51bb4a520 100644
index fc29654dd7ee3329edf1ccf705f45631d0ecc079..042f026f707e1a75b4ec7dc231e0eeb1b5afacc3 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -813,6 +813,44 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs
@@ -122,7 +159,7 @@ index fc29654dd7ee3329edf1ccf705f45631d0ecc079..9b8ee2df5a0b6d76d9bfc747187f6cd5
}
} else {
+ // Lophine start - fix some bug if player is cross scheduler >> to remove monster if the region don't have any valid player
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ List<net.minecraft.server.level.ServerPlayer> playerList = this.level().getServer().getPlayerList().getPlayers();
+ if (!playerList.isEmpty()) {
+ double d = -1.0;
@@ -36,10 +36,10 @@ index 24f5b890b0126fc817863f99b676da1a548f7608..a25bc31c04778bf12e3b6301ffcfb227
throw PacketUtils.makeReportedException(var3, this.packet, this.listener);
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index f99c02b4d88cea924e20ca8dced67873c83c093f..0c042c4af5d52c08e9fbc03a04c4b696d8a0a7ed 100644
index 5889aa815ab02261f26048c5ef43f5bdfa2939fc..af245af0fba14892095961a71925f3a53ce3d477 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2019,11 +2019,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2022,11 +2022,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
try {
foliaProfiler.startTimer(level.tickTimerId); try { // Folia - profiler
level.tick(haveTime, region); // Folia - region threading
@@ -74,7 +74,7 @@ index f99c02b4d88cea924e20ca8dced67873c83c093f..0c042c4af5d52c08e9fbc03a04c4b696
profiler.pop();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index c0e62a69bb5c9e777265b5474d76ba8d06ccec4b..3e7420cd98504732db17cb6b0fcfdfbb8deeb552 100644
index 1d60c20649b2a6469bfceb5b44c38bfd133e21eb..b884e06a5e9d6a93c548820a99e5d05157e9d128 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -967,7 +967,18 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -98,10 +98,10 @@ index c0e62a69bb5c9e777265b5474d76ba8d06ccec4b..3e7420cd98504732db17cb6b0fcfdfbb
}
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index cdb4a52cbd34322903144364c3686a4e1bf0fbb8..3a3a335a7659ebe946221186b56150df4a89c004 100644
index 4f6010285a5ff9cf939248c4d93043133680d383..020b2fcb5213a618b557f0578a7d44db5a8dc109 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1130,6 +1130,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1133,6 +1133,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
// Folia - region threading - move to main tick loop where we can detect duplicates
// CraftBukkit end
@@ -5,7 +5,7 @@ Subject: [PATCH] Instant Block Updater
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
index 64d407c5a6140a7e5dc47a8e304b4c00602e2bdd..9911c70d89cfb43b803cab9bbe6eedd1142f59d6 100644
index 7ea91dbfb988aff3215a91cf62c9beae94461484..491d108cc8e440653746f20fc5b5bca3b791eb88 100644
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
@@ -506,7 +506,7 @@ public final class RegionizedWorldData {
@@ -38,7 +38,7 @@ index 64d407c5a6140a7e5dc47a8e304b4c00602e2bdd..9911c70d89cfb43b803cab9bbe6eedd1
\ No newline at end of file
+}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 3e7420cd98504732db17cb6b0fcfdfbb8deeb552..257b440a0eea379433e9a249175c8eb16c37accb 100644
index b884e06a5e9d6a93c548820a99e5d05157e9d128..cb449a5063f7944551c2e66b603c0f910d84e50f 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1001,11 +1001,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -128,7 +128,7 @@ index 1a2b57a100c997b39f8f25ad3da121e04700d5d2..6b0d0a2c0067065b4a995a9f12791066
// 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 3a3a335a7659ebe946221186b56150df4a89c004..8ed9aa981883458d11f8cddce56e04b021026cc2 100644
index 020b2fcb5213a618b557f0578a7d44db5a8dc109..5e70e4e8a67e50a067dff1e592d617ca6a0426a9 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -257,6 +257,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -139,7 +139,7 @@ index 3a3a335a7659ebe946221186b56150df4a89c004..8ed9aa981883458d11f8cddce56e04b0
private @Nullable Vec3 startingToFallPosition;
private @Nullable Vec3 enteredNetherPosition;
private @Nullable Vec3 enteredLavaOnVehiclePosition;
@@ -2828,6 +2829,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -2831,6 +2832,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.setShoulderEntityRight(oldPlayer.getShoulderEntityRight());
this.setLastDeathLocation(oldPlayer.getLastDeathLocation());
this.waypointIcon().copyFrom(oldPlayer.waypointIcon());
@@ -151,7 +151,7 @@ index 3a3a335a7659ebe946221186b56150df4a89c004..8ed9aa981883458d11f8cddce56e04b0
}
private void transferInventoryXpAndScore(final Player oldPlayer) {
@@ -3111,6 +3117,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -3114,6 +3120,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.particleStatus = information.particleStatus();
this.getEntityData().set(DATA_PLAYER_MODE_CUSTOMISATION, (byte)information.modelCustomisation());
this.getEntityData().set(DATA_PLAYER_MAIN_HAND, information.mainHand());
@@ -481,10 +481,10 @@ index 459a05ca83583538f995f45c4d2c977c6d6fcd00..35a275ff953a271a2769a18af8163e81
}
}
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 5e7e99410c7597ec5330cc82e441fa30c53c9532..f34631cd7d5d1c76f2b1522200e5c9f6bf5406f5 100644
index 97057675369875ed71c228a87f5a4d3c3489dded..79bc1c2320ffd7b7017b664b5fe376566968c265 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -555,7 +555,15 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -556,7 +556,15 @@ public abstract class Player extends Avatar implements ContainerUser {
}
if (!orbs.isEmpty()) {
@@ -501,7 +501,7 @@ index 5e7e99410c7597ec5330cc82e441fa30c53c9532..f34631cd7d5d1c76f2b1522200e5c9f6
}
}
@@ -1066,6 +1074,28 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1069,6 +1077,28 @@ public abstract class Player extends Avatar implements ContainerUser {
if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable.
// Paper end - PlayerAttackEntityEvent
@@ -530,7 +530,7 @@ index 5e7e99410c7597ec5330cc82e441fa30c53c9532..f34631cd7d5d1c76f2b1522200e5c9f6
float baseDamage = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE);
ItemStack attackingItemStack = this.getWeaponItem();
DamageSource damageSource = this.createAttackSource(attackingItemStack); final DamageSource dmgSourceFinal = damageSource; // Paper - damage events
@@ -1123,6 +1153,18 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1126,6 +1156,18 @@ public abstract class Player extends Avatar implements ContainerUser {
}
}
@@ -676,10 +676,10 @@ index 298908003d5422b8b58de631145fad381e8294c1..2e5519813260033daff127fef2598cd1
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 f0ae87545bd38c38cffbc2217acb9008a4183531..95ec0e3b78a8740dd593c80d5dd8f1bf693c35af 100644
index 8c051d7322d8efc1ae2e151964fd0124740fd04d..d419d9e3c8f7af424a1b4783f7e7a015bbf541b0 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1176,6 +1176,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -1175,6 +1175,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
BlockState state = newState;
BlockState blockState = oldState;
BlockState blockState1 = currentState;
@@ -692,7 +692,7 @@ index f0ae87545bd38c38cffbc2217acb9008a4183531..95ec0e3b78a8740dd593c80d5dd8f1bf
if (blockState1 == state) {
if (blockState != blockState1) {
this.setBlocksDirty(pos, blockState, blockState1);
@@ -1192,7 +1198,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -1191,7 +1197,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
}
}
@@ -53,10 +53,10 @@ index 74ef76058e5a410d12f88aa09450e7d90f63b5e6..1761167da363cd074a26499caadeaeb9
}
// Luminol end - Add a config to enable tick command
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 8ed9aa981883458d11f8cddce56e04b021026cc2..fb200adb544a9cc5eb7d9d0051a6c70da017b858 100644
index 5e70e4e8a67e50a067dff1e592d617ca6a0426a9..63300acdcb1cdab2bf080c4939abb256fe05efa1 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2188,7 +2188,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -2191,7 +2191,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.lastSentFood = -1;
this.teleportSpectators(transition, oldLevel);
// Leaves start - bot support
@@ -66,10 +66,10 @@ index 8ed9aa981883458d11f8cddce56e04b021026cc2..fb200adb544a9cc5eb7d9d0051a6c70d
}
// Leaves end - bot support
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index baa295f3dd8cf10bf7347ee4d1c249b1f82c9279..1d5376650d0f5eeb23fde8d7116b47cfae37576f 100644
index c95c7b9a3968fc34a900a613b65b5d3e1abb24bf..64779d7b28e61c91897db5226158d65c32bfc835 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -280,7 +280,7 @@ public abstract class PlayerList {
@@ -281,7 +281,7 @@ public abstract class PlayerList {
// org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
// Leaves start - bot support
@@ -78,7 +78,7 @@ index baa295f3dd8cf10bf7347ee4d1c249b1f82c9279..1d5376650d0f5eeb23fde8d7116b47cf
org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
if (bot != null) {
this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
@@ -441,7 +441,7 @@ public abstract class PlayerList {
@@ -442,7 +442,7 @@ public abstract class PlayerList {
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
// Leaves start - bot support
@@ -87,7 +87,7 @@ index baa295f3dd8cf10bf7347ee4d1c249b1f82c9279..1d5376650d0f5eeb23fde8d7116b47cf
org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
if (bot != null) {
this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
@@ -969,7 +969,7 @@ public abstract class PlayerList {
@@ -971,7 +971,7 @@ public abstract class PlayerList {
).callEvent();
// Paper end
// Leaves start - bot support
@@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Tue, 23 Jun 2026 02:32:14 +0800
Subject: [PATCH] PCA sync protocol
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/252a16955f6e1e31aac85d222b093b0797d392f8/leaves-server/minecraft-patches/features/0027-PCA-sync-protocol.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/SimpleContainer.java b/net/minecraft/world/SimpleContainer.java
index 049c6ab6472415479435f2caab0444c3cbd33902..d9bb641c07e2e8d3780fadac44ff5e3ee0e35c8b 100644
--- a/net/minecraft/world/SimpleContainer.java
+++ b/net/minecraft/world/SimpleContainer.java
@@ -199,6 +199,11 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled && this.getOwner() instanceof org.bukkit.craftbukkit.entity.CraftEntity entity) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(entity.getHandle());
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java b/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
index 8da479d04c04366561549617c477b0811a9b3d7c..345f63ccac2579acf4cf4ee9507c231da12b03ba 100644
--- a/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
+++ b/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
@@ -140,6 +140,11 @@ public abstract class AbstractChestBoat extends AbstractBoat implements HasCusto
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
index d2c4b47b2f95c8e6bafc93e436041143e68ffa4f..12938642aa58b6b64d7536575712dc3eadfb6e13 100644
--- a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
+++ b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
@@ -66,6 +66,11 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java
index 5e7612ad30c218fcbb7c9cdd66ecb69d78d8875d..0fa8f720e3b386a5466b3a94d18d5dbbd0d48836 100644
--- a/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -256,6 +256,14 @@ public abstract class BlockEntity implements DebugValueSource, TypedInstance<Blo
if (!blockState.isAir()) {
level.updateNeighbourForOutputSignal(worldPosition, blockState.getBlock());
}
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled && !level.isClientSide()) {
+ BlockEntity blockEntity = level.getBlockEntity(worldPosition);
+ if (blockEntity != null) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(blockEntity);
+ }
+ }
+ // Leaves end - PCA sync protocol
}
public BlockPos getBlockPos() {
@@ -0,0 +1,256 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Tue, 23 Jun 2026 03:06:41 +0800
Subject: [PATCH] Add Vanilla-like experience Config
diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java
index b97d65b81ec4b86e00b7c06341b40dc5c02b9044..d997e4f7ae6ee4e81f5fffe874f2895dda314df9 100644
--- a/ca/spottedleaf/moonrise/paper/PaperHooks.java
+++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java
@@ -204,6 +204,11 @@ public class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
@Override
public int configMaxAutoSavePerTick(final ServerLevel world) {
+ // Lophine start - Vanilla-like experience
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled) {
+ return 200;
+ }
+ // Lophine end - Vanilla-like experience
return world.paperConfig().chunks.maxAutoSaveChunksPerTick;
}
@@ -308,4 +313,4 @@ public class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
public boolean addTicketForEnderPearls(final ServerLevel world) {
return !world.paperConfig().misc.legacyEnderPearlBehavior;
}
-}
\ No newline at end of file
+}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 63300acdcb1cdab2bf080c4939abb256fe05efa1..99e61bbe15430a72096489777a4e417ec5125337 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2390,7 +2390,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
public boolean isInvulnerableTo(final ServerLevel level, final DamageSource source) {
// Paper start - disable player cramming
return (super.isInvulnerableTo(level, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.connection.hasClientLoaded())
- || (!this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING));
+ || (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING)); // Lophine - Vanilla-like experience
// Paper end - disable player cramming
}
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 0bd4d786c8e957a31811f52514a992543a0cee92..31212878ac31a8d9849b471b103b95553b274501 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3993,7 +3993,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
// Paper start - Cap entity collisions
this.numCollisions = Math.max(0, this.numCollisions - this.level().paperConfig().collisions.maxEntityCollisions);
for (Entity entityx : pushableEntities) {
- if (this.numCollisions >= this.level().paperConfig().collisions.maxEntityCollisions) {
+ if (this.numCollisions >= (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled ? Integer.MAX_VALUE : this.level().paperConfig().collisions.maxEntityCollisions)) { // Lophine - Vanilla-like experience
break;
}
diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java
index c3f1f875b1adc75f9e9747e148f214e4623a0b4f..04c264611273872a9a33fe2a4d1e2a041e6e78d2 100644
--- a/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -383,7 +383,7 @@ public class FallingBlockEntity extends Entity {
ResourceKey<Level> oldDimension = this.level().dimension();
boolean fromOrToEnd = (oldDimension == Level.END || newDimension == Level.END) && oldDimension != newDimension;
Entity newEntity = super.teleport(transition);
- this.forceTickAfterTeleportToDuplicate = newEntity != null && fromOrToEnd && (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation || me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled); // Paper // Luminol - Unsafe teleportation
+ this.forceTickAfterTeleportToDuplicate = newEntity != null && fromOrToEnd && (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation || me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled || fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled); // Paper // Luminol - Unsafe teleportation // Lophine - Vanilla-like experience
return newEntity;
}
}
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index 679a941a2af886697fbfcbc7f21e5f4e0ec77dc3..1d4856c477441dd3dc57432c7129fc7f54b528bd 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -259,7 +259,7 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
if (this.isMergable()) {
double radius = this.level().spigotConfig.itemMerge; // Spigot
for (ItemEntity entity : this.level()
- .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, this.level().paperConfig().entities.behavior.onlyMergeItemsHorizontally ? 0 : radius - 0.5D, radius), other -> other != this && other.isMergable())) { // Spigot // Paper - configuration to only merge items horizontally
+ .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled ? radius : (this.level().paperConfig().entities.behavior.onlyMergeItemsHorizontally ? 0 : radius - 0.5D), radius), other -> other != this && other.isMergable())) { // Spigot // Paper - configuration to only merge items horizontally // Lophine - Vanilla-like experience
if (entity.isMergable()) {
// Paper start - Fix items merging through walls
if (this.level().paperConfig().fixes.fixItemsMergingThroughWalls) {
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
index 5b5717a886dab57b2fe9ad926a8ae7b3d4f30155..05d8ba6e5a984660be2fba97f9022393bb84f62b 100644
--- a/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
@@ -107,7 +107,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
@Override
public void tick() {
- if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().getCurrentWorldData().currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot // Folia - region threading
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().getCurrentWorldData().currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot // Folia - region threading // Lophine - Vanilla-like experience
//this.handlePortal(); // Folia - region threading
this.applyGravity();
this.move(MoverType.SELF, this.getDeltaMovement());
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
index 61ca77cceeacf0c4ebecf3bb66c4eb99c62033d2..fb3651bb6ebc4b75c17c2443dc9f95caeea98ef0 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
@@ -259,7 +259,7 @@ public class Phantom extends Mob implements Enemy {
for (Player player : players) {
if (Phantom.this.canAttack(level, player, TargetingConditions.DEFAULT)) {
- if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls
+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls // Lophine - Vanilla-like experience
Phantom.this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit - reason
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 c99c66563192629e399d1d904cb654c624fe9837..04e4e03399e5484bdbe8695fc2da5e5df152ba34 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -90,7 +90,8 @@ public final class NaturalSpawner {
MobCategory category = entity.getType().getCategory();
if (category != MobCategory.MISC) {
// Paper start - Only count natural spawns
- if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && // Lophine - Vanilla-like experience
+ !entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index 69d436268492183ae41fb9a60e61ed1f58a674d9..27e99cdd3a20c8c9177ccf8daa8fdf6984d51318 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -451,7 +451,7 @@ public class ServerExplosion implements Explosion {
if (this.fire || !cachedBlock.blockState.isAir()) {
ret.add(cachedBlock.immutablePos);
// Paper start - prevent headless pistons from forming
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == net.minecraft.world.level.block.Blocks.MOVING_PISTON) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == net.minecraft.world.level.block.Blocks.MOVING_PISTON) { // Lophine - Vanilla-like experience
net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(cachedBlock.immutablePos); // Paper - optimise collisions
if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) {
net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING);
diff --git a/net/minecraft/world/level/block/Block.java b/net/minecraft/world/level/block/Block.java
index 30f7e8f5e3e9440713e36ee25c90150b6b93c6ff..8527e46cab53ce6e67319cb87e9dcdda6b729de5 100644
--- a/net/minecraft/world/level/block/Block.java
+++ b/net/minecraft/world/level/block/Block.java
@@ -116,7 +116,7 @@ public class Block extends BlockBehaviour implements ItemLike {
private BlockState defaultBlockState;
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
public final boolean isDestroyable() {
- return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
+ return fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || // Lophine - Vanilla-like experience
this != Blocks.BARRIER &&
this != Blocks.BEDROCK &&
this != Blocks.END_PORTAL_FRAME &&
diff --git a/net/minecraft/world/level/block/TripWireHookBlock.java b/net/minecraft/world/level/block/TripWireHookBlock.java
index 836eae0c3e0891a3e3309b684f15d65f891215cf..a0fe40351ebb95fd5207bc63be82dbb887baebef 100644
--- a/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -188,7 +188,7 @@ public class TripWireHookBlock extends Block {
if (!cancelledEmitterHook) { // Paper - Call BlockRedstoneEvent
emitState(level, pos, attached, powered, wasAttached, wasPowered);
if (!isBeingDestroyed) {
- if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipTripwireHookPlacementValidation || level.getBlockState(pos).is(Blocks.TRIPWIRE_HOOK)) // Paper - Validate tripwire hook placement before update
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipTripwireHookPlacementValidation || level.getBlockState(pos).is(Blocks.TRIPWIRE_HOOK)) // Paper - Validate tripwire hook placement before update // Lophine - Vanilla-like experience
level.setBlock(pos, newState.setValue(FACING, direction), Block.UPDATE_ALL);
if (canUpdate) {
notifyNeighbors(block, level, pos, direction);
diff --git a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
index 62d7a44f139c28a38b14833380e2ec2bf84f3a75..12af97b9ffcf7c0f9e815ccbd81f99a80c6a5819 100644
--- a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
@@ -332,7 +332,7 @@ public class BeehiveBlockEntity extends BlockEntity {
iterator.remove();
}
// Paper start - Fix bees aging inside; use exitTickCounter to keep actual bee life
- else if (level.paperConfig().entities.behavior.cooldownFailedBeehiveReleases) {
+ else if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && level.paperConfig().entities.behavior.cooldownFailedBeehiveReleases) { // Lophine - Vanilla-like experience
data.exitTickCounter = data.occupant.minTicksInHive / 2;
}
// Paper end - Fix bees aging inside; use exitTickCounter to keep actual bee life
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 8066cdcaba8d2fcfa2e9ba3b040a2867dbbc6978..c904e35d49a36e2722295490a5a6aea67f29826e 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -346,7 +346,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
origItemStack.setCount(originalItemCount);
}
}
- if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
+ if (foundItem && !fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown // Lophine - Vanilla-like experience
hopper.setCooldown(level.spigotConfig.hopperTransfer);
}
return false;
diff --git a/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index a4d8ed890fc6bea1e961df814c00d22ae147734f..da037fbc38b4e605890711f4497ac8755a4f76f0 100644
--- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -152,7 +152,7 @@ public class PistonBaseBlock extends DirectionalBlock {
Direction direction = state.getValue(FACING);
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
Direction directionQueuedAs = Direction.from3DDataValue(b1 & 7); // Paper - copied from below
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && direction != directionQueuedAs) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && direction != directionQueuedAs) { // Lophine - Vanilla-like experience
return false;
}
// Paper end - Protect Bedrock and End Portal/Frames from being destroyed
@@ -237,7 +237,7 @@ public class PistonBaseBlock extends DirectionalBlock {
} else {
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed; fix headless pistons breaking blocks
BlockPos headPos = pos.relative(direction);
- if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || level.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, direction)) { // double check to make sure we're not a headless piston
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || level.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, direction)) { // double check to make sure we're not a headless piston // Lophine - Vanilla-like experience
level.removeBlock(headPos, false);
} else {
((ServerLevel) level).getChunkSource().blockChanged(headPos); // ... fix client desync
@@ -379,7 +379,7 @@ public class PistonBaseBlock extends DirectionalBlock {
for (int i = toPush.size() - 1; i >= 0; i--) {
// Paper start - fix a variety of piston desync dupes
- boolean allowDesync = !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntDupingFix;
+ boolean allowDesync = fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntDupingFix; // Lophine - Vanilla-like experience
BlockPos oldPos = toPush.get(i);
BlockPos pos = oldPos;
BlockState blockState = allowDesync ? level.getBlockState(oldPos) : null;
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index 22663ad55f669081b43644ad2cf1bd4aac48b745..0d79157ac9b7d099c29a933c171fe87718f34f8e 100644
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -334,7 +334,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
if (level.getBlockState(pos).is(Blocks.MOVING_PISTON)) {
BlockState newState = Block.updateFromNeighbourShapes(entity.movedState, level, pos);
if (newState.isAir()) {
- level.setBlock(pos, entity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE | (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 0 : Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air
+ level.setBlock(pos, entity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE | ((fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication) ? 0 : Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air // Lophine - Vanilla-like experience
Block.updateOrDestroy(entity.movedState, newState, level, pos, Block.UPDATE_ALL);
} else {
if (newState.hasProperty(BlockStateProperties.WATERLOGGED) && newState.getValue(BlockStateProperties.WATERLOGGED)) {
diff --git a/net/minecraft/world/level/levelgen/PhantomSpawner.java b/net/minecraft/world/level/levelgen/PhantomSpawner.java
index 142ab133d3b68eb9b88651e307653f1aafdf1de3..6061ac704e504d53492f405e92c17b6a4b44716f 100644
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -41,7 +41,7 @@ public class PhantomSpawner implements CustomSpawner {
// Paper end - Ability to control player's insomnia and phantoms
if (level.getSkyDarken() >= 5 || !level.dimensionType().hasSkyLight()) {
for (ServerPlayer player : level.getLocalPlayers()) { // Folia - region threading
- if (!player.isSpectator() && (!level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !player.isCreative())) { // Paper - Add phantom creative and insomniac controls
+ if (!player.isSpectator() && (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || !level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !player.isCreative())) { // Paper - Add phantom creative and insomniac controls // Lophine - Vanilla-like experience
BlockPos playerPos = player.blockPosition();
if (!level.dimensionType().hasSkyLight() || playerPos.getY() >= level.getSeaLevel() && level.canSeeSky(playerPos)) {
DifficultyInstance difficulty = level.getCurrentDifficultyAt(playerPos);
diff --git a/net/minecraft/world/level/portal/PortalForcer.java b/net/minecraft/world/level/portal/PortalForcer.java
index 4e4903d38d705dca6ff16418e54a7a367074aa08..b61259024c167f951d0fad292f40d2a814f6b8a5 100644
--- a/net/minecraft/world/level/portal/PortalForcer.java
+++ b/net/minecraft/world/level/portal/PortalForcer.java
@@ -233,7 +233,7 @@ public class PortalForcer {
origin, direction.getStepX() * width + clockWise.getStepX() * offset, height, direction.getStepZ() * width + clockWise.getStepZ() * offset
);
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) { // Lophine - Vanilla-like experience
if (!this.level.getBlockState(mutable).isDestroyable()) {
return false;
}
@@ -0,0 +1,219 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Wed, 24 Jun 2026 00:00:00 +0800
Subject: [PATCH] Restore vanilla ender pearl loading
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 99e61bbe15430a72096489777a4e417ec5125337..3b76045aa0b4cd97f7b104921a7fa8e29234e1d3 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -272,7 +272,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private @Nullable BlockPos raidOmenPosition;
private Vec3 lastKnownClientMovement = Vec3.ZERO;
private Input lastClientInput = Input.EMPTY;
- private final Set<ThrownEnderpearl> enderPearls = new HashSet<>();
+ private final Set<ThrownEnderpearl> enderPearls = java.util.concurrent.ConcurrentHashMap.newKeySet(); // Lophine - restore vanilla ender pearl loading on Folia
private long timeEntitySatOnShoulder;
private CompoundTag shoulderEntityLeft = new CompoundTag();
private CompoundTag shoulderEntityRight = new CompoundTag();
@@ -796,18 +796,20 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private void saveEnderPearls(final ValueOutput playerOutput) {
if (!this.enderPearls.isEmpty()) {
- ValueOutput.ValueOutputList pearlsOutput = playerOutput.childrenList("ender_pearls");
-
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ ValueOutput.TypedOutputList<CompoundTag> pearlsOutput = null;
for (ThrownEnderpearl enderPearl : this.enderPearls) {
- if (enderPearl.level().paperConfig().misc.legacyEnderPearlBehavior) continue; // Paper - Allow using old ender pearl behavior
- if (enderPearl.isRemoved()) {
- LOGGER.warn("Trying to save removed ender pearl, skipping");
+ CompoundTag pearlTag = enderPearl.getLastSavedEnderPearlTag();
+ if (pearlTag == null) {
+ LOGGER.warn("Trying to save ender pearl without a region-owned snapshot, skipping");
} else {
- ValueOutput pearlTag = pearlsOutput.addChild();
- enderPearl.save(pearlTag);
- pearlTag.store("ender_pearl_dimension", Level.RESOURCE_KEY_CODEC, enderPearl.level().dimension());
+ if (pearlsOutput == null) {
+ pearlsOutput = playerOutput.list(ServerPlayer.ENDER_PEARLS_TAG, CompoundTag.CODEC);
+ }
+ pearlsOutput.add(pearlTag);
}
}
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
}
@@ -3598,11 +3600,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
public void registerEnderPearl(final ThrownEnderpearl enderPearl) {
- //this.enderPearls.add(enderPearl); // Folia - region threading - do not track ender pearls
+ this.enderPearls.add(enderPearl); // Lophine - restore vanilla ender pearl loading on Folia
}
public void deregisterEnderPearl(final ThrownEnderpearl enderPearl) {
- //this.enderPearls.remove(enderPearl); // Folia - region threading - do not track ender pearls
+ this.enderPearls.remove(enderPearl); // Lophine - restore vanilla ender pearl loading on Folia
}
public Set<ThrownEnderpearl> getEnderPearls() {
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 64779d7b28e61c91897db5226158d65c32bfc835..f665ff0bc9068aaca6d6719ef6f7d87592f39816 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -752,11 +752,13 @@ public abstract class PlayerList {
player.unRide();
for (ThrownEnderpearl enderpearl : player.getEnderPearls()) {
- // Paper start - Allow using old ender pearl behavior
- if (!enderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) {
- enderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause
- }
- // Paper end - Allow using old ender pearl behavior
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ enderpearl.getBukkitEntity().taskScheduler.scheduleOrExecute((Entity pearl) -> {
+ if (!pearl.isRemoved()) {
+ pearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause
+ }
+ });
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
level.removePlayerImmediately(player, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
diff --git a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
index dc135f1a5d1ec33195e9ac897aa7acee4cbd13c6..bc9ca4680c18f28b97c4d1afe202cc2fff320daf 100644
--- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
+++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
@@ -29,7 +29,11 @@ import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
public class ThrownEnderpearl extends ThrowableItemProjectile {
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Lophine - restore vanilla ender pearl loading on Folia
private long ticketTimer = 0L;
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ private volatile net.minecraft.nbt.@Nullable CompoundTag lastSavedEnderPearlTag;
+ // Lophine end - restore vanilla ender pearl loading on Folia
public ThrownEnderpearl(final EntityType<? extends ThrownEnderpearl> type, final Level level) {
super(type, level);
@@ -37,6 +41,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
public ThrownEnderpearl(final Level level, final LivingEntity mob, final ItemStack itemStack) {
super(EntityType.ENDER_PEARL, mob, level, itemStack);
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
@Override
@@ -49,21 +56,73 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
this.deregisterFromCurrentOwner();
super.setOwner(owner);
this.registerToCurrentOwner();
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
private void deregisterFromCurrentOwner() {
- // Folia - region threading - we remove the registration logic, we do not need to fetch the owner
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ if (this.owner != null && this.level() instanceof ServerLevel serverLevel && serverLevel.getServer().getPlayerList().getPlayer(this.owner.getUUID()) instanceof ServerPlayer serverPlayer) {
+ serverPlayer.deregisterEnderPearl(this);
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
private void registerToCurrentOwner() {
- // Folia - region threading - we remove the registration logic, we do not need to fetch the owner
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ if (this.owner != null
+ && this.level() instanceof ServerLevel serverLevel
+ && !serverLevel.paperConfig().misc.legacyEnderPearlBehavior
+ && serverLevel.getServer().getPlayerList().getPlayer(this.owner.getUUID()) instanceof ServerPlayer serverPlayer) {
+ serverPlayer.registerEnderPearl(this);
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ public net.minecraft.nbt.@Nullable CompoundTag getLastSavedEnderPearlTag() {
+ net.minecraft.nbt.CompoundTag tag = this.lastSavedEnderPearlTag;
+ return tag == null ? null : tag.copy();
+ }
+
+ public void updateLastSavedEnderPearlTag() {
+ if (this.owner == null || this.isRemoved() || !(this.level() instanceof ServerLevel serverLevel) || serverLevel.paperConfig().misc.legacyEnderPearlBehavior) {
+ this.lastSavedEnderPearlTag = null;
+ return;
+ }
+ try (net.minecraft.util.ProblemReporter.ScopedCollector problemReporter = new net.minecraft.util.ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) {
+ net.minecraft.world.level.storage.TagValueOutput pearlOutput = net.minecraft.world.level.storage.TagValueOutput.createWithContext(problemReporter, this.registryAccess());
+ if (this.save(pearlOutput)) {
+ pearlOutput.store(ServerPlayer.ENDER_PEARL_DIMENSION_TAG, Level.RESOURCE_KEY_CODEC, this.level().dimension());
+ this.lastSavedEnderPearlTag = pearlOutput.buildResult();
+ } else {
+ this.lastSavedEnderPearlTag = null;
+ }
+ }
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
+
@Override
public @Nullable Entity getOwner() {
return this.owner != null && this.level() instanceof ServerLevel serverLevel ? this.owner.getEntity(serverLevel, Entity.class) : super.getOwner();
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ @Override
+ protected void readAdditionalSaveData(final net.minecraft.world.level.storage.ValueInput input) {
+ super.readAdditionalSaveData(input);
+ this.updateLastSavedEnderPearlTag();
+ }
+
+ @Override
+ public void restoreFrom(final Entity oldEntity) {
+ super.restoreFrom(oldEntity);
+ this.registerToCurrentOwner();
+ this.updateLastSavedEnderPearlTag();
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
+
private static @Nullable Entity findOwnerIncludingDeadPlayer(final ServerLevel serverLevel, final UUID uuid) {
Entity owner = serverLevel.getEntityInAnyDimension(uuid);
return (Entity)(owner != null ? owner : serverLevel.getServer().getPlayerList().getPlayer(uuid));
@@ -281,6 +340,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
&& owner instanceof ServerPlayer serverPlayer) {
this.ticketTimer = serverPlayer.registerAndUpdateEnderPearlTicket(this);
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
} else {
super.tick();
@@ -328,6 +390,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
public void onRemoval(final Entity.RemovalReason reason) {
if (reason != Entity.RemovalReason.UNLOADED_WITH_PLAYER) {
this.deregisterFromCurrentOwner();
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.lastSavedEnderPearlTag = null;
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
super.onRemoval(reason);
diff --git a/net/minecraft/world/item/EnderpearlItem.java b/net/minecraft/world/item/EnderpearlItem.java
index 17a005321601b0fef71604e4468134f1e98cd974..a270b4ca7d65b91ffcf292ff80f3a23124cd595c 100644
--- a/net/minecraft/world/item/EnderpearlItem.java
+++ b/net/minecraft/world/item/EnderpearlItem.java
@@ -27,6 +27,7 @@ public class EnderpearlItem extends Item {
final Projectile.Delayed<ThrownEnderpearl> thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemStack, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F);
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity());
if (event.callEvent() && thrownEnderpearl.attemptSpawn()) {
+ thrownEnderpearl.projectile().updateLastSavedEnderPearlTag(); // Lophine - restore vanilla ender pearl loading on Folia
if (event.shouldConsume()) {
itemStack.consume(1, player);
} else {
@@ -35,7 +35,7 @@ index fcdfd4f6de5e1c2d5e80c7f3d8cb0b33a62d257d..6eaa4e9bd1ecbfa531313ce1f470d55e
metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
index a5f2e4454258886536251288c3694f58386c7420..28371ecf31d5fc280aaa03ed9a86f5b565cf32f6 100644
index 45611868dfdfee05380c390a11e8041685a76a19..434dcd0216a217d6f5a7dc008efd069c125c823f 100644
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -40,8 +40,8 @@ public class PaperVersionFetcher implements VersionFetcher {
@@ -44,8 +44,8 @@ index a5f2e4454258886536251288c3694f58386c7420..28371ecf31d5fc280aaa03ed9a86f5b5
private static final int DISTANCE_UNKNOWN = -2;
- private static final String DOWNLOAD_PAGE = "https://github.com/LuminolMC/Luminol"; // Luminol
- private static final String REPOSITORY = "LuminolMC/Luminol"; // Luminol
+ private static final String DOWNLOAD_PAGE = "https://github.com/LuminolMC/Lophine"; // Luminol // Lophine
+ private static final String REPOSITORY = "LuminolMC/Lophine"; // Luminol // Lophine
+ private static final String DOWNLOAD_PAGE = "https://github.com/LophineCraft/Lophine"; // Luminol // Lophine
+ private static final String REPOSITORY = "LophineCraft/Lophine"; // Luminol // Lophine
private static final ServerBuildInfo BUILD_INFO = ServerBuildInfo.buildInfo();
private static final String USER_AGENT = BUILD_INFO.brandName() + "/" + BUILD_INFO.asString(VERSION_SIMPLE) + " (https://papermc.io)";
private static final Gson GSON = new Gson();
@@ -8,7 +8,7 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/3e7f4a313ff0d2469
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index ba0779211405b8b83f7c7e7b1c55b3e4846029a3..5f685b07878443bfe5f63147a0728df0708d79ad 100644
index f19ad4f317f911eb50802c325bcfce829d98524e..75ef8eab6665401bb2a9603de89172e341f8a2c4 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -483,6 +483,7 @@ public final class CraftServer implements Server {
@@ -53,7 +53,7 @@ index 5339ff469a38d35e72ea7227503a84395462f84a..d75b4ecb24f2ea42afc82ac255775d8f
if (nmsEntity.level() != this.getHandle().getLevel()) {
throw new IllegalArgumentException(entity + " wasn't created with this world, you must create the entity with the world you want to add it to.");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 5f685b07878443bfe5f63147a0728df0708d79ad..0eb89fc127738e02e8d4d49418b83baaffe00cbd 100644
index 75ef8eab6665401bb2a9603de89172e341f8a2c4..42df6c661ec5ab18387b12743771bdb156a98e93 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -303,6 +303,7 @@ public final class CraftServer implements Server {
@@ -81,7 +81,7 @@ index 5f685b07878443bfe5f63147a0728df0708d79ad..0eb89fc127738e02e8d4d49418b83baa
return false;
}
@@ -3113,6 +3115,13 @@ public final class CraftServer implements Server {
@@ -3117,6 +3119,13 @@ public final class CraftServer implements Server {
}
// Leaves end - Feature API
@@ -21,7 +21,7 @@ index d0b763f07aee56f69a67c87d7dd15a44b6f44db7..bd301425f4c3cdf2b2bd22c1775b7ca9
}
// Leaves end - skip bot
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0eb89fc127738e02e8d4d49418b83baaffe00cbd..53e49df883ec0fab984f2329d044d12ed6b1edff 100644
index 42df6c661ec5ab18387b12743771bdb156a98e93..feccf57b61200aead73fe97b897c1ad0fad563fb 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -304,6 +304,7 @@ public final class CraftServer implements Server {
@@ -41,7 +41,7 @@ index 0eb89fc127738e02e8d4d49418b83baaffe00cbd..53e49df883ec0fab984f2329d044d12e
@Override
public CraftPlayer apply(ServerPlayer player) {
return player.getBukkitEntity();
@@ -3186,4 +3187,11 @@ public final class CraftServer implements Server {
@@ -3190,4 +3191,11 @@ public final class CraftServer implements Server {
}
}
// Folia end - region TPS API
@@ -66,7 +66,7 @@ index 42c2c6a05645e5aef26e9d3a91ad93563a297ca3..759d54f1f012461fc322d452bb26f7fd
// Special case complex part, since there is no extra entity type for them
if (entity instanceof EnderDragonPart complexPart) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 47926ff2fba43bb83e2d9747420a526cce8ebe65..e72cd3c9919978a0ed91614d51d018bfb2cdb900 100644
index 59e3a15cce0ed34aa3b75b92db9e349c9fe481fa..044f3168583b23542e18fe14853d3b98bad3fa4d 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2086,7 +2086,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa
@@ -4,6 +4,7 @@ import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
import fun.bm.lophine.carpet.config.modules.GeneralCompatConfig;
import fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig;
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
import fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig;
import fun.bm.lophine.protocol.CarpetLoggerProtocol;
import org.leavesmc.leaves.protocol.CarpetServerProtocol;
@@ -24,75 +25,83 @@ public final class CarpetCompatSync {
}
private static void registerProtocolRules() {
CarpetServerProtocol.CarpetRules.clear();
CarpetServerProtocol.CarpetRules.beginBatch();
try {
CarpetServerProtocol.CarpetRules.clear();
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "language", GeneralCompatConfig.language));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "amsUpdateSuppressionCrashFix", GeneralCompatConfig.amsUpdateSuppressionCrashFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetUpdateSuppressionCrash", GeneralCompatConfig.yeetUpdateSuppressionCrash));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "dustTrapdoorReintroduced", GeneralCompatConfig.dustTrapdoorReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "shulkerBoxCCEReintroduced", GeneralCompatConfig.shulkerBoxCCEReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "instantBlockUpdaterReintroduced", GeneralCompatConfig.instantBlockUpdaterReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandTick", GeneralCompatConfig.commandTick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "creativeNoClip", GeneralCompatConfig.creativeNoClip));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedDragonRespawn", GeneralCompatConfig.optimizedDragonRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "antiSpamDisabled", GeneralCompatConfig.antiSpamDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "blockPlacementIgnoreEntity", GeneralCompatConfig.blockPlacementIgnoreEntity));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeOpenContainerForcibly", GeneralCompatConfig.creativeOpenContainerForcibly));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "creativeOneHitKill", GeneralCompatConfig.creativeOneHitKill));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "observerNoDetection", GeneralCompatConfig.observerNoDetection));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "bambooModelNoOffset", GeneralCompatConfig.bambooModelNoOffset));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeNoItemCooldown", GeneralCompatConfig.creativeNoItemCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "ctrlQCraftingFix", GeneralCompatConfig.ctrlQCraftingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "carpetAlwaysSetDefault", GeneralCompatConfig.carpetAlwaysSetDefault));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "placementRotationFix", GeneralCompatConfig.placementRotationFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntDoNotUpdate", GeneralCompatConfig.tntDoNotUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "totallyNoBlockUpdate", GeneralCompatConfig.totallyNoBlockUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tiscmNetworkProtocol", GeneralCompatConfig.tiscmNetworkProtocol));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "hopperNoItemCost", GeneralCompatConfig.hopperNoItemCost));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "explosionNoBlockDamage", GeneralCompatConfig.explosionNoBlockDamage));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedTNTHighPriority", GeneralCompatConfig.optimizedTNTHighPriority));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntPrimerMomentumRemoved", GeneralCompatConfig.tntPrimerMomentumRemoved));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntIgnoreRedstoneSignal", GeneralCompatConfig.tntIgnoreRedstoneSignal));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntDupingFix", GeneralCompatConfig.tntDupingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "interactionUpdates", GeneralCompatConfig.interactionUpdates));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "xpNoCooldown", GeneralCompatConfig.xpNoCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "powerfulExpMending", GeneralCompatConfig.powerfulExpMending));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "clientSettingsLostOnRespawnFix", GeneralCompatConfig.clientSettingsLostOnRespawnFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "sensibleEnderman", GeneralCompatConfig.sensibleEnderman));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "entityInstantDeathRemoval", GeneralCompatConfig.entityInstantDeathRemoval));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "farmlandTrampledDisabled", GeneralCompatConfig.farmlandTrampledDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "shulkerGolem", GeneralCompatConfig.shulkerGolem));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "preventEndSpikeRespawn", GeneralCompatConfig.preventEndSpikeRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetOutOfOrderChatKick", GeneralCompatConfig.yeetOutOfOrderChatKick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableBoneBlock", GeneralCompatConfig.betterCraftableBoneBlock));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableDispenser", GeneralCompatConfig.betterCraftableDispenser));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "viewDistance", GeneralCompatConfig.viewDistance));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickCommandPermission", GeneralCompatConfig.normalizedTickCommandPermission()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickFreezeCommandToggleable", GeneralCompatConfig.tickFreezeCommandToggleable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "syncServerMsptMetricsData", GeneralCompatConfig.syncServerMsptMetricsData));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "simpleInGameCalculator", GeneralCompatConfig.simpleInGameCalculator));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "microTiming", GeneralCompatConfig.microTiming));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "fastRedstoneDust", GeneralCompatConfig.fastRedstoneDust));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "lagFreeSpawning", GeneralCompatConfig.lagFreeSpawning));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedFastEntityMovement", GeneralCompatConfig.optimizedFastEntityMovement));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedHardHitBoxEntityCollision", GeneralCompatConfig.optimizedHardHitBoxEntityCollision));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntFuseDuration", GeneralCompatConfig.normalizedTntFuseDuration()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "defaultLoggers", CarpetLoggerProtocol.serializeConfiguredDefaults(sanitizeDefaultLoggers(GeneralCompatConfig.defaultLoggers))));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "language", GeneralCompatConfig.language));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "amsUpdateSuppressionCrashFix", GeneralCompatConfig.amsUpdateSuppressionCrashFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetUpdateSuppressionCrash", GeneralCompatConfig.yeetUpdateSuppressionCrash));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "dustTrapdoorReintroduced", GeneralCompatConfig.dustTrapdoorReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "shulkerBoxCCEReintroduced", GeneralCompatConfig.shulkerBoxCCEReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "instantBlockUpdaterReintroduced", GeneralCompatConfig.instantBlockUpdaterReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandTick", GeneralCompatConfig.commandTick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "creativeNoClip", GeneralCompatConfig.creativeNoClip));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedDragonRespawn", GeneralCompatConfig.optimizedDragonRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "antiSpamDisabled", GeneralCompatConfig.antiSpamDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "blockPlacementIgnoreEntity", GeneralCompatConfig.blockPlacementIgnoreEntity));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeOpenContainerForcibly", GeneralCompatConfig.creativeOpenContainerForcibly));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "creativeOneHitKill", GeneralCompatConfig.creativeOneHitKill));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "observerNoDetection", GeneralCompatConfig.observerNoDetection));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "bambooModelNoOffset", GeneralCompatConfig.bambooModelNoOffset));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeNoItemCooldown", GeneralCompatConfig.creativeNoItemCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "ctrlQCraftingFix", GeneralCompatConfig.ctrlQCraftingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "carpetAlwaysSetDefault", GeneralCompatConfig.carpetAlwaysSetDefault));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "placementRotationFix", GeneralCompatConfig.placementRotationFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntDoNotUpdate", GeneralCompatConfig.tntDoNotUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "totallyNoBlockUpdate", GeneralCompatConfig.totallyNoBlockUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tiscmNetworkProtocol", GeneralCompatConfig.tiscmNetworkProtocol));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "hopperNoItemCost", GeneralCompatConfig.hopperNoItemCost));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "explosionNoBlockDamage", GeneralCompatConfig.explosionNoBlockDamage));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedTNTHighPriority", GeneralCompatConfig.optimizedTNTHighPriority));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntPrimerMomentumRemoved", GeneralCompatConfig.tntPrimerMomentumRemoved));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntIgnoreRedstoneSignal", GeneralCompatConfig.tntIgnoreRedstoneSignal));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntDupingFix", GeneralCompatConfig.tntDupingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "interactionUpdates", GeneralCompatConfig.interactionUpdates));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "xpNoCooldown", GeneralCompatConfig.xpNoCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "powerfulExpMending", GeneralCompatConfig.powerfulExpMending));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "clientSettingsLostOnRespawnFix", GeneralCompatConfig.clientSettingsLostOnRespawnFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "sensibleEnderman", GeneralCompatConfig.sensibleEnderman));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "entityInstantDeathRemoval", GeneralCompatConfig.entityInstantDeathRemoval));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "farmlandTrampledDisabled", GeneralCompatConfig.farmlandTrampledDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "shulkerGolem", GeneralCompatConfig.shulkerGolem));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "preventEndSpikeRespawn", GeneralCompatConfig.preventEndSpikeRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetOutOfOrderChatKick", GeneralCompatConfig.yeetOutOfOrderChatKick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableBoneBlock", GeneralCompatConfig.betterCraftableBoneBlock));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableDispenser", GeneralCompatConfig.betterCraftableDispenser));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "viewDistance", GeneralCompatConfig.viewDistance));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickCommandPermission", GeneralCompatConfig.normalizedTickCommandPermission()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickFreezeCommandToggleable", GeneralCompatConfig.tickFreezeCommandToggleable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "syncServerMsptMetricsData", GeneralCompatConfig.syncServerMsptMetricsData));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "simpleInGameCalculator", GeneralCompatConfig.simpleInGameCalculator));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "microTiming", GeneralCompatConfig.microTiming));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "fastRedstoneDust", GeneralCompatConfig.fastRedstoneDust));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "lagFreeSpawning", GeneralCompatConfig.lagFreeSpawning));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedFastEntityMovement", GeneralCompatConfig.optimizedFastEntityMovement));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedHardHitBoxEntityCollision", GeneralCompatConfig.optimizedHardHitBoxEntityCollision));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntFuseDuration", GeneralCompatConfig.normalizedTntFuseDuration()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "defaultLoggers", CarpetLoggerProtocol.serializeConfiguredDefaults(sanitizeDefaultLoggers(GeneralCompatConfig.defaultLoggers))));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "commandBot", FakeplayerConfig.enable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandPlayer", FakePlayerCompatConfig.commandPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerResident", FakePlayerCompatConfig.fakePlayerResident));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "openFakePlayerInventory", FakePlayerCompatConfig.openFakePlayerInventory));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "fakePlayerTicksLikeRealPlayer", FakePlayerCompatConfig.fakePlayerTicksLikeRealPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerDefaultSurvivalMode", FakePlayerCompatConfig.fakePlayerDefaultSurvivalMode));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerInteractLikeClient", FakePlayerCompatConfig.fakePlayerInteractLikeClient));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplaceTool", FakePlayerCompatConfig.fakePlayerAutoReplaceTool));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplenishment", FakePlayerCompatConfig.fakePlayerAutoReplenishment));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerAutoReplenishmentFormShulkerBox", FakePlayerCompatConfig.fakePlayerAutoReplenishmentFormShulkerBox));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoFish", FakePlayerCompatConfig.fakePlayerAutoFish));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerReloadAction", FakePlayerCompatConfig.fakePlayerReloadAction));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "commandBot", FakeplayerConfig.enable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandPlayer", FakePlayerCompatConfig.commandPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerResident", FakePlayerCompatConfig.fakePlayerResident));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "openFakePlayerInventory", FakePlayerCompatConfig.openFakePlayerInventory));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "fakePlayerTicksLikeRealPlayer", FakePlayerCompatConfig.fakePlayerTicksLikeRealPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerDefaultSurvivalMode", FakePlayerCompatConfig.fakePlayerDefaultSurvivalMode));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerInteractLikeClient", FakePlayerCompatConfig.fakePlayerInteractLikeClient));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplaceTool", FakePlayerCompatConfig.fakePlayerAutoReplaceTool));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplenishment", FakePlayerCompatConfig.fakePlayerAutoReplenishment));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerAutoReplenishmentFormShulkerBox", FakePlayerCompatConfig.fakePlayerAutoReplenishmentFormShulkerBox));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoFish", FakePlayerCompatConfig.fakePlayerAutoFish));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerReloadAction", FakePlayerCompatConfig.fakePlayerReloadAction));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "hopperCounters", WoolHopperCounterConfig.hopperCounters));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "hopperCountersUnlimitedSpeed", WoolHopperCounterConfig.hopperCountersUnlimitedSpeed));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "hopperCounters", WoolHopperCounterConfig.hopperCounters));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "hopperCountersUnlimitedSpeed", WoolHopperCounterConfig.hopperCountersUnlimitedSpeed));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("pca", "pcaSyncProtocol", PcaSyncProtocolConfig.enabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("pca", "pcaSyncPlayerEntity", PcaSyncProtocolConfig.syncPlayerEntity));
} finally {
CarpetServerProtocol.CarpetRules.endBatch();
}
}
}
@@ -70,7 +70,7 @@ public class FakePlayerCompatConfig implements IConfigModule {
@Override
public void onLoaded(CommentedFileConfig configInstance, @Nullable Set<Exception> exs) {
if (commandPlayer) {
if (commandPlayer && command == null) {
command = new BotCommand("player");
command.register();
}
@@ -1,20 +1,67 @@
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;
@ConfigClassInfo(name = "global_entities_counter", category = EnumConfigCategory.EXPERIMENT)
public class GlobalEntitiesCounter implements IConfigModule {
@HotReloadUnsupported
@ConfigInfo(name = "enabled", comments = """
Enable global entities counter.
@ConfigInfo(name = "version", comments = """
DISABLED
DEFAULT_SYNC: Enable global entities counter origin version with sync counter module.
DEFAULT_ASYNC: Enable global entities counter origin version with async counter module.
PRECISE: Enable precise mob cap calculation with incremental counting. Replaces the periodic full-scan with event-driven real-time updates.
You need to set per-player-mob-spawns to false on paper-world-defaults.yml or paper-world.yml""")
public static boolean enabled = false;
public static GlobalEntitiesCounterType type = GlobalEntitiesCounterType.DISABLED;
@HotReloadUnsupported
@ConfigInfo(name = "async", comments = "Enable Asynchronous(maybe cause bugs)")
public static boolean async = false;
@DoNotLoad
private static boolean enabled;
@DoNotLoad
private static boolean async;
@DoNotLoad
private static boolean defaultModule;
public static boolean isEnabled() {
return enabled;
}
public static boolean isAsync() {
return async;
}
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;
}
}
@@ -0,0 +1,13 @@
package fun.bm.lophine.config.modules.fixes;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigClassInfo;
import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.enums.EnumConfigCategory;
@ConfigClassInfo(category = EnumConfigCategory.FIXES, name = "vanilla-like-experience")
public class VanillaLikeExperienceConfig implements IConfigModule {
@ConfigInfo(name = "enabled", comments = """
Restore a more vanilla-like technical gameplay experience by bypassing some Paper safety and behavior changes.""")
public static boolean enabled = false;
}
@@ -95,7 +95,7 @@ public class FakeplayerConfig implements IConfigModule {
@Override
public void onLoaded(CommentedFileConfig configInstance, @Nullable Set<Exception> exs) {
if (enable) {
if (enable && command == null) {
command = new BotCommand("bot");
command.register();
}
@@ -12,7 +12,7 @@ public class LanguageConfig implements IConfigModule {
@ConfigInfo(name = "lang", comments = """
Please use the key from https://minecraft.wiki/w/Language
Sample of format: en_us zh_cn zh_hk zh_tw
ATTENTION: If you want to edit language for carpet ststem,
ATTENTION: If you want to edit language for carpet system,
please edit it in carpet config file.""")
public static String lang = "en_us";
@@ -13,6 +13,9 @@ public class OldFeatureConfig implements IConfigModule {
@ConfigInfo(name = "old_zombie_reinforcement")
public static boolean oldZombieReinforcement = false;
@ConfigInfo(name = "old_leader_zombie_health")
public static boolean oldLeaderZombieHealth = false;
@ConfigInfo(name = "old_explosion_damage_calculator")
public static boolean oldExplosionDamageCalculator = false;
@@ -0,0 +1,43 @@
package fun.bm.lophine.config.modules.function.protocol;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import fun.bm.lophine.carpet.CarpetCompatSync;
import fun.bm.lophine.enums.PcaPlayerEntityType;
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.TransformedConfig;
import me.earthme.luminol.enums.EnumConfigCategory;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.protocol.PcaSyncProtocol;
import java.util.Set;
@ConfigClassInfo(category = EnumConfigCategory.FUNCTION, name = "pca", directory = {"protocol"})
public class PcaSyncProtocolConfig implements IConfigModule {
private static boolean lastEnabled = false;
@TransformedConfig(name = "pca-sync-protocol", directory = {"protocol"})
@ConfigInfo(name = "enabled", comments = """
Enable PCA sync protocol support""")
public static boolean enabled = false;
@TransformedConfig(name = "pca-sync-player-entity", directory = {"protocol"})
@ConfigInfo(name = "sync-player-entity", comments = """
Controls which player entities can be watched through the PCA sync protocol.
NOBODY: never sync player entities
BOT: only sync Lophine fake players
OPS: sync fake players and allow operators to sync real players
OPS_AND_SELF: sync fake players, operators, and a player's own entity
EVERYONE: allow all player entities""")
public static PcaPlayerEntityType syncPlayerEntity = PcaPlayerEntityType.OPS;
@Override
public void onLoaded(CommentedFileConfig configInstance, @Nullable Set<Exception> e) {
if (lastEnabled != enabled) {
PcaSyncProtocol.onConfigModify(enabled);
lastEnabled = enabled;
}
CarpetCompatSync.apply();
}
}
@@ -0,0 +1,8 @@
package fun.bm.lophine.enums;
public enum GlobalEntitiesCounterType {
DISABLED,
DEFAULT_SYNC,
DEFAULT_ASYNC,
PRECISE
}
@@ -0,0 +1,9 @@
package fun.bm.lophine.enums;
public enum PcaPlayerEntityType {
NOBODY,
BOT,
OPS,
OPS_AND_SELF,
EVERYONE
}
@@ -6,6 +6,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.mojang.logging.LogUtils;
import fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter;
import fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
@@ -24,10 +25,10 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import static net.minecraft.world.level.NaturalSpawner.getRoughBiome;
import java.util.concurrent.atomic.AtomicInteger;
public class EntitiesCounterUtil {
// global entities counter
private static final Map<ServerLevel, Cache<Integer, ReferenceList<Entity>>> globalLoadedEntities = new ConcurrentHashMap<>();
private static final Map<ServerLevel, Object2IntOpenHashMap<MobCategory>> mobsMap = Collections.synchronizedMap(new WeakHashMap<>());
private static final Map<ServerLevel, Cache<Integer, PositionCountingAreaMap<ServerPlayer>>> mobsAreaMap = new ConcurrentHashMap<>();
@@ -35,6 +36,9 @@ public class EntitiesCounterUtil {
private static final Map<ServerLevel, CompletableFuture<Void>> tasks = new ConcurrentHashMap<>();
private static final Set<Integer> UniqueIds = ConcurrentHashMap.newKeySet();
// precise mob counter extra
private static final Map<ServerLevel, EnumMap<MobCategory, AtomicInteger>> globalMobCounts = new ConcurrentHashMap<>();
private static int lastUsedId = 0;
private static final int CLEANUP_INTERVAL = 200; // each 200 ids used
@@ -104,94 +108,193 @@ public class EntitiesCounterUtil {
}
public static void tick(ServerLevel level) {
Runnable task = () -> {
try {
Cache<Integer, ReferenceList<Entity>> data0 = globalLoadedEntities.get(level);
if (data0 == null) return;
if (GlobalEntitiesCounter.isDefaultModule()) {
Runnable task = () -> {
try {
Cache<Integer, ReferenceList<Entity>> data0 = globalLoadedEntities.get(level);
if (data0 == null) return;
Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
Collection<ReferenceList<Entity>> snapshot = data0.asMap().values();
Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
Collection<ReferenceList<Entity>> snapshot = data0.asMap().values();
for (ReferenceList<Entity> data : snapshot) {
if (data == null) continue;
for (Entity entity : GlobalEntitiesCounter.async ? data.copy() : data) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
MobCategory category = entity.getType().getCategory();
if (category != MobCategory.MISC) {
// Paper start - Only count natural spawns
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
for (ReferenceList<Entity> data : snapshot) {
if (data == null) continue;
for (Entity entity : GlobalEntitiesCounter.isAsync() ? data.copy() : data) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
MobCategory category = entity.getType().getCategory();
if (category != MobCategory.MISC) {
// Paper start - Only count natural spawns
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
}
// Paper end - Only count natural spawns
map.addTo(category, 1);
}
// Paper end - Only count natural spawns
map.addTo(category, 1);
}
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
}
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
}
mobsMap.put(level, map);
mobsMap.put(level, map);
Cache<Integer, PositionCountingAreaMap<ServerPlayer>> collection = mobsAreaMap.get(level);
if (collection != null) {
int count = 0;
for (PositionCountingAreaMap<ServerPlayer> areaMap : collection.asMap().values()) {
if (areaMap != null) {
count += areaMap.getTotalPositions();
Cache<Integer, PositionCountingAreaMap<ServerPlayer>> collection = mobsAreaMap.get(level);
if (collection != null) {
int count = 0;
for (PositionCountingAreaMap<ServerPlayer> areaMap : collection.asMap().values()) {
if (areaMap != null) {
count += areaMap.getTotalPositions();
}
}
spawnableChunkCount.put(level, count);
}
spawnableChunkCount.put(level, count);
} catch (Exception e) {
LogUtils.getClassLogger().error("Failed to run task", e);
}
} catch (Exception e) {
LogUtils.getClassLogger().error("Failed to run task", e);
};
if (GlobalEntitiesCounter.isAsync()) {
tasks.put(level, CompletableFuture.runAsync(task).exceptionally(ex -> {
LogUtils.getClassLogger().error("Failed to run task", ex);
return null;
}));
} else {
task.run();
}
};
if (GlobalEntitiesCounter.async) {
tasks.put(level, CompletableFuture.runAsync(task).exceptionally(ex -> {
LogUtils.getClassLogger().error("Failed to run task", ex);
return null;
}));
} else {
task.run();
Cache<Integer, PositionCountingAreaMap<ServerPlayer>> cache = mobsAreaMap.get(level);
if (cache == null) return;
int total = 0;
for (PositionCountingAreaMap<ServerPlayer> map : cache.asMap().values()) {
if (map != null) {
total += map.getTotalPositions();
}
}
spawnableChunkCount.put(level, total);
}
}
public static NaturalSpawner.SpawnState runRemainingTasks(
public static NaturalSpawner.SpawnState createSpawnState(
ServerLevel level, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs
) {
Object2IntOpenHashMap<MobCategory> map = getMobsMap(level);
if (map == null) return null; // skip if no data
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
PotentialCalculator potentialCalculator = new PotentialCalculator();
for (Entity entity : entities) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
// Paper start - Only count natural spawns
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
if (GlobalEntitiesCounter.isDefaultModule()) {
Object2IntOpenHashMap<MobCategory> map = getMobsMap(level);
if (map == null) return null; // skip if no data
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
PotentialCalculator potentialCalculator = new PotentialCalculator();
for (Entity entity : entities) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
// Paper start - Only count natural spawns
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
}
// Paper end - Only count natural spawns
BlockPos blockPos = entity.blockPosition();
chunkGetter.query(ChunkPos.pack(blockPos), chunk -> {
MobSpawnSettings.MobSpawnCost mobSpawnCost = NaturalSpawner.getRoughBiome(blockPos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
if (mobSpawnCost != null) {
potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
}
if (calculator != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
calculator.addMob(chunk.getPos(), entity.getType().getCategory());
}
// Paper start - Optional per player mob spawns
if (countMobs) {
chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
}
// Paper end - Optional per player mob spawns
});
}
// Paper end - Only count natural spawns
BlockPos blockPos = entity.blockPosition();
chunkGetter.query(ChunkPos.pack(blockPos), chunk -> {
MobSpawnSettings.MobSpawnCost mobSpawnCost = getRoughBiome(blockPos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
if (mobSpawnCost != null) {
potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
}
return new NaturalSpawner.SpawnState(getTotalChunkCount(level), map, potentialCalculator, calculator);
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
} else {
int chunkCount = getSpawnableChunkCount(level);
if (chunkCount == 0) return null;
if (calculator != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
calculator.addMob(chunk.getPos(), entity.getType().getCategory());
}
Object2IntOpenHashMap<MobCategory> globalCounts = getGlobalCounts(level);
// Paper start - Optional per player mob spawns
if (countMobs) {
chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
}
// Paper end - Optional per player mob spawns
});
PotentialCalculator potentialCalculator = new PotentialCalculator();
for (Entity entity : entities) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
if (!shouldCount(entity)) continue;
BlockPos pos = entity.blockPosition();
chunkGetter.query(ChunkPos.pack(pos), chunk -> {
MobSpawnSettings.MobSpawnCost mobSpawnCost = NaturalSpawner.getRoughBiome(pos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
if (mobSpawnCost != null) {
potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
}
if (calculator != null && entity instanceof Mob) {
calculator.addMob(chunk.getPos(), entity.getType().getCategory());
}
});
}
return new NaturalSpawner.SpawnState(chunkCount, globalCounts, potentialCalculator, calculator);
}
}
public static Object2IntOpenHashMap<MobCategory> getGlobalCounts(ServerLevel level) {
EnumMap<MobCategory, AtomicInteger> counts = globalMobCounts.get(level);
Object2IntOpenHashMap<MobCategory> result = new Object2IntOpenHashMap<>();
if (counts != null) {
for (Map.Entry<MobCategory, AtomicInteger> entry : counts.entrySet()) {
result.put(entry.getKey(), entry.getValue().get());
}
}
return result;
}
public static int getSpawnableChunkCount(ServerLevel level) {
Integer value = spawnableChunkCount.get(level);
return value != null ? value : 0;
}
public static void onWorldUnload(ServerLevel level) {
globalMobCounts.remove(level);
mobsAreaMap.remove(level);
spawnableChunkCount.remove(level);
}
public static void onEntityTrackingStart(ServerLevel level, Entity entity) {
if (!shouldCount(entity)) return;
MobCategory category = entity.getType().getCategory();
getOrCreateCounts(level).computeIfAbsent(category, k -> new AtomicInteger(0)).incrementAndGet();
}
public static boolean shouldCount(Entity entity) {
MobCategory category = entity.getType().getCategory();
if (category == MobCategory.MISC) return false;
if (entity instanceof Mob mob && (mob.isPersistenceRequired() || mob.requiresCustomPersistence())) {
return false;
}
if (VanillaLikeExperienceConfig.enabled || entity.level().paperConfig().entities.spawning.countAllMobsForSpawning) {
return true;
}
return entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL
|| entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN;
}
private static EnumMap<MobCategory, AtomicInteger> getOrCreateCounts(ServerLevel level) {
return globalMobCounts.computeIfAbsent(level, _ -> new EnumMap<>(MobCategory.class));
}
public static void onEntityTrackingEnd(ServerLevel level, Entity entity) {
if (!shouldCount(entity)) return;
MobCategory category = entity.getType().getCategory();
EnumMap<MobCategory, AtomicInteger> counts = getOrCreateCounts(level);
AtomicInteger counter = counts.get(category);
if (counter != null) {
counter.updateAndGet(v -> Math.max(0, v - 1));
}
return new NaturalSpawner.SpawnState(getTotalChunkCount(level), map, potentialCalculator, calculator);
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
}
}
@@ -315,11 +315,13 @@ public class BotList {
bot.unRide();
for (ThrownEnderpearl thrownEnderpearl : bot.getEnderPearls()) {
if (!thrownEnderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) {
thrownEnderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT);
} else {
thrownEnderpearl.setOwner(null);
}
// Lophine start - restore vanilla ender pearl loading on Folia
thrownEnderpearl.getBukkitEntity().taskScheduler.scheduleOrExecute((Entity pearl) -> {
if (!pearl.isRemoved()) {
pearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT);
}
});
// Lophine end - restore vanilla ender pearl loading on Folia
}
bot.level().getCurrentWorldData().connections.remove(bot.connection.connection);
@@ -27,10 +27,11 @@ import org.leavesmc.leaves.command.bot.subcommands.*;
import static org.leavesmc.leaves.command.CommandUtils.registerPermissions;
public class BotCommand extends RootNode {
private static final String PERM_BASE = "bukkit.command.bot";
private static final String PERM_BASE_BOT = "bukkit.command.bot";
private static final String PERM_BASE_PLAYER = "bukkit.command.player";
public BotCommand(String key) {
super(key, PERM_BASE);
super(key, getPermBase(key));
this.children(
ListCommand::new,
ConfigCommand::new,
@@ -44,15 +45,26 @@ public class BotCommand extends RootNode {
@Override
protected ArgumentBuilder<CommandSourceStack, ?> compile() {
registerPermissions(PERM_BASE, this.children);
registerPermissions(getPermBase(this.getName()), this.children);
return super.compile();
}
public static boolean hasPermission(@NotNull CommandSender sender) {
return sender.hasPermission(PERM_BASE);
return sender.hasPermission(PERM_BASE_BOT) || sender.hasPermission(PERM_BASE_PLAYER);
}
public static boolean hasPermission(@NotNull CommandSender sender, String subcommand) {
return sender.hasPermission(PERM_BASE) || sender.hasPermission(PERM_BASE + "." + subcommand);
return sender.hasPermission(PERM_BASE_BOT) || sender.hasPermission(PERM_BASE_BOT + "." + subcommand)
|| sender.hasPermission(PERM_BASE_PLAYER) || sender.hasPermission(PERM_BASE_PLAYER + "." + subcommand);
}
public static String getPermBase(String key) {
if (key.equals("bot")) {
return PERM_BASE_BOT;
}
if (key.equals("player")) {
return PERM_BASE_PLAYER;
}
throw new IllegalArgumentException("Invalid key: " + key);
}
}
@@ -56,11 +56,13 @@ public class StartCommand extends LiteralNode {
ServerBot bot = getBot(context);
CommandSender sender = context.getSender();
action.loadCommand(context);
if (bot.addBotAction(action, sender)) {
// Create a new instance of the action to avoid sharing state between multiple actions
AbstractBotAction<?> newAction = action.create();
newAction.loadCommand(context);
if (bot.addBotAction(newAction, sender)) {
sender.sendMessage(join(spaces(),
text("Action", GRAY),
text(action.getName(), AQUA).hoverEvent(showText(text(action.getActionDataString()))),
text(newAction.getName(), AQUA).hoverEvent(showText(text(newAction.getActionDataString()))),
text("has been issued to", GRAY),
asAdventure(bot.getDisplayName())
));
@@ -141,13 +141,13 @@ public class StopCommand extends LiteralNode {
if (canceled.isEmpty()) {
sender.sendMessage(join(spaces(),
asAdventure(bot.getDisplayName()).append(text("'s", GRAY)),
text("'s action list cleared", GRAY)
text("action list cleared", GRAY)
));
} else {
sender.sendMessage(join(spaces(),
text("Tried to clear", GRAY),
asAdventure(bot.getDisplayName()).append(text("'s", GRAY)),
text("'s action list, but following actions' stop was canceled by plugin:", GRAY)
text("action list, but following actions' stop was canceled by plugin:", GRAY)
));
for (AbstractBotAction<?> action : canceled) {
context.getSender().sendMessage(
@@ -6,18 +6,22 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.Identifier;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
import org.slf4j.Logger;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@LeavesProtocol.Register(namespace = "carpet")
public class CarpetServerProtocol implements LeavesProtocol {
@@ -28,6 +32,9 @@ public class CarpetServerProtocol implements LeavesProtocol {
private static final String HI = "69";
private static final String HELLO = "420";
private static final Set<UUID> activePlayers = ConcurrentHashMap.newKeySet();
private static boolean batchingRules = false;
private static boolean rulesDirty = false;
@Contract("_ -> new")
public static Identifier id(String path) {
@@ -44,21 +51,68 @@ public class CarpetServerProtocol implements LeavesProtocol {
@ProtocolHandler.PayloadReceiver(payload = CarpetPayload.class)
private static void handleHello(@NotNull ServerPlayer player, @NotNull CarpetServerProtocol.CarpetPayload payload) {
if (payload.nbt.contains(HELLO)) {
LOGGER.info("Player {} joined with carpet {}", player.getScoreboardName(), payload.nbt.getString(HELLO).orElse("Unknown"));
CompoundTag data = new CompoundTag();
CarpetRules.write(data);
ProtocolUtils.sendPayloadPacket(player, new CarpetPayload(data));
UUID playerId = player.getUUID();
String carpetVersion = payload.nbt.getString(HELLO).orElse("Unknown");
player.getBukkitEntity().getScheduler().execute(MinecraftInternalPlugin.INSTANCE, () -> {
ServerPlayer onlinePlayer = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (onlinePlayer == null) {
return;
}
LOGGER.info("Player {} joined with carpet {}", onlinePlayer.getScoreboardName(), carpetVersion);
sendServerData(onlinePlayer);
activePlayers.add(playerId);
}, null, 1L);
}
}
@ProtocolHandler.PlayerLeave
public static void onPlayerLeave(ServerPlayer player) {
activePlayers.remove(player.getUUID());
}
@Override
public boolean isActive() {
return CarpetRules.hasRules();
}
private static void sendServerData(ServerPlayer player) {
sendServerData(player.getUUID());
}
private static void sendServerData(UUID playerId) {
ServerPlayer player = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (player == null) {
activePlayers.remove(playerId);
return;
}
CompoundTag data = new CompoundTag();
CarpetRules.write(data);
player.getBukkitEntity().getScheduler().execute(MinecraftInternalPlugin.INSTANCE, () -> {
ServerPlayer onlinePlayer = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (onlinePlayer != null) {
ProtocolUtils.sendPayloadPacket(onlinePlayer, new CarpetPayload(data));
}
}, null, 1L);
}
public static class CarpetRules {
private static final Map<String, CarpetRule> rules = new HashMap<>();
private static final Map<String, CarpetRule> rules = new ConcurrentHashMap<>();
public static void beginBatch() {
batchingRules = true;
rulesDirty = false;
}
public static void endBatch() {
batchingRules = false;
if (rulesDirty) {
activePlayers.forEach(CarpetServerProtocol::sendServerData);
rulesDirty = false;
}
}
public static void write(@NotNull CompoundTag tag) {
CompoundTag rulesNbt = new CompoundTag();
@@ -69,15 +123,25 @@ public class CarpetServerProtocol implements LeavesProtocol {
public static void register(CarpetRule rule) {
rules.put(rule.name, rule);
markDirty();
}
public static void clear() {
rules.clear();
markDirty();
}
public static boolean hasRules() {
return !rules.isEmpty();
}
private static void markDirty() {
if (batchingRules) {
rulesDirty = true;
} else {
activePlayers.forEach(CarpetServerProtocol::sendServerData);
}
}
}
public record CarpetRule(String identifier, String name, String value) {
@@ -0,0 +1,483 @@
/*
* 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.protocol;
import ca.spottedleaf.moonrise.common.util.TickThread;
import fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.Identifier;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.ChestType;
import net.minecraft.world.level.chunk.LevelChunk;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
import org.leavesmc.leaves.util.TagUtil;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@LeavesProtocol.Register(namespace = "pca")
public class PcaSyncProtocol implements LeavesProtocol {
public static final String PROTOCOL_ID = "pca";
private static final Identifier ENABLE_PCA_SYNC_PROTOCOL = id("enable_pca_sync_protocol");
private static final Identifier DISABLE_PCA_SYNC_PROTOCOL = id("disable_pca_sync_protocol");
private static final ConcurrentMap<UUID, Pair<Identifier, BlockPos>> playerWatchBlockPos = new ConcurrentHashMap<>();
private static final ConcurrentMap<UUID, Pair<Identifier, UUID>> playerWatchEntity = new ConcurrentHashMap<>();
private static final ConcurrentMap<Pair<Identifier, BlockPos>, Set<UUID>> blockPosWatchPlayerSet = new ConcurrentHashMap<>();
private static final ConcurrentMap<Pair<Identifier, UUID>, Set<UUID>> entityWatchPlayerSet = new ConcurrentHashMap<>();
@Contract("_ -> new")
public static Identifier id(String path) {
return Identifier.fromNamespaceAndPath(PROTOCOL_ID, path);
}
@ProtocolHandler.PlayerJoin
private static void onJoin(ServerPlayer player) {
if (PcaSyncProtocolConfig.enabled) {
enablePcaSyncProtocol(player);
}
}
@ProtocolHandler.PlayerLeave
private static void onLeave(ServerPlayer player) {
clearPlayerWatchData(player);
}
@ProtocolHandler.BytebufReceiver(key = "cancel_sync_block_entity")
private static void cancelSyncBlockEntityHandler(ServerPlayer player, FriendlyByteBuf buf) {
clearPlayerWatchBlock(player);
}
@ProtocolHandler.BytebufReceiver(key = "cancel_sync_entity")
private static void cancelSyncEntityHandler(ServerPlayer player, FriendlyByteBuf buf) {
clearPlayerWatchEntity(player);
}
@ProtocolHandler.PayloadReceiver(payload = SyncBlockEntityPayload.class)
private static void syncBlockEntityHandler(ServerPlayer player, SyncBlockEntityPayload payload) {
if (!PcaSyncProtocolConfig.enabled) {
return;
}
UUID playerId = player.getUUID();
player.getBukkitEntity().getScheduler().execute(MinecraftInternalPlugin.INSTANCE, () -> {
ServerPlayer onlinePlayer = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (!PcaSyncProtocolConfig.enabled || onlinePlayer == null || onlinePlayer.hasDisconnected() || !TickThread.isTickThreadFor(onlinePlayer)) {
return;
}
ServerLevel world = onlinePlayer.level();
BlockPos pos = payload.pos;
Bukkit.getRegionScheduler().execute(MinecraftInternalPlugin.INSTANCE, world.getWorld(), pos.getX() >> 4, pos.getZ() >> 4, () -> {
if (!PcaSyncProtocolConfig.enabled || MinecraftServer.getServer().getPlayerList().getPlayer(playerId) == null || !TickThread.isTickThreadFor(world, pos)) {
return;
}
BlockState blockState = world.getBlockState(pos);
clearPlayerWatchData(playerId);
BlockEntity blockEntityAdj = null;
if (blockState.getBlock() instanceof ChestBlock && blockState.getValue(ChestBlock.TYPE) != ChestType.SINGLE) {
BlockPos posAdj = pos.relative(ChestBlock.getConnectedDirection(blockState));
if (TickThread.isTickThreadFor(world, posAdj)) {
blockEntityAdj = getLoadedBlockEntity(world, posAdj);
} else {
scheduleBlockEntityUpdate(playerId, world, posAdj);
}
}
if (blockEntityAdj != null) {
updateBlockEntity(playerId, blockEntityAdj);
}
BlockEntity blockEntity = getLoadedBlockEntity(world, pos);
if (blockEntity != null) {
updateBlockEntity(playerId, blockEntity);
}
Pair<Identifier, BlockPos> pair = new ImmutablePair<>(world.dimension().identifier(), pos);
playerWatchBlockPos.put(playerId, pair);
blockPosWatchPlayerSet.computeIfAbsent(pair, ignored -> ConcurrentHashMap.newKeySet()).add(playerId);
});
}, null, 1L);
}
@ProtocolHandler.PayloadReceiver(payload = SyncEntityPayload.class)
private static void syncEntityHandler(ServerPlayer player, SyncEntityPayload payload) {
if (!PcaSyncProtocolConfig.enabled) {
return;
}
UUID playerId = player.getUUID();
player.getBukkitEntity().getScheduler().execute(MinecraftInternalPlugin.INSTANCE, () -> {
ServerPlayer onlinePlayer = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (!PcaSyncProtocolConfig.enabled || onlinePlayer == null || onlinePlayer.hasDisconnected() || !TickThread.isTickThreadFor(onlinePlayer)) {
return;
}
ServerLevel world = onlinePlayer.level();
Entity entity = world.getEntity(payload.entityId);
if (entity == null) {
return;
}
boolean viewerIsOp = MinecraftServer.getServer().getPlayerList().isOp(onlinePlayer.nameAndId());
if (TickThread.isTickThreadFor(entity)) {
syncEntityForWatcher(playerId, viewerIsOp, entity);
} else {
entity.getBukkitEntity().getScheduler().execute(MinecraftInternalPlugin.INSTANCE, () -> syncEntityForWatcher(playerId, viewerIsOp, entity), null, 1L);
}
}, null, 1L);
}
public static void onConfigModify(boolean enable) {
if (enable) {
enablePcaSyncProtocolGlobal();
} else {
disablePcaSyncProtocolGlobal();
}
}
public static void enablePcaSyncProtocol(@NotNull ServerPlayer player) {
sendEmptyPacket(player.getUUID(), ENABLE_PCA_SYNC_PROTOCOL);
}
public static void disablePcaSyncProtocol(@NotNull ServerPlayer player) {
sendEmptyPacket(player.getUUID(), DISABLE_PCA_SYNC_PROTOCOL);
}
public static void updateEntity(@NotNull ServerPlayer player, @NotNull Entity entity) {
updateEntity(player.getUUID(), entity);
}
private static void updateEntity(@NotNull UUID playerId, @NotNull Entity entity) {
if (!TickThread.isTickThreadFor(entity) || entity.isRemoved()) {
return;
}
CompoundTag nbt = TagUtil.saveEntity(entity);
sendPayloadPacket(playerId, new UpdateEntityPayload(entity.level().dimension().identifier(), entity.getId(), nbt));
}
public static void updateBlockEntity(@NotNull ServerPlayer player, @NotNull BlockEntity blockEntity) {
updateBlockEntity(player.getUUID(), blockEntity);
}
private static void updateBlockEntity(@NotNull UUID playerId, @NotNull BlockEntity blockEntity) {
Level world = blockEntity.getLevel();
if (world == null || world.isClientSide() || !TickThread.isTickThreadFor(world, blockEntity.getBlockPos())) {
return;
}
sendPayloadPacket(playerId, new UpdateBlockEntityPayload(world.dimension().identifier(), blockEntity.getBlockPos(), blockEntity.saveWithoutMetadata(world.registryAccess())));
}
public static boolean syncEntityToClient(@NotNull Entity entity) {
if (!PcaSyncProtocolConfig.enabled || entity.level().isClientSide() || !TickThread.isTickThreadFor(entity) || entity.isRemoved()) {
return false;
}
Pair<Identifier, UUID> pair = new ImmutablePair<>(entity.level().dimension().identifier(), entity.getUUID());
Set<UUID> playerIds = entityWatchPlayerSet.get(pair);
if (playerIds == null || playerIds.isEmpty()) {
return false;
}
ArrayList<UUID> stalePlayers = new ArrayList<>();
boolean ret = false;
for (UUID playerId : playerIds) {
if (MinecraftServer.getServer().getPlayerList().getPlayer(playerId) == null) {
stalePlayers.add(playerId);
continue;
}
updateEntity(playerId, entity);
ret = true;
}
stalePlayers.forEach(playerIds::remove);
if (playerIds.isEmpty()) {
entityWatchPlayerSet.remove(pair, playerIds);
}
return ret;
}
public static boolean syncBlockEntityToClient(@NotNull BlockEntity blockEntity) {
Level world = blockEntity.getLevel();
if (!PcaSyncProtocolConfig.enabled || world == null || world.isClientSide() || !TickThread.isTickThreadFor(world, blockEntity.getBlockPos())) {
return false;
}
BlockPos pos = blockEntity.getBlockPos();
BlockState blockState = world.getBlockState(pos);
Set<UUID> playerIds = collectWatchers(world, pos);
if (blockState.getBlock() instanceof ChestBlock && blockState.getValue(ChestBlock.TYPE) != ChestType.SINGLE) {
BlockPos posAdj = pos.relative(ChestBlock.getConnectedDirection(blockState));
playerIds.addAll(collectWatchers(world, posAdj));
}
if (playerIds.isEmpty()) {
return false;
}
boolean ret = false;
for (UUID playerId : playerIds) {
if (MinecraftServer.getServer().getPlayerList().getPlayer(playerId) == null) {
removePlayerFromWatchers(playerId);
continue;
}
updateBlockEntity(playerId, blockEntity);
ret = true;
}
return ret;
}
public static void disablePcaSyncProtocolGlobal() {
playerWatchBlockPos.clear();
playerWatchEntity.clear();
blockPosWatchPlayerSet.clear();
entityWatchPlayerSet.clear();
for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().getPlayers()) {
disablePcaSyncProtocol(player);
}
}
public static void enablePcaSyncProtocolGlobal() {
for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().getPlayers()) {
enablePcaSyncProtocol(player);
}
}
public static void clearPlayerWatchData(ServerPlayer player) {
clearPlayerWatchData(player.getUUID());
}
private static void clearPlayerWatchData(UUID playerId) {
clearPlayerWatchBlock(playerId);
clearPlayerWatchEntity(playerId);
}
private static void clearPlayerWatchEntity(ServerPlayer player) {
clearPlayerWatchEntity(player.getUUID());
}
private static void clearPlayerWatchEntity(UUID playerId) {
Pair<Identifier, UUID> pair = playerWatchEntity.remove(playerId);
if (pair != null) {
removeFromSet(entityWatchPlayerSet, pair, playerId);
}
}
private static void clearPlayerWatchBlock(ServerPlayer player) {
clearPlayerWatchBlock(player.getUUID());
}
private static void clearPlayerWatchBlock(UUID playerId) {
Pair<Identifier, BlockPos> pair = playerWatchBlockPos.remove(playerId);
if (pair != null) {
removeFromSet(blockPosWatchPlayerSet, pair, playerId);
}
}
private static void removePlayerFromWatchers(UUID playerId) {
Pair<Identifier, BlockPos> blockPair = playerWatchBlockPos.remove(playerId);
if (blockPair != null) {
removeFromSet(blockPosWatchPlayerSet, blockPair, playerId);
}
Pair<Identifier, UUID> entityPair = playerWatchEntity.remove(playerId);
if (entityPair != null) {
removeFromSet(entityWatchPlayerSet, entityPair, playerId);
}
}
private static <K> void removeFromSet(ConcurrentMap<K, Set<UUID>> map, K key, UUID playerId) {
Set<UUID> playerSet = map.get(key);
if (playerSet != null) {
playerSet.remove(playerId);
if (playerSet.isEmpty()) {
map.remove(key, playerSet);
}
}
}
private static Set<UUID> collectWatchers(@NotNull Level world, @NotNull BlockPos blockPos) {
Set<UUID> playerIds = blockPosWatchPlayerSet.get(new ImmutablePair<>(world.dimension().identifier(), blockPos));
return playerIds == null ? new HashSet<>() : new HashSet<>(playerIds);
}
private static @org.jetbrains.annotations.Nullable BlockEntity getLoadedBlockEntity(ServerLevel world, BlockPos pos) {
LevelChunk chunk = world.getChunkIfLoaded(pos);
return chunk == null ? null : chunk.getBlockEntity(pos);
}
private static void scheduleBlockEntityUpdate(UUID playerId, ServerLevel world, BlockPos pos) {
Bukkit.getRegionScheduler().execute(MinecraftInternalPlugin.INSTANCE, world.getWorld(), pos.getX() >> 4, pos.getZ() >> 4, () -> {
if (!PcaSyncProtocolConfig.enabled || MinecraftServer.getServer().getPlayerList().getPlayer(playerId) == null || !TickThread.isTickThreadFor(world, pos)) {
return;
}
BlockEntity blockEntity = getLoadedBlockEntity(world, pos);
if (blockEntity != null) {
updateBlockEntity(playerId, blockEntity);
}
});
}
private static void syncEntityForWatcher(UUID playerId, boolean viewerIsOp, Entity entity) {
if (!PcaSyncProtocolConfig.enabled || MinecraftServer.getServer().getPlayerList().getPlayer(playerId) == null || !TickThread.isTickThreadFor(entity) || entity.isRemoved()) {
return;
}
if (entity instanceof Player && !maySyncPlayerEntity(playerId, viewerIsOp, entity)) {
return;
}
clearPlayerWatchData(playerId);
updateEntity(playerId, entity);
Pair<Identifier, UUID> pair = new ImmutablePair<>(entity.level().dimension().identifier(), entity.getUUID());
playerWatchEntity.put(playerId, pair);
entityWatchPlayerSet.computeIfAbsent(pair, ignored -> ConcurrentHashMap.newKeySet()).add(playerId);
}
private static boolean maySyncPlayerEntity(UUID viewerId, boolean viewerIsOp, Entity entity) {
return switch (PcaSyncProtocolConfig.syncPlayerEntity) {
case NOBODY -> false;
case BOT -> entity instanceof ServerBot;
case OPS -> entity instanceof ServerBot || viewerIsOp;
case OPS_AND_SELF -> entity instanceof ServerBot || viewerIsOp || entity.getUUID().equals(viewerId);
case EVERYONE -> true;
};
}
private static void sendEmptyPacket(UUID playerId, Identifier id) {
ServerPlayer player = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (player == null) {
removePlayerFromWatchers(playerId);
return;
}
player.getBukkitEntity().getScheduler().execute(MinecraftInternalPlugin.INSTANCE, () -> {
ServerPlayer onlinePlayer = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (onlinePlayer != null) {
ProtocolUtils.sendEmptyPacket(onlinePlayer, id);
}
}, null, 1L);
}
private static void sendPayloadPacket(UUID playerId, CustomPacketPayload payload) {
ServerPlayer player = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (player == null) {
removePlayerFromWatchers(playerId);
return;
}
player.getBukkitEntity().getScheduler().execute(MinecraftInternalPlugin.INSTANCE, () -> {
ServerPlayer onlinePlayer = MinecraftServer.getServer().getPlayerList().getPlayer(playerId);
if (onlinePlayer != null) {
ProtocolUtils.sendPayloadPacket(onlinePlayer, payload);
}
}, null, 1L);
}
@Override
public boolean isActive() {
return PcaSyncProtocolConfig.enabled;
}
public record UpdateEntityPayload(Identifier dimension, int entityId,
CompoundTag tag) implements LeavesCustomPayload {
@ID
public static final Identifier UPDATE_ENTITY = PcaSyncProtocol.id("update_entity");
@Codec
public static final StreamCodec<FriendlyByteBuf, UpdateEntityPayload> CODEC = StreamCodec.composite(
Identifier.STREAM_CODEC,
UpdateEntityPayload::dimension,
ByteBufCodecs.INT,
UpdateEntityPayload::entityId,
ByteBufCodecs.COMPOUND_TAG,
UpdateEntityPayload::tag,
UpdateEntityPayload::new
);
}
public record UpdateBlockEntityPayload(Identifier dimension, BlockPos blockPos,
CompoundTag tag) implements LeavesCustomPayload {
@ID
private static final Identifier UPDATE_BLOCK_ENTITY = PcaSyncProtocol.id("update_block_entity");
@Codec
private static final StreamCodec<FriendlyByteBuf, UpdateBlockEntityPayload> CODEC = StreamCodec.composite(
Identifier.STREAM_CODEC,
UpdateBlockEntityPayload::dimension,
BlockPos.STREAM_CODEC,
UpdateBlockEntityPayload::blockPos,
ByteBufCodecs.COMPOUND_TAG,
UpdateBlockEntityPayload::tag,
UpdateBlockEntityPayload::new
);
}
public record SyncBlockEntityPayload(BlockPos pos) implements LeavesCustomPayload {
@ID
public static final Identifier SYNC_BLOCK_ENTITY = PcaSyncProtocol.id("sync_block_entity");
@Codec
private static final StreamCodec<FriendlyByteBuf, SyncBlockEntityPayload> CODEC = StreamCodec.composite(
BlockPos.STREAM_CODEC, SyncBlockEntityPayload::pos, SyncBlockEntityPayload::new
);
}
public record SyncEntityPayload(int entityId) implements LeavesCustomPayload {
@ID
public static final Identifier SYNC_ENTITY = PcaSyncProtocol.id("sync_entity");
@Codec
private static final StreamCodec<FriendlyByteBuf, SyncEntityPayload> CODEC = StreamCodec.composite(
ByteBufCodecs.INT, SyncEntityPayload::entityId, SyncEntityPayload::new
);
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ pluginManagement {
gradlePluginPortal()
mavenLocal()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.menthamc.org/repository/maven-public/")
maven("https://repo.bacteriawa.com/repository/maven-public/")
}
plugins {