* 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>
This commit is contained in:
@@ -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
|
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||||
index eedbeb005d3c8090333c36b9857c837dfb75dbd4..5817f087187e9d3479c752129a1a9d853623a3f7 100644
|
index eedbeb005d3c8090333c36b9857c837dfb75dbd4..7ea91dbfb988aff3215a91cf62c9beae94461484 100644
|
||||||
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||||
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||||
@@ -558,6 +558,9 @@ public final class RegionizedWorldData {
|
@@ -558,6 +558,9 @@ public final class RegionizedWorldData {
|
||||||
@@ -23,10 +23,10 @@ index eedbeb005d3c8090333c36b9857c837dfb75dbd4..5817f087187e9d3479c752129a1a9d85
|
|||||||
this.regionData = regionData;
|
this.regionData = regionData;
|
||||||
|
|
||||||
+ // Lophine start - Global Entities Counter
|
+ // 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();
|
+ uniqueId = fun.bm.lophine.utils.EntitiesCounterUtil.generateUniqueId();
|
||||||
+ fun.bm.lophine.utils.EntitiesCounterUtil.reportAreaMap(world, spawnChunkTracker, uniqueId);
|
+ 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;
|
+ underGlobalEntitiesCounter = true;
|
||||||
+ }
|
+ }
|
||||||
+ // Lophine end - Global Entities Counter
|
+ // Lophine end - Global Entities Counter
|
||||||
@@ -35,15 +35,15 @@ index eedbeb005d3c8090333c36b9857c837dfb75dbd4..5817f087187e9d3479c752129a1a9d85
|
|||||||
this.updateTickData();
|
this.updateTickData();
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
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
|
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||||
+++ b/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);
|
this.chunkMap.tick(haveTime);
|
||||||
profiler.pop();
|
profiler.pop();
|
||||||
this.clearCache();
|
this.clearCache();
|
||||||
+ // Lophine start - Global Entities Counter
|
+ // 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();
|
+ io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.level.getCurrentWorldData();
|
||||||
+ if (regionizedWorldData != null) {
|
+ if (regionizedWorldData != null) {
|
||||||
+ if (regionizedWorldData.underGlobalEntitiesCounter) {
|
+ if (regionizedWorldData.underGlobalEntitiesCounter) {
|
||||||
@@ -53,6 +53,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
|
|||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
+ if (!regionizedWorldData.getLocalPlayers().isEmpty()) {
|
+ 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.reportAreaMap(level, regionizedWorldData.spawnChunkTracker, regionizedWorldData.uniqueId);
|
||||||
+ fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(level, (ca.spottedleaf.moonrise.common.list.ReferenceList<Entity>) regionizedWorldData.getLoadedEntities(), regionizedWorldData.uniqueId);
|
+ fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(level, (ca.spottedleaf.moonrise.common.list.ReferenceList<Entity>) regionizedWorldData.getLoadedEntities(), regionizedWorldData.uniqueId);
|
||||||
+ regionizedWorldData.underGlobalEntitiesCounter = true;
|
+ regionizedWorldData.underGlobalEntitiesCounter = true;
|
||||||
@@ -64,14 +65,14 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void tickChunks() {
|
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
|
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 {
|
} 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
|
- 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
|
+ // Lophine start - Global Entities Counter
|
||||||
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
|
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
|
||||||
+ spawnCookie = fun.bm.lophine.utils.EntitiesCounterUtil.runRemainingTasks(level, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
|
+ 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 {
|
+ } 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
|
+ 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
|
} finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.MOB_SPAWN_ENTITY_COUNT); } // Folia - profiler
|
||||||
// Paper end - Optional per player mob spawns
|
// 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
|
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);
|
int tickSpeed = this.level.getGameRules().get(GameRules.RANDOM_TICK_SPEED);
|
||||||
List<MobCategory> spawningCategories;
|
List<MobCategory> spawningCategories;
|
||||||
@@ -88,7 +89,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
|
|||||||
// Paper start - PlayerNaturallySpawnCreaturesEvent
|
// Paper start - PlayerNaturallySpawnCreaturesEvent
|
||||||
for (ServerPlayer player : this.level.getLocalPlayers()) { // Folia - region threading
|
for (ServerPlayer player : this.level.getLocalPlayers()) { // Folia - region threading
|
||||||
int chunkRange = Math.min(level.spigotConfig.mobSpawnRange, player.getBukkitEntity().getViewDistance());
|
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);
|
this.level.tickThunder(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +99,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
|
|||||||
NaturalSpawner.spawnForChunk(this.level, chunk, spawnCookie, spawningCategories);
|
NaturalSpawner.spawnForChunk(this.level, chunk, spawnCookie, spawningCategories);
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
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
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/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
|
@@ -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
|
public void tick(BooleanSupplier haveTime, final io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking
|
||||||
+ // Lophine start - Global Entities Counter
|
+ // 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);
|
+ if (fun.bm.lophine.utils.EntitiesCounterUtil.canRunNewTask(this)) fun.bm.lophine.utils.EntitiesCounterUtil.tick(this);
|
||||||
+ }
|
+ }
|
||||||
+ // Lophine end - Global Entities Counter
|
+ // Lophine end - Global Entities Counter
|
||||||
final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - regionised ticking
|
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
|
final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle foliaProfiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler
|
||||||
ProfilerFiller profiler = Profiler.get();
|
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
|
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
|
--- a/net/minecraft/world/entity/Mob.java
|
||||||
+++ b/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
|
@@ -813,6 +813,44 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs
|
||||||
@@ -122,7 +159,7 @@ index fc29654dd7ee3329edf1ccf705f45631d0ecc079..9b8ee2df5a0b6d76d9bfc747187f6cd5
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
+ // Lophine start - fix some bug if player is cross scheduler >> to remove monster if the region don't have any valid player
|
+ // 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();
|
+ List<net.minecraft.server.level.ServerPlayer> playerList = this.level().getServer().getPlayerList().getPlayers();
|
||||||
+ if (!playerList.isEmpty()) {
|
+ if (!playerList.isEmpty()) {
|
||||||
+ double d = -1.0;
|
+ double d = -1.0;
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ index f99c02b4d88cea924e20ca8dced67873c83c093f..0c042c4af5d52c08e9fbc03a04c4b696
|
|||||||
|
|
||||||
profiler.pop();
|
profiler.pop();
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
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
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/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
|
@@ -967,7 +967,18 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
||||||
|
|||||||
@@ -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
|
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||||
index 5817f087187e9d3479c752129a1a9d853623a3f7..1d50a626c15fba4947c966e46f38e7684511e9fe 100644
|
index 7ea91dbfb988aff3215a91cf62c9beae94461484..491d108cc8e440653746f20fc5b5bca3b791eb88 100644
|
||||||
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||||
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||||
@@ -506,7 +506,7 @@ public final class RegionizedWorldData {
|
@@ -506,7 +506,7 @@ public final class RegionizedWorldData {
|
||||||
@@ -38,7 +38,7 @@ index 5817f087187e9d3479c752129a1a9d853623a3f7..1d50a626c15fba4947c966e46f38e768
|
|||||||
\ No newline at end of file
|
\ No newline at end of file
|
||||||
+}
|
+}
|
||||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
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
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/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
|
@@ -1001,11 +1001,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
||||||
|
|||||||
@@ -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() {
|
||||||
+256
@@ -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;
|
||||||
|
}
|
||||||
+219
@@ -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 {
|
||||||
@@ -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.GeneralCompatConfig;
|
||||||
import fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig;
|
import fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig;
|
||||||
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
|
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
|
||||||
|
import fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig;
|
||||||
import fun.bm.lophine.protocol.CarpetLoggerProtocol;
|
import fun.bm.lophine.protocol.CarpetLoggerProtocol;
|
||||||
import org.leavesmc.leaves.protocol.CarpetServerProtocol;
|
import org.leavesmc.leaves.protocol.CarpetServerProtocol;
|
||||||
|
|
||||||
@@ -24,75 +25,83 @@ public final class CarpetCompatSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void registerProtocolRules() {
|
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("carpet", "language", GeneralCompatConfig.language));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "amsUpdateSuppressionCrashFix", GeneralCompatConfig.amsUpdateSuppressionCrashFix));
|
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", "yeetUpdateSuppressionCrash", GeneralCompatConfig.yeetUpdateSuppressionCrash));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "dustTrapdoorReintroduced", GeneralCompatConfig.dustTrapdoorReintroduced));
|
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", "shulkerBoxCCEReintroduced", GeneralCompatConfig.shulkerBoxCCEReintroduced));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "instantBlockUpdaterReintroduced", GeneralCompatConfig.instantBlockUpdaterReintroduced));
|
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", "commandTick", GeneralCompatConfig.commandTick));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "creativeNoClip", GeneralCompatConfig.creativeNoClip));
|
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", "optimizedDragonRespawn", GeneralCompatConfig.optimizedDragonRespawn));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "antiSpamDisabled", GeneralCompatConfig.antiSpamDisabled));
|
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", "blockPlacementIgnoreEntity", GeneralCompatConfig.blockPlacementIgnoreEntity));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeOpenContainerForcibly", GeneralCompatConfig.creativeOpenContainerForcibly));
|
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("carpetamsaddition", "creativeOneHitKill", GeneralCompatConfig.creativeOneHitKill));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "observerNoDetection", GeneralCompatConfig.observerNoDetection));
|
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("carpetamsaddition", "bambooModelNoOffset", GeneralCompatConfig.bambooModelNoOffset));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeNoItemCooldown", GeneralCompatConfig.creativeNoItemCooldown));
|
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("carpet", "ctrlQCraftingFix", GeneralCompatConfig.ctrlQCraftingFix));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "carpetAlwaysSetDefault", GeneralCompatConfig.carpetAlwaysSetDefault));
|
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", "placementRotationFix", GeneralCompatConfig.placementRotationFix));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntDoNotUpdate", GeneralCompatConfig.tntDoNotUpdate));
|
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", "totallyNoBlockUpdate", GeneralCompatConfig.totallyNoBlockUpdate));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tiscmNetworkProtocol", GeneralCompatConfig.tiscmNetworkProtocol));
|
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("carpetorgaddition", "hopperNoItemCost", GeneralCompatConfig.hopperNoItemCost));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "explosionNoBlockDamage", GeneralCompatConfig.explosionNoBlockDamage));
|
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("carpettisaddition", "optimizedTNTHighPriority", GeneralCompatConfig.optimizedTNTHighPriority));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntPrimerMomentumRemoved", GeneralCompatConfig.tntPrimerMomentumRemoved));
|
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", "tntIgnoreRedstoneSignal", GeneralCompatConfig.tntIgnoreRedstoneSignal));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntDupingFix", GeneralCompatConfig.tntDupingFix));
|
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", "interactionUpdates", GeneralCompatConfig.interactionUpdates));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "xpNoCooldown", GeneralCompatConfig.xpNoCooldown));
|
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("carpetamsaddition", "powerfulExpMending", GeneralCompatConfig.powerfulExpMending));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "clientSettingsLostOnRespawnFix", GeneralCompatConfig.clientSettingsLostOnRespawnFix));
|
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("carpetamsaddition", "sensibleEnderman", GeneralCompatConfig.sensibleEnderman));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "entityInstantDeathRemoval", GeneralCompatConfig.entityInstantDeathRemoval));
|
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("carpettisaddition", "farmlandTrampledDisabled", GeneralCompatConfig.farmlandTrampledDisabled));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "shulkerGolem", GeneralCompatConfig.shulkerGolem));
|
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("carpetamsaddition", "preventEndSpikeRespawn", GeneralCompatConfig.preventEndSpikeRespawn));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetOutOfOrderChatKick", GeneralCompatConfig.yeetOutOfOrderChatKick));
|
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", "betterCraftableBoneBlock", GeneralCompatConfig.betterCraftableBoneBlock));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableDispenser", GeneralCompatConfig.betterCraftableDispenser));
|
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("carpet", "viewDistance", GeneralCompatConfig.viewDistance));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickCommandPermission", GeneralCompatConfig.normalizedTickCommandPermission()));
|
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", "tickFreezeCommandToggleable", GeneralCompatConfig.tickFreezeCommandToggleable));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "syncServerMsptMetricsData", GeneralCompatConfig.syncServerMsptMetricsData));
|
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("carpetorgaddition", "simpleInGameCalculator", GeneralCompatConfig.simpleInGameCalculator));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "microTiming", GeneralCompatConfig.microTiming));
|
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", "fastRedstoneDust", GeneralCompatConfig.fastRedstoneDust));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "lagFreeSpawning", GeneralCompatConfig.lagFreeSpawning));
|
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", "optimizedFastEntityMovement", GeneralCompatConfig.optimizedFastEntityMovement));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedHardHitBoxEntityCollision", GeneralCompatConfig.optimizedHardHitBoxEntityCollision));
|
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("carpettisaddition", "tntFuseDuration", GeneralCompatConfig.normalizedTntFuseDuration()));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "defaultLoggers", CarpetLoggerProtocol.serializeConfiguredDefaults(sanitizeDefaultLoggers(GeneralCompatConfig.defaultLoggers))));
|
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("lophine", "commandBot", FakeplayerConfig.enable));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandPlayer", FakePlayerCompatConfig.commandPlayer));
|
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", "fakePlayerResident", FakePlayerCompatConfig.fakePlayerResident));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "openFakePlayerInventory", FakePlayerCompatConfig.openFakePlayerInventory));
|
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("carpettisaddition", "fakePlayerTicksLikeRealPlayer", FakePlayerCompatConfig.fakePlayerTicksLikeRealPlayer));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerDefaultSurvivalMode", FakePlayerCompatConfig.fakePlayerDefaultSurvivalMode));
|
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("carpetamsaddition", "fakePlayerInteractLikeClient", FakePlayerCompatConfig.fakePlayerInteractLikeClient));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplaceTool", FakePlayerCompatConfig.fakePlayerAutoReplaceTool));
|
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("lophine", "fakePlayerAutoReplenishment", FakePlayerCompatConfig.fakePlayerAutoReplenishment));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerAutoReplenishmentFormShulkerBox", FakePlayerCompatConfig.fakePlayerAutoReplenishmentFormShulkerBox));
|
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", "fakePlayerAutoFish", FakePlayerCompatConfig.fakePlayerAutoFish));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerReloadAction", FakePlayerCompatConfig.fakePlayerReloadAction));
|
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("carpet", "hopperCounters", WoolHopperCounterConfig.hopperCounters));
|
||||||
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "hopperCountersUnlimitedSpeed", WoolHopperCounterConfig.hopperCountersUnlimitedSpeed));
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-6
@@ -1,20 +1,67 @@
|
|||||||
package fun.bm.lophine.config.modules.experiment;
|
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.IConfigModule;
|
||||||
import me.earthme.luminol.config.flags.ConfigClassInfo;
|
import me.earthme.luminol.config.flags.ConfigClassInfo;
|
||||||
import me.earthme.luminol.config.flags.ConfigInfo;
|
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.config.flags.HotReloadUnsupported;
|
||||||
import me.earthme.luminol.enums.EnumConfigCategory;
|
import me.earthme.luminol.enums.EnumConfigCategory;
|
||||||
|
|
||||||
@ConfigClassInfo(name = "global_entities_counter", category = EnumConfigCategory.EXPERIMENT)
|
@ConfigClassInfo(name = "global_entities_counter", category = EnumConfigCategory.EXPERIMENT)
|
||||||
public class GlobalEntitiesCounter implements IConfigModule {
|
public class GlobalEntitiesCounter implements IConfigModule {
|
||||||
@HotReloadUnsupported
|
@HotReloadUnsupported
|
||||||
@ConfigInfo(name = "enabled", comments = """
|
@ConfigInfo(name = "version", comments = """
|
||||||
Enable global entities counter.
|
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""")
|
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
|
@DoNotLoad
|
||||||
@ConfigInfo(name = "async", comments = "Enable Asynchronous(maybe cause bugs)")
|
private static boolean enabled;
|
||||||
public static boolean async = false;
|
@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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -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;
|
||||||
|
}
|
||||||
+43
@@ -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.google.common.cache.CacheBuilder;
|
||||||
import com.mojang.logging.LogUtils;
|
import com.mojang.logging.LogUtils;
|
||||||
import fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter;
|
import fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter;
|
||||||
|
import fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@@ -24,10 +25,10 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import static net.minecraft.world.level.NaturalSpawner.getRoughBiome;
|
|
||||||
|
|
||||||
public class EntitiesCounterUtil {
|
public class EntitiesCounterUtil {
|
||||||
|
// global entities counter
|
||||||
private static final Map<ServerLevel, Cache<Integer, ReferenceList<Entity>>> globalLoadedEntities = new ConcurrentHashMap<>();
|
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, Object2IntOpenHashMap<MobCategory>> mobsMap = Collections.synchronizedMap(new WeakHashMap<>());
|
||||||
private static final Map<ServerLevel, Cache<Integer, PositionCountingAreaMap<ServerPlayer>>> mobsAreaMap = new ConcurrentHashMap<>();
|
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 Map<ServerLevel, CompletableFuture<Void>> tasks = new ConcurrentHashMap<>();
|
||||||
private static final Set<Integer> UniqueIds = ConcurrentHashMap.newKeySet();
|
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 int lastUsedId = 0;
|
||||||
|
|
||||||
private static final int CLEANUP_INTERVAL = 200; // each 200 ids used
|
private static final int CLEANUP_INTERVAL = 200; // each 200 ids used
|
||||||
@@ -104,94 +108,193 @@ public class EntitiesCounterUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void tick(ServerLevel level) {
|
public static void tick(ServerLevel level) {
|
||||||
Runnable task = () -> {
|
if (GlobalEntitiesCounter.isDefaultModule()) {
|
||||||
try {
|
Runnable task = () -> {
|
||||||
Cache<Integer, ReferenceList<Entity>> data0 = globalLoadedEntities.get(level);
|
try {
|
||||||
if (data0 == null) return;
|
Cache<Integer, ReferenceList<Entity>> data0 = globalLoadedEntities.get(level);
|
||||||
|
if (data0 == null) return;
|
||||||
|
|
||||||
Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
|
Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
|
||||||
Collection<ReferenceList<Entity>> snapshot = data0.asMap().values();
|
Collection<ReferenceList<Entity>> snapshot = data0.asMap().values();
|
||||||
|
|
||||||
for (ReferenceList<Entity> data : snapshot) {
|
for (ReferenceList<Entity> data : snapshot) {
|
||||||
if (data == null) continue;
|
if (data == null) continue;
|
||||||
for (Entity entity : GlobalEntitiesCounter.async ? data.copy() : data) {
|
for (Entity entity : GlobalEntitiesCounter.isAsync() ? data.copy() : data) {
|
||||||
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
|
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
|
||||||
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
|
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
|
||||||
MobCategory category = entity.getType().getCategory();
|
MobCategory category = entity.getType().getCategory();
|
||||||
if (category != MobCategory.MISC) {
|
if (category != MobCategory.MISC) {
|
||||||
// Paper start - Only count natural spawns
|
// Paper start - Only count natural spawns
|
||||||
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
|
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
|
||||||
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
|
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
|
||||||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
|
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
|
||||||
continue;
|
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);
|
Cache<Integer, PositionCountingAreaMap<ServerPlayer>> collection = mobsAreaMap.get(level);
|
||||||
if (collection != null) {
|
if (collection != null) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (PositionCountingAreaMap<ServerPlayer> areaMap : collection.asMap().values()) {
|
for (PositionCountingAreaMap<ServerPlayer> areaMap : collection.asMap().values()) {
|
||||||
if (areaMap != null) {
|
if (areaMap != null) {
|
||||||
count += areaMap.getTotalPositions();
|
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 {
|
} 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
|
ServerLevel level, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs
|
||||||
) {
|
) {
|
||||||
Object2IntOpenHashMap<MobCategory> map = getMobsMap(level);
|
if (GlobalEntitiesCounter.isDefaultModule()) {
|
||||||
if (map == null) return null; // skip if no data
|
Object2IntOpenHashMap<MobCategory> map = getMobsMap(level);
|
||||||
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
|
if (map == null) return null; // skip if no data
|
||||||
PotentialCalculator potentialCalculator = new PotentialCalculator();
|
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
|
||||||
for (Entity entity : entities) {
|
PotentialCalculator potentialCalculator = new PotentialCalculator();
|
||||||
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
|
for (Entity entity : entities) {
|
||||||
// Paper start - Only count natural spawns
|
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
|
||||||
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
|
// Paper start - Only count natural spawns
|
||||||
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
|
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
|
||||||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
|
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
|
||||||
continue;
|
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
|
return new NaturalSpawner.SpawnState(getTotalChunkCount(level), map, potentialCalculator, calculator);
|
||||||
BlockPos blockPos = entity.blockPosition();
|
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
|
||||||
chunkGetter.query(ChunkPos.pack(blockPos), chunk -> {
|
} else {
|
||||||
MobSpawnSettings.MobSpawnCost mobSpawnCost = getRoughBiome(blockPos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
|
int chunkCount = getSpawnableChunkCount(level);
|
||||||
if (mobSpawnCost != null) {
|
if (chunkCount == 0) return null;
|
||||||
potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (calculator != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
|
Object2IntOpenHashMap<MobCategory> globalCounts = getGlobalCounts(level);
|
||||||
calculator.addMob(chunk.getPos(), entity.getType().getCategory());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Paper start - Optional per player mob spawns
|
PotentialCalculator potentialCalculator = new PotentialCalculator();
|
||||||
if (countMobs) {
|
for (Entity entity : entities) {
|
||||||
chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
|
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
|
||||||
}
|
if (!shouldCount(entity)) continue;
|
||||||
// Paper end - Optional per player mob spawns
|
|
||||||
});
|
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();
|
bot.unRide();
|
||||||
for (ThrownEnderpearl thrownEnderpearl : bot.getEnderPearls()) {
|
for (ThrownEnderpearl thrownEnderpearl : bot.getEnderPearls()) {
|
||||||
if (!thrownEnderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) {
|
// Lophine start - restore vanilla ender pearl loading on Folia
|
||||||
thrownEnderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT);
|
thrownEnderpearl.getBukkitEntity().taskScheduler.scheduleOrExecute((Entity pearl) -> {
|
||||||
} else {
|
if (!pearl.isRemoved()) {
|
||||||
thrownEnderpearl.setOwner(null);
|
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);
|
bot.level().getCurrentWorldData().connections.remove(bot.connection.connection);
|
||||||
|
|||||||
+70
-6
@@ -6,18 +6,22 @@ import net.minecraft.network.FriendlyByteBuf;
|
|||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
import net.minecraft.resources.Identifier;
|
import net.minecraft.resources.Identifier;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
|
||||||
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@LeavesProtocol.Register(namespace = "carpet")
|
@LeavesProtocol.Register(namespace = "carpet")
|
||||||
public class CarpetServerProtocol implements LeavesProtocol {
|
public class CarpetServerProtocol implements LeavesProtocol {
|
||||||
@@ -28,6 +32,9 @@ public class CarpetServerProtocol implements LeavesProtocol {
|
|||||||
|
|
||||||
private static final String HI = "69";
|
private static final String HI = "69";
|
||||||
private static final String HELLO = "420";
|
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")
|
@Contract("_ -> new")
|
||||||
public static Identifier id(String path) {
|
public static Identifier id(String path) {
|
||||||
@@ -44,21 +51,68 @@ public class CarpetServerProtocol implements LeavesProtocol {
|
|||||||
@ProtocolHandler.PayloadReceiver(payload = CarpetPayload.class)
|
@ProtocolHandler.PayloadReceiver(payload = CarpetPayload.class)
|
||||||
private static void handleHello(@NotNull ServerPlayer player, @NotNull CarpetServerProtocol.CarpetPayload payload) {
|
private static void handleHello(@NotNull ServerPlayer player, @NotNull CarpetServerProtocol.CarpetPayload payload) {
|
||||||
if (payload.nbt.contains(HELLO)) {
|
if (payload.nbt.contains(HELLO)) {
|
||||||
LOGGER.info("Player {} joined with carpet {}", player.getScoreboardName(), payload.nbt.getString(HELLO).orElse("Unknown"));
|
UUID playerId = player.getUUID();
|
||||||
CompoundTag data = new CompoundTag();
|
String carpetVersion = payload.nbt.getString(HELLO).orElse("Unknown");
|
||||||
CarpetRules.write(data);
|
player.getBukkitEntity().getScheduler().execute(MinecraftInternalPlugin.INSTANCE, () -> {
|
||||||
ProtocolUtils.sendPayloadPacket(player, new CarpetPayload(data));
|
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
|
@Override
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
return CarpetRules.hasRules();
|
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 {
|
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) {
|
public static void write(@NotNull CompoundTag tag) {
|
||||||
CompoundTag rulesNbt = new CompoundTag();
|
CompoundTag rulesNbt = new CompoundTag();
|
||||||
@@ -69,15 +123,25 @@ public class CarpetServerProtocol implements LeavesProtocol {
|
|||||||
|
|
||||||
public static void register(CarpetRule rule) {
|
public static void register(CarpetRule rule) {
|
||||||
rules.put(rule.name, rule);
|
rules.put(rule.name, rule);
|
||||||
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
rules.clear();
|
rules.clear();
|
||||||
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasRules() {
|
public static boolean hasRules() {
|
||||||
return !rules.isEmpty();
|
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) {
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user