Compare commits

...

177 Commits

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

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

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

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

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

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

* Add Vanilla-like experience config and updates

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

* Restore vanilla ender pearl loading on Folia

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

* Restore vanilla ender pearl loading

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

* remove extra import

* Add Precise mob cap and adjust ender pearl patch

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

* remove extra import

* pre merge config

* transform config

* merge config

* rebuild patches

* fix a bug in new counter

* simplify code

---------

Co-authored-by: Helvetica Volubi <suisuroru@blue-millennium.fun>
Co-authored-by: Helvetica Volubi <88063803+Suisuroru@users.noreply.github.com>
2026-07-02 18:11:12 +08:00
Helvetica Volubi 37c22202ab [ci skip] oops 2026-06-28 04:18:47 +08:00
Helvetica Volubi 2e67f978ec Update Luminol 2026-06-28 03:16:11 +08:00
Helvetica Volubi ed2f464914 fixup build 2026-06-25 18:12:18 +08:00
Helvetica Volubi 1cd09226f6 fixes #152 2026-06-25 17:49:55 +08:00
Helvetica Volubi 8cd8f4fbad Update Luminol 2026-06-25 17:48:52 +08:00
Bacteriawa e90c758a01 Lophine: add configs and update-suppression guards
Add Lophine-specific configuration support (global and carpet configs) and a temporary config transform step during init. Introduce config-controlled command registrations (function, scoreboard, trigger, tick) and enable tick-rate/command tweaks and an entity raytracing tracker flag. Fix datapack command save/listing behavior. Integrate Leaves update-suppression handling broadly: catch and convert update-suppression exceptions across packet handling, ticking, neighbor updates, block state updates and more; add configurable shulker CCE behavior and redstone upward-update compatibility. Provide an option to reintroduce an InstantNeighborUpdater (instant block updater) and other small compatibility/rebrand adjustments.
2026-06-23 01:35:57 +08:00
Helvetica Volubi e508462093 Update Luminol 2026-06-23 00:37:42 +08:00
dependabot[bot] b9c68a9b84 [ci skip]Bump actions/checkout from 6 to 7 (#153)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-20 16:36:49 +08:00
Helvetica Volubi 74d0b5ca5f Update Luminol & remove a unused config 2026-06-19 23:28:39 +08:00
Helvetica Volubi 4df4d07ae9 Merge the duplicate configuration items (#151)
* do not release & push repo before finished

* langs update

* updateSuppression config moved up

* redirect tick command option to carpet config system

* optimizedDragonRespawn

* diff in files

* counter rules transformed

* oops!

* some fakeplayer options moved up

* simplify

* creative no clip moved

* pre remove core module

* pre update luminol to further fix a bug that config not saved to real file

* fix up transform

* fix up transform

* fix up

* fix up some problem in PR

* redirect forgotten moved config

* fix bugs in PR

* refix

* switch for final merge
2026-06-15 20:27:41 +08:00
Helvetica Volubi cfc73efc9a Update Luminol 2026-06-14 18:43:18 +08:00
Helvetica Volubi 0989bcaec7 [ci skip]refactor: convert AbstractConcurrentTable to interface and update ConcurrentTable implementation 2026-06-13 01:19:56 +08:00
Helvetica Volubi 3763d0b885 Update clip & weight 2026-06-10 03:20:21 +08:00
Roberta001 cd3db4ae8c Fix bot connection region crash (#149)
* Fix: bot connection causing region crash, fix readme

* Fix NPE on Region Shutdown with bots

* simple fix up

* Revert "Fix NPE on Region Shutdown with bots"

This reverts commit b55c982cb9.

* Revert "fix: fix a bug in server shutdown with fakeplayer"

This reverts commit a721c27e96.

* fix: improve bot shutdown handling to prevent region crashes

---------

Co-authored-by: Helvetica Volubi <suisuroru@blue-millennium.fun>
2026-06-09 16:17:13 +08:00
Bacteriawa 11e9760eb3 Add validation and safety checks across protocols
Harden NBT/packet handling and add defensive checks across multiple protocols and utilities.

- ServerBot: Improved create-state NBT parsing, fill legacy fallbacks, validate skin list entries, and guard loading of saved actions/configs with try/catch and logged warnings.
- LeavesProtocolManager: Treat malformed payloads as rejected (INVALID_PAYLOAD), avoid throwing on decode failures, add safe bytebuf invocation with logging, and a selector description helper.
- REIServerProtocol: Enforce tag types and presence, validate indices and slot bounds, and improve error messages for malformed REI data.
- LitematicaSchematic: Validate schematic metadata (non-empty regions, palette), check region sizes and limit volume to a maximum, and avoid silent failures.
- ServuxLitematicsProtocol: Wrap Litematica paste handling in try/catch, notify player on invalid data, and log warnings.
- LitematicaBitArray: Validate array size/backing storage, prevent oversized backing arrays, and add index bounds checks.
- LitematicaBlockStatePalette: Improve error messaging for invalid palette entries.
- SchematicPlacement: Validate required tags (Schematics/Origin/SubRegion positions), use safe enum-by-ordinal lookup, and guard against null vanilla boxes when streaming chunk positions.
- CommunicationManager: Validate ordinals for rotation/mirror, limit sub-region modification counts, and catch/reject malformed Syncmatica packets with logging.

Overall this commit improves robustness by validating inputs, avoiding unhandled runtime exceptions from malformed or malicious data, and adding informative logs for rejected payloads.
2026-06-09 02:24:45 +08:00
Helvetica Volubi 13c5bd7331 Update Luminol to fix endportal teleport problem 2026-06-07 15:36:24 +08:00
Helvetica Volubi bbcc103643 Update Luminol 2026-06-06 22:10:57 +08:00
Helvetica Volubi a721c27e96 fix: fix a bug in server shutdown with fakeplayer 2026-06-06 04:48:38 +08:00
Helvetica Volubi 09011f05e6 Update Luminol 2026-06-05 16:31:04 +08:00
Helvetica Volubi b8692e23d2 [ci skip]remove some import in patches 2026-06-04 14:56:05 +08:00
Helvetica Volubi 1bb1811027 Add trigger command unsafe support 2026-06-04 01:02:14 +08:00
Helvetica Volubi a4936582bb [ci skip] switch to release
because of no code update, we will start release next commit
2026-06-04 00:53:49 +08:00
Helvetica Volubi fc760a047f port: port 1.21.11 changes, fix some bugs in lagFree (https://github.com/LuminolMC/Lophine/issues/145)
Origin Commit: 311fd32acb
2026-06-03 20:19:26 +08:00
Helvetica Volubi 5567b194d7 update file's sign & add update suppression event to Leaves Features Manager 2026-06-03 13:57:27 +08:00
Helvetica Volubi f6f2781237 enabled forgotten config sync 2026-06-03 13:25:28 +08:00
Bacteriawa f469ad848b Add MiniTweaks mob fire/explosion rules
Add a MiniTweaks patch that adjusts mob explosion and fire behavior and expose new config flags.

- Add patch file features/0043-MiniTweaks-mob-fire-and-explosion-rules.patch updating Creeper, LargeFireball and SmallFireball logic to consult config flags when deciding whether explosions break blocks or create fire.
- Add four new config options to GeneralCompatConfig: noCreeperBlockBreaking, noGhastBlockBreaking, disableBlazeFire, disableGhastFire.

These changes allow disabling creeper/ghast block breaking and suppressing blaze/ghast-caused fire while preserving existing explosion event handling.
2026-06-03 13:22:25 +08:00
Bacteriawa 924ab75f1d Remove Carpet features patches and protocols
Delete Carpet integration: remove luminol and minecraft Carpet feature patch files (1todos/server/luminol-patches/features/0006-Carpet-features.patch and 1todos/server/minecraft-patches/features/0044-Carpet-features.patch) and remove related protocol implementations (1todos/server/src/lophine/protocol/CarpetLoggerProtocol.java and 1todos/server/src/lophine/protocol/tiscm/TISCMProtocol.java). These files contained the Carpet feature backport/compat patches and protocol helpers; removing them cleans up the obsolete Carpet-specific changes.
2026-06-03 13:22:25 +08:00
Bacteriawa 1b2f577e42 Add Carpet features, update Leaves patches
Register a new lophine_carpet config and add Carpet feature patches and protocol classes. Adds luminol and minecraft Carpet feature patches, plus CarpetLoggerProtocol and TISCMProtocol Java files. Updates many Leaves-related patch files (metadata and authors/dates) and applies Leaves behaviour changes across numerous block classes (onRemove handling, affectNeighborsAfterRemoval wiring, Containers.dropContentsOnDestroy, etc.) to preserve pre-1.21.1 behaviour and compatibility. These changes enable Carpet integration and ensure Leaves patches are consistently applied across the codebase.
2026-06-03 13:22:24 +08:00
Helvetica Volubi 76c504e86f add new option for push repo (#148)
* ci test push repo - false

* ci test push repo - true

* ci test push repo - auto

* set to correct value
2026-06-03 01:55:40 +08:00
Helvetica Volubi 7ada14e6b6 Update Luminol 2026-06-03 00:56:30 +08:00
Helvetica Volubi 24965b48c5 old block behavior re-patched 2026-06-03 00:33:11 +08:00
Bacteriawa 5dab6a557b Add redstone & crash-fix configs; fix exception
Add RedStoneConfig (EXPERIMENT) with toggles for redstone update behaviors, CCE usage, instant block updater, and old block removal; add UpdateSuppressionCrashFixConfig (FIXES) to enable crash prevention. Fix UpdateSuppressionException: provideLevel and provideBlock now assign their fields only when those fields are currently null, ensuring the first-provided context is preserved and preventing unintended overwrites.
2026-06-02 22:59:40 +08:00
Bacteriawa e27300d2c2 Add Leaves update-suppression & redstone patches
Flip release flag to 0 and add multiple Leaves-related minecraft patches. These patches add broad UpdateSuppressionException handling (providing player/level/block context and consuming exceptions) across packet processing, ticking, entity events, chunk updates and redstone logic to avoid crashes and lost drops. Also add CCE-safe redstone handling, an opt-in redstone "ignore upwards" update, instant block updater selection, revert TrapDoorBlock Paper changes, preserve item drops when breaking blocks, and avoid resetting placed blocks on exception / suppressing block-entity crashes. Patches rely on config flags (e.g. UpdateSuppressionCrashFixConfig and RedStoneConfig) and introduce new patch files under lophine-server/minecraft-patches/features.
2026-06-02 20:56:23 +08:00
Helvetica Volubi cd665f0168 [ci skip] update clip 2026-05-26 22:40:41 +08:00
Helvetica Volubi aa07ef21ca Update Luminol 2026-05-26 01:25:35 +08:00
Helvetica Volubi d50ad73a17 global entities counter applied 2026-05-21 16:46:53 +08:00
Helvetica Volubi 0d794003bc Update Luminol 2026-05-21 14:45:32 +08:00
Helvetica Volubi 3856196543 Start Pre-release 26.1.2
some patches still not applied, need further update
2026-05-17 05:37:52 +08:00
Helvetica Volubi eff43b61ff fake player patches applied 2026-05-17 04:24:05 +08:00
Helvetica Volubi 06514362b8 protocols update
patches 28/44
2026-05-17 03:29:22 +08:00
Helvetica Volubi 5b94c79f39 patches 22/44 2026-05-17 02:46:52 +08:00
Helvetica Volubi 24a315a368 fix up ci 2026-05-11 11:30:05 +08:00
Helvetica Volubi 3d54e47c5e more patches - stage 16/44 2026-05-11 11:12:58 +08:00
Helvetica Volubi 6aadb1ca19 update Luminol 2026-05-11 10:27:28 +08:00
Helvetica Volubi 0a4a6baf70 update Luminol 2026-05-07 14:36:44 +08:00
Helvetica Volubi ee36fab64c apply patch: Leaves - Item overstack util 2026-05-04 22:44:14 +08:00
Helvetica Volubi e85db692f3 Update Luminol 2026-05-04 17:04:01 +08:00
Helvetica Volubi 9635e516dd more patches - stage 12/44 2026-05-04 00:57:49 +08:00
Helvetica Volubi d7e1b3a6bb more patches - stage 8/44 2026-05-04 00:20:54 +08:00
Helvetica Volubi 0fc9a1426d apply more patches 2026-05-03 16:45:10 +08:00
Helvetica Volubi 017e49da8a apply some patches 2026-05-03 00:30:08 +08:00
M2ke4U 42d870e32b Updated upstream & Ported some leaves patches & Fixed issues in gitignore
Signed-off-by: MrHua269 <mrhua269@gmail.com>
2026-05-02 23:09:13 +08:00
Helvetica Volubi 54ff033ef6 fix: fix up ci 2026-05-02 01:46:03 +08:00
Helvetica Volubi 9761fde77d baseline of 26.1.2
WARNING: no patch merged, we will start merge later

there are to many update between 1.21.11 and 26.1.2, so we need more time to build a base version which can stable to use
2026-05-02 00:46:03 +08:00
Helvetica Volubi e0d42cb1d3 Update Luminol 2026-05-01 23:12:36 +08:00
xiaoyueyoqwq 559b2e089a Fix Syncmatica modifier cleanup (#141)
Co-authored-by: xiaoyueyoqwq <xiaoyueyoqwq@users.noreply.github.com>
2026-05-01 23:07:35 +08:00
Helvetica Volubi a07649d14d [ci skip]update code from Leaves to fix some bug 2026-05-01 23:06:47 +08:00
Helvetica Volubi 6aa709cf75 [ci skip] fixup ci 2026-04-22 18:30:09 +08:00
Helvetica Volubi 6a452799cc feat: add full blocking load option for localized language support 2026-04-22 13:26:54 +08:00
Helvetica Volubi e17a3f2033 perf: some perform update && update Gradle wrapper to version 9.4.1 2026-04-22 01:40:07 +08:00
Helvetica Volubi 74ac0bccf5 fix: fix some function is not covered by core config 2026-04-14 00:41:54 +08:00
xiaoxijun f65b7f176b Carpet features (#134)
* Carpet features

* refactor(config): move up config

* refactor file

diff in file system

* Update Luminol

* move up - stage 1

* Revert "Update Luminol"

This reverts commit 6f02993bfe.

* move up - stage 2

* new carpet features

* upload docs

* stage - pre update

* [ci skip]Update Luminol

only update for dev branch, so skip ci

* remove blank

* feat:add carpet core config & move some function to config load stage

* remove some unused value & logic

* fix up

* Update Luminol

* fix up

* remove imports update

* add warning to carpet system if it is enabled

* Update Luminol

* use new function to sync config

* oops!

* Update Luminol

* fix up a bug

* refactor

* Update Luminol

* move up directory

* Update Luminol

* oops!

* refactor need

* feat: add CoreConfig to enable general rules in CarpetCompatSync

* modify some default value

* fix: enhance HUD logger subscriptions and improve player data handling

---------

Co-authored-by: Helvetica Volubi <suisuroru@blue-millennium.fun>
Co-authored-by: Helvetica Volubi <88063803+Suisuroru@users.noreply.github.com>
2026-04-13 19:45:35 +08:00
Helvetica Volubi 97a17dbf78 fix: update Luminol plugin versions in build configuration 2026-04-13 18:35:25 +08:00
Bacteriawa c5194eeb8f Update Luminol 2026-04-11 03:40:59 +08:00
Helvetica Volubi 58c5573421 fix: fix some crash problem 2026-04-08 09:49:45 +08:00
Helvetica Volubi 1907a41329 perf: some perform update for global entities counter 2026-04-08 09:15:55 +08:00
Helvetica Volubi 21cce73216 fix GlobalEntitiesCounter again 2026-04-07 20:25:57 +08:00
Helvetica Volubi 163a9902cc fix: fix mob despawn when player is away from all the player 2026-04-02 18:38:19 +08:00
Helvetica Volubi ba1216d4d3 Update Luminol 2026-03-30 00:08:27 +08:00
dependabot[bot] beb5cbeb52 [ci skip]Bump gradle/actions from 5 to 6 (#135)
Bumps [gradle/actions](https://github.com/gradle/actions) from 5 to 6.
- [Release notes](https://github.com/gradle/actions/releases)
- [Commits](https://github.com/gradle/actions/compare/v5...v6)

---
updated-dependencies:
- dependency-name: gradle/actions
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 18:41:16 +08:00
Helvetica Volubi 5cc4371833 Update Luminol 2026-03-26 08:50:42 +08:00
Helvetica Volubi 35f1e58d4d [ci skip]Update Luminol
only update for dev branch, so skip ci
2026-03-22 15:14:15 +08:00
Helvetica Volubi 690d7c2785 Update Luminol 2026-03-21 21:56:12 +08:00
Helvetica Volubi 115c9f8ee8 fix: try to fix a bug in syncmatica protocol 2026-03-19 19:00:17 +08:00
Helvetica Volubi faa3529943 feat: split timeout options to config file 2026-03-19 18:39:37 +08:00
Helvetica Volubi 3c3a2a6ff4 [ci skip] fixup 2026-03-16 18:09:49 +08:00
Helvetica Volubi 25776c7200 Update Luminol
我去,这个怎么没提交上
2026-03-16 16:39:26 +08:00
Helvetica Volubi 74e9d146e3 Update Luminol & adapt auto update system 2026-03-16 16:08:58 +08:00
Helvetica Volubi a8b2972e0e [ci skip] fix up a config transform flag 2026-03-14 01:38:42 +08:00
xiaoxijun ed3063a477 [ci skip]Update gradle.properties 2026-03-10 23:40:16 +08:00
Helvetica Volubi 85d2fa3372 feat: add Leaves' Creative Fly No Clip feature
fix #16
2026-03-09 00:13:34 +08:00
Helvetica Volubi b22e9e588b Update Luminol 2026-03-08 00:20:08 +08:00
Helvetica Volubi 90b751da5a Update Luminol 2026-03-03 20:55:18 +08:00
dependabot[bot] 7efeb48a7e [ci skip]Bump actions/upload-artifact from 6 to 7 (#133)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 16:29:34 +08:00
Helvetica Volubi e5cc20ba9b Update Luminol 2026-02-23 21:23:49 +08:00
Helvetica Volubi 46e7abe59c Update Luminol 2026-02-18 00:25:23 +08:00
Helvetica Volubi 40df6b9dfb Switch to release cannel
Update Luminol
2026-02-13 21:14:41 +08:00
Bacteriawa 5559fa8bcc Update Luminol 2026-02-13 16:21:55 +08:00
Helvetica Volubi 6319ddf78f [ci skip]update qodana (#131)
* qodana update test

use community version

* fix: update bug-report.yml and qodana.yaml for improved configuration clarity

* chore: configure Git user details for CI environment

* [ci skip]fix: update linter image in qodana.yaml to use community version

* fix: update linter and action versions to use latest releases

* Revert "chore: configure Git user details for CI environment"

This reverts commit e53b12ac49.

* fix: update qodana.yaml to exclude all files instead of just JavaFiles

* Revert "qodana update test"

This reverts commit 4aac78cb72.

* [ci skip]fix: update .gitignore and qodana.yaml for project structure changes
2026-02-08 01:20:10 +08:00
Bacteriawa e74300a756 Fix Server crash when using CCE #109 2026-02-08 00:02:31 +08:00
Bacteriawa d9674b4e7c Update Luminol 2026-02-07 23:20:40 +08:00
Helvetica Volubi 6d02f00ac0 Update Luminol to fix #127
fixes #127
2026-01-30 19:47:50 +08:00
Helvetica Volubi 2960e7d24f perf: add cache for replay api 2026-01-28 22:45:50 +08:00
Helvetica Volubi d950c6d3e8 Update Luminol 2026-01-26 23:48:23 +08:00
Helvetica Volubi 357c351b95 fix up version fetcher 2026-01-22 00:59:08 +08:00
Helvetica Volubi a780b13fcc Update Luminol 2026-01-21 21:37:37 +08:00
Helvetica Volubi cf80fc6a86 Update Luminol 2026-01-18 03:31:10 +08:00
Helvetica Volubi 20acc9ccf5 feat: add save-all support 2026-01-16 02:41:01 +08:00
Helvetica Volubi e49ab25111 simply fix for replay api
fixed https://github.com/MC-XiaoHei/ISeeYou/issues/70
2026-01-14 01:57:42 +08:00
Helvetica Volubi eed4457419 add removed check before all checks start in addEffects 2026-01-13 21:06:48 +08:00
Helvetica Volubi 429a0345d9 refactor(bot): delay some logic of extra load in fakeplayer spawn 2026-01-13 20:47:55 +08:00
Helvetica Volubi 670d4e39c9 Update Luminol 2026-01-13 19:30:32 +08:00
Helvetica Volubi 5d4ddb9a6b fix #124 (refix of #121) 2026-01-09 19:10:28 +08:00
Helvetica Volubi 0ad90dc36e Update Luminol 2026-01-07 17:13:18 +08:00
Helvetica Volubi 284810dfb8 fixes #121 2026-01-04 17:51:09 +08:00
Helvetica Volubi 0f67f445b9 Update Luminol 2026-01-04 12:32:42 +08:00
Helvetica Volubi 018cc61204 Update Luminol 2026-01-03 13:59:49 +08:00
Helvetica Volubi b9c3d8deea fix ender dragon caused server crash 2026-01-03 01:40:35 +08:00
Helvetica Volubi 0d5b289d65 Update Luminol 2026-01-03 01:04:31 +08:00
Helvetica Volubi 5b20ad2e2c Update Luminol 2025-12-29 23:39:50 +08:00
Helvetica Volubi 9fcce731d0 Update Luminol 2025-12-29 01:28:30 +08:00
Helvetica Volubi 0783c97224 Update Protocols from Leaves 2025-12-28 00:29:37 +08:00
Helvetica Volubi 300e891906 Update Luminol 2025-12-27 23:42:13 +08:00
Helvetica Volubi a3e0a3ee1a Update Wool Counter & FakePlayer code from Leaves 2025-12-27 20:39:17 +08:00
Helvetica Volubi b3703e2069 fix a bug in way point 2025-12-27 20:36:30 +08:00
Helvetica Volubi d3c8da4edb Update Luminol 2025-12-27 17:16:52 +08:00
Helvetica Volubi bed0bfff06 fix: refix waypoint
related issue: https://github.com/LuminolMC/Lophine/issues/110
2025-12-26 03:38:04 +08:00
Helvetica Volubi 238231b28b Update Luminol 2025-12-26 03:28:41 +08:00
Helvetica Volubi db772aaf62 fix: fix waypoint module 2025-12-23 10:07:28 +08:00
Helvetica Volubi b1bee59e6c Update Luminol 2025-12-23 10:06:50 +08:00
Helvetica Volubi a9d24bd32c Update Luminol 2025-12-21 01:31:40 +08:00
dependabot[bot] f299d5188d [ciskip]build(deps): bump JetBrains/qodana-action from 2025.2 to 2025.3 (#108)
Bumps [JetBrains/qodana-action](https://github.com/jetbrains/qodana-action) from 2025.2 to 2025.3.
- [Release notes](https://github.com/jetbrains/qodana-action/releases)
- [Commits](https://github.com/jetbrains/qodana-action/compare/v2025.2...v2025.3)

---
updated-dependencies:
- dependency-name: JetBrains/qodana-action
  dependency-version: '2025.3'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-21 01:30:55 +08:00
Helvetica Volubi bbcc85fa93 1.21.11 Early Access
waypoint has force disabled because of some serious bug
2025-12-18 09:42:25 +08:00
Helvetica Volubi c26d8d1ee3 [ci skip]before we start to update to 1.21.11, we need push to maven repo 2025-12-18 03:43:04 +08:00
Helvetica Volubi 7bc12d2487 fix: add null check in RegionizedWorldData >> conections
some of our function patches will crash because of get null in conn.getPlayer(), then when we process player.chunkPosition() will get NPE, so we need to fix it.
2025-12-17 00:26:36 +08:00
dependabot[bot] 2c3aa4b68e [ci skip]build(deps): bump actions/upload-artifact from 5 to 6 (#106)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 15:44:44 +08:00
Bacteriawa 91312b7a15 Update Luminol 2025-12-14 00:18:07 +08:00
Helvetica Volubi 77c412bfe8 feat: update concurrent in waypoint 2025-12-11 02:05:57 +08:00
Helvetica Volubi c06d875df7 feat: add optimized concurrent table for waypoint management 2025-12-10 15:22:58 +08:00
Helvetica Volubi 5e96851513 fix a bug in entities counter 2025-12-10 02:52:55 +08:00
Helvetica Volubi 91b3ad527c fix waypoint manager
we use thread safe method to load it
2025-12-10 01:49:10 +08:00
dependabot[bot] 959a1c346c [ci skip]build(deps): bump actions/checkout from 3 to 6 (#102)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 15:51:58 +08:00
Helvetica Volubi b594382a6a [ci skip] fixup ci 2025-12-07 19:06:04 +08:00
Helvetica Volubi 37f1b4e5f1 fix: fix some async bugs 2025-12-07 18:42:46 +08:00
mrhua269 af2af944bf Fix issues of photographer with folia region threading 2025-12-06 23:25:37 +08:00
mrhua269 54688d8e34 Fix issues of fakeplayer with folia region threading 2025-12-06 22:35:51 +08:00
Helvetica Volubi 7b7f0b6d1f [ci skip] fix up branch in qodana 2025-12-06 21:58:02 +08:00
Helvetica Volubi 0ab3983145 Update Luminol
We need to check folia-supported,so we update it now
2025-12-06 16:52:56 +08:00
Helvetica Volubi 24a9d5cea8 fix https://github.com/MC-XiaoHei/ISeeYou/issues/68#issuecomment-3619619509 2025-12-06 15:45:34 +08:00
Helvetica Volubi 8ee77c3354 [ci skip] remove unused check
we have checked in protocol manager
2025-12-06 15:45:12 +08:00
qodana-cloud[bot] 98df254bad [ci skip]Add qodana CI checks (#100)
* Add qodana.yaml file

* Add github workflow file

---------

Co-authored-by: Qodana Application <qodana-support@jetbrains.com>
2025-12-04 14:19:47 +08:00
Helvetica Volubi 19f001ad1b [ci skip] remove unused data 2025-12-04 14:05:46 +08:00
Helvetica Volubi 106dfeaa38 fix: fix global entity count max limit problem 2025-12-04 13:37:48 +08:00
Helvetica Volubi 403ae2b2d0 feat: chunkCount 2025-12-04 12:13:14 +08:00
Helvetica Volubi 96c99519d5 fix: fix an async bug
if latest task is not done, skip this tick so that we can not block thread and run the task have not done, after it done, the new data will be processed in the next tick
2025-12-03 20:33:13 +08:00
Helvetica Volubi 5c4031b836 [ci skip] fixup template & comment 2025-12-03 20:20:59 +08:00
Helvetica Volubi 376857ff97 feat: global entities counter
We provided a new way to use entities counter to spawn mobs, maybe have some bugs, so we set this to experiment config

 - Update file update
 - Update Luminol
2025-12-03 16:31:34 +08:00
Helvetica Volubi fa1ab90579 fix a ConcurrentModificationException caused by ServuxStructuresProtocol
Update Luminol
2025-11-30 15:53:28 +08:00
Creeam fc9c6937b6 Add LeavesConfig dummy class (#99)
For some plugin detections
2025-11-30 07:28:01 +00:00
Helvetica Volubi 12d8ba9050 Update Luminol 2025-11-29 06:03:01 +08:00
Helvetica Volubi 38a1ce0443 fix: fix crash caused by uncheck data access 2025-11-26 22:32:20 +08:00
dependabot[bot] a5a415e495 build(deps): bump actions/checkout from 5 to 6 (#93)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 08:21:49 +00:00
Helvetica Volubi b7bf1b5916 Update Luminol 2025-11-24 00:16:50 +08:00
Helvetica Volubi 4a8888c578 try fixes bugs caused by Bukkit.getScheduler().runTaskLater
we use (FoliaGlobalRegionScheduler.GlobalScheduledTask) Bukkit.getGlobalRegionScheduler().runDelayed to instead of Bukkit.getScheduler().runTaskLater, and we also provided a brand-new way to cancel task by task id
2025-11-22 01:57:16 +08:00
Helvetica Volubi 2c59a32afe [ci skip] Update context 2025-11-20 15:36:46 +08:00
Helvetica Volubi cc5382977d Update Luminol 2025-11-20 15:32:41 +08:00
xiaoxijun c07dde1c0b feat: CCE Update Suppression support and other dependences (#84)
add cce update suppression & prevent crashes caused by update suppres & dustTrapdoorReintroduced & instantBlockUpdater & old Block remove behaviour & do not reset placed block on exception & do not prevent block entity and entity crash at LevelChunk (#84)

* add cce update suppression & prevent crashes caused by update suppression

* no need for this transformed flag

* Add Redstone ignore upwards update

* fix up license

* move config

* instant Block Updater

* feat: Update Suppression!

* Leaves: Do not reset placed block on exception & Do not prevent block entity and entity crash at LevelChunk

---------

Co-authored-by: Helvetica Volubi <suisuroru@blue-millennium.fun>
Co-authored-by: Helvetica Volubi <88063803+Suisuroru@users.noreply.github.com>
2025-11-19 00:04:34 +08:00
Helvetica Volubi 871a003a2e Update Luminol to fix open-gui bug 2025-11-17 17:54:27 +08:00
Helvetica Volubi d6a981a6e9 [ci skip] skip release and push in unexpect branch
See https://github.com/LuminolMC/Luminol/commit/ec746a66f0813f60eb59de11b8207f773fc4728c
2025-11-17 17:26:24 +08:00
Helvetica Volubi bc166a9fb6 [ci skip] refactor code 2025-11-16 21:22:06 +08:00
Helvetica Volubi feebf388f8 Add Replay Api (#86)
* feat: base replay api support

* fix an async bug
2025-11-16 21:05:01 +08:00
Helvetica Volubi dbcf764e76 fix ServuxStructuresProtocol (#89)
* Add LeaveHooks to fix bug caused by servux structures protocol

* add missing file

* add comment

* add license
2025-11-16 20:51:19 +08:00
Helvetica Volubi 735fe8855a try to fix a bug in fake player spawn 2025-11-16 18:53:16 +08:00
Helvetica Volubi 1b45a090f6 Update Luminol 2025-11-16 14:09:42 +08:00
Helvetica Volubi bb1335d390 [ci skip] Update Luminol
do not release yet, release at next commit
2025-11-15 15:38:52 +08:00
Helvetica Volubi 00743c841f Update Luminol 2025-11-14 22:27:06 +08:00
xiaoxijun bdb9c9dec4 Add Alternative block placement Protocol (#81)
* Add Alternative block placement Protocol

* fix: fix config error caused by config system

- TODO: fix config system read enum bug in luminol

* remove Leaves logger & use mojang logger

* update code from leaves

---------

Co-authored-by: Helvetica Volubi <suisuroru@blue-millennium.fun>
Co-authored-by: Helvetica Volubi <88063803+Suisuroru@users.noreply.github.com>
2025-11-12 19:15:21 +08:00
Helvetica Volubi ac3653dda7 [ci skip]Update Gradle wrapper to version 9.2.0 2025-11-12 00:56:44 +08:00
Helvetica Volubi a08fd04751 Update Luminol to fix a sentry bug 2025-11-12 00:20:46 +08:00
Helvetica Volubi f5debe9ee1 [ci skip] Update Luminol 2025-11-10 17:27:08 +08:00
303 changed files with 14660 additions and 4335 deletions
+17 -3
View File
@@ -1,7 +1,7 @@
name: Bug反馈 Bug report
description:
报告Bug,插件不兼容情况,以及其他相关问题。
Report issues with plugin incompatbility or other behavior related issues.
Report issues with plugin incompatibility or other behavior related issues.
labels:
- bug
- pending
@@ -25,7 +25,7 @@ body:
LophineMC服务端发行版本 LophineMC server release version (contains the git commit's hash)<br>
通过执行`/version`命令将获取到的内容复制到这里。 Run `/version` on your server and paste the full, unmodified output here.
placeholder: >
e.g. git-Lophine-"0635a89" (MC: 1.20.4)
e.g. git-Lophine-"fa1ab90" (MC: 1.21.8)
validations:
required: true
- type: textarea
@@ -41,7 +41,7 @@ body:
attributes:
label: 观测到的实际行为 Observed/Actual behavior
description: 你实际看到的。 What you actually saw.
placeholder: e.g. 使用 /tpsbar [NAME] 命令切换不了TPSBAR
placeholder: e.g. 使用 /tpsbar 命令切换不了TPSBAR
validations:
required: true
- type: textarea
@@ -65,6 +65,20 @@ body:
To list plugins, run `/plugins`. For datapacks, run `/datapack list`.
validations:
required: true
- type: textarea
id: config-file-list
attributes:
label: 配置文件列表(如果可以)。 Config File List (if possible).
description:
服务器上的配置文件列表。
All config files on your server.
例如以下文件(或者文件夹):
Example files (or folders)
- \spigot.yml
- \bukkit.yml
- \config\\\*
- \lophine_config\\\*
- \luminol_config\\\*
- type: textarea
id: other
attributes:
+1 -1
View File
@@ -28,7 +28,7 @@ body:
validations:
required: true
- type: textarea
id: othre
id: other
attributes:
label: 其他 Other
description: 添加其他的信息。 Add any other context or screenshots about the feature request below.
+29 -14
View File
@@ -10,11 +10,11 @@ on:
workflow_dispatch:
inputs:
force-release:
description: "Force disable release if you enter 2, force release if you enter 1, default release if not released else skip release"
description: "Force disable release if you enter false, force release if you enter true, default release if not released else skip release"
required: false
default: ""
force-push:
description: "Force disable push to repo if you enter 2, push to repo if you enter 1, default push if not released else skip push repo"
description: "Force disable push to repo if you enter false, force push to repo if you enter true, default push if not released else skip push repo"
required: false
default: ""
comments:
@@ -28,18 +28,20 @@ jobs:
build:
runs-on: ubuntu-latest
environment: default
env:
BUILD_NUMBER: ${{ github.run_number }}
steps:
- name: Checkout Git Repository
uses: actions/checkout@v5
uses: actions/checkout@v7
- name: Set Up JDK
uses: actions/setup-java@v5
with:
distribution: zulu
java-version: 21
java-version: 25
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
uses: gradle/actions/setup-gradle@v6
- name: Grant execute permission for gradlew
run: chmod +x gradlew
@@ -51,13 +53,13 @@ jobs:
run: ./gradlew --refresh-dependencies applyAllPatches
- name: Build Paperclip Jar
run: ./gradlew --refresh-dependencies createMojmapPaperclipJar
run: ./gradlew --refresh-dependencies createPaperclipJar
- name: Upload Artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: ${{ env.project_id_b }} CI Artifacts
path: lophine-server/build/libs/*-paperclip-*-mojmap.jar
path: lophine-server/build/libs/*-paperclip-*.jar
- name: Set Environment
if: github.event_name != 'pull_request'
@@ -81,11 +83,23 @@ jobs:
done
echo "tag=${{ env.tag }}-${counter}" >> $GITHUB_ENV
echo "release_count= - ${counter}" >> $GITHUB_ENV
release_exists=false
fi
echo "release_exists=${release_exists}" >> $GITHUB_ENV
- name: Check If Branch In Expectations
if: github.event_name != 'pull_request' && env.flag_release == 'true'
run: |
if [[ "$GITHUB_REF_NAME" == ver/* ]] || [[ "$GITHUB_REF_NAME" == exp/* ]] || [[ "$GITHUB_REF_NAME" == dev/* ]]; then
echo "Branch is in expected prefixes"
echo "unexpect=false" >> $GITHUB_ENV
else
echo "Branch is NOT in expected prefixes"
echo "unexpect=true" >> $GITHUB_ENV
fi
- name: Publish To Repo
if: (( github.event_name != 'pull_request' && env.flag_release == 'true' && env.release_exists != 'true' && !(inputs.force-push == '2')) || inputs.force-push == '1') && false # do not push to any repo
if: ( github.event_name != 'pull_request' && !( env.unexpect == 'true' ) && env.flag_push_repo == 'true' && !( inputs.force-push == 'false' )) || inputs.force-push == 'true'
continue-on-error: true
run: ./gradlew --refresh-dependencies generateDevelopmentBundle publish -PpublishDevBundle=true
env:
@@ -93,13 +107,14 @@ jobs:
PRIVATE_MAVEN_REPO_USERNAME: ${{ secrets.PRIVATE_MAVEN_REPO_USERNAME }}
- name: Create Release - Pre Process
if: ( github.event_name != 'pull_request' && env.flag_release == 'true' && env.release_exists != 'true' && !(inputs.force-release == '2')) || inputs.force-release == '1'
if: ( github.event_name != 'pull_request' && !( env.unexpect == 'true' ) && env.flag_release == 'true' && env.release_exists != 'true' && !(inputs.force-release == 'false')) || inputs.force-release == 'true'
run: |
if [ ${{ inputs.comments }} == "" ]; then
echo "No comments provided"
echo "flag_comment=true" >> $GITHUB_ENV
if [ "${{ inputs.comments }}" == "" ]; then
echo "No comments provided"
echo "flag_comment=false" >> $GITHUB_ENV
else
echo "flag_comment=false" >> $GITHUB_ENV
echo "Comments provided: ${{ inputs.comments }}"
echo "flag_comment=true" >> $GITHUB_ENV
fi
- name: Create Release - No Comment
+29
View File
@@ -0,0 +1,29 @@
name: Qodana
on:
workflow_dispatch:
pull_request:
push:
branches: # Specify your branches here
- ver/* # Stable branch
- exp/* # Experimental branch
- dev/* # Development Branch
jobs:
qodana:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
checks: write
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit
fetch-depth: 0 # a full history is required for pull request analysis
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@latest
with:
pr-mode: false
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN_1658551725 }}
QODANA_ENDPOINT: 'https://qodana.cloud'
+2 -4
View File
@@ -6,12 +6,10 @@ build
/run
/lightingluminol-server/build.gradle.kts
/lightingluminol-api/build.gradle.kts
/luminol-server/build.gradle.kts
/lophine-server/build.gradle.kts
/lophine-api/build.gradle.kts
/luminol-server/src/minecraft
/paper-server
/luminol-api/build.gradle.kts
/paper-api
/paper-api-generator
+6 -6
View File
@@ -45,7 +45,7 @@ git clone https://github.com/LuminolMC/Lophine.git
cd Lophine
# 应用补丁并构建 Paperclip JAR
./gradlew applyAllPatches && ./gradlew createMojmapPaperclipJar
./gradlew applyAllPatches && ./gradlew createPaperclipJar
```
构建完成后,您可以在 `lophine-server/build/libs` 目录中找到生成的 JAR 文件。
@@ -57,12 +57,12 @@ cd Lophine
```kotlin
repositories {
maven {
url = "https://repo.menthamc.org/repository/maven-public/"
url = "https://repo.bacteriawa.com/repository/maven-public/"
}
}
dependencies {
compileOnly("me.earthme.luminol:luminol-api:$VERSION")
compileOnly("fun.bm.lophine:lophine-api:$VERSION")
}
```
@@ -71,14 +71,14 @@ dependencies {
```xml
<repositories>
<repository>
<id>menthamc</id>
<url>https://repo.menthamc.org/repository/maven-public/</url>
<id>repository</id>
<url>https://repo.bacteriawa.com/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>me.earthme.luminol</groupId>
<groupId>fun.bm.lophine</groupId>
<artifactId>luminol-api</artifactId>
<version>$VERSION</version>
</dependency>
+6 -6
View File
@@ -45,7 +45,7 @@ git clone https://github.com/LuminolMC/Lophine.git
cd Lophine
# Apply patches and build Paperclip JAR
./gradlew applyAllPatches && ./gradlew createMojmapPaperclipJar
./gradlew applyAllPatches && ./gradlew createPaperclipJar
```
After building, you can find the generated JAR file in the `lophine-server/build/libs` directory.
@@ -57,12 +57,12 @@ After building, you can find the generated JAR file in the `lophine-server/build
```kotlin
repositories {
maven {
url = "https://repo.menthamc.org/repository/maven-public/"
url = "https://repo.bacteriawa.com/repository/maven-public/"
}
}
dependencies {
compileOnly("me.earthme.luminol:luminol-api:$VERSION")
compileOnly("fun.bm.lophine:lophine-api:$VERSION")
}
```
@@ -71,14 +71,14 @@ dependencies {
```xml
<repositories>
<repository>
<id>menthamc</id>
<url>https://repo.menthamc.org/repository/maven-public/</url>
<id>repository</id>
<url>https://repo.bacteriawa.com/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>me.earthme.luminol</groupId>
<groupId>fun.bm.lophine</groupId>
<artifactId>luminol-api</artifactId>
<version>$VERSION</version>
<scope>provided</scope>
+11 -8
View File
@@ -3,14 +3,17 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent
plugins {
java // TODO java launcher tasks
id("moe.luminolmc.hyacinthusweight.patcher") version "+" // Automatically pulls the latest
id("moe.luminolmc.hyacinthusweight.patcher")
}
paperweight {
filterPatches = false
upstreams.register("luminol") {
repo = github("LuminolMC", "Luminol")
ref = providers.gradleProperty("luminolRef")
println("Upstream commit ref: " + ref.get())
patchFile {
path = "luminol-server/build.gradle.kts"
outputFile = file("lophine-server/build.gradle.kts")
@@ -41,7 +44,7 @@ paperweight {
}
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
val menthaMavenPublicUrl = "https://repo.menthamc.org/repository/maven-public/";
val bacteriawaMavenPublicUrl = "https://repo.bacteriawa.com/repository/maven-public/";
subprojects {
apply(plugin = "java-library")
@@ -49,14 +52,14 @@ subprojects {
extensions.configure<JavaPluginExtension> {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
languageVersion = JavaLanguageVersion.of(25)
}
}
repositories {
mavenCentral()
maven(paperMavenPublicUrl)
maven(menthaMavenPublicUrl)
maven(bacteriawaMavenPublicUrl)
}
dependencies {
@@ -69,7 +72,7 @@ subprojects {
}
tasks.withType<JavaCompile>().configureEach {
options.encoding = Charsets.UTF_8.name()
options.release = 21
options.release = 25
options.isFork = true
}
tasks.withType<Javadoc>().configureEach {
@@ -88,8 +91,8 @@ subprojects {
extensions.configure<PublishingExtension> {
repositories {
maven("https://repo.menthamc.org/repository/maven-snapshots/") {
name = "MenthaMC"
maven("https://repo.bacteriawa.com/repository/maven-releases/") {
name = "Bacteriawa"
credentials(PasswordCredentials::class) {
username = System.getenv("PRIVATE_MAVEN_REPO_USERNAME")
password = System.getenv("PRIVATE_MAVEN_REPO_PASSWORD")
@@ -106,4 +109,4 @@ subprojects {
}
}
}
}
}
+89
View File
@@ -0,0 +1,89 @@
### Carpet 原版
| 规则 | 状态 | 说明 |
| --- | --- | --- |
| `language` | 已映射 | 转发到 `lophine.function.language.lang` |
| `commandTick` | 已映射 | 转发到现有的 tick 指令补丁 |
| `creativeNoClip` | 已映射 | 转发到 Lophine 的创造飞行穿墙实现 |
| `ctrlQCraftingFix` | 结构等价 | 当前的合成与切石机菜单已经自带修复后的 Ctrl+Q 结果槽丢弃行为 |
| `placementRotationFix` | 已移植 | 放置朝向判断可使用玩家身体朝向而不是头部旋转 |
| `tntDoNotUpdate` | 已移植 | 新放置的 TNT 不会再因放置时更新而自动点燃 |
| `explosionNoBlockDamage` | 已移植 | 爆炸仍会伤害实体,但不会破坏方块 |
| `interactionUpdates` | 已移植 | 玩家交互和破坏方块时可以在不触发邻居更新与形状更新的情况下运行 |
| `xpNoCooldown` | 已移植 | 经验球可以在同一 tick 内被连续吸收,不再有拾取冷却 |
| `viewDistance` | 已移植 | 专用服务器启动视距会被兼容配置覆盖 |
| `fastRedstoneDust` | 已移植 | 规则启用时,红石粉更新会统一走 Alternate Current 快速更新后端 |
| `lagFreeSpawning` | 已移植 | 自然生成会使用轻量碰撞检查与预构造实体路径 |
| `defaultLoggers` | 已移植 | 按 Carpet 默认订阅语义为玩家启用 HUD logger,当前支持 `tps``mobcaps``counter` |
| `commandPlayer` | 已映射 | 当前由同一套 `/bot` 假人能力承接 |
| `hopperCounters` | 已映射 | 转发到 Lophine 的羊毛漏斗计数器 |
### Carpet TIS Addition
| 规则 | 状态 | 说明 |
| --- | --- | --- |
| `yeetUpdateSuppressionCrash` | 已映射 | 转发到同一套 Lophine 崩溃修复逻辑 |
| `dustTrapdoorReintroduced` | 已映射 | 转发到 `lophine.experiment.redstone.redstone-ignore-upwards-update` |
| `shulkerBoxCCEReintroduced` | 已映射 | 转发到 `lophine.experiment.redstone.cce-update-suppression` |
| `instantBlockUpdaterReintroduced` | 已映射 | 转发到 `lophine.experiment.redstone.instant-block-updater` |
| `optimizedDragonRespawn` | 已映射 | 转发到 Luminol 的末影龙重生优化 |
| `antiSpamDisabled` | 已移植 | 在 `ServerGamePacketListenerImpl` 中关闭聊天和创造丢物防刷屏限制 |
| `blockPlacementIgnoreEntity` | 已移植 | 创造模式放置方块时忽略实体碰撞检查 |
| `creativeOpenContainerForcibly` | 已移植 | 创造玩家可以强制打开被阻挡的箱子、末影箱和潜影盒 |
| `observerNoDetection` | 已移植 | 观察者的检测触发会在发出脉冲前被取消 |
| `creativeNoItemCooldown` | 已移植 | 创造玩家不会应用物品冷却 |
| `totallyNoBlockUpdate` | 已移植 | 邻居更新和形状更新会在 `NeighborUpdater` 中被统一短路 |
| `tiscmNetworkProtocol` | 已移植 | 原生 `tiscm:network/v1` 握手与数据包协商已经通过专用 Leaves 协议接入 |
| `optimizedTNTHighPriority` | 结构等价 | 当前 `ServerExplosion` 路径已经运行在优化过的服务端爆炸实现上 |
| `tntIgnoreRedstoneSignal` | 已移植 | TNT 在自动点燃判断时忽略红石信号 |
| `tntDupingFix` | 已移植 | 活塞复制 TNT 的路径现在由 `PistonBaseBlock` 中的兼容规则直接控制 |
| `clientSettingsLostOnRespawnFix` | 已移植 | 玩家上一次的客户端设置会在 `ServerPlayer.restoreFrom` 中恢复 |
| `entityInstantDeathRemoval` | 已移植 | 已死亡生物不会再保留原版的 20gt 延迟,而是立即移除 |
| `farmlandTrampledDisabled` | 已移植 | 耕地不会再因实体踩踏而变回泥土 |
| `yeetOutOfOrderChatKick` | 已移植 | 乱序的签名聊天不会再破坏安全聊天链 |
| `tickCommandPermission` | 已移植 | `/tick` 的权限等级可通过兼容配置调整 |
| `tickFreezeCommandToggleable` | 已移植 | 已冻结时再次执行 `/tick freeze` 会切换回运行状态 |
| `syncServerMsptMetricsData` | 已移植 | 实时 MSPT 样本会通过原生 TISCM 协议通道广播 |
| `microTiming` | 结构等价 | 当前 Folia 的区块级性能分析与计时钩子已经提供对应的服务端观测能力 |
| `optimizedFastEntityMovement` | 结构等价 | Moonrise/Paper 的快速实体移动碰撞优化已经是基础运行时的一部分 |
| `optimizedHardHitBoxEntityCollision` | 结构等价 | Moonrise/Paper 的硬碰撞箱实体碰撞优化已经是基础运行时的一部分 |
| `tntFuseDuration` | 已移植 | 可配置的 TNT 引信时长已接入 NMS TNT 逻辑 |
| `fakePlayerTicksLikeRealPlayer` | 已映射 | 转发到 Leaves 的假人网络阶段 tick 行为 |
| `hopperCountersUnlimitedSpeed` | 已映射 | 转发到不限速计数器模式 |
### Carpet Org Addition
| 规则 | 状态 | 说明 |
| --- | --- | --- |
| `hopperNoItemCost` | 已移植 | 漏斗上方放置羊毛时,可在传输后恢复被推出的物品堆,实现零消耗供给线 |
| `simpleInGameCalculator` | 已移植 | 以 `=` 开头的聊天内容会作为简单计算表达式私聊回复 |
### Carpet AMS Addition
| 规则 | 状态 | 说明 |
| --- | --- | --- |
| `amsUpdateSuppressionCrashFix` | 已映射 | 转发到 Lophine 现有的更新抑制崩溃修复 |
| `creativeOneHitKill` | 已移植 | 创造玩家可通过 `Player.attack` 瞬间击杀附近符合条件的目标 |
| `bambooModelNoOffset` | 已移植 | 竹子和竹笋始终返回零模型偏移 |
| `carpetAlwaysSetDefault` | 结构等价 | 兼容配置默认值已经会在 `ConfigsInstance.preLoadConfig` 中被写入 |
| `powerfulExpMending` | 已移植 | 经验拾取会修复玩家整个背包内所有受损的经验修补物品 |
| `sensibleEnderman` | 已移植 | 末影人仅会在规则开启时拾取南瓜和西瓜 |
| `shulkerGolem` | 已移植 | 潜影盒上方放置雕刻南瓜时可以召唤潜影贝 |
| `preventEndSpikeRespawn` | 已移植 | 末影龙重生时会跳过黑曜石柱重建和柱顶水晶重建 |
| `betterCraftableBoneBlock` | 已移植 | 向配方管理器注入 AMS 的替代骨块配方 |
| `betterCraftableDispenser` | 已移植 | 向配方管理器注入 AMS 的替代发射器配方 |
| `fakePlayerDefaultSurvivalMode` | 已移植 | 新创建的假人可以被强制设为生存模式,而不是沿用服务器默认游戏模式 |
| `fakePlayerInteractLikeClient` | 已移植 | 假人与盔甲架交互时会先按真实客户端方式回退,再进入普通实体交互 |
| `fakePlayerAutoReplenishmentFormShulkerBox` | 已移植 | 假人自动补货现在可以从背包里的潜影盒中抽取匹配物品 |
### Lophine 扩展承接
| 规则 | 状态 | 说明 |
| --- | --- |----------------------------------|
| `commandBot` | 已映射 | 启用 Lophine `/bot` |
| `fakePlayerResident` | 已映射 | 转发到 Lophine 的假人常驻模式 |
| `openFakePlayerInventory` | 已映射 | 转发到 Lophine 的假人背包打开功能 |
| `fakePlayerAutoReplaceTool` | 已映射 | 为现有自动换工具逻辑增加了新开关 |
| `fakePlayerAutoReplenishment` | 已映射 | 为现有自动补货逻辑增加了新开关 |
| `fakePlayerReloadAction` | 已映射 | 为假人动作持久化增加了新开关 |
| `fakePlayerAutoFish` | 已移植 | 手持鱼竿的假人会自动抛竿和收杆,除非显式执行 `fish` 动作 |
+10 -5
View File
@@ -1,10 +1,15 @@
group=fun.bm.lophine
version=1.21.8-R0.1-SNAPSHOT
mcVersion=1.21.8
release=2
# 0 for skip release, 1 for pre-release, 2 for release
mcVersion=26.1.2
apiVersion=26.1.2
channel=STABLE
clipVersion=3.0.18
weightVersion=2.0.15
# true for release, false for skip release, pre for pre-release
release=true
# true for push to repo, false for skip push repo, auto for detect by release value
pushRepo=auto
luminolRef=a34046ee4c3bd7d350ebf30be16729ef90b64ce4
luminolRef=b796645fdaae7d6b3d3c84fd79f9c090a6458a48
org.gradle.configuration-cache=true
org.gradle.caching=true
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+1 -1
View File
@@ -1,6 +1,6 @@
--- a/luminol-api/build.gradle.kts
+++ b/luminol-api/build.gradle.kts
@@ -103,20 +_,24 @@
@@ -104,20 +_,24 @@
srcDir(generatedDir)
srcDir(file("../paper-api/src/main/java"))
srcDir(file("../folia-api/src/main/java"))
@@ -0,0 +1,21 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 11 May 2026 10:47:42 +0800
Subject: [PATCH] Add cancel task by task id in FoliaGlobalRegionScheduler
diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java
index 57455aca80ecc458b96b44c086cea94ddcecae47..763d27d303b9a588526445c453e07f5886534e82 100644
--- a/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java
+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java
@@ -55,4 +55,10 @@ public interface GlobalRegionScheduler {
* @param plugin Specified plugin.
*/
void cancelTasks(@NotNull Plugin plugin);
+
+ /**
+ * Attempts to cancel the specified task.
+ * @param taskId The task id.
+ */
+ void cancelTask(final int taskId);
}
@@ -1,17 +1,20 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Sat, 30 Aug 2025 16:51:26 +0800
Subject: [PATCH] Add fakeplayer api
Subject: [PATCH] Leaves: Add fakeplayer api
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index 85b778980e762835ac278528087e91b2e3effb43..89f00f4b6ff64305fa44ebb71f22a113c1296d26 100644
index 8e96326c55510642df01ef15e1a3edb1e81176cb..592a3c59bf5edbc65c7c0472e2382593b7b22086 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -3052,4 +3052,15 @@ public final class Bukkit {
public static void restart() {
server.restart();
@@ -3048,4 +3048,15 @@ public final class Bukkit {
return server.getFeatureManager();
}
// Leaves end - Feature API
+
+ // Leaves start - Bot API
+ /**
@@ -25,10 +28,10 @@ index 85b778980e762835ac278528087e91b2e3effb43..89f00f4b6ff64305fa44ebb71f22a113
+ // Leaves end - Bot API
}
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index a0540d7de5c2536aed5231f9e67b73345817921d..c7ae463fb166750bbd0638a2ccf81753b293a381 100644
index 473b0e02c003d5317ef798c320e5c845124f4e12..978e015e91408503b4ec84ec5b3c5193255ba7db 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2753,4 +2753,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
@@ -2813,4 +2813,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
*/
double @Nullable [] getRegionTPS(@NotNull World world, int chunkX, int chunkZ);
// Folia end - region TPS API
@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 16 Nov 2025 15:50:28 +0800
Subject: [PATCH] Leaves: Replay Mod API
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index 592a3c59bf5edbc65c7c0472e2382593b7b22086..838ad878528267b57b69d2938aee0eb6326948eb 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -3059,4 +3059,10 @@ public final class Bukkit {
return server.getBotManager();
}
// Leaves end - Bot API
+
+ // Leaves start - Photographer API
+ public static @NotNull org.leavesmc.leaves.entity.photographer.PhotographerManager getPhotographerManager() {
+ return server.getPhotographerManager();
+ }
+ // Leaves end - Photographer API
}
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 978e015e91408503b4ec84ec5b3c5193255ba7db..d054926f6082bba7d0b59e610e5d725ff5f9ffa4 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2822,4 +2822,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
*/
@NotNull org.leavesmc.leaves.entity.bot.BotManager getBotManager();
// Leaves end - Bot API
+
+ // Leaves start - Photographer API
+ @NotNull org.leavesmc.leaves.entity.photographer.PhotographerManager getPhotographerManager();
+ // Leaves end - Photographer API
}
@@ -39,9 +39,9 @@ public interface Bot extends Player {
/**
* Gets the fakeplayer name without prefix and suffix
*
* @return fakeplayer real name
* @return fakeplayer raw name
*/
@NotNull String getRealName();
@NotNull String getRawName();
/**
* Gets the creator's UUID of the fakeplayer
@@ -91,4 +91,13 @@ public interface Bot extends Player {
* @return success
*/
boolean remove(boolean save);
/**
* Remove the fakeplayer
*
* @param save should save
* @param resume should resume at next server start
* @return success
*/
boolean remove(boolean save, boolean resume);
}
@@ -27,8 +27,8 @@ import java.util.function.Consumer;
public interface BotCreator {
static BotCreator of(String realName, Location location) {
return Bukkit.getBotManager().botCreator(realName, location);
static BotCreator of(String rawName, Location location) {
return Bukkit.getBotManager().botCreator(rawName, location);
}
BotCreator name(String name);
@@ -61,5 +61,5 @@ public interface BotManager {
*/
<T extends BotAction<T>> T newAction(@NotNull Class<T> type);
BotCreator botCreator(@NotNull String realName, @NotNull Location location);
BotCreator botCreator(@NotNull String rawName, @NotNull Location location);
}
@@ -0,0 +1,43 @@
/*
* 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.entity.photographer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
public interface Photographer extends Player {
@NotNull String getId();
void setRecordFile(@NotNull File file);
void stopRecording();
void stopRecording(boolean async);
void stopRecording(boolean async, boolean save);
void pauseRecording();
void resumeRecording();
void setFollowPlayer(@Nullable Player player);
}
@@ -0,0 +1,44 @@
/*
* 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.entity.photographer;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.replay.BukkitRecorderOption;
import java.util.Collection;
import java.util.UUID;
public interface PhotographerManager {
@Nullable Photographer getPhotographer(@NotNull UUID uuid);
@Nullable Photographer getPhotographer(@NotNull String id);
@Nullable Photographer createPhotographer(@NotNull String id, @NotNull Location location);
@Nullable Photographer createPhotographer(@NotNull String id, @NotNull Location location, @NotNull BukkitRecorderOption recorderOption);
void removePhotographer(@NotNull String id);
void removePhotographer(@NotNull UUID uuid);
void removeAllPhotographers();
Collection<Photographer> getPhotographers();
}
@@ -15,17 +15,21 @@
* along with Leaves. If not, see <https://www.gnu.org/licenses/>.
*/
package org.leavesmc.leaves.bot;
package org.leavesmc.leaves.replay;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.storage.ValueInput;
public class BukkitRecorderOption {
import java.util.Optional;
// public int recordDistance = -1;
public String serverName = "Lophine"; // Lophine - rebrand to Lophine to avoid confusion
public BukkitRecordWeather forceWeather = BukkitRecordWeather.NULL;
public int forceDayTime = -1;
public boolean ignoreChat = false;
// public boolean ignoreItem = false;
public interface IPlayerDataStorage {
void save(Player player);
Optional<ValueInput> load(Player player, ProblemReporter reporter);
public enum BukkitRecordWeather {
CLEAR,
RAIN,
THUNDER,
NULL
}
}
+18 -27
View File
@@ -1,6 +1,6 @@
--- a/luminol-server/build.gradle.kts
+++ b/luminol-server/build.gradle.kts
@@ -52,7 +_,23 @@
@@ -50,7 +_,23 @@
}
}
@@ -24,8 +24,8 @@
+ activeFork = lophine
spigot {
@@ -142,12 +_,16 @@
@@ -125,12 +_,16 @@
resources { srcDir("../paper-server/src/main/resources") }
java { srcDir("../folia-server/src/main/java") }
resources { srcDir("../folia-server/src/main/resources") }
@@ -42,40 +42,31 @@
}
}
val log4jPlugins = sourceSets.create("log4jPlugins") {
@@ -174,7 +_,7 @@
@@ -158,7 +_,7 @@
}
dependencies {
- implementation(project(":luminol-api")) // Luminol
+ implementation(project(":lophine-api")) // Lophine
- implementation(project(":luminol-api"))
+ implementation(project(":lophine-api"))
// Luminol start - Dependenices insert
implementation("com.electronwill.night-config:toml:3.8.2") // Night config
implementation("com.github.luben:zstd-jni:1.5.4-1")
@@ -275,14 +_,14 @@
implementation("net.objecthunter:exp4j:0.4.8")
implementation("com.electronwill.night-config:toml:3.9.0") // Night config
@@ -234,14 +_,14 @@
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main",
- "Implementation-Title" to "Luminol",
+ "Implementation-Title" to "Lophine",
- "Implementation-Title" to "Luminol", // Luminol - Rebrand
+ "Implementation-Title" to "Lophine", // Luminol - Rebrand
"Implementation-Version" to implementationVersion,
"Implementation-Vendor" to date,
- "Specification-Title" to "Luminol",
+ "Specification-Title" to "Lophine",
- "Specification-Title" to "Luminol", // Luminol - Rebrand
+ "Specification-Title" to "Lophine", // Luminol - Rebrand
"Specification-Version" to project.version,
"Specification-Vendor" to "LuminolMC org",
- "Brand-Id" to "luminolmc:luminol",
- "Brand-Name" to "Luminol",
+ "Brand-Id" to "luminolmc:lophine",
+ "Brand-Name" to "Lophine",
"Specification-Vendor" to "LuminoLMC", // Luminol - Rebrand
- "Brand-Id" to "luminolmc:luminol", // Luminol - Rebrand
- "Brand-Name" to "Luminol", // Luminol - Rebrand
+ "Brand-Id" to "luminolmc:lophine", // Luminol - Rebrand
+ "Brand-Name" to "Lophine", // Luminol - Rebrand
"Build-Number" to (build ?: ""),
"Build-Time" to buildTime.toString(),
"Git-Branch" to gitBranch,
@@ -446,7 +_,7 @@
}
fill {
- project("luminol")
+ project("lophine")
versionFamily(paperweight.minecraftVersion.map { it.split(".", "-").takeWhile { part -> part.toIntOrNull() != null }.take(2).joinToString(".") })
version(paperweight.minecraftVersion)
@@ -5,27 +5,27 @@ Subject: [PATCH] Rebrand to Lophine
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index d8066afd5f3f2ea9a5dff87d853562e22268785c..f8b2364fa162a41304a99a4993354e33528ab801 100644
index 3b700b214ac6818cd75c34b207aa1436f52231e7..315c137cb9dbac51a8ac0d63f0ae0127e57c6c9f 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -21,6 +21,7 @@ public class ConfigManager {
@@ -25,6 +25,7 @@ public class ConfigManager {
public static void initConfigs() {
configfiles.put("luminol", ConfigsInstance.of("luminol", "me.earthme.luminol.config.modules"));
+ configfiles.put("lophine", ConfigsInstance.of("lophine", "fun.bm.lophine.config.modules")); // add lophine config to global config
registerConfig("luminol", builder.of("luminol", "me.earthme.luminol.config.modules"));
+ registerConfig("lophine", builder.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
preLoad();
}
diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
index df5d926fb4401dd93d658fe14ae4d9d58cff68f9..b6d84fea596cfa78032151ab2f206b6b3d5dd197 100644
index e4022494b050b68d54bac3cde87bdfc9e908859c..a4188ef831825764c0756b826651e2e7a9f99c5b 100644
--- a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
+++ b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
@@ -8,7 +8,7 @@ import me.earthme.luminol.enums.EnumConfigCategory;
@ConfigClassInfo(category = EnumConfigCategory.MISC, name = "server_mod_name")
public class ServerModNameConfig implements IConfigModule {
@ConfigInfo(name = "name")
@ConfigInfo(name = "name", comments = "Decides the server mod name shown in your F3 debug screen.")
- public static String serverModName = "Luminol";
+ public static String serverModName = "Lophine";
@ConfigInfo(name = "vanilla_spoof")
@ConfigInfo(name = "vanilla_spoof", comments = "Ignore any plugin's modification and server mod name set in this config block, only force sending brand name of vanilla")
public static boolean fakeVanilla = false;
@@ -0,0 +1,141 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 16 Mar 2026 15:51:40 +0800
Subject: [PATCH] Diff in auto-update patch
diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/AutoUpdateConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/AutoUpdateConfig.java
index ce01352b637547c1cf8308d56d4b3f9c48fcca70..9b5623ce1de3d68c949c3c00b966cedab3a4c986 100644
--- a/src/main/java/me/earthme/luminol/config/modules/misc/AutoUpdateConfig.java
+++ b/src/main/java/me/earthme/luminol/config/modules/misc/AutoUpdateConfig.java
@@ -16,13 +16,13 @@ import java.util.Set;
category = EnumConfigCategory.MISC,
name = "auto_update",
comments = """
- Checks GitHub Releases for newer Luminol jars on a schedule.
- Downloads are staged under auto_update/luminol and written to auto_update/core.path,
+ Checks GitHub Releases for newer version's jars on a schedule.
+ Downloads are staged under auto_update/lophine and written to auto_update/core.path,
which Hyacinthusclip can consume on the next restart.
- If target_jar_path is set, Luminol will also try to replace that launcher jar directly."""
+ If target_jar_path is set, server will also try to replace that launcher jar directly."""
)
public class AutoUpdateConfig implements IConfigModule {
- @ConfigInfo(name = "enabled", comments = "Whether Luminol should check for updates automatically.")
+ @ConfigInfo(name = "enabled", comments = "Whether the server should check for updates automatically.")
public static boolean enabled = false;
@ConfigInfo(name = "check_times", comments = "List of daily check times in HH:mm, based on the server's local time zone.")
@@ -33,7 +33,7 @@ public class AutoUpdateConfig implements IConfigModule {
@ConfigInfo(name = "target_jar_path", comments = """
Optional launcher jar path to replace after a successful download.
- Leave this blank to keep the downloaded jar staged in auto_update/luminol
+ Leave this blank to keep the downloaded jar staged in auto_update/lophine
and let Hyacinthusclip switch to it through auto_update/core.path on restart.""")
public static String targetJarPath = "";
diff --git a/src/main/java/me/earthme/luminol/utils/AutoUpdateHelper.java b/src/main/java/me/earthme/luminol/utils/AutoUpdateHelper.java
index 94a25cd681c9352d6931edafd9ec67fd7ba8a777..d0d0cf5e5ff8d4b8efa4d9778c27267b41cf8cf8 100644
--- a/src/main/java/me/earthme/luminol/utils/AutoUpdateHelper.java
+++ b/src/main/java/me/earthme/luminol/utils/AutoUpdateHelper.java
@@ -35,10 +35,10 @@ public final class AutoUpdateHelper {
private final Logger LOGGER = LogUtils.getClassLogger();
private final Gson GSON = new Gson();
- private final String GITHUB_API_BASE = "https://api.github.com/repos/LuminolMC/Luminol";
+ private final String GITHUB_API_BASE = "https://api.github.com/repos/lophineMC/lophine";
private final Path AUTO_UPDATE_DIR = Path.of("auto_update");
private final Path CORE_PATH_FILE = AUTO_UPDATE_DIR.resolve("core.path");
- private final Path LUMINOL_UPDATE_DIR = AUTO_UPDATE_DIR.resolve("luminol");
+ private final Path LUMINOL_UPDATE_DIR = AUTO_UPDATE_DIR.resolve("lophine");
private final Path LATEST_PATH_FILE = LUMINOL_UPDATE_DIR.resolve("latest.path");
private final long DAILY_TASK_PERIOD_MILLIS = TimeUnit.DAYS.toMillis(1);
@@ -51,13 +51,13 @@ public final class AutoUpdateHelper {
ensureWorkingDirectories();
scheduler = Executors.newSingleThreadScheduledExecutor(task -> {
- final Thread thread = new Thread(task, "Luminol Auto Update Scheduler");
+ final Thread thread = new Thread(task, "Lophine Auto Update Scheduler");
thread.setDaemon(true);
return thread;
});
if (AutoUpdateConfig.checkTimes.isEmpty()) {
- LOGGER.warn("Luminol auto-update is enabled, but misc.auto_update.check_times is empty.");
+ LOGGER.warn("Lophine auto-update is enabled, but misc.auto_update.check_times is empty.");
return;
}
@@ -95,14 +95,14 @@ public final class AutoUpdateHelper {
private void checkForUpdatesSafely() {
if (!UPDATE_RUNNING.compareAndSet(false, true)) {
- LOGGER.info("A Luminol auto-update check is already running, skipping this schedule.");
+ LOGGER.info("A Lophine auto-update check is already running, skipping this schedule.");
return;
}
try {
checkForUpdates();
} catch (Exception e) {
- LOGGER.warn("Luminol auto-update failed.", e);
+ LOGGER.warn("Lophine auto-update failed.", e);
} finally {
UPDATE_RUNNING.set(false);
}
@@ -123,7 +123,7 @@ public final class AutoUpdateHelper {
final ReleaseAssetInfo latestRelease = getLatestCompatibleRelease(mcVersion, gitBranch);
if (latestRelease == null) {
- LOGGER.warn("No compatible Luminol release was found for Minecraft {}{}.",
+ LOGGER.warn("No compatible Lophine release was found for Minecraft {}{}.",
mcVersion,
gitBranch == null ? "" : " on branch " + gitBranch
);
@@ -132,7 +132,7 @@ public final class AutoUpdateHelper {
final UpdateStatus updateStatus = compareReleaseWithCurrentBuild(latestRelease.releaseCommitHash(), currentGitHash);
if (updateStatus == UpdateStatus.UP_TO_DATE) {
- LOGGER.info("You are already running the latest compatible Luminol release: {}", latestRelease.tagName());
+ LOGGER.info("You are already running the latest compatible Lophine release: {}", latestRelease.tagName());
return;
}
@@ -154,7 +154,7 @@ public final class AutoUpdateHelper {
return;
}
- LOGGER.info("Found a newer Luminol release: {}", latestRelease.tagName());
+ LOGGER.info("Found a newer Lophine release: {}", latestRelease.tagName());
final Path stagedJar = downloadAndStageRelease(latestRelease);
final Path finalJarPath = tryApplyTargetJar(stagedJar);
@@ -163,7 +163,7 @@ public final class AutoUpdateHelper {
if (finalJarPath.equals(stagedJar)) {
LOGGER.info(
- "Downloaded the latest Luminol jar to {} and refreshed auto_update/core.path for Hyacinthusclip. Please restart your server.",
+ "Downloaded the latest Lophine jar to {} and refreshed auto_update/core.path for Hyacinthusclip. Please restart your server.",
finalJarPath.toAbsolutePath()
);
} else {
@@ -179,7 +179,7 @@ public final class AutoUpdateHelper {
try {
Files.createDirectories(LUMINOL_UPDATE_DIR);
} catch (IOException e) {
- throw new RuntimeException("Failed to create Luminol auto update directory", e);
+ throw new RuntimeException("Failed to create Lophine auto update directory", e);
}
}
@@ -440,7 +440,7 @@ public final class AutoUpdateHelper {
private @NotNull HttpURLConnection openConnection(String url) throws IOException, URISyntaxException {
final HttpURLConnection connection = (HttpURLConnection) new URI(url).toURL().openConnection();
connection.setRequestProperty("Accept", "application/vnd.github+json");
- connection.setRequestProperty("User-Agent", "Luminol Auto Update");
+ connection.setRequestProperty("User-Agent", "Lophine Auto Update");
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
return connection;
@@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 26 Aug 2025 22:08:54 +0800
Subject: [PATCH] Transformed Configs
diff --git a/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java b/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
index 4051384e82dba0416838c3c9889a6e368367b601..a5535b479cdcca870d0c8be6ed6fbcb32f266ac2 100644
--- a/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
+++ b/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
@@ -11,6 +11,7 @@ public class CommandConfig implements IConfigModule {
@TransformedConfig(name = "enable", directory = {"experiment", "force_the_data_command_to_be_enabled"})
@ConfigInfo(name = "enable_data_command")
public static boolean data = false;
+ @TransformedConfig(name = "command_block_enabled", directory = {"experiment", "command"}, originInstance = "lophine")
@TransformedConfig(name = "enabled", directory = {"experiment", "force_enable_command_block_command_execution"})
@ConfigInfo(name = "enable_command_block", comments = """
Force to enable command blocks.
diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/PaperPacketLimiterConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/PaperPacketLimiterConfig.java
index 35e6014f04093050a9a62b895b43e5c5d8c6a28e..11abfb884f972fd73ca4c13a6e309de1bcd23fd5 100644
--- a/src/main/java/me/earthme/luminol/config/modules/optimizations/PaperPacketLimiterConfig.java
+++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/PaperPacketLimiterConfig.java
@@ -8,6 +8,7 @@ import me.earthme.luminol.enums.EnumConfigCategory;
@ConfigClassInfo(category = EnumConfigCategory.OPTIMIZATIONS, name = "force_disable_packet_limiter_of_paper")
public class PaperPacketLimiterConfig implements IConfigModule {
+ @TransformedConfig(name = "unlimit-packet", directory = {"misc", "network"}, originInstance = "lophine")
@TransformedConfig(name = "force_disable", directory = {"misc", "force_disable_packet_limiter_of_paper"})
@ConfigInfo(name = "force_disable")
public static boolean forceDisable = false;
@@ -3,15 +3,12 @@ From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 13 Aug 2025 22:23:46 +0800
Subject: [PATCH] Leaves: Item overstack util
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/d93e9766d3797d130f66179e70a1b374c546fef7/leaves-server/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java b/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java
index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981c4e34aed 100644
index a5df7e40369cf2c309f4d37fede6615f34a467e2..84d0e1a7cd687ac4ed9f1bf824ca28940c2fab1e 100644
--- a/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java
+++ b/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java
@@ -17,12 +17,173 @@
@@ -17,10 +17,98 @@
package org.leavesmc.leaves.util;
@@ -30,8 +27,9 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+import java.util.Objects;
+import java.util.Optional;
// Only the used part is retained
// Only used part of the original code was copied
public class ItemOverstackUtils {
+
+ private static final List<ItemUtil> overstackUtils = List.of(
+ new ShulkerBox()
+ );
@@ -39,7 +37,7 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+ public static int getItemStackMaxCount(ItemStack stack) {
+ int size;
+ for (ItemUtil util : overstackUtils) {
+ if ((size = util.getMaxServerStackCount(stack)) != -1) {
+ if (util.isEnabled() && (size = util.getMaxServerStackCount(stack)) != -1) {
+ return size;
+ }
+ }
@@ -49,7 +47,7 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+ public static int getNetworkMaxCount(ItemStack stack) {
+ int size;
+ for (ItemUtil util : overstackUtils) {
+ if ((size = util.getMaxClientStackCount(stack)) != -1) {
+ if (util.isEnabled() && (size = util.getMaxClientStackCount(stack)) != -1) {
+ return size;
+ }
+ }
@@ -58,7 +56,7 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+
+ public static boolean tryStackItems(ItemEntity self, ItemEntity other) {
+ for (ItemUtil util : overstackUtils) {
+ if (util.tryStackItems(self, other)) {
+ if (util.isEnabled() && util.tryStackItems(self, other)) {
+ return true;
+ }
+ }
@@ -66,7 +64,12 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+ }
+
+ public static boolean hasOverstackingItem() {
+ return overstackUtils.stream().anyMatch(ItemUtil::isEnabled);
+ for (ItemUtil util : overstackUtils) {
+ if (util.isEnabled()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static int getItemStackMaxCountReal(ItemStack stack) {
@@ -103,6 +106,9 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+
public static float getItemStackSignalStrength(int maxStackSize, ItemStack itemStack) {
float result = (float) itemStack.getCount() / Math.min(maxStackSize, itemStack.getMaxStackSize());
/*if (LeavesConfig.modify.oldMC.allowGrindstoneOverstacking && CurseEnchantedBook.isCursedEnchantedBook(itemStack)) { // Luminol
@@ -28,4 +116,80 @@ public class ItemOverstackUtils {
}*/ // Luminol
return Math.clamp(result, 0f, 1f);
}
+
@@ -110,7 +116,6 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+ return getItemStackMaxCount(itemStack) > 1 && (!itemStack.isDamageableItem() || !itemStack.isDamaged());
+ }
+
+
+ private interface ItemUtil {
+ boolean isEnabled();
+
@@ -134,7 +139,8 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+ }
+
+ public static boolean shulkerBoxNoItem(@NotNull ItemStack stack) {
+ return stack.getComponents().getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).stream().findAny().isEmpty();
+ // Leaves - Paper 26.1: ItemContainerContents#stream() removed, use nonEmptyItemCopyStream()
+ return stack.getComponents().getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).nonEmptyItemCopyStream().findAny().isEmpty();
+ }
+
+ @Override
@@ -145,10 +151,7 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+ @Override
+ public boolean tryStackItems(ItemEntity self, ItemEntity other) {
+ ItemStack selfStack = self.getItem();
+ if (!isEnabled() ||
+ !(selfStack.getItem() instanceof BlockItem blockItem) ||
+ !(blockItem.getBlock() instanceof ShulkerBoxBlock)
+ ) {
+ if (!(selfStack.getItem() instanceof BlockItem blockItem) || !(blockItem.getBlock() instanceof ShulkerBoxBlock)) {
+ return false;
+ }
+
@@ -177,7 +180,7 @@ index 3a6314ed7f62c6473ce9ddc9deeee2a32b9d2893..23a0f8100eb3162331161635e8051981
+
+ @Override
+ public int getMaxServerStackCount(ItemStack stack) {
+ if (isEnabled() && stack.getItem() instanceof BlockItem bi &&
+ if (stack.getItem() instanceof BlockItem bi &&
+ bi.getBlock() instanceof ShulkerBoxBlock && (ContainerExpansionConfig.nbtShulkerStackable || shulkerBoxNoItem(stack))) {
+ return ContainerExpansionConfig.shulkerCount;
+ }
@@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 18 Feb 2026 00:15:08 +0800
Subject: [PATCH] Leaves: Fakeplayer
diff --git a/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java b/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
index a4c188f71564fc77a9fa22b4cae032e1919d06f2..019266803f1452cb1e76350da8edae10a77020ac 100644
--- a/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
+++ b/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
@@ -54,6 +54,12 @@ public class FoliaServerWaypointManager extends ServerWaypointManager {
return;
}
+ // Leaves start - fakeplayer
+ if (waypoint instanceof org.leavesmc.leaves.bot.ServerBot bot && !bot.getConfigValue(org.leavesmc.leaves.bot.agent.Configs.ENABLE_LOCATOR_BAR)) {
+ return;
+ }
+ // Leaves end - fakeplayer
+
this.waypoints.add(waypoint);
for (ServerPlayer toCreateFor : this.trackingPlayers) {
@@ -110,6 +116,11 @@ public class FoliaServerWaypointManager extends ServerWaypointManager {
this.trackingPlayers.add(player);
scheduleIfOffTarget(player, () -> {
+ // Leaves start - fakeplayer
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ return;
+ }
+ // Leaves end - fakeplayer
for (WaypointTransmitter transmitter : this.waypoints) {
this.createConnection(player, transmitter);
}
diff --git a/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java b/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
index 063cc27df9c8f3ad5c8db5cedcaa3d2bccf6dc24..5ad6aab5e72e27bb402494873770ab5822601939 100644
--- a/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
+++ b/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
@@ -11,14 +11,7 @@ public class ServerFeatureManager implements FeatureManager {
private final Set<String> availableFeatures = new HashSet<>();
private ServerFeatureManager() {
- if (false) { // Luminol not provide this
- availableFeatures.addAll(Set.of(
- FAKEPLAYER,
- PHOTOGRAPHER,
- BYTEBUF,
- UPDATE_SUPPRESSION_EVENT
- ));
- }
+ availableFeatures.add(FAKEPLAYER); // Lophine - fakeplayer support
if (Boolean.getBoolean("leavesclip.enable.mixin") || Boolean.getBoolean("hyacinthusclip.enable.mixin")) {
availableFeatures.add(MIXIN);
}
@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 17 May 2026 05:33:21 +0800
Subject: [PATCH] Leaves: Replay Mod API
diff --git a/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java b/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
index 5ad6aab5e72e27bb402494873770ab5822601939..0ac9edfa36833a7ebe0353c4aff40955ab3ddf8c 100644
--- a/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
+++ b/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
@@ -12,6 +12,7 @@ public class ServerFeatureManager implements FeatureManager {
private ServerFeatureManager() {
availableFeatures.add(FAKEPLAYER); // Lophine - fakeplayer support
+ availableFeatures.add(PHOTOGRAPHER); // Lophine - Replay Mod API support
if (Boolean.getBoolean("leavesclip.enable.mixin") || Boolean.getBoolean("hyacinthusclip.enable.mixin")) {
availableFeatures.add(MIXIN);
}
@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 3 Jun 2026 13:49:39 +0800
Subject: [PATCH] Update suppression event
diff --git a/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java b/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
index 0ac9edfa36833a7ebe0353c4aff40955ab3ddf8c..c3db6c5281728fa1a2b4d84f9ebff9fcfd696698 100644
--- a/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
+++ b/src/main/java/org/leavesmc/leaves/plugin/ServerFeatureManager.java
@@ -13,6 +13,7 @@ public class ServerFeatureManager implements FeatureManager {
private ServerFeatureManager() {
availableFeatures.add(FAKEPLAYER); // Lophine - fakeplayer support
availableFeatures.add(PHOTOGRAPHER); // Lophine - Replay Mod API support
+ availableFeatures.add(UPDATE_SUPPRESSION_EVENT); // Lophine - update suppression event support
if (Boolean.getBoolean("leavesclip.enable.mixin") || Boolean.getBoolean("hyacinthusclip.enable.mixin")) {
availableFeatures.add(MIXIN);
}
@@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Sun, 22 Mar 2026 01:39:17 +0800
Subject: [PATCH] Carpet features
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index 315c137cb9dbac51a8ac0d63f0ae0127e57c6c9f..2a2d6aff636ad960638b357d224a631c89d23d33 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -26,6 +26,15 @@ public class ConfigManager {
public static void initConfigs() {
registerConfig("luminol", builder.of("luminol", "me.earthme.luminol.config.modules"));
registerConfig("lophine", builder.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
+ // Lophine start - add carpet config
+ registerConfig("lophine_carpet", builder.of(
+ new java.io.File("lophine_config"),
+ "lophine_carpet",
+ "lophine_carpet_config.toml",
+ "lophinecarpetconfig",
+ "fun.bm.lophine.carpet.config.modules"
+ ));
+ // Lophine end - add carpet config
preLoad();
}
@@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Fri, 5 Jun 2026 16:10:25 +0800
Subject: [PATCH] Carpet Features Compatible
diff --git a/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java b/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
index f079a1cd99d648dc7ca97fb65406b7a42ad5a74e..30f78cbae7aea3e9fcee6d97f229ddf8e8344299 100644
--- a/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
+++ b/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
@@ -23,9 +23,4 @@ public class CommandConfig implements IConfigModule {
""")
@HotReloadUnsupported
public static boolean waypointsAndWaypointCommand = false;
- @ConfigInfo(name = "enable_tick_command", comments = """
- Only freeze/unfreeze/step/query command is allowed if you enabled it.
- WARN: This should disabled in production environment!
- """)
- public static boolean tick = false;
}
diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/OptimizedDragonRespawnConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/OptimizedDragonRespawnConfig.java
deleted file mode 100644
index f791feed92abd750ac10775c05150f122ecbe886..0000000000000000000000000000000000000000
--- a/src/main/java/me/earthme/luminol/config/modules/optimizations/OptimizedDragonRespawnConfig.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package me.earthme.luminol.config.modules.optimizations;
-
-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.OPTIMIZATIONS, name = "end_dragon")
-public class OptimizedDragonRespawnConfig implements IConfigModule {
- @ConfigInfo(name = "optimized_dragon_respawn")
- public static boolean optimizedRespawn = false;
-}
@@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 15 Jun 2026 01:33:32 +0800
Subject: [PATCH] TEMP: Temporarily transform config between different config
system
Should be removed in Minecraft 26.2 Update
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index 2a2d6aff636ad960638b357d224a631c89d23d33..536e8d7df4ce9de1dbe587c1af6b2474a530a165 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -65,6 +65,12 @@ public class ConfigManager {
CompletableFuture.allOf(futures).join();
CommandRegister.register(); // register command after config loaded to enable some command didn't depend on config files
initialized = true;
+
+ // Lophine start - temporarily transform configs
+ reApplyStagedConfigs();
+ saveConfigs();
+ configfiles.values().forEach((config) -> config.reload(true, false));
+ // Lophine end - temporarily transform configs
}
public static void registerRunnableBeforeFinalLoad(Runnable runnable) {
@@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 26 Aug 2025 02:55:23 +0800
Subject: [PATCH] Add config to allow generation of end void rings
diff --git a/net/minecraft/world/level/levelgen/DensityFunctions.java b/net/minecraft/world/level/levelgen/DensityFunctions.java
index 04527a5c65ad630f794fed9071d485aedd02257a..57e4c6c60f7d012a9de411b07d000f3504c27e6b 100644
--- a/net/minecraft/world/level/levelgen/DensityFunctions.java
+++ b/net/minecraft/world/level/levelgen/DensityFunctions.java
@@ -528,7 +528,7 @@ public final class DensityFunctions {
int i1 = z / 2;
int i2 = x % 2;
int i3 = z % 2;
- float f = 100.0F - Mth.sqrt((long)x * (long)x + (long)z * (long)z) * 8.0F; // Paper - cast ints to long to avoid integer overflow
+ float f = fun.bm.lophine.config.modules.fixes.EndVoidRingsConfig.enabled ? 100.0F - Mth.sqrt(x * x + z * z) * 8.0F : 100.0F - Mth.sqrt((long)x * (long)x + (long)z * (long)z) * 8.0F; // Paper - cast ints to long to avoid integer overflow // Lophine - customize end void rings generation
f = Mth.clamp(f, -100.0F, 80.0F);
NoiseCache cache = noiseCache.get().computeIfAbsent(noise, noiseKey -> new NoiseCache()); // Paper - Perf: Optimize end generation
@@ -1,32 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 12 Jun 2025 04:44:24 +0800
Subject: [PATCH] I18n support
Subject: [PATCH] Server I18n
diff --git a/net/minecraft/locale/Language.java b/net/minecraft/locale/Language.java
index 7b9e2a1a208b46a69c16e6afd8b502259893574f..c300ae4363298fecef8fa9bf739f01c0a11e145f 100644
index 49c7f8194be8222e329fc3215a6aa6db0b221b11..c6c968d28e0d14a4c50e66bdd5176a000944b707 100644
--- a/net/minecraft/locale/Language.java
+++ b/net/minecraft/locale/Language.java
@@ -36,6 +36,7 @@ public abstract class Language {
Map<String, String> map = new HashMap<>();
BiConsumer<String, String> biConsumer = map::put;
parseTranslations(biConsumer, "/assets/minecraft/lang/en_us.json");
+ fun.bm.lophine.utils.ServerI18nUtil.loadLophineI18nDefault(biConsumer);
deprecatedTranslationsInfo.applyToMap(map);
final Map<String, String> map1 = Map.copyOf(map);
@@ -37,6 +37,7 @@ public abstract class Language {
Map<String, String> loadedData = new HashMap<>();
BiConsumer<String, String> output = loadedData::put;
parseTranslations(output, "/assets/minecraft/lang/en_us.json");
+ fun.bm.lophine.utils.ServerI18nUtil.loadLophineI18nDefault(output); // Lophine - Server I18n
deprecatedInfo.applyToMap(loadedData);
final Map<String, String> storage = Map.copyOf(loadedData);
return new Language() {
@@ -65,7 +66,7 @@ public abstract class Language {
@@ -66,7 +67,7 @@ public abstract class Language {
};
}
- private static void parseTranslations(BiConsumer<String, String> output, String languagePath) {
+ public static void parseTranslations(BiConsumer<String, String> output, String languagePath) { // Lophine - private -> public
try (InputStream resourceAsStream = Language.class.getResourceAsStream(languagePath)) {
loadFromJson(resourceAsStream, output);
- private static void parseTranslations(final BiConsumer<String, String> output, final String path) {
+ public static void parseTranslations(final BiConsumer<String, String> output, final String path) { // Lophine - private -> public
try (InputStream stream = Language.class.getResourceAsStream(path)) {
loadFromJson(stream, output);
} catch (JsonParseException | IOException var7) {
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
index cf72cb8b418239b56c755486b03a321672e16bc3..b69c06607ca900beeebf4892a978442dad2db19b 100644
index 143ad4e342b184aa02b6fbbe81508e244eebc7a2..89be42b8519522398920eb424c894fd2ab8c9666 100644
--- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java
@@ -155,6 +155,8 @@ public class Main {
@@ -39,10 +39,10 @@ index cf72cb8b418239b56c755486b03a321672e16bc3..b69c06607ca900beeebf4892a978442d
String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck();
if (awtException != null) {
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index c93feb64b6088a4878fcdb6e7c733a5f37e9385b..79c911003c7b1c3d94e7e9d3974eeadcc16bde3a 100644
index dfac07850b02abba160f8f143eba4569172ab9e9..fcd4b4785f0d09f87fe214202468c75395157e14 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -172,6 +172,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -283,6 +283,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
// Paper end - initialize global and world-defaults configuration
me.earthme.luminol.config.ConfigManager.loadConfigFiles(); // Luminol - load config file
@@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 2 Jul 2025 23:36:25 +0800
Subject: [PATCH] Fix datapack command save function
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index e7eec08a4d8943b35a76173e39529498c348140c..61983a80191e64942bfdac74c6d2f23cf781484d 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2475,6 +2475,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return this.reloadResources(packsToEnable, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN);
}
+ // Lophine start - region thread skip reload // TODO - add reload support
+ public void saveDatapacks(Collection<String> selectedPacks) {
+ this.packRepository.setSelected(selectedPacks, false); // Paper - add pendingReload flag to determine required pack loading - false as this is *after* a reload (see above)
+ WorldDataConfiguration worldDataConfiguration = new WorldDataConfiguration(
+ getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()
+ );
+ this.worldData.setDataConfiguration(worldDataConfiguration);
+ }
+ // Lophine end - region thread skip reload // TODO - add reload support
+
public CompletableFuture<Void> reloadResources(
final Collection<String> packsToEnable, final io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause
) {
diff --git a/net/minecraft/server/commands/DataPackCommand.java b/net/minecraft/server/commands/DataPackCommand.java
index 0c7c829270d3cd3dd05a3dc7dfe82ee01d5c6bd8..991e0362e96488b64d994f1bdfb8ed5d66f98666 100644
--- a/net/minecraft/server/commands/DataPackCommand.java
+++ b/net/minecraft/server/commands/DataPackCommand.java
@@ -98,7 +98,7 @@ public class DataPackCommand {
dispatcher.register(
Commands.literal("datapack")
.requires(Commands.hasPermission(Commands.LEVEL_GAMEMASTERS))
- /*.then( // Luminol - Add back read-only datapack command
+ .then( // Lophine - Fix datapack command save function
Commands.literal("enable")
.then(
Commands.argument("name", StringArgumentType.string())
@@ -145,11 +145,11 @@ public class DataPackCommand {
.suggests(SELECTED_PACKS)
.executes(c -> disablePack(c.getSource(), getPack(c, "name", false)))
)
- )*/ // Luminol - Add back read-only datapack command
+ )
.then(
Commands.literal("list")
.executes(c -> listPacks(c.getSource()))
- //.then(Commands.literal("available").executes(c -> listAvailablePacks(c.getSource()))) // Luminol - Add back read-only datapack command
+ .then(Commands.literal("available").executes(c -> listAvailablePacks(c.getSource()))) // Luminol - Add back read-only datapack command
.then(Commands.literal("enabled").executes(c -> listEnabledPacks(c.getSource())))
)
.then(
@@ -235,7 +235,7 @@ public class DataPackCommand {
}
private static int listPacks(final CommandSourceStack source) {
- return listEnabledPacks(source) ;// + listAvailablePacks(source); // Luminol - Add back read-only datapack command
+ return listEnabledPacks(source) + listAvailablePacks(source); // Lophine - Fix datapack command save function
}
private static int listAvailablePacks(final CommandSourceStack source) {
diff --git a/net/minecraft/server/commands/ReloadCommand.java b/net/minecraft/server/commands/ReloadCommand.java
index 80fef4277b9e986c17a4cb895e130726bdb63229..4bed8d0432508cbe5c0d1fc7d68052ec2af7260f 100644
--- a/net/minecraft/server/commands/ReloadCommand.java
+++ b/net/minecraft/server/commands/ReloadCommand.java
@@ -16,11 +16,17 @@ public class ReloadCommand {
private static final Logger LOGGER = LogUtils.getLogger();
public static void reloadPacks(final Collection<String> selectedPacks, final CommandSourceStack source) {
+ // Lophine start - region thread skip reload // TODO - add reload support
+ source.getServer().saveDatapacks(selectedPacks);
+ source.getSender().sendMessage("You need to restart server to load datapacks update.");
+ if (false) {
source.getServer().reloadResources(selectedPacks, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.COMMAND).exceptionally(throwable -> { // Paper - Add ServerResourcesReloadedEvent
LOGGER.warn("Failed to execute reload", throwable);
source.sendFailure(Component.translatable("commands.reload.failure"));
return null;
});
+ }
+ // Lophine end - region thread skip reload // TODO - add reload support
}
private static Collection<String> discoverNewPacks(final PackRepository packRepository, final WorldData worldData, final Collection<String> currentPacks) {
@@ -3,15 +3,15 @@ From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 20 Feb 2025 01:00:28 +0800
Subject: [PATCH] Purpur: Barrels and enderchests 6 rows
Co-authored by: William Blake Galbreath <Blake.Galbreath@GMail.com>
As part of: Purpur (https://github.com/PurpurMC/Purpur/blob/09f547de09fc5d886f18f6d99ff389289766ec9d/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch)
Licensed under: MIT (https://github.com/PurpurMC/Purpur/blob/09f547de09fc5d886f18f6d99ff389289766ec9d/LICENSE)
Co-authored by: William Blake Galbreath <blake.galbreath@gmail.com>
As part of: Purpur (https://github.com/PurpurMC/Purpur/blob/dc46f46d28dcdcaf33bb533f9571a107db98c1d7/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch)
Licensed under: MIT (https://github.com/PurpurMC/Purpur/blob/dc46f46d28dcdcaf33bb533f9571a107db98c1d7/LICENSE)
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 593dbcda4b497291eb1ecdc64b947a8d279f8be6..cb863a36fc67e993956ec3be655e6e4b9764c051 100644
index c9d3b000a328fe3583a7053a94c72dc003c1e10c..45e5ac1e8e2ec30935e96fa20d18e77bbd0e20bd 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -1087,6 +1087,10 @@ public abstract class PlayerList {
@@ -963,6 +963,10 @@ public abstract class PlayerList {
player.getBukkitEntity().recalculatePermissions(); // CraftBukkit
this.server.getCommands().sendCommands(player);
} // Paper - Add sendOpLevel API
@@ -23,11 +23,11 @@ index 593dbcda4b497291eb1ecdc64b947a8d279f8be6..cb863a36fc67e993956ec3be655e6e4b
// Paper start - whitelist verify event / login event
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 09b549fa9568aa1ae13b1b975db14a6268fdaa46..6c933c27ce155eb516a9ede96fb2c3bd19251bfa 100644
index 592ce8beb28ebe8aaac2ed167abb24148afb0bc3..ce8ab4b7eee5e0715e780d189d2f6554c5a9dc3c 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -219,6 +219,7 @@ public abstract class Player extends LivingEntity {
private int currentImpulseContextResetGraceTime = 0;
@@ -175,6 +175,7 @@ public abstract class Player extends Avatar implements ContainerUser {
public float hurtDir;
public boolean affectsSpawning = true; // Paper - Affects Spawning API
public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage
+ public int enderChestSlotCount = -1; // Purpur - Barrels and enderchests 6 rows
@@ -35,42 +35,42 @@ index 09b549fa9568aa1ae13b1b975db14a6268fdaa46..6c933c27ce155eb516a9ede96fb2c3bd
// CraftBukkit start
public boolean fauxSleeping;
diff --git a/net/minecraft/world/inventory/ChestMenu.java b/net/minecraft/world/inventory/ChestMenu.java
index 0fffa384f928ab84451331380968fb4650eafe26..d84a10396395939149da88bcb01be59e220c340e 100644
index e77bfcd31cdcfd5836dc5db561e3fe2bc552a4b1..297657f38ce4c4bfa58cca27d440595246200d94 100644
--- a/net/minecraft/world/inventory/ChestMenu.java
+++ b/net/minecraft/world/inventory/ChestMenu.java
@@ -66,10 +66,30 @@ public class ChestMenu extends AbstractContainerMenu {
return new ChestMenu(MenuType.GENERIC_9x6, containerId, playerInventory, 6);
return new ChestMenu(MenuType.GENERIC_9x6, containerId, inventory, 6);
}
+ // Purpur start - Barrels and enderchests 6 rows
+ public static ChestMenu oneRow(int syncId, Inventory playerInventory, Container inventory) {
+ return new ChestMenu(MenuType.GENERIC_9x1, syncId, playerInventory, inventory, 1);
+ public static ChestMenu oneRow(final int containerId, final Inventory inventory, final Container container) {
+ return new ChestMenu(MenuType.GENERIC_9x3, containerId, inventory, container, 1);
+ }
+
+ public static ChestMenu twoRows(int syncId, Inventory playerInventory, Container inventory) {
+ return new ChestMenu(MenuType.GENERIC_9x2, syncId, playerInventory, inventory, 2);
+ public static ChestMenu twoRows(final int containerId, final Inventory inventory, final Container container) {
+ return new ChestMenu(MenuType.GENERIC_9x3, containerId, inventory, container, 2);
+ }
+ // Purpur end - Barrels and enderchests 6 rows
+
public static ChestMenu threeRows(int containerId, Inventory playerInventory, Container container) {
return new ChestMenu(MenuType.GENERIC_9x3, containerId, playerInventory, container, 3);
public static ChestMenu threeRows(final int containerId, final Inventory inventory, final Container container) {
return new ChestMenu(MenuType.GENERIC_9x3, containerId, inventory, container, 3);
}
+ // Purpur start - Barrels and enderchests 6 rows
+ public static ChestMenu fourRows(int syncId, Inventory playerInventory, Container inventory) {
+ return new ChestMenu(MenuType.GENERIC_9x4, syncId, playerInventory, inventory, 4);
+ public static ChestMenu fourRows(final int containerId, final Inventory inventory, final Container container) {
+ return new ChestMenu(MenuType.GENERIC_9x3, containerId, inventory, container, 4);
+ }
+
+ public static ChestMenu fiveRows(int syncId, Inventory playerInventory, Container inventory) {
+ return new ChestMenu(MenuType.GENERIC_9x5, syncId, playerInventory, inventory, 5);
+ public static ChestMenu fiveRows(final int containerId, final Inventory inventory, final Container container) {
+ return new ChestMenu(MenuType.GENERIC_9x3, containerId, inventory, container, 5);
+ }
+ // Purpur end - Barrels and enderchests 6 rows
+
public static ChestMenu sixRows(int containerId, Inventory playerInventory, Container container) {
return new ChestMenu(MenuType.GENERIC_9x6, containerId, playerInventory, container, 6);
public static ChestMenu sixRows(final int containerId, final Inventory inventory, final Container container) {
return new ChestMenu(MenuType.GENERIC_9x6, containerId, inventory, container, 6);
}
diff --git a/net/minecraft/world/inventory/PlayerEnderChestContainer.java b/net/minecraft/world/inventory/PlayerEnderChestContainer.java
index 51148b7b95c93a9e25da70ac9275c63f1458d84c..dba8acfcacfe9a7b7e0fb9943fba49468214616e 100644
index 4df3a32faf85595372f4b250482d852c985ea3ab..101b3711bfb98888837ebed323561cac6efb274d 100644
--- a/net/minecraft/world/inventory/PlayerEnderChestContainer.java
+++ b/net/minecraft/world/inventory/PlayerEnderChestContainer.java
@@ -26,11 +26,18 @@ public class PlayerEnderChestContainer extends SimpleContainer {
@@ -90,38 +90,38 @@ index 51148b7b95c93a9e25da70ac9275c63f1458d84c..dba8acfcacfe9a7b7e0fb9943fba4946
+ }
+ // Purpur end - Barrels and enderchests 6 rows
+
public void setActiveChest(EnderChestBlockEntity enderChestBlockEntity) {
this.activeChest = enderChestBlockEntity;
public void setActiveChest(final EnderChestBlockEntity activeChest) {
this.activeChest = activeChest;
}
diff --git a/net/minecraft/world/level/block/EnderChestBlock.java b/net/minecraft/world/level/block/EnderChestBlock.java
index 5077a9ff7b78801bdc53536a37aee07b8d86ee4d..cef29289b7bc7fdf9613c0cd52f2bf4f715f288d 100644
index 24a2c411da0ebbb7f97d621bb76ff686621f9aae..a9f511a549681a76a962855c26b9af5980f36df7 100644
--- a/net/minecraft/world/level/block/EnderChestBlock.java
+++ b/net/minecraft/world/level/block/EnderChestBlock.java
@@ -85,8 +85,14 @@ public class EnderChestBlock extends AbstractChestBlock<EnderChestBlockEntity> i
enderChestInventory.setActiveChest(enderChestBlockEntity); // Needs to happen before ChestMenu.threeRows as it is required for opening animations
@@ -88,7 +88,15 @@ public class EnderChestBlock extends AbstractChestBlock<EnderChestBlockEntity> i
// Paper start - Fix InventoryOpenEvent cancellation - moved up;
container.setActiveChest(enderChest); // Needs to happen before ChestMenu.threeRows as it is required for opening animations
if (level instanceof ServerLevel serverLevel && player.openMenu(
new SimpleMenuProvider(
- (containerId, playerInventory, player1) -> ChestMenu.threeRows(containerId, playerInventory, enderChestInventory), CONTAINER_TITLE
- )
+ (containerId, playerInventory, player1) -> switch (fun.bm.lophine.config.modules.function.ContainerExpansionConfig.enderchestRows) {
+ case 6 -> ChestMenu.sixRows(containerId, playerInventory, enderChestInventory);
+ case 5 -> ChestMenu.fiveRows(containerId, playerInventory, enderChestInventory);
+ case 4 -> ChestMenu.fourRows(containerId, playerInventory, enderChestInventory);
+ case 2 -> ChestMenu.twoRows(containerId, playerInventory, enderChestInventory);
+ case 1 -> ChestMenu.oneRow(containerId, playerInventory, enderChestInventory);
+ default -> ChestMenu.threeRows(containerId, playerInventory, enderChestInventory);
- new SimpleMenuProvider((containerId, inventory, p) -> ChestMenu.threeRows(containerId, inventory, container), CONTAINER_TITLE)
+ new SimpleMenuProvider(
+ (containerId, inventory, p) -> switch (fun.bm.lophine.config.modules.function.ContainerExpansionConfig.enderchestRows) {
+ case 6 -> ChestMenu.sixRows(containerId, inventory, container);
+ case 5 -> ChestMenu.fiveRows(containerId, inventory, container);
+ case 4 -> ChestMenu.fourRows(containerId, inventory, container);
+ case 2 -> ChestMenu.twoRows(containerId, inventory, container);
+ case 1 -> ChestMenu.oneRow(containerId, inventory, container);
+ default -> ChestMenu.threeRows(containerId, inventory, container);
+ }, CONTAINER_TITLE) // Purpur - Barrels and enderchests 6 rows
).isPresent()) {
// Paper end - Fix InventoryOpenEvent cancellation - moved up;
player.awardStat(Stats.OPEN_ENDERCHEST);
diff --git a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
index de99652629c7301a4bc0e9ec48bed9a26a338f0d..b43445d8313c330a0376aaa4eb872495ebd87b5f 100644
index 61e39a18c0fba22699750e5c0187d19a0433b9a2..98c48426fcbb4aeba479e87ab27b03e17b50d7f5 100644
--- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
@@ -56,7 +56,17 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -60,7 +60,17 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity implemen
}
// CraftBukkit end
private static final Component DEFAULT_NAME = Component.translatable("container.barrel");
- private NonNullList<ItemStack> items = NonNullList.withSize(27, ItemStack.EMPTY);
+ // Purpur start - Barrels and enderchests 6 rows
+ private NonNullList<ItemStack> items = NonNullList.withSize(switch (fun.bm.lophine.config.modules.function.ContainerExpansionConfig.barrelRows) {
@@ -135,9 +135,9 @@ index de99652629c7301a4bc0e9ec48bed9a26a338f0d..b43445d8313c330a0376aaa4eb872495
+ // Purpur end - Barrels and enderchests 6 rows
+
public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() {
@Override
protected void onOpen(Level level, BlockPos pos, BlockState state) {
@@ -108,7 +118,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity implemen
{
Objects.requireNonNull(BarrelBlockEntity.this);
@@ -123,7 +133,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity implemen
@Override
public int getContainerSize() {
@@ -155,19 +155,19 @@ index de99652629c7301a4bc0e9ec48bed9a26a338f0d..b43445d8313c330a0376aaa4eb872495
}
@Override
@@ -129,7 +148,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -144,7 +163,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity implemen
@Override
protected AbstractContainerMenu createMenu(int id, Inventory player) {
- return ChestMenu.threeRows(id, player, this);
protected AbstractContainerMenu createMenu(final int containerId, final Inventory inventory) {
- return ChestMenu.threeRows(containerId, inventory, this);
+ // Purpur start - Barrels and enderchests 6 rows
+ return switch (fun.bm.lophine.config.modules.function.ContainerExpansionConfig.barrelRows) {
+ case 6 -> ChestMenu.sixRows(id, player, this);
+ case 5 -> ChestMenu.fiveRows(id, player, this);
+ case 4 -> ChestMenu.fourRows(id, player, this);
+ case 2 -> ChestMenu.twoRows(id, player, this);
+ case 1 -> ChestMenu.oneRow(id, player, this);
+ default -> ChestMenu.threeRows(id, player, this);
+ case 6 -> ChestMenu.sixRows(containerId, inventory, this);
+ case 5 -> ChestMenu.fiveRows(containerId, inventory, this);
+ case 4 -> ChestMenu.fourRows(containerId, inventory, this);
+ case 2 -> ChestMenu.twoRows(containerId, inventory, this);
+ case 1 -> ChestMenu.oneRow(containerId, inventory, this);
+ default -> ChestMenu.threeRows(containerId, inventory, this);
+ };
+ // Purpur end - Barrels and enderchests 6 rows
}
@@ -1,55 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 3 Aug 2025 14:26:37 +0800
Subject: [PATCH] Disable some check for operators
Subject: [PATCH] Add config to disable some check for operators
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index f06b9d8ad9512d35f3f460eb77c869690321c67f..e17f9629369f8653b484b4cc71de4874b5faa4d6 100644
index e12927623e8de82a6105b0cb0e6b58a6c45cff7e..0b5f2060062a354bd6cafa8f53a5734dc83d062d 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -367,7 +367,7 @@ public class ServerGamePacketListenerImpl
@@ -399,7 +399,7 @@ public class ServerGamePacketListenerImpl
this.tickCount++;
this.knownMovePacketCount = this.receivedMovePacketCount;
if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger() && !this.player.isDeadOrDying()) {
- if (++this.aboveGroundTickCount > this.getMaximumFlyingTicks(this.player)) {
+ if (++this.aboveGroundTickCount > this.getMaximumFlyingTicks(this.player) && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpFlyCheck && this.player.hasPermissions(2))) { // Lophine - disable fly check for operator
// LOGGER.warn("{} was kicked for floating too long!", this.player.getName().getString()); // Paper - Logging moved to net.minecraft.server.network.ServerCommonPacketListenerImpl.disconnect()
+ if (++this.aboveGroundTickCount > this.getMaximumFlyingTicks(this.player) && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpFlyCheck && MinecraftServer.getServer().getPlayerList().isOp(this.player.nameAndId()))) { // Lophine - disable fly check for operator
// LOGGER.warn("{} was kicked for floating too long!", this.player.getPlainTextName()); // Paper - Logging moved to net.minecraft.server.network.ServerCommonPacketListenerImpl.disconnect()
this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_PLAYER); // Paper - use configurable kick message & kick event cause
return;
@@ -386,7 +386,7 @@ public class ServerGamePacketListenerImpl
return true;
@@ -418,7 +418,7 @@ public class ServerGamePacketListenerImpl
this.vehicleLastGoodY = this.lastVehicle.getY();
this.vehicleLastGoodZ = this.lastVehicle.getZ();
if (this.clientVehicleIsFloating && this.lastVehicle.getControllingPassenger() == this.player) {
- if (++this.aboveGroundVehicleTickCount > this.getMaximumFlyingTicks(this.lastVehicle)) {
+ if (++this.aboveGroundVehicleTickCount > this.getMaximumFlyingTicks(this.lastVehicle) && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpFlyCheck && this.player.hasPermissions(2))) { // Lophine - disable fly check for operator
// LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getName().getString()); // Paper - Logging moved to net.minecraft.server.network.ServerCommonPacketListenerImpl.disconnect()
+ if (++this.aboveGroundVehicleTickCount > this.getMaximumFlyingTicks(this.lastVehicle) && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpFlyCheck && MinecraftServer.getServer().getPlayerList().isOp(this.player.nameAndId()))) { // Lophine - disable fly check for operator
// LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getPlainTextName()); // Paper - Logging moved to net.minecraft.server.network.ServerCommonPacketListenerImpl.disconnect()
this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_VEHICLE); // Paper - use configurable kick message & kick event cause
return;
@@ -644,7 +644,7 @@ public class ServerGamePacketListenerImpl
d5 = d2 - rootVehicle.getZ();
d7 = d3 * d3 + d4 * d4 + d5 * d5;
boolean flag1 = false;
- if (!me.earthme.luminol.config.modules.misc.DisableMovedWronglyThreshold.enabled && d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
+ if (!me.earthme.luminol.config.modules.misc.DisableMovedWronglyThreshold.enabled && d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpMoveCheck && this.player.hasPermissions(2))) { // Spigot // Lophine - disable move check for operator
flag1 = true; // Paper - diff on change, this should be moved wrongly
LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7));
return true;
@@ -671,7 +671,7 @@ public class ServerGamePacketListenerImpl
zDist = targetZ - vehicle.getZ();
movedDist = xDist * xDist + yDist * yDist + zDist * zDist;
boolean fail = false;
- if (!me.earthme.luminol.config.modules.misc.DisableWarningConfig.disableMovedWronglyThresholdWarning && movedDist > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot // Leaves - disable can
+ if (!me.earthme.luminol.config.modules.misc.DisableWarningConfig.disableMovedWronglyThresholdWarning && movedDist > org.spigotmc.SpigotConfig.movedWronglyThreshold && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpMoveCheck && MinecraftServer.getServer().getPlayerList().isOp(this.player.nameAndId()))) { // Spigot // Leaves - disable can // Lophine - disable move check for operator
fail = true;
LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", vehicle.getPlainTextName(), this.player.getPlainTextName(), Math.sqrt(movedDist));
}
@@ -1540,7 +1540,7 @@ public class ServerGamePacketListenerImpl
@@ -1603,7 +1603,7 @@ public class ServerGamePacketListenerImpl
// Paper start - Add fail move event
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY,
toX, toY, toZ, toYaw, toPitch, true);
targetX, targetY, targetZ, targetYRot, targetXRot, true);
- if (!event.isAllowed()) {
+ if (!event.isAllowed() && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpMoveCheck && this.player.hasPermissions(2))) { // Lophine - disable move check for operator
+ if (!event.isAllowed() && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpMoveCheck && MinecraftServer.getServer().getPlayerList().isOp(this.player.nameAndId()))) { // Lophine - disable move check for operator
if (event.getLogWarning()) {
LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getName().getString(), d3, d4, d5);
LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getPlainTextName(), xDist, yDist, zDist);
}
@@ -1618,7 +1618,7 @@ public class ServerGamePacketListenerImpl
@@ -1682,7 +1682,7 @@ public class ServerGamePacketListenerImpl
// Paper start - Add fail move event
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_WRONGLY,
toX, toY, toZ, toYaw, toPitch, true);
targetX, targetY, targetZ, targetYRot, targetXRot, true);
- if (!event.isAllowed()) {
+ if (!event.isAllowed() && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpMoveCheck && this.player.hasPermissions(2))) { // Lophine - disable move check for operator
+ if (!event.isAllowed() && !(fun.bm.lophine.config.modules.misc.DisableCheckConfig.disableOpMoveCheck && MinecraftServer.getServer().getPlayerList().isOp(this.player.nameAndId()))) { // Lophine - disable move check for operator
movedWrongly = true;
if (event.getLogWarning())
// Paper end
@@ -5,24 +5,24 @@ Subject: [PATCH] Add config to enable cross region damage trace
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 11e6197dec541b28733715f0d7eaa4c7b834d632..de1263404395c28209234a556347284fa557f81c 100644
index ad50feba5cbc5fe904850e6da06a866eeb23b519..f7869f06ab29e4bbd003c807176345dec9e9e5ab 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1345,6 +1345,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.awardStat(Stats.ENTITY_KILLED_BY.get(killCredit.getType()));
killCredit.awardKillScore(this, cause);
this.createWitherRose(killCredit);
@@ -1467,6 +1467,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.awardStat(Stats.ENTITY_KILLED_BY.get(killer.getType()));
killer.awardKillScore(this, source);
this.createWitherRose(killer);
+ // Luminol Start - Cross Region Damage trace
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ final LivingEntity entitylivingnew = this.getKillCreditOrigin();
+ if (entitylivingnew != null) {
+ this.damageTransferToAsync(entitylivingnew, cause);
+ this.damageTransferToAsync(entitylivingnew, source);
+ }
+ // Luminol End - Cross Region Damage trace
+ // Luminol End - Cross Region Damage trace
}
this.level().broadcastEntityEvent(this, (byte)3);
@@ -1368,6 +1375,24 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.level().broadcastEntityEvent(this, EntityEvent.DEATH);
@@ -1490,6 +1497,24 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// Leaves end - exp fix
@@ -48,24 +48,24 @@ index 11e6197dec541b28733715f0d7eaa4c7b834d632..de1263404395c28209234a556347284f
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
this.level()
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 0c6d48363cd65cd22b4cc0ab97be977e133b64be..e94687b3aa960f9c630f459fedc17bc01846eaf7 100644
index cd2fb9e2110d0dba1358daa283af767db3f4e80a..cc7b2ea7fda1326e3f9ed46373190a05f60c4d34 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -1948,6 +1948,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -1961,6 +1961,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
final LivingEntity killer = this.getKillCredit();
if (killer != null) {
killer.awardKillScore(this, damageSource);
killer.awardKillScore(this, source);
+ // Luminol Start - Cross Region Damage trace
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ final LivingEntity killernew = this.getKillCreditOrigin();
+ if (killernew != null) {
+ this.damageTransferToAsync(killernew, damageSource);
+ this.damageTransferToAsync(killernew, source);
+ }
+ // Luminol End - Cross Region Damage trace
}
}); // Paper end
this.postDeathDropItems(deathEvent); // Paper
@@ -1958,6 +1965,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -1971,6 +1978,19 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
return deathEvent; // Paper
}
@@ -73,6 +73,7 @@ index 0c6d48363cd65cd22b4cc0ab97be977e133b64be..e94687b3aa960f9c630f459fedc17bc0
+ private void damageTransferToAsync(LivingEntity entity, DamageSource damageSource) {
+ entity.getBukkitEntity().taskScheduler.schedule((LivingEntity nmsEntity) -> {
+ try {
+ if (nmsEntity.isRemoved()) return;
+ nmsEntity.awardKillScore(this, damageSource);
+ } catch (Throwable ex) {
+ LOGGER.error(ex.getMessage(), ex);
@@ -81,10 +82,10 @@ index 0c6d48363cd65cd22b4cc0ab97be977e133b64be..e94687b3aa960f9c630f459fedc17bc0
+ }
+ // Luminol End - Cross Region Damage trace
+
protected void dropEquipment(ServerLevel level) {
protected void dropEquipment(final ServerLevel level) {
}
protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {} // Paper - method for post death logic that cannot be ran before the event is potentially cancelled
@@ -2556,6 +2575,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -2629,6 +2649,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
}
}
@@ -0,0 +1,94 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Fri, 16 Jan 2026 02:34:43 +0800
Subject: [PATCH] Add config to enable save-all command
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index 11cacb26ce260373476dad764014ba1852477831..981f63b75584dbcb4bb0d5672e8c8bb140c52f9d 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -364,6 +364,8 @@ public final class RegionizedServer {
// tick player ping sample
this.tickPlayerSample();
+ fun.bm.lophine.utils.SaveAllUtil.checkTimeout(); // Lophine - save-all fix
+
// tick worlds
for (final ServerLevel world : this.worlds) {
this.globalTick(world, tickCount);
diff --git a/io/papermc/paper/threadedregions/TickRegions.java b/io/papermc/paper/threadedregions/TickRegions.java
index 02c004bc7f9a0203523ce4b27cd766d6bdc478c0..3d86e21198f2888422330b6f7c27712f40a6aabc 100644
--- a/io/papermc/paper/threadedregions/TickRegions.java
+++ b/io/papermc/paper/threadedregions/TickRegions.java
@@ -190,6 +190,8 @@ public final class TickRegions implements ThreadedRegionizer.RegionCallbacks<Tic
public final ThreadedRegionizer.ThreadedRegion<TickRegionData, TickRegionSectionData> region;
public final ServerLevel world;
+ public long lastSavedTime = 0; // Lophine - save-all fix
+
// generic regionised data
private final Reference2ReferenceOpenHashMap<RegionizedData<?>, Object> regionizedData = new Reference2ReferenceOpenHashMap<>();
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 89f61f5715942d2b521e04b9fdc8b1b379c0c957..2c2487e1c1c65438119a13bd705a9e44697955ed 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -299,7 +299,11 @@ public class Commands {
PardonCommand.register(this.dispatcher);
PardonIpCommand.register(this.dispatcher);
//PerfCommand.register(this.dispatcher); // Folia - region threading - TODO later
- //SaveAllCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ // Lophine start - Add a config to enable save all command
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.saveAll) {
+ SaveAllCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ }
+ // Lophine end - Add a config to enable save all command
SaveOffCommand.register(this.dispatcher);
SaveOnCommand.register(this.dispatcher);
SetPlayerIdleTimeoutCommand.register(this.dispatcher);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 61983a80191e64942bfdac74c6d2f23cf781484d..99edebf474277e680df63930b51fef579b712def 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1686,6 +1686,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Folia start - region threading
public void tickServer(final long startTime, final long scheduledEnd, final long targetBuffer,
final io.papermc.paper.threadedregions.TickRegions.TickRegionData region) {
+ // Lophine start - save-all fix
+ if (fun.bm.lophine.utils.SaveAllUtil.isSaving()) {
+ fun.bm.lophine.utils.SaveAllUtil.postRegionSave(region);
+ }
+ // Lophine end - save-all fix
final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle foliaProfiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler
// Folia end - region threading
org.spigotmc.WatchdogThread.tick(); // Spigot
diff --git a/net/minecraft/server/commands/SaveAllCommand.java b/net/minecraft/server/commands/SaveAllCommand.java
index bc6d01996dde0870f6ebbda14176352777938a0c..8314d239435debf7aff947b7dd3bab83e3c80dc6 100644
--- a/net/minecraft/server/commands/SaveAllCommand.java
+++ b/net/minecraft/server/commands/SaveAllCommand.java
@@ -21,7 +21,9 @@ public class SaveAllCommand {
}
private static int saveAll(final CommandSourceStack source, final boolean flush) throws CommandSyntaxException {
- source.sendSuccess(() -> Component.translatable("commands.save.saving"), false);
+ // Lophine start - save all
+ fun.bm.lophine.utils.SaveAllUtil.preSaveAll(source, flush);
+/* source.sendSuccess(() -> Component.translatable("commands.save.saving"), false);
MinecraftServer server = source.getServer();
boolean success = server.saveEverything(true, flush, true);
if (!success) {
@@ -29,6 +31,12 @@ public class SaveAllCommand {
} else {
source.sendSuccess(() -> Component.translatable("commands.save.success"), true);
return 1;
- }
+ }*/
+ return 1;
}
+
+ public static SimpleCommandExceptionType getErrorFailed() {
+ return ERROR_FAILED;
+ }
+ // Lophine end - save all
}
@@ -1,167 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 1 May 2025 22:43:08 +0800
Subject: [PATCH] Add config to enable tick command
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index e1842ab8f20271a8b20ab8462b09a4745a612a9a..8405157ec35a443e238fa6866772c839621d73d7 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -299,6 +299,11 @@ public final class RegionizedServer {
this.randomWalk();
*/
++this.tickCount;
+ // Luminol start - Add a config to enable tick command
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ MinecraftServer.tickRateManager.tick();
+ }
+ // Luminol end - Add a config to enable tick command
// expire invalid click command callbacks
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.ADVENTURE_CLICK_MANAGER.handleQueue((int)this.tickCount); // Paper // Folia - region threading - moved to global tick
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue((int)this.tickCount); // Paper // Folia - region threading - moved to global tick
@@ -322,6 +327,13 @@ public final class RegionizedServer {
this.globalTick(world, tickCount);
}
+ // Luminol start - Add a config to enable tick command
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ MinecraftServer.tickRateManager.reduceSprintTicks();
+ MinecraftServer.tickRateManager.endTickWork();
+ }
+ // Luminol end - Add a config to enable tick command
+
// tick connections
this.tickConnections();
@@ -455,7 +467,7 @@ public final class RegionizedServer {
}
private void tickTime(final ServerLevel world, final int tickCount) {
- if (world.tickTime) {
+ if ((!fun.bm.lophine.config.modules.experiment.CommandConfig.tick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command
if (world.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) {
world.setDayTime(world.levelData.getDayTime() + (long)tickCount);
}
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
index c485d5b3ba95f2a969bdf0dab9654ac284976f8d..b957585cf7cf7f845e20f59c7b355722880f3b4e 100644
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
@@ -31,8 +31,8 @@ public final class TickRegionScheduler {
}
}
- public static final int TICK_RATE = 20;
- public static final long TIME_BETWEEN_TICKS = 1_000_000_000L / TICK_RATE; // ns
+ public static float TICK_RATE = 20; // Luminol - Add tick command support
+ public static long TIME_BETWEEN_TICKS = (long) (1_000_000_000L / TICK_RATE); // ns // Luminol - Add tick command support
// Folia start - watchdog
public static final FoliaWatchdogThread WATCHDOG_THREAD = new FoliaWatchdogThread();
@@ -394,8 +394,23 @@ public final class TickRegionScheduler {
final long cpuStart = MEASURE_CPU_TIME ? THREAD_MX_BEAN.getCurrentThreadCpuTime() : 0L;
final long tickStart = System.nanoTime();
- // use max(), don't assume that tickStart >= scheduledStart
- final int tickCount = Math.max(1, this.tickSchedule.getPeriodsAhead(TIME_BETWEEN_TICKS, tickStart));
+ // Luminol start - Add a config to enable tick command
+ final int tickCount;
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ if (MinecraftServer.tickRateManager.isSprinting() && MinecraftServer.tickRateManager.checkShouldSprintThisTick()) {
+ TICK_RATE = net.minecraft.server.commands.TickCommand.MAX_TICKRATE;
+ TIME_BETWEEN_TICKS = (long) (1_000_000_000L / TICK_RATE);
+ tickCount = 1;
+ } else {
+ TICK_RATE = MinecraftServer.tickRateManager.tickrate();
+ TIME_BETWEEN_TICKS = (long) (1_000_000_000L / TICK_RATE);
+ tickCount = Math.max(1, this.tickSchedule.getPeriodsAhead(TIME_BETWEEN_TICKS, tickStart));
+ }
+ } else {
+ // use max(), don't assume that tickStart >= scheduledStart
+ tickCount = Math.max(1, this.tickSchedule.getPeriodsAhead(TIME_BETWEEN_TICKS, tickStart));
+ }
+ // Luminol end - Add tick command support
if (!this.tryMarkTicking()) {
if (!this.cancelled.get()) {
@@ -435,6 +450,11 @@ public final class TickRegionScheduler {
try {
// next start isn't updated until the end of this tick
this.tickRegion(tickCount, tickStart, scheduledEnd);
+ // Luminol start - Add a config to enable tick command
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ MinecraftServer.tickRateManager.endTickWork();
+ }
+ // Luminol end - Add a config to enable tick command
} catch (final Throwable thr) {
this.scheduler.regionFailed(this, false, thr);
// regionFailed will schedule a shutdown, so we should avoid letting this region tick further
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 22d211bee83e3ef34d6ac81dd89c0e73924bee90..1fb359073342a657e9e493403263b56be5b3393f 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -249,7 +249,11 @@ public class Commands {
TeleportCommand.register(this.dispatcher);
TellRawCommand.register(this.dispatcher, context);
//TestCommand.register(this.dispatcher, context); // Folia - region threading
- //TickCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ // Luminol start - Add a config to enable tick command
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ TickCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ }
+ // Luminol end - Add a config to enable tick command
TimeCommand.register(this.dispatcher);
TitleCommand.register(this.dispatcher, context);
//TriggerCommand.register(this.dispatcher); // Folia - region threading - TODO later
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 75027e73859c955a54034640f905cb5d91a6a2f4..2f4970242c754cfba8ff5656a63af07d9d0a723c 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -267,7 +267,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private String serverId;
public MinecraftServer.ReloadableResources resources;
private final StructureTemplateManager structureTemplateManager;
- private final ServerTickRateManager tickRateManager;
+ public static ServerTickRateManager tickRateManager; // Luminol - Add tick command support
protected WorldData worldData;
public PotionBrewing potionBrewing;
private FuelValues fuelValues;
diff --git a/net/minecraft/server/ServerTickRateManager.java b/net/minecraft/server/ServerTickRateManager.java
index 40338efd1c0e56d869d03f1d0687e7ff0fcbf11a..d0d90a25a10bbecfffceee1992af88c60d14fd87 100644
--- a/net/minecraft/server/ServerTickRateManager.java
+++ b/net/minecraft/server/ServerTickRateManager.java
@@ -105,7 +105,7 @@ public class ServerTickRateManager extends TickRateManager {
return false;
} else if (this.remainingSprintTicks > 0L) {
this.sprintTickStartTime = System.nanoTime();
- this.remainingSprintTicks--;
+ // this.remainingSprintTicks--; // Luminol - Add tick command support
return true;
} else {
this.finishTickSprint();
@@ -113,6 +113,12 @@ public class ServerTickRateManager extends TickRateManager {
}
}
+ // Luminol start - Add tick command support
+ public void reduceSprintTicks() {
+ this.remainingSprintTicks--;
+ }
+ // Luminol end - Add tick command support
+
public void endTickWork() {
this.sprintTimeSpend = this.sprintTimeSpend + (System.nanoTime() - this.sprintTickStartTime);
}
diff --git a/net/minecraft/server/commands/TickCommand.java b/net/minecraft/server/commands/TickCommand.java
index 126685fb266692082b432ed297a499149e921dfb..9d8f6025c420e651611da17e77a362c738228b72 100644
--- a/net/minecraft/server/commands/TickCommand.java
+++ b/net/minecraft/server/commands/TickCommand.java
@@ -14,7 +14,7 @@ import net.minecraft.server.ServerTickRateManager;
import net.minecraft.util.TimeUtil;
public class TickCommand {
- private static final float MAX_TICKRATE = 10000.0F;
+ public static final float MAX_TICKRATE = 10000.0F; // Luminol - Add tick command support
private static final String DEFAULT_TICKRATE = String.valueOf(20);
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
@@ -5,17 +5,19 @@ Subject: [PATCH] Add config to enable function command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 11697e65a7f7871920ca7bad37de07f78a3da1f8..25ccbfa12d57d540195ecc16aa54a144f8ecc0e8 100644
index 2c2487e1c1c65438119a13bd705a9e44697955ed..4e0428948d618b0a072679762dc3cb39d6e12c2f 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -204,7 +204,9 @@ public class Commands {
@@ -217,7 +217,11 @@ public class Commands {
FillCommand.register(this.dispatcher, context);
FillBiomeCommand.register(this.dispatcher, context);
ForceLoadCommand.register(this.dispatcher);
- //FunctionCommand.register(this.dispatcher); // Folia - region threading - TODO
+ // Lophine start - Add config to enable function command
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.function) {
+ FunctionCommand.register(this.dispatcher); // Folia - region threading - TODO
+ }
+ // Lophine end - Add config to enable function command
GameModeCommand.register(this.dispatcher);
GameRuleCommand.register(this.dispatcher, context);
GiveCommand.register(this.dispatcher, context);
@@ -1,92 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 7 Jul 2025 18:19:00 +0800
Subject: [PATCH] Add config to enable waypoint command & bar
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 1fb359073342a657e9e493403263b56be5b3393f..451a685782da46f5683ea6707289bbaf3193771f 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -257,7 +257,11 @@ public class Commands {
TimeCommand.register(this.dispatcher);
TitleCommand.register(this.dispatcher, context);
//TriggerCommand.register(this.dispatcher); // Folia - region threading - TODO later
- //WaypointCommand.register(this.dispatcher, context); // Folia - region threading - TODO later
+ // Lophine start - unsafe waypoint bar
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.waypoint) {
+ WaypointCommand.register(this.dispatcher, context); // Folia - region threading - TODO later
+ }
+ // Lophine end - unsafe waypoint bar
WeatherCommand.register(this.dispatcher);
WorldBorderCommand.register(this.dispatcher);
if (JvmProfiler.INSTANCE.isAvailable()) {
diff --git a/net/minecraft/server/waypoints/ServerWaypointManager.java b/net/minecraft/server/waypoints/ServerWaypointManager.java
index 0f8cacbb8fe55a60e2f0c98bf36c005b29f41a4b..52fd730998535ea071bfc99b7cc2c254b9b656d7 100644
--- a/net/minecraft/server/waypoints/ServerWaypointManager.java
+++ b/net/minecraft/server/waypoints/ServerWaypointManager.java
@@ -22,7 +22,14 @@ public class ServerWaypointManager implements WaypointManager<WaypointTransmitte
@Override
public void trackWaypoint(WaypointTransmitter waypoint) {
- // Folia - region threading
+ // Lophine start - unsafe waypoint bar
+ if (!fun.bm.lophine.config.modules.experiment.CommandConfig.waypoint) return;
+ this.waypoints.add(waypoint);
+
+ for (ServerPlayer serverPlayer : this.players) {
+ this.createConnection(serverPlayer, waypoint);
+ }
+ // Lophine end - unsafe waypoint bar
}
@Override
@@ -50,14 +57,48 @@ public class ServerWaypointManager implements WaypointManager<WaypointTransmitte
public void addPlayer(ServerPlayer player) {
// Folia - region threading
+ // Lophine start - unsafe waypoint bar
+ if (!fun.bm.lophine.config.modules.experiment.CommandConfig.waypoint) return;
+ this.players.add(player);
+
+ for (WaypointTransmitter waypointTransmitter : this.waypoints) {
+ this.createConnection(player, waypointTransmitter);
+ }
+
+ if (player.isTransmittingWaypoint()) {
+ this.trackWaypoint((WaypointTransmitter)player);
+ }
+ // Lophine end - unsafe waypoint bar
}
public void updatePlayer(ServerPlayer player) {
// Folia - region threading
+ // Lophine start - unsafe waypoint bar
+ if (!fun.bm.lophine.config.modules.experiment.CommandConfig.waypoint) return;
+ Map<WaypointTransmitter, WaypointTransmitter.Connection> map = this.connections.row(player);
+ SetView<WaypointTransmitter> set = Sets.difference(this.waypoints, map.keySet());
+
+ for (Entry<WaypointTransmitter, WaypointTransmitter.Connection> entry : ImmutableSet.copyOf(map.entrySet())) {
+ this.updateConnection(player, entry.getKey(), entry.getValue());
+ }
+
+ for (WaypointTransmitter waypointTransmitter : set) {
+ this.createConnection(player, waypointTransmitter);
+ }
+ // Lophine end - unsafe waypoint bar
}
public void removePlayer(ServerPlayer player) {
// Folia - region threading
+ // Lophine start - unsafe waypoint bar
+ if (!fun.bm.lophine.config.modules.experiment.CommandConfig.waypoint) return;
+ this.connections.row(player).values().removeIf(connection -> {
+ connection.disconnect();
+ return true;
+ });
+ this.untrackWaypoint((WaypointTransmitter)player);
+ this.players.remove(player);
+ // Lophine end - unsafe waypoint bar
}
public void breakAllConnections() {
@@ -5,11 +5,11 @@ Subject: [PATCH] Add config to enable scoreboard command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 25ccbfa12d57d540195ecc16aa54a144f8ecc0e8..22d211bee83e3ef34d6ac81dd89c0e73924bee90 100644
index 4e0428948d618b0a072679762dc3cb39d6e12c2f..87ffca5ff0c2775cb85a6058c9be66e00c94f01f 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -229,7 +229,11 @@ public class Commands {
//RotateCommand.register(this.dispatcher); // Folia - region threading - TODO later
@@ -246,7 +246,11 @@ public class Commands {
RotateCommand.register(this.dispatcher);
SayCommand.register(this.dispatcher);
//ScheduleCommand.register(this.dispatcher); // Folia - region threading
- //ScoreboardCommand.register(this.dispatcher, context); // Folia - region threading
@@ -17,7 +17,7 @@ index 25ccbfa12d57d540195ecc16aa54a144f8ecc0e8..22d211bee83e3ef34d6ac81dd89c0e73
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.scoreboard) {
+ ScoreboardCommand.register(this.dispatcher, context); // Folia - region threading
+ }
+ // Lophine start - Add a config to enable scoreboard command
SeedCommand.register(this.dispatcher, selection != Commands.CommandSelection.INTEGRATED);
VersionCommand.register(this.dispatcher, selection != Commands.CommandSelection.INTEGRATED);
+ // Lophine end - Add a config to enable scoreboard command
SeedCommand.register(this.dispatcher, commandSelection != Commands.CommandSelection.INTEGRATED);
VersionCommand.register(this.dispatcher, commandSelection != Commands.CommandSelection.INTEGRATED);
SetBlockCommand.register(this.dispatcher, context);
@@ -1,94 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 2 Jul 2025 23:36:25 +0800
Subject: [PATCH] Fix datapack command save function
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 2f4970242c754cfba8ff5656a63af07d9d0a723c..b156b5c635f931a3d4abc0584591f90476d011a6 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2353,6 +2353,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return this.reloadResources(selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN);
}
+ // Lophine start - region thread skip reload // TODO - add reload support
+ public void saveDatapacks(Collection<String> selectedIds) {
+ this.packRepository.setSelected(selectedIds, false); // Paper - add pendingReload flag to determine required pack loading - false as this is *after* a reload (see above)
+ WorldDataConfiguration worldDataConfiguration = new WorldDataConfiguration(
+ getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()
+ );
+ this.worldData.setDataConfiguration(worldDataConfiguration);
+ }
+ // Lophine end - region thread skip reload // TODO - add reload support
+
public CompletableFuture<Void> reloadResources(Collection<String> selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause) {
// Paper end - Add ServerResourcesReloadedEvent
CompletableFuture<Void> completableFuture = CompletableFuture.<ImmutableList>supplyAsync(
diff --git a/net/minecraft/server/commands/DataPackCommand.java b/net/minecraft/server/commands/DataPackCommand.java
index a5032b34752061d61fd9ddb4db828d35e403f5e7..3eaa9c85d06f6ecc8ed639d8befa861439390eb7 100644
--- a/net/minecraft/server/commands/DataPackCommand.java
+++ b/net/minecraft/server/commands/DataPackCommand.java
@@ -98,7 +98,7 @@ public class DataPackCommand {
dispatcher.register(
Commands.literal("datapack")
.requires(Commands.hasPermission(2))
- /*.then( // Luminol - Add back read-only datapack command
+ .then(
Commands.literal("enable")
.then(
Commands.argument("name", StringArgumentType.string())
@@ -160,11 +160,11 @@ public class DataPackCommand {
.suggests(SELECTED_PACKS)
.executes(commandContext -> disablePack(commandContext.getSource(), getPack(commandContext, "name", false)))
)
- )*/ // Luminol - Add back read-only datapack command
+ )
.then(
Commands.literal("list")
.executes(commandContext -> listPacks(commandContext.getSource()))
- // .then(Commands.literal("available").executes(commandContext -> listAvailablePacks(commandContext.getSource()))) // Luminol - Add back read-only datapack command
+ .then(Commands.literal("available").executes(commandContext -> listAvailablePacks(commandContext.getSource())))
.then(Commands.literal("enabled").executes(commandContext -> listEnabledPacks(commandContext.getSource())))
)
.then(
@@ -252,7 +252,7 @@ public class DataPackCommand {
}
private static int listPacks(CommandSourceStack source) {
- return listEnabledPacks(source) ;// + listAvailablePacks(source); // Luminol - Add back read-only datapack command
+ return listEnabledPacks(source) + listAvailablePacks(source);
}
private static int listAvailablePacks(CommandSourceStack source) {
@@ -280,7 +280,7 @@ public class DataPackCommand {
private static int listEnabledPacks(CommandSourceStack source) {
PackRepository packRepository = source.getServer().getPackRepository();
- // packRepository.reload(); // Luminol - Add back read-only datapack command
+ packRepository.reload();
Collection<? extends Pack> selectedPacks = packRepository.getSelectedPacks();
if (selectedPacks.isEmpty()) {
source.sendSuccess(() -> Component.translatable("commands.datapack.list.enabled.none"), false);
diff --git a/net/minecraft/server/commands/ReloadCommand.java b/net/minecraft/server/commands/ReloadCommand.java
index b540a3c3a02f7242578a63477e34b9063e86f1d2..bc999de32931558d0d8dc26264653dd63c1cad19 100644
--- a/net/minecraft/server/commands/ReloadCommand.java
+++ b/net/minecraft/server/commands/ReloadCommand.java
@@ -16,11 +16,17 @@ public class ReloadCommand {
private static final Logger LOGGER = LogUtils.getLogger();
public static void reloadPacks(Collection<String> selectedIds, CommandSourceStack source) {
+ // Lophine start - region thread skip reload // TODO - add reload support
+ source.getServer().saveDatapacks(selectedIds);
+ source.getSender().sendMessage("You need to restart server to load datapacks update.");
+ if (false) {
source.getServer().reloadResources(selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.COMMAND).exceptionally(throwable -> { // Paper - Add ServerResourcesReloadedEvent
LOGGER.warn("Failed to execute reload", throwable);
source.sendFailure(Component.translatable("commands.reload.failure"));
return null;
});
+ }
+ // Lophine end - region thread skip reload // TODO - add reload support
}
private static Collection<String> discoverNewPacks(PackRepository packRepository, WorldData worldData, Collection<String> selectedIds) {
@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 4 Jun 2026 00:56:32 +0800
Subject: [PATCH] Add config to enable trigger command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 87ffca5ff0c2775cb85a6058c9be66e00c94f01f..74ef76058e5a410d12f88aa09450e7d90f63b5e6 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -274,7 +274,11 @@ public class Commands {
// Luminol end - Add a config to enable tick command
TimeCommand.register(this.dispatcher, context);
TitleCommand.register(this.dispatcher, context);
- //TriggerCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ // Lophine start - Add a config to enable trigger command
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.trigger) {
+ TriggerCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ }
+ // Lophine end - Add a config to enable trigger command
if (me.earthme.luminol.config.modules.experiment.CommandConfig.waypointsAndWaypointCommand) WaypointCommand.register(this.dispatcher, context); // Folia - region threading - TODO later // Luminol - Restore waypoints
WeatherCommand.register(this.dispatcher);
WorldBorderCommand.register(this.dispatcher);
@@ -5,35 +5,36 @@ Subject: [PATCH] Add config to enable raytracing tracker
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 6868b915bf3deb85783a638d4441a15fea6da2dc..70740381c6501c1a518c52b24381edd16792507f 100644
index 0c0775bbb0c0ba0c37d1b884bb106b5250e94750..0dfb25ad032429a2aea7aa441dd5fd1848a6c617 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -1278,7 +1278,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
double d1 = vec3_dx * vec3_dx + vec3_dz * vec3_dz; // Paper
double d2 = d * d;
@@ -1350,7 +1350,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
double distanceSquared = deltaToPlayerX * deltaToPlayerX + deltaToPlayerZ * deltaToPlayerZ; // Paper
double rangeSquared = visibleRange * visibleRange;
// Paper start - Configurable entity tracking range by Y
- boolean flag = d1 <= d2;
+ boolean flag = d1 <= d2 && !entity.isCulled(); // Luminol - Ray tracing entity tracker
if (flag && level.paperConfig().entities.trackingRangeY.enabled) {
- boolean visibleToPlayer = distanceSquared <= rangeSquared;
+ boolean visibleToPlayer = distanceSquared <= rangeSquared && !entity.isCulled(); // Luminol - Ray tracing entity tracker
if (visibleToPlayer && level.paperConfig().entities.trackingRangeY.enabled) {
double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1);
if (rangeY != -1) {
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index f5539ca5964abb18124522a8aa7ce940517b2011..1258591aae1b926ee8085b1984d553b8d3a1df7e 100644
index 552fd994ee30deb6e9f4228b17a2883cf26b164c..f090b8d77bd2731debfc61c263bd77550f52212b 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -147,7 +147,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter;
import org.jetbrains.annotations.Contract;
import org.slf4j.Logger;
-public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker
+public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity, dev.tr7zw.entityculling.versionless.access.Cullable { // Paper - rewrite chunk system // Paper - optimise entity tracker // Luminol - Ray tracing entity tracker
@@ -167,7 +167,7 @@ public abstract class Entity
ItemOwner,
SlotProvider,
DebugValueSource,
- TypedInstance<EntityType<?>>, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker
+ TypedInstance<EntityType<?>>, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity, dev.tr7zw.entityculling.versionless.access.Cullable { // Paper - rewrite chunk system // Paper - optimise entity tracker // Luminol - Ray tracing entity tracker
// CraftBukkit start
private static final int CURRENT_LEVEL = 2;
public boolean preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; keep initial motion on first snapTo
@@ -6482,4 +6482,46 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
static boolean isLevelAtLeast(ValueInput input, int level) {
@@ -6432,4 +6432,48 @@ public abstract class Entity
// Paper end - Expose entity id counter
public boolean shouldTickHot() { return this.tickCount > 20 * 10 && this.isAlive(); } // KioCG
+ // Lophine start - Add config to enable raytracing tracker
+
+ private long lasttime = 0;
+ private boolean culled = false;
@@ -76,26 +77,29 @@ index f5539ca5964abb18124522a8aa7ce940517b2011..1258591aae1b926ee8085b1984d553b8
+ return this.outOfCamera;
+ }
+
+ // Lophine end - Add config to enable raytracing tracker
}
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
index 6f00ffa05d9597917574357e0069c9b056aa5ce2..5cc7a91e32f17d8d9585ae4844a4ed3b706e3273 100644
index cb0a52dc3795e1cf54069bcbe82abf7877a658b8..0d743a01ae70baa789cd0e0bb9abd4c4f8310b99 100644
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
@@ -1119,6 +1119,9 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
@@ -1252,6 +1252,11 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
public final int passengerTickTimerId;
public final int passengerInactiveTickTimerId;
// Folia end - profiler
+ // Lophine start - Add config to enable raytracing tracker
+ // Luminol - Raytracing entity tracker
+ public boolean skipRaytracningCheck = false;
+ // Luminol end
+ // Lophine end - Add config to enable raytracing tracker
public EntityType(
EntityType.EntityFactory<T> factory,
final EntityType.EntityFactory<T> factory,
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 2842314c712449625e9275aff7707c916c3ea767..09b549fa9568aa1ae13b1b975db14a6268fdaa46 100644
index ce8ab4b7eee5e0715e780d189d2f6554c5a9dc3c..06c6d30f3aef605bc25c42db8a6d26bbde57f40b 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -229,6 +229,25 @@ public abstract class Player extends LivingEntity {
@@ -186,6 +186,25 @@ public abstract class Player extends Avatar implements ContainerUser {
return (org.bukkit.craftbukkit.entity.CraftHumanEntity) super.getBukkitEntity();
}
// CraftBukkit end
@@ -119,9 +123,9 @@ index 2842314c712449625e9275aff7707c916c3ea767..09b549fa9568aa1ae13b1b975db14a62
+ }
+ // Luminol end
public Player(Level level, GameProfile gameProfile) {
public Player(final Level level, final GameProfile gameProfile) {
super(EntityType.PLAYER, level);
@@ -287,6 +306,26 @@ public abstract class Player extends LivingEntity {
@@ -241,6 +260,26 @@ public abstract class Player extends Avatar implements ContainerUser {
@Override
public void tick() {
@@ -148,8 +152,8 @@ index 2842314c712449625e9275aff7707c916c3ea767..09b549fa9568aa1ae13b1b975db14a62
this.noPhysics = this.isSpectator();
if (this.isSpectator() || this.isPassenger()) {
this.setOnGround(false);
@@ -1426,6 +1465,7 @@ public abstract class Player extends LivingEntity {
if (this.containerMenu != null && this.hasContainerOpen()) {
@@ -1355,6 +1394,7 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.hasContainerOpen()) {
this.doCloseContainer();
}
+ if (this.cullTask != null) this.cullTask.signalStop(); // Luminol - Ray tracing entity tracker
@@ -0,0 +1,123 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 21 Jan 2026 21:28:21 +0800
Subject: [PATCH] Add tick rate support
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index 981f63b75584dbcb4bb0d5672e8c8bb140c52f9d..6e8ee04967afa410ce9dccff34bf9a43201694fd 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -371,6 +371,14 @@ public final class RegionizedServer {
this.globalTick(world, tickCount);
}
+ // Lophine start - Add a config to enable tick command
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) {
+ net.minecraft.server.ServerTickRateManager rateManager = MinecraftServer.getServer().tickRateManager();
+ rateManager.reduceSprintTicks();
+ rateManager.endTickWork();
+ }
+ // Lophine end - Add a config to enable tick command
+
// tick connections
this.tickConnections();
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
index 86c51506c518ee445d00f7eef36ee2c9adbd9b4c..a37f392146ccc0319cf56ee0058ae8782b598fe3 100644
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
@@ -40,8 +40,8 @@ public final class TickRegionScheduler {
}
}
- public static final int TICK_RATE = 20;
- public static final long TIME_BETWEEN_TICKS = 1_000_000_000L / TICK_RATE; // ns
+ public static float TICK_RATE = 20; // Lophine - Add tick command support
+ public static long TIME_BETWEEN_TICKS = (long) (1_000_000_000L / TICK_RATE); // ns // Lophine - Add tick command support
// Folia start - watchdog
public static final FoliaWatchdogThread WATCHDOG_THREAD = new FoliaWatchdogThread();
static {
@@ -509,8 +509,24 @@ public final class TickRegionScheduler {
final long cpuStart = MEASURE_CPU_TIME ? THREAD_MX_BEAN.getCurrentThreadCpuTime() : 0L;
final long tickStart = System.nanoTime();
- // use max(), don't assume that tickStart >= scheduledStart
- final long tickCount = Math.max(1L, this.tickSchedule.getPeriodsAhead(TIME_BETWEEN_TICKS, tickStart));
+ // Lophine start - Add a config to enable tick command
+ final long tickCount;
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) {
+ net.minecraft.server.ServerTickRateManager rateManager = MinecraftServer.getServer().tickRateManager();
+ if (rateManager.isSprinting() && rateManager.checkShouldSprintThisTick()) {
+ TICK_RATE = net.minecraft.server.commands.TickCommand.MAX_TICKRATE;
+ TIME_BETWEEN_TICKS = (long) (1_000_000_000L / TICK_RATE);
+ tickCount = 1;
+ } else {
+ TICK_RATE = rateManager.tickrate();
+ TIME_BETWEEN_TICKS = (long) (1_000_000_000L / TICK_RATE);
+ tickCount = Math.max(1L, this.tickSchedule.getPeriodsAhead(TIME_BETWEEN_TICKS, tickStart));
+ }
+ } else {
+ // use max(), don't assume that tickStart >= scheduledStart
+ tickCount = Math.max(1L, this.tickSchedule.getPeriodsAhead(TIME_BETWEEN_TICKS, tickStart));
+ }
+ // Lophine end - Add a config to enable tick command
if (!this.tryMarkTicking()) {
if (!this.cancelled.get()) {
diff --git a/net/minecraft/server/ServerTickRateManager.java b/net/minecraft/server/ServerTickRateManager.java
index 8d0f810100a4eac65831913feeb9a9eeb0e6006a..ca35415e152dc63cb9f4ae8da8b06766600922fd 100644
--- a/net/minecraft/server/ServerTickRateManager.java
+++ b/net/minecraft/server/ServerTickRateManager.java
@@ -110,7 +110,7 @@ public class ServerTickRateManager extends TickRateManager {
return false;
} else if (this.remainingSprintTicks > 0L) {
this.sprintTickStartTime = System.nanoTime();
- this.remainingSprintTicks--;
+ // this.remainingSprintTicks--; // Luminol - Add tick command support
return true;
} else {
this.finishTickSprint();
@@ -118,6 +118,12 @@ public class ServerTickRateManager extends TickRateManager {
}
}
+ // Lophine start - Add tick command support
+ public void reduceSprintTicks() {
+ this.remainingSprintTicks--;
+ }
+ // Lophine end - Add tick command support
+
public void endTickWork() {
this.sprintTimeSpend = this.sprintTimeSpend + (System.nanoTime() - this.sprintTickStartTime);
}
diff --git a/net/minecraft/server/commands/TickCommand.java b/net/minecraft/server/commands/TickCommand.java
index cae943bae4701f74b46a49d68da83ae797841590..9f43eff6160ac6855c2e5dd9c23c384b03b7e96c 100644
--- a/net/minecraft/server/commands/TickCommand.java
+++ b/net/minecraft/server/commands/TickCommand.java
@@ -14,7 +14,7 @@ import net.minecraft.server.ServerTickRateManager;
import net.minecraft.util.TimeUtil;
public class TickCommand {
- private static final float MAX_TICKRATE = 10000.0F;
+ public static final float MAX_TICKRATE = 10000.0F; // Lophine - Add tick command support
private static final String DEFAULT_TICKRATE = String.valueOf(20);
public static void register(final CommandDispatcher<CommandSourceStack> dispatcher) {
@@ -22,14 +22,14 @@ public class TickCommand {
Commands.literal("tick")
.requires(Commands.hasPermission(Commands.LEVEL_ADMINS))
.then(Commands.literal("query").executes(c -> tickQuery(c.getSource())))
-/* .then(
+ .then( // Lophine - Add tick rate support
Commands.literal("rate")
.then(
Commands.argument("rate", FloatArgumentType.floatArg(1.0F, 10000.0F))
.suggests((c, b) -> SharedSuggestionProvider.suggest(new String[]{DEFAULT_TICKRATE}, b))
.executes(c -> setTickingRate(c.getSource(), FloatArgumentType.getFloat(c, "rate")))
)
- )*/
+ )
.then(
Commands.literal("step")
.executes(c -> step(c.getSource(), 1))
@@ -1,472 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sat, 26 Jul 2025 01:11:54 +0800
Subject: [PATCH] Leaves: Item overstack util
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/46cccfc39cafbca1681620d03947bc3ad558327f/leaves-server/minecraft-patches/features/0034-Item-overstack-util.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/commands/arguments/item/ItemInput.java b/net/minecraft/commands/arguments/item/ItemInput.java
index 643797124fe5a4489d0b7419b7e600c04f283ef2..04b4100da96aad50f08e8c59200eec934e7e873d 100644
--- a/net/minecraft/commands/arguments/item/ItemInput.java
+++ b/net/minecraft/commands/arguments/item/ItemInput.java
@@ -39,11 +39,13 @@ public class ItemInput {
public ItemStack createItemStack(int count, boolean allowOversizedStacks) throws CommandSyntaxException {
ItemStack itemStack = new ItemStack(this.item, count);
itemStack.applyComponents(this.components);
- if (allowOversizedStacks && count > itemStack.getMaxStackSize()) {
- throw ERROR_STACK_TOO_BIG.create(this.getItemName(), itemStack.getMaxStackSize());
+ // Leaves start - item over-stack util
+ if (allowOversizedStacks && count > org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack)) {
+ throw ERROR_STACK_TOO_BIG.create(this.getItemName(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack));
} else {
return itemStack;
}
+ // Leaves end - item over-stack util
}
public String serialize(HolderLookup.Provider levelRegistry) {
diff --git a/net/minecraft/server/commands/GiveCommand.java b/net/minecraft/server/commands/GiveCommand.java
index 7ef109cb9921c25987905149616eddbd0b2f9b9c..70fc9d6c5b226211ff5964464c37e11695d5f745 100644
--- a/net/minecraft/server/commands/GiveCommand.java
+++ b/net/minecraft/server/commands/GiveCommand.java
@@ -55,7 +55,7 @@ public class GiveCommand {
private static int giveItem(CommandSourceStack source, ItemInput item, Collection<ServerPlayer> targets, int count) throws CommandSyntaxException {
ItemStack itemStack = item.createItemStack(1, false);
final Component displayName = itemStack.getDisplayName(); // Paper - get display name early
- int maxStackSize = itemStack.getMaxStackSize();
+ int maxStackSize = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
int i = maxStackSize * 100;
if (count > i) {
source.sendFailure(Component.translatable("commands.give.failed.toomanyitems", i, itemStack.getDisplayName()));
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 74ec003486f9362d2bafbad8392b9bbdf0c15882..f06b9d8ad9512d35f3f460eb77c869690321c67f 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3079,7 +3079,7 @@ public class ServerGamePacketListenerImpl
} else if (slot.mayPlace(cursor)) {
if (ItemStack.isSameItemSameComponents(clickedItem, cursor)) {
int toPlace = packet.buttonNum() == 0 ? cursor.getCount() : 1;
- toPlace = Math.min(toPlace, clickedItem.getMaxStackSize() - clickedItem.getCount());
+ toPlace = Math.min(toPlace, org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(clickedItem) - clickedItem.getCount()); // Leaves - item over-stack util
toPlace = Math.min(toPlace, slot.container.getMaxStackSize() - clickedItem.getCount());
if (toPlace == 1) {
action = InventoryAction.PLACE_ONE;
@@ -3115,7 +3115,7 @@ public class ServerGamePacketListenerImpl
}
} else if (ItemStack.isSameItemSameComponents(cursor, clickedItem)) {
if (clickedItem.getCount() >= 0) {
- if (clickedItem.getCount() + cursor.getCount() <= cursor.getMaxStackSize()) {
+ if (clickedItem.getCount() + cursor.getCount() <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(cursor)) { // Leaves - item over-stack util
// As of 1.5, this is result slots only
action = InventoryAction.PICKUP_ALL;
}
@@ -3326,6 +3326,7 @@ public class ServerGamePacketListenerImpl
this.player.containerMenu.broadcastFullState();
} else {
this.player.containerMenu.broadcastChanges();
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.broadcastCarriedItem(); // Leaves - item over-stack util - force send carried item
}
if (packet.buttonNum() == Inventory.SLOT_OFFHAND && this.player.containerMenu != this.player.inventoryMenu) this.player.containerSynchronizer.sendOffHandSlotChange(); // Paper - update offhand data when the player is clicking in an inventory not their own as the sychronizer does not include offhand slots
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
@@ -3437,7 +3438,7 @@ public class ServerGamePacketListenerImpl
}
boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45;
- boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize();
+ boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
if (flag || (flag1 && !ItemStack.matches(this.player.inventoryMenu.getSlot(packet.slotNum()).getItem(), packet.itemStack()))) { // Insist on valid slot
// CraftBukkit start - Call click event
org.bukkit.inventory.InventoryView inventory = this.player.inventoryMenu.getBukkitView();
@@ -3479,6 +3480,7 @@ public class ServerGamePacketListenerImpl
this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemStack);
this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemStack);
this.player.inventoryMenu.broadcastChanges();
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.sendSingleSlot(packet.slotNum(), itemStack); // Leaves - item over-stack util - force send carried item
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
} else if (flag && flag2) {
if (this.dropSpamThrottler.isUnderThreshold()) {
diff --git a/net/minecraft/world/Container.java b/net/minecraft/world/Container.java
index 2afaf6a3f18af7889f4f3b35cee9bbb5e4ec01f2..da99b4bc7fe8460945070915073be141f9bd6778 100644
--- a/net/minecraft/world/Container.java
+++ b/net/minecraft/world/Container.java
@@ -32,6 +32,12 @@ public interface Container extends Clearable, Iterable<ItemStack>, org.leavesmc.
return Math.min(this.getMaxStackSize(), stack.getMaxStackSize());
}
+ // Leaves start - item over-stack util
+ default int getMaxStackLeaves(ItemStack stack) {
+ return Math.min(this.getMaxStackSize(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack));
+ }
+ // Leaves end - item over-stack util
+
void setChanged();
boolean stillValid(Player player);
diff --git a/net/minecraft/world/SimpleContainer.java b/net/minecraft/world/SimpleContainer.java
index d907e24d563e27acab2f2bf9711b1755ea9afd19..75170c8d3be477a6ea2a1d62018a6ab630b0e54e 100644
--- a/net/minecraft/world/SimpleContainer.java
+++ b/net/minecraft/world/SimpleContainer.java
@@ -211,7 +211,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
@Override
public void setItem(int index, ItemStack stack) {
this.items.set(index, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
this.setChanged();
}
@@ -286,7 +286,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
}
private void moveItemsBetweenStacks(ItemStack stack, ItemStack other) {
- int maxStackSize = this.getMaxStackSize(other);
+ int maxStackSize = this.getMaxStackLeaves(other); // Leaves - item over-stack util
int min = Math.min(stack.getCount(), maxStackSize - other.getCount());
if (min > 0) {
other.grow(min);
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index fd4f1e63f980b6959fc80084651991f8f8bc6c34..e5e8c752129a6ebb0dd1315c9b8ec459be11ef07 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -283,10 +283,15 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
private boolean isMergable() {
ItemStack item = this.getItem();
- return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < item.getMaxStackSize(); // Paper - Alternative item-despawn-rate
+ return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(item); // Paper - Alternative item-despawn-rate // Leaves - item over-stack util
}
private void tryToMerge(ItemEntity itemEntity) {
+ // Leaves start - item over-stack util
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.tryStackItems(this, itemEntity)) {
+ return;
+ }
+ // Leaves end - item over-stack util
ItemStack item = this.getItem();
ItemStack item1 = itemEntity.getItem();
if (Objects.equals(this.target, itemEntity.target) && areMergable(item, item1)) {
diff --git a/net/minecraft/world/entity/player/Inventory.java b/net/minecraft/world/entity/player/Inventory.java
index a6bb436dc80daf6901dc027a6011ead4b3ed27e2..71df58ae26325a2d28b6679733c474c0c59f7654 100644
--- a/net/minecraft/world/entity/player/Inventory.java
+++ b/net/minecraft/world/entity/player/Inventory.java
@@ -165,10 +165,12 @@ public class Inventory implements Container, Nameable {
}
private boolean hasRemainingSpaceForItem(ItemStack destination, ItemStack origin) {
+ // Leaves start - item over-stack util
return !destination.isEmpty()
- && destination.isStackable()
- && destination.getCount() < this.getMaxStackSize(destination)
+ && org.leavesmc.leaves.util.ItemOverstackUtils.isStackable(destination)
+ && destination.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(destination)
&& ItemStack.isSameItemSameComponents(destination, origin); // Paper - check if itemstack is stackable first
+ // Leaves end - item over-stack util
}
// CraftBukkit start - Watch method above! :D
@@ -181,7 +183,7 @@ public class Inventory implements Container, Nameable {
}
if (this.hasRemainingSpaceForItem(itemInSlot, itemStack)) {
- remains -= (itemInSlot.getMaxStackSize() < this.getMaxStackSize() ? itemInSlot.getMaxStackSize() : this.getMaxStackSize()) - itemInSlot.getCount();
+ remains -= (org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInSlot) < this.getMaxStackSize() ? org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInSlot) : this.getMaxStackSize()) - itemInSlot.getCount(); // Leaves - item over-stack util
}
if (remains <= 0) {
return itemStack.getCount();
@@ -190,7 +192,7 @@ public class Inventory implements Container, Nameable {
ItemStack itemInOffhand = this.equipment.get(EquipmentSlot.OFFHAND);
if (this.hasRemainingSpaceForItem(itemInOffhand, itemStack)) {
- remains -= (itemInOffhand.getMaxStackSize() < this.getMaxStackSize() ? itemInOffhand.getMaxStackSize() : this.getMaxStackSize()) - itemInOffhand.getCount();
+ remains -= (org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInOffhand) < this.getMaxStackSize() ? org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInOffhand) : this.getMaxStackSize()) - itemInOffhand.getCount(); // Leaves - item over-stack util
}
if (remains <= 0) {
return itemStack.getCount();
@@ -314,7 +316,7 @@ public class Inventory implements Container, Nameable {
this.setItem(slot, item);
}
- int i = this.getMaxStackSize(item) - item.getCount();
+ int i = this.getMaxStackLeaves(item) - item.getCount(); // Leaves - item over-stack util
int min = Math.min(count, i);
if (min == 0) {
return count;
@@ -420,7 +422,7 @@ public class Inventory implements Container, Nameable {
break;
}
- int i = stack.getMaxStackSize() - this.getItem(slotWithRemainingSpace).getCount();
+ int i = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack) - this.getItem(slotWithRemainingSpace).getCount(); // Leaves - item over-stack util
if (this.add(slotWithRemainingSpace, stack.split(i)) && sendPacket && this.player instanceof ServerPlayer serverPlayer) {
serverPlayer.connection.send(this.createInventoryUpdatePacket(slotWithRemainingSpace));
}
diff --git a/net/minecraft/world/entity/player/StackedItemContents.java b/net/minecraft/world/entity/player/StackedItemContents.java
index 83ccde54c625d40dc595e000c533f60aa929bd5a..6779503888e6d311758cffde582b0efbd66a33de 100644
--- a/net/minecraft/world/entity/player/StackedItemContents.java
+++ b/net/minecraft/world/entity/player/StackedItemContents.java
@@ -23,7 +23,7 @@ public class StackedItemContents {
}
public void accountStack(ItemStack stack) {
- this.accountStack(stack, stack.getMaxStackSize());
+ this.accountStack(stack, org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack)); // Leaves - item over-stack util
}
public void accountStack(ItemStack stack, int maxStackSize) {
diff --git a/net/minecraft/world/entity/vehicle/ContainerEntity.java b/net/minecraft/world/entity/vehicle/ContainerEntity.java
index 02d2efef2dc0f0e12eac0c71fa290af706f7694d..99f109e2653eff10c011f380694bd77a76381cee 100644
--- a/net/minecraft/world/entity/vehicle/ContainerEntity.java
+++ b/net/minecraft/world/entity/vehicle/ContainerEntity.java
@@ -163,7 +163,7 @@ public interface ContainerEntity extends Container, MenuProvider {
default void setChestVehicleItem(int slot, ItemStack stack) {
this.unpackChestVehicleLootTable(null);
this.getItemStacks().set(slot, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
}
default SlotAccess getChestVehicleSlot(final int index) {
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
index 2d6acceffb2cb7e55dd504018a70b05afccd9c11..bdc0ca1f625dc264bef6e5722ec66121ba48625a 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -295,6 +295,13 @@ public abstract class AbstractContainerMenu {
this.sendAllDataToRemote();
}
+ // Leaves start - item over-stack util
+ public void sendSingleSlot(int slotIndex, ItemStack item) {
+ if (this.synchronizer != null) {
+ this.synchronizer.sendSlotChange(this, slotIndex, item);
+ }
+ }
+ // Leaves end - item over-stack util
private void updateDataSlotListeners(int slotIndex, int value) {
for (ContainerListener containerListener : this.containerListeners) {
containerListener.dataChanged(this, slotIndex, value);
@@ -451,7 +458,7 @@ public abstract class AbstractContainerMenu {
&& (this.quickcraftType == 2 || carried1.getCount() >= this.quickcraftSlots.size())
&& this.canDragTo(slot1)) {
int i2 = slot1.hasItem() ? slot1.getItem().getCount() : 0;
- int min = Math.min(itemStack.getMaxStackSize(), slot1.getMaxStackSize(itemStack));
+ int min = Math.min(org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack), slot1.getMaxStackSize(itemStack)); // Leaves - item over-stack util
int min1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemStack) + i2, min);
count -= min1 - i2;
// slot1.setByPlayer(itemStack.copyWithCount(min1));
@@ -563,7 +570,7 @@ public abstract class AbstractContainerMenu {
slot.setByPlayer(carried2);
}
} else if (ItemStack.isSameItemSameComponents(carried, carried2)) {
- Optional<ItemStack> optional1 = slot.tryRemove(carried.getCount(), carried2.getMaxStackSize() - carried2.getCount(), player);
+ Optional<ItemStack> optional1 = slot.tryRemove(carried.getCount(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(carried2) - carried2.getCount(), player); // Leaves - item over-stack util
optional1.ifPresent(itemStack2 -> {
carried2.grow(itemStack2.getCount());
slot.onTake(player, itemStack2);
@@ -625,7 +632,7 @@ public abstract class AbstractContainerMenu {
Slot slot2 = this.slots.get(slotId);
if (slot2.hasItem()) {
ItemStack itemStack = slot2.getItem();
- this.setCarried(itemStack.copyWithCount(itemStack.getMaxStackSize()));
+ this.setCarried(itemStack.copyWithCount(org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack))); // Leaves - item over-stack util
}
} else if (clickType == ClickType.THROW && this.getCarried().isEmpty() && slotId >= 0) {
Slot slot2 = this.slots.get(slotId);
@@ -660,15 +667,15 @@ public abstract class AbstractContainerMenu {
int maxStackSize = button == 0 ? 1 : -1;
for (int i3 = 0; i3 < 2; i3++) {
- for (int i4 = count; i4 >= 0 && i4 < this.slots.size() && itemStack.getCount() < itemStack.getMaxStackSize(); i4 += maxStackSize) {
+ for (int i4 = count; i4 >= 0 && i4 < this.slots.size() && itemStack.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); i4 += maxStackSize) { // Leaves - item over-stack util
Slot slot3 = this.slots.get(i4);
if (slot3.hasItem()
&& canItemQuickReplace(slot3, itemStack, true)
&& slot3.mayPickup(player)
&& this.canTakeItemForPickAll(itemStack, slot3)) {
ItemStack item1 = slot3.getItem();
- if (i3 != 0 || item1.getCount() != item1.getMaxStackSize()) {
- ItemStack itemStack1 = slot3.safeTake(item1.getCount(), itemStack.getMaxStackSize() - itemStack.getCount(), player);
+ if (i3 != 0 || item1.getCount() != org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(item1)) { // Leaves - item over-stack util
+ ItemStack itemStack1 = slot3.safeTake(item1.getCount(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack) - itemStack.getCount(), player); // Leaves - item over-stack util
itemStack.grow(itemStack1.getCount());
}
}
@@ -770,7 +777,7 @@ public abstract class AbstractContainerMenu {
i = endIndex - 1;
}
- if (stack.isStackable()) {
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.isStackable(stack)) { // Leaves - item over-stack util
while (!stack.isEmpty() && (reverseDirection ? i >= startIndex : i < endIndex)) {
Slot slot = this.slots.get(i);
ItemStack item = slot.getItem();
@@ -871,7 +878,7 @@ public abstract class AbstractContainerMenu {
public static boolean canItemQuickReplace(@Nullable Slot slot, ItemStack stack, boolean stackSizeMatters) {
boolean flag = slot == null || !slot.hasItem();
return !flag && ItemStack.isSameItemSameComponents(stack, slot.getItem())
- ? slot.getItem().getCount() + (stackSizeMatters ? 0 : stack.getCount()) <= stack.getMaxStackSize()
+ ? slot.getItem().getCount() + (stackSizeMatters ? 0 : stack.getCount()) <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack) // Leaves - item over-stack util
: flag;
}
@@ -879,7 +886,7 @@ public abstract class AbstractContainerMenu {
return switch (type) {
case 0 -> Mth.floor((float)stack.getCount() / slots.size());
case 1 -> 1;
- case 2 -> stack.getMaxStackSize();
+ case 2 -> org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack); // Leaves - item over-stack util
default -> stack.getCount();
};
}
@@ -902,7 +909,7 @@ public abstract class AbstractContainerMenu {
for (int i = 0; i < container.getContainerSize(); i++) {
ItemStack item = container.getItem(i);
if (!item.isEmpty()) {
- f += (float)item.getCount() / container.getMaxStackSize(item);
+ f += Math.clamp((float) item.getCount() / container.getMaxStackSize(item), 0f, 1f); // Leaves - item over-stack util
}
}
diff --git a/net/minecraft/world/inventory/MerchantContainer.java b/net/minecraft/world/inventory/MerchantContainer.java
index 1e5dfb1f9e371fa23cdfa9280797aa0e183d4cd2..1a593d5bfc4574fd071604105422cd1d395648b8 100644
--- a/net/minecraft/world/inventory/MerchantContainer.java
+++ b/net/minecraft/world/inventory/MerchantContainer.java
@@ -109,7 +109,7 @@ public class MerchantContainer implements Container {
@Override
public void setItem(int index, ItemStack stack) {
this.itemStacks.set(index, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
if (this.isPaymentSlot(index)) {
this.updateSellItem();
}
diff --git a/net/minecraft/world/inventory/Slot.java b/net/minecraft/world/inventory/Slot.java
index 5ceb8964476b40db4511bec91ff13c4f522a1357..f416d7976e41a06b5a8be93485eaa233ffceda5c 100644
--- a/net/minecraft/world/inventory/Slot.java
+++ b/net/minecraft/world/inventory/Slot.java
@@ -75,7 +75,7 @@ public class Slot {
}
public int getMaxStackSize(ItemStack stack) {
- return Math.min(this.getMaxStackSize(), stack.getMaxStackSize());
+ return Math.min(this.getMaxStackSize(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack)); // Leaves - item over-stack util
}
@Nullable
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index 33c3a5e39e8e1aa023baab76ef94f8aed481480e..a27e1d53abc2d8b8912226add33510067e10ed52 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -166,7 +166,7 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
@Deprecated
@Nullable
private Item item;
- PatchedDataComponentMap components;
+ public PatchedDataComponentMap components; // Leaves - item over-stack util
@Nullable
private Entity entityRepresentation;
@@ -193,7 +193,8 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
} else {
Holder<Item> holder = Item.STREAM_CODEC.decode(buffer);
DataComponentPatch dataComponentPatch = codec.decode(buffer);
- return new ItemStack(holder, varInt, dataComponentPatch);
+ ItemStack itemStack = new ItemStack(holder, varInt, dataComponentPatch);
+ return org.leavesmc.leaves.util.ItemOverstackUtils.decodeMaxStackSize(itemStack);
}
}
@@ -202,13 +203,15 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
if (value.isEmpty() || value.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem()
buffer.writeVarInt(0);
} else {
- buffer.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), value, value.getCount())); // Paper - potentially sanitize count
- Item.STREAM_CODEC.encode(buffer, value.getItemHolder());
+ // Leaves start - item over-stack util
+ final ItemStack itemStack = org.leavesmc.leaves.util.ItemOverstackUtils.encodeMaxStackSize(value.copy());
+ buffer.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), itemStack, itemStack.getCount())); // Paper - potentially sanitize count
+ Item.STREAM_CODEC.encode(buffer, itemStack.getItemHolder());
// Paper start - adventure; conditionally render translatable components
boolean prev = net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.get();
- try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.itemStack(value))) { // pass the itemstack as context to the obfuscation session
+ try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.itemStack(itemStack))) { // pass the itemstack as context to the obfuscation session
net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(true);
- codec.encode(buffer, value.components.asPatch());
+ codec.encode(buffer, itemStack.components.asPatch());
} finally {
net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(prev);
}
@@ -303,7 +306,7 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
for (ItemStack itemStack : itemContainerContents.nonEmptyItems()) {
int count = itemStack.getCount();
- int maxStackSize = itemStack.getMaxStackSize();
+ int maxStackSize = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
if (count > maxStackSize) {
return DataResult.error(() -> "Item stack with count of " + count + " was larger than maximum: " + maxStackSize);
}
diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java
index 38b03c7b02bdfc579e5e126c12de3d878e26d188..caf31218a1aff84367da126ee1dc46b8c8a1e5d1 100644
--- a/net/minecraft/world/level/block/CrafterBlock.java
+++ b/net/minecraft/world/level/block/CrafterBlock.java
@@ -192,7 +192,7 @@ public class CrafterBlock extends BaseEntityBlock {
Direction direction = state.getValue(ORIENTATION).front();
Container containerAt = HopperBlockEntity.getContainerAt(level, pos.relative(direction));
ItemStack itemStack = stack.copy();
- if (containerAt != null && (containerAt instanceof CrafterBlockEntity || stack.getCount() > containerAt.getMaxStackSize(stack))) {
+ if (containerAt != null && (containerAt instanceof CrafterBlockEntity || stack.getCount() > containerAt.getMaxStackLeaves(stack))) { // Leaves - item over-stack util
// CraftBukkit start - InventoryMoveItemEvent
org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
diff --git a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index d7a211220d5eba7e34b9083f06f39e9527962599..cef2d6d9a42ae36d6e2a0b31685a7738d2a400cf 100644
--- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -411,7 +411,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
ItemStack itemStack = this.items.get(index);
boolean flag = !stack.isEmpty() && ItemStack.isSameItemSameComponents(itemStack, stack);
this.items.set(index, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
if (index == 0 && !flag && this.level instanceof ServerLevel serverLevel) {
this.cookingTotalTime = getTotalCookTime(serverLevel, this, this.recipeType, this.cookSpeedMultiplier); // Paper - cook speed multiplier API
this.cookingTimer = 0;
diff --git a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
index 10b2cc20bbf3b70e4e09dbbe14b90506e6366158..1535bb8cec8692e8d26eaff090288f1b8f75c253 100644
--- a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
@@ -155,7 +155,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
@Override
public void setItem(int slot, ItemStack stack) {
this.getItems().set(slot, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
this.setChanged();
}
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 699bb3cc2b680a4ee438a88c05854e5ab05ea910..d4fe03fd766caca1d7693a5317460ca1a9b9fa4f 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -148,7 +148,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public void setItem(int index, ItemStack stack) {
this.unpackLootTable(null);
this.getItems().set(index, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
}
@Override
@@ -743,9 +743,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (item.isEmpty()) {
// Spigot start - SPIGOT-6693, SimpleContainer#setItem
ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size
- if (!stack.isEmpty() && stack.getCount() > destination.getMaxStackSize()) {
+ if (!stack.isEmpty() && (stack.getCount() > destination.getMaxStackSize() || stack.getCount() > stack.getMaxStackSize())) { // Leaves - item over-stack util
leftover = stack; // Paper - Make hoppers respect inventory max stack size
- stack = stack.split(destination.getMaxStackSize());
+ stack = stack.split(Math.min(destination.getMaxStackSize(), stack.getMaxStackSize())); // Leaves - item over-stack util
}
// Spigot end
//IGNORE_TILE_UPDATES.set(Boolean.TRUE); // Paper - Perf: Optimize Hoppers // Folia - region threading // Luminol - Use vanilla hopper logic
@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Fri, 3 Oct 2025 19:43:36 +0800
Subject: [PATCH] Modify merge ItemEntity logic
Add followTickSequenceMerge to modify merge items, due to Paper's modification of the merge radius,
when the merge radius is large and stacks containing many items get stuck in an unexpected position,
individual items may never reach their destination.
This configuration option is added to fix this behavior.
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index aed1641b4e09384d40da1ac6e66c1641ca34b063..44b06b1585e7630fa17d8dfb01f737b14efebcbc 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -287,7 +287,7 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
ItemStack thisItemStack = this.getItem();
ItemStack otherItemStack = other.getItem();
if (Objects.equals(this.target, other.target) && areMergable(thisItemStack, otherItemStack)) {
- if (otherItemStack.getCount() < thisItemStack.getCount()) {
+ if (fun.bm.lophine.config.modules.misc.ItemEntityConfig.followTickSequenceMerge || otherItemStack.getCount() < thisItemStack.getCount()) { // Lophine - add follow Tick Sequence Merge, see Paper#13073
merge(this, thisItemStack, other, otherItemStack);
} else {
merge(other, otherItemStack, this, thisItemStack);
@@ -1,216 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Fri, 11 Apr 2025 16:53:57 +0800
Subject: [PATCH] Leaves: Old raid behavior
Co-authored by: huanli233 <392352840@qq.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/79d9ef74c2684eb49060f07e1ab31c827326c9a5/leaves-server/minecraft-patches/features/0106-Old-raid-behavior.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/effect/BadOmenMobEffect.java b/net/minecraft/world/effect/BadOmenMobEffect.java
index 80f17f33f670018240c854df589cf90cdeab6e70..c9af615ff9120c07787f436dbb6024e54e3a498b 100644
--- a/net/minecraft/world/effect/BadOmenMobEffect.java
+++ b/net/minecraft/world/effect/BadOmenMobEffect.java
@@ -22,6 +22,11 @@ class BadOmenMobEffect extends MobEffect {
&& !serverPlayer.isSpectator()
&& level.getDifficulty() != Difficulty.PEACEFUL
&& level.isVillage(serverPlayer.blockPosition())) {
+ // Leaves start - Revert raid changes
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
+ return level.getRaids().createOrExtendRaid(serverPlayer, serverPlayer.blockPosition()) == null;
+ }
+ // Leaves end - Revert raid changes
Raid raidAt = level.getRaidAt(serverPlayer.blockPosition());
if (raidAt == null || raidAt.getRaidOmenLevel() < raidAt.getMaxRaidOmenLevel()) {
serverPlayer.addEffect(new MobEffectInstance(MobEffects.RAID_OMEN, 600, amplifier));
diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java
index 1910bff3f08147bfd63703097e30b9f88c84e337..f45aa44a7a17946aeb406a447f18de34320a4fa2 100644
--- a/net/minecraft/world/entity/raid/Raid.java
+++ b/net/minecraft/world/entity/raid/Raid.java
@@ -263,7 +263,7 @@ public class Raid {
}
public boolean absorbRaidOmen(ServerPlayer player) {
- MobEffectInstance effect = player.getEffect(MobEffects.RAID_OMEN);
+ MobEffectInstance effect = player.getEffect(fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior ? MobEffects.BAD_OMEN : MobEffects.RAID_OMEN); // Leaves - old Raid Behavior
if (effect == null) {
return false;
} else {
@@ -340,7 +340,13 @@ public class Raid {
}
if (flag1) {
- this.waveSpawnPos = this.getValidSpawnPos(level);
+ // Leaves Start - old FindSpawnPosition
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
+ this.waveSpawnPos = this.preCalcRavagerSpawnLocation(level, this.raidCooldownTicks < 100 ? 1 : 0);
+ } else {
+ this.waveSpawnPos = this.getValidSpawnPos(level);
+ }
+ // Leaves End - old FindSpawnPosition
}
if (this.raidCooldownTicks == 300 || this.raidCooldownTicks % 20 == 0) {
@@ -375,7 +381,14 @@ public class Raid {
int i = 0;
while (this.shouldSpawnGroup()) {
- BlockPos blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
+ // Leaves Start - old FindSpawnPosition
+ BlockPos blockPos;
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
+ blockPos = this.getRavagerSpawnLocation(level, i, 20);
+ } else {
+ blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
+ }
+ // Leaves End - old FindSpawnPosition
if (blockPos != null) {
this.started = true;
this.spawnGroup(level, blockPos);
@@ -387,7 +400,7 @@ public class Raid {
i++;
}
- if (i > 5) {
+ if (i > (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior ? 3 : 5)) { // Leaves - old FindSpawnPosition
org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(level, this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE); // CraftBukkit
this.stop();
break;
@@ -683,7 +696,7 @@ public class Raid {
int i2 = this.center.getX() + Mth.floor(Mth.cos(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
int i3 = this.center.getZ() + Mth.floor(Mth.sin(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
int height = level.getHeight(Heightmap.Types.WORLD_SURFACE, i2, i3);
- if (Mth.abs(height - this.center.getY()) <= 96) {
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior || Mth.abs(height - this.center.getY()) <= 96) { // Leaves - skippable
mutableBlockPos.set(i2, height, i3);
if (!level.isVillage(mutableBlockPos) || i <= 7) {
int i4 = 10;
@@ -702,6 +715,36 @@ public class Raid {
return null;
}
+ // Leaves Start - old FindSpawnPosition
+ @Nullable
+ private BlockPos findRandomSpawnPos(ServerLevel level, int n, int n2) {
+ int n3 = 2 - n;
+ BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+ SpawnPlacementType spawnPlacementType = SpawnPlacements.getPlacementType(EntityType.RAVAGER);
+ for (int i = 0; i < n2; ++i) {
+ float f = level.random.nextFloat() * ((float)Math.PI * 2);
+ int n4 = this.center.getX() + Mth.floor(Mth.cos(f) * 32.0f * (float)n3) + level.random.nextInt(5);
+ int n5 = this.center.getZ() + Mth.floor(Mth.sin(f) * 32.0f * (float)n3) + level.random.nextInt(5);
+ int n6 = level.getHeight(Heightmap.Types.WORLD_SURFACE, n4, n5);
+ mutableBlockPos.set(n4, n6, n5);
+ if (level.isVillage(mutableBlockPos) && n < 2) continue;
+ if (!level.hasChunksAt(mutableBlockPos.getX() - 10, mutableBlockPos.getZ() - 10, mutableBlockPos.getX() + 10, mutableBlockPos.getZ() + 10) || !level.isPositionEntityTicking(mutableBlockPos) || !spawnPlacementType.isSpawnPositionOk(level, mutableBlockPos, EntityType.RAVAGER) && (!level.getBlockState((BlockPos)mutableBlockPos.below()).is(Blocks.SNOW) || !level.getBlockState(mutableBlockPos).isAir())) continue;
+ return mutableBlockPos;
+ }
+ return null;
+ }
+
+ private Optional<BlockPos> getValidSpawnPos(ServerLevel level, int n) {
+ for (int i = 0; i < 3; ++i) {
+ BlockPos blockPos = this.findRandomSpawnPos(level, n, 1);
+ if (blockPos == null) continue;
+ return Optional.of(blockPos);
+ }
+ return Optional.empty();
+ }
+ // Leaves End - old FindSpawnPosition
+
+
private boolean addWaveMob(ServerLevel level, int wave, Raider raider) {
// Folia start - make raids thread-safe
if (!this.ownsRaid(level)) {
@@ -864,4 +907,43 @@ public class Raid {
this.spawnsPerWaveBeforeBonus = spawnsPerWaveBeforeBonus;
}
}
+
+ // Leaves start - old FindSpawnPosition
+ private BlockPos getRavagerSpawnLocation(ServerLevel serverWorld, int proximity, int tries) {
+ int i = proximity == 0 ? 2 : 2 - proximity;
+ BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
+ SpawnPlacementType spawnLocation = SpawnPlacements.getPlacementType(EntityType.RAVAGER);
+
+ for (int j = 0; j < tries; j++) {
+ float f = serverWorld.random.nextFloat() * (float) (Math.PI * 2);
+ int k = this.center.getX() + Mth.floor(Mth.cos(f) * 32.0F * (float) i + serverWorld.random.nextInt(5));
+ int l = this.center.getZ() + Mth.floor(Mth.sin(f) * 32.0F * (float) i + serverWorld.random.nextInt(5));
+ int m = serverWorld.getHeight(Heightmap.Types.WORLD_SURFACE, k, l);
+ mutable.set(k, m, l);
+
+ if (serverWorld.isVillage(mutable) && proximity < 2) {
+ continue;
+ }
+ if (serverWorld.hasChunksAt(mutable.getX() - 10, mutable.getZ() - 10, mutable.getX() + 10, mutable.getZ() + 10)
+ && serverWorld.isPositionEntityTicking(mutable)
+ && (spawnLocation.isSpawnPositionOk(serverWorld, mutable, EntityType.RAVAGER)
+ || serverWorld.getBlockState(mutable.below()).is(Blocks.SNOW)
+ && serverWorld.getBlockState(mutable).isAir())
+ ) {
+ return mutable;
+ }
+ }
+ return null;
+ }
+
+ private Optional<BlockPos> preCalcRavagerSpawnLocation(ServerLevel serverWorld, int proximity) {
+ for (int i = 0; i < 3; i++) {
+ BlockPos blockPos = this.getRavagerSpawnLocation(serverWorld, proximity, 1);
+ if (blockPos != null) {
+ return Optional.of(blockPos);
+ }
+ }
+ return Optional.empty();
+ }
+ // Leaves end - old FindSpawnPosition
}
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
index 3e30989c99cd11c8c94d6fd194d2969e3a7efda6..2d163f3d5eb1af4d539d24c0256855bbec960de4 100644
--- a/net/minecraft/world/entity/raid/Raider.java
+++ b/net/minecraft/world/entity/raid/Raider.java
@@ -128,6 +128,43 @@ public abstract class Raider extends PatrollingMonster {
currentRaid.removeFromRaid(serverLevel, this, false);
}
+
+ // Leaves start - Revert raid changes
+ if (this.level() instanceof ServerLevel) {
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior && !this.hasRaid()) {
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
+ net.minecraft.world.entity.player.Player entityhuman = null;
+ if (entity instanceof net.minecraft.world.entity.player.Player player) {
+ entityhuman = player;
+ } else if (entity instanceof net.minecraft.world.entity.animal.wolf.Wolf wolf) {
+ LivingEntity entityliving = wolf.getOwner();
+ if (wolf.isTame() && entityliving instanceof net.minecraft.world.entity.player.Player player) {
+ entityhuman = player;
+ }
+ }
+
+ if (entityhuman != null && !itemstack.isEmpty() && this.isCaptain()) {
+ net.minecraft.world.effect.MobEffectInstance mobeffect = entityhuman.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN);
+ int i = 1;
+
+ if (mobeffect != null) {
+ i += mobeffect.getAmplifier();
+ entityhuman.removeEffectNoUpdate(net.minecraft.world.effect.MobEffects.BAD_OMEN);
+ } else {
+ --i;
+ }
+
+ i = net.minecraft.util.Mth.clamp(i, 0, 4);
+ net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, 120000, i, false, false, true);
+
+ if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DISABLE_RAIDS)) {
+ entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit
+ }
+ this.setPatrolLeader(false);
+ }
+ }
+ }
+ // Leaves end - Revert raid changes
}
super.die(cause);
@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 19 May 2025 00:42:17 +0800
Subject: [PATCH] Old zombie reinforcement
diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
index 0008aa0ca02fc4ea67b795b3f0a0e9656233ce89..2734ffc103ee4760d3521609fdd090ab99df675b 100644
--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
+++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
@@ -331,7 +331,7 @@ public class Zombie extends Monster {
int x = Mth.floor(this.getX());
int y = Mth.floor(this.getY());
int z = Mth.floor(this.getZ());
- EntityType<? extends Zombie> type = this.getType();
+ EntityType<? extends Zombie> type = fun.bm.lophine.config.modules.function.OldFeatureConfig.oldZombieReinforcement ? EntityType.ZOMBIE : this.getType(); // Lophine - old zombie reinforcement
Zombie reinforcement = type.create(level, EntitySpawnReason.REINFORCEMENT);
if (reinforcement == null) {
return true;
@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 2 Jul 2026 18:49:40 +0800
Subject: [PATCH] Old leader zombie health logic
diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
index 2734ffc103ee4760d3521609fdd090ab99df675b..a99683d341f52139003dfa5190ee118d5b06f59f 100644
--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
+++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
@@ -597,7 +597,7 @@ public class Zombie extends Monster {
.addOrReplacePermanentModifier(
new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)
);
- if (spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) {
+ if (!fun.bm.lophine.config.modules.function.OldFeatureConfig.oldLeaderZombieHealth && spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) { // Lophine - Configurable option to disable health boost for leader zombies
this.setHealth(this.getMaxHealth());
}
@@ -5,36 +5,36 @@ Subject: [PATCH] Spawn invulnerable time
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index de1263404395c28209234a556347284fa557f81c..44f0e3a675c612e9ca2bc40cc3898bdbca0f6718 100644
index f7869f06ab29e4bbd003c807176345dec9e9e5ab..295be200cb0696bd2ae2b655f89d96dd7723a541 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -232,6 +232,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -242,6 +242,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private int lastSentFood = -99999999;
private boolean lastFoodSaturationZero = true;
public int lastSentExp = -99999999;
+ private int spawnInvulnerableTime = 60; // Lophine - spawn invulnerable time
+ protected int spawnInvulnerableTime = 60; // Lophine - spawn invulnerable time
private ChatVisiblity chatVisibility = ChatVisiblity.FULL;
public ParticleStatus particleStatus = ParticleStatus.ALL;
private boolean canChatColor = true;
@@ -925,6 +926,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.tickClientLoadTimeout();
@@ -923,6 +924,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.connection.tickClientLoadTimeout();
this.gameMode.tick();
this.wardenSpawnTracker.tick();
+ if (this.spawnInvulnerableTime > 0) --this.spawnInvulnerableTime; // Lophine - spawn invulnerable time
if (this.invulnerableTime > 0) {
this.invulnerableTime--;
}
@@ -1435,6 +1437,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
if (this.isInvulnerableTo(level, damageSource)) {
@@ -1559,6 +1561,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
if (this.isInvulnerableTo(level, source)) {
return false;
} else {
+ // Lophine start - spawn invulnerable time
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.spawnInvulnerableTime) {
+ if (this.spawnInvulnerableTime > 0 && !damageSource.is(net.minecraft.tags.DamageTypeTags.BYPASSES_INVULNERABILITY)) {
+ if (this.spawnInvulnerableTime > 0 && !source.is(net.minecraft.tags.DamageTypeTags.BYPASSES_INVULNERABILITY)) {
+ return false;
+ }
+ }
+ // Lophine end - spawn invulnerable time
Entity entity = damageSource.getEntity();
Entity entity = source.getEntity();
if (!( // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false.
!(entity instanceof Player player && !this.canHarmPlayer(player))
!(entity instanceof Player playerx && !this.canHarmPlayer(playerx))
@@ -0,0 +1,466 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sat, 26 Jul 2025 01:11:54 +0800
Subject: [PATCH] Leaves: Item overstack util
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/f3784ec0525069a37e9ab8921b196f5533edbd56/leaves-server/minecraft-patches/features/0118-Item-overstack-util.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/commands/arguments/item/ItemInput.java b/net/minecraft/commands/arguments/item/ItemInput.java
index 28aab52fb14e9086d81dd7a3fa32e7f12136d53a..1f033b970be82b0bdb4e51b6e1c5bb03170066ae 100644
--- a/net/minecraft/commands/arguments/item/ItemInput.java
+++ b/net/minecraft/commands/arguments/item/ItemInput.java
@@ -20,8 +20,10 @@ public record ItemInput(Holder<Item> item, DataComponentPatch components) {
public ItemStack createItemStack(final int count) throws CommandSyntaxException {
ItemStack result = new ItemStack(this.item, count, this.components);
- if (count > result.getMaxStackSize()) {
- throw ERROR_STACK_TOO_BIG.create(this.item.getRegisteredName(), result.getMaxStackSize());
+ // Leaves start - item over-stack util
+ if (count > org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(result)) {
+ throw ERROR_STACK_TOO_BIG.create(this.item.getRegisteredName(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(result));
+ // Leaves end - item over-stack util
} else {
DataResult<ItemStack> validationResult = ItemStack.validateStrict(result);
return validationResult.getOrThrow(ERROR_MALFORMED_ITEM::create);
diff --git a/net/minecraft/server/commands/GiveCommand.java b/net/minecraft/server/commands/GiveCommand.java
index c147a1acd4fd9f94c73bee69febf651ca00c28ce..f8004bf74edeabce871515fb73fa00f331941dca 100644
--- a/net/minecraft/server/commands/GiveCommand.java
+++ b/net/minecraft/server/commands/GiveCommand.java
@@ -47,7 +47,7 @@ public class GiveCommand {
private static int giveItem(final CommandSourceStack source, final ItemInput input, final Collection<ServerPlayer> players, final int count) throws CommandSyntaxException {
ItemStack prototypeItemStack = input.createItemStack(1);
- int maxStackSize = prototypeItemStack.getMaxStackSize();
+ int maxStackSize = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(prototypeItemStack); // Leaves - item over-stack util
int maxAllowedCount = maxStackSize * 100;
if (count > maxAllowedCount) {
source.sendFailure(Component.translatable("commands.give.failed.toomanyitems", maxAllowedCount, prototypeItemStack.getDisplayName()));
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 0b5f2060062a354bd6cafa8f53a5734dc83d062d..e15be199d690954d99d710de4046e721a943b3a9 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3229,7 +3229,7 @@ public class ServerGamePacketListenerImpl
} else if (slot.mayPlace(cursor)) {
if (ItemStack.isSameItemSameComponents(clickedItem, cursor)) {
int toPlace = packet.buttonNum() == 0 ? cursor.getCount() : 1;
- toPlace = Math.min(toPlace, clickedItem.getMaxStackSize() - clickedItem.getCount());
+ toPlace = Math.min(toPlace, org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(clickedItem) - clickedItem.getCount()); // Leaves - item over-stack util
toPlace = Math.min(toPlace, slot.container.getMaxStackSize() - clickedItem.getCount());
if (toPlace == 1) {
action = InventoryAction.PLACE_ONE;
@@ -3265,7 +3265,7 @@ public class ServerGamePacketListenerImpl
}
} else if (ItemStack.isSameItemSameComponents(cursor, clickedItem)) {
if (clickedItem.getCount() >= 0) {
- if (clickedItem.getCount() + cursor.getCount() <= cursor.getMaxStackSize()) {
+ if (clickedItem.getCount() + cursor.getCount() <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(cursor)) { // Leaves - item over-stack util
// As of 1.5, this is result slots only
action = InventoryAction.PICKUP_ALL;
}
@@ -3482,6 +3482,7 @@ public class ServerGamePacketListenerImpl
this.player.containerMenu.broadcastFullState();
} else {
this.player.containerMenu.broadcastChanges();
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.broadcastCarriedItem(); // Leaves - item over-stack util - force send carried item
}
if (packet.buttonNum() == Inventory.SLOT_OFFHAND && this.player.containerMenu != this.player.inventoryMenu) this.player.containerSynchronizer.sendOffHandSlotChange(); // Paper - update offhand data when the player is clicking in an inventory not their own as the sychronizer does not include offhand slots
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
@@ -3593,7 +3594,7 @@ public class ServerGamePacketListenerImpl
}
boolean validSlot = packet.slotNum() >= 1 && packet.slotNum() <= 45;
- boolean validData = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize();
+ boolean validData = itemStack.isEmpty() || itemStack.getCount() <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
if (drop || (validSlot && !ItemStack.matches(this.player.inventoryMenu.getSlot(packet.slotNum()).getItem(), packet.itemStack()))) { // Insist on valid slot
// CraftBukkit start - Call click event
org.bukkit.inventory.InventoryView inventory = this.player.inventoryMenu.getBukkitView();
@@ -3635,6 +3636,7 @@ public class ServerGamePacketListenerImpl
this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemStack);
this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemStack);
this.player.inventoryMenu.broadcastChanges();
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.sendSingleSlot(packet.slotNum(), itemStack); // Leaves - item over-stack util - force send carried item
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
} else if (drop && validData) {
if (this.dropSpamThrottler.isUnderThreshold()) {
diff --git a/net/minecraft/world/Container.java b/net/minecraft/world/Container.java
index 54d99625cfec60530e8a3288871e6dc21e179b2d..2a1c1bd2e9c326b7298978cec1fe13112e670d33 100644
--- a/net/minecraft/world/Container.java
+++ b/net/minecraft/world/Container.java
@@ -38,6 +38,12 @@ public interface Container extends Clearable, Iterable<ItemStack>, SlotProvider,
return Math.min(this.getMaxStackSize(), itemStack.getMaxStackSize());
}
+ // Leaves start - item over-stack util
+ default int getMaxStackLeaves(final ItemStack stack) {
+ return Math.min(this.getMaxStackSize(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack));
+ }
+ // Leaves end - item over-stack util
+
void setChanged();
boolean stillValid(Player player);
diff --git a/net/minecraft/world/SimpleContainer.java b/net/minecraft/world/SimpleContainer.java
index 21f576bb39bfd78dca87606ba3a044db8e13e28e..049c6ab6472415479435f2caab0444c3cbd33902 100644
--- a/net/minecraft/world/SimpleContainer.java
+++ b/net/minecraft/world/SimpleContainer.java
@@ -193,7 +193,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
@Override
public void setItem(final int slot, final ItemStack itemStack) {
this.items.set(slot, itemStack);
- itemStack.limitSize(this.getMaxStackSize(itemStack));
+ itemStack.limitSize(this.getMaxStackLeaves(itemStack)); // Leaves - item over-stack util
this.setChanged();
}
@@ -263,7 +263,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
}
private void moveItemsBetweenStacks(final ItemStack sourceStack, final ItemStack targetStack) {
- int maxCount = this.getMaxStackSize(targetStack);
+ int maxCount = this.getMaxStackLeaves(targetStack); // Leaves - item over-stack util
int diff = Math.min(sourceStack.getCount(), maxCount - targetStack.getCount());
if (diff > 0) {
targetStack.grow(diff);
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index 44b06b1585e7630fa17d8dfb01f737b14efebcbc..679a941a2af886697fbfcbc7f21e5f4e0ec77dc3 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -280,10 +280,15 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
private boolean isMergable() {
ItemStack item = this.getItem();
- return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < item.getMaxStackSize(); // Paper - Alternative item-despawn-rate
+ return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(item); // Paper - Alternative item-despawn-rate // Leaves - item over-stack util
}
private void tryToMerge(final ItemEntity other) {
+ // Leaves start - item over-stack util
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.tryStackItems(this, other)) {
+ return;
+ }
+ // Leaves end - item over-stack util
ItemStack thisItemStack = this.getItem();
ItemStack otherItemStack = other.getItem();
if (Objects.equals(this.target, other.target) && areMergable(thisItemStack, otherItemStack)) {
diff --git a/net/minecraft/world/entity/player/Inventory.java b/net/minecraft/world/entity/player/Inventory.java
index f004911c438e6f89d6e079437e3f4104d6cbacbd..a248b1d11303237ebdf7cac4fa63865287d91a10 100644
--- a/net/minecraft/world/entity/player/Inventory.java
+++ b/net/minecraft/world/entity/player/Inventory.java
@@ -166,10 +166,12 @@ public class Inventory implements Container, Nameable {
}
private boolean hasRemainingSpaceForItem(final ItemStack slotItemStack, final ItemStack newItemStack) {
+ // Leaves start - item over-stack util
return !slotItemStack.isEmpty()
- && slotItemStack.isStackable()
- && slotItemStack.getCount() < this.getMaxStackSize(slotItemStack)
+ && org.leavesmc.leaves.util.ItemOverstackUtils.isStackable(slotItemStack)
+ && slotItemStack.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(slotItemStack)
&& ItemStack.isSameItemSameComponents(slotItemStack, newItemStack); // Paper - check if itemstack is stackable first
+ // Leaves end - item over-stack util
}
// CraftBukkit start - Watch method above! :D
@@ -182,7 +184,7 @@ public class Inventory implements Container, Nameable {
}
if (this.hasRemainingSpaceForItem(itemInSlot, itemStack)) {
- remains -= (itemInSlot.getMaxStackSize() < this.getMaxStackSize() ? itemInSlot.getMaxStackSize() : this.getMaxStackSize()) - itemInSlot.getCount();
+ remains -= (org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInSlot) < this.getMaxStackSize() ? org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInSlot) : this.getMaxStackSize()) - itemInSlot.getCount(); // Leaves - item over-stack util
}
if (remains <= 0) {
return itemStack.getCount();
@@ -191,7 +193,7 @@ public class Inventory implements Container, Nameable {
ItemStack itemInOffhand = this.equipment.get(EquipmentSlot.OFFHAND);
if (this.hasRemainingSpaceForItem(itemInOffhand, itemStack)) {
- remains -= (itemInOffhand.getMaxStackSize() < this.getMaxStackSize() ? itemInOffhand.getMaxStackSize() : this.getMaxStackSize()) - itemInOffhand.getCount();
+ remains -= (org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInOffhand) < this.getMaxStackSize() ? org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInOffhand) : this.getMaxStackSize()) - itemInOffhand.getCount(); // Leaves - item over-stack util
}
if (remains <= 0) {
return itemStack.getCount();
@@ -315,7 +317,7 @@ public class Inventory implements Container, Nameable {
this.setItem(slot, itemStackInSlot);
}
- int maxToAdd = this.getMaxStackSize(itemStackInSlot) - itemStackInSlot.getCount();
+ int maxToAdd = this.getMaxStackLeaves(itemStackInSlot) - itemStackInSlot.getCount(); // Leaves - item over-stack util
int toAdd = Math.min(count, maxToAdd);
if (toAdd == 0) {
return count;
@@ -421,7 +423,7 @@ public class Inventory implements Container, Nameable {
break;
}
- int slotHasSpaceFor = itemStack.getMaxStackSize() - this.getItem(slot).getCount();
+ int slotHasSpaceFor = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack) - this.getItem(slot).getCount(); // Leaves - item over-stack util
if (this.add(slot, itemStack.split(slotHasSpaceFor)) && shouldSendSetSlotPacket && this.player instanceof ServerPlayer serverPlayer) {
serverPlayer.connection.send(this.createInventoryUpdatePacket(slot));
}
diff --git a/net/minecraft/world/entity/player/StackedItemContents.java b/net/minecraft/world/entity/player/StackedItemContents.java
index 1ace17d8fc7e7b8b4722a1889d49233c0ec55e20..d146f02338852810679a45bff932d9d68ee86d60 100644
--- a/net/minecraft/world/entity/player/StackedItemContents.java
+++ b/net/minecraft/world/entity/player/StackedItemContents.java
@@ -36,7 +36,7 @@ public class StackedItemContents {
}
public void accountStack(final ItemStack itemStack) {
- this.accountStack(itemStack, itemStack.getMaxStackSize());
+ this.accountStack(itemStack, org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack)); // Leaves - item over-stack util
}
public void accountStack(final ItemStack itemStack, final int maxCount) {
diff --git a/net/minecraft/world/entity/vehicle/ContainerEntity.java b/net/minecraft/world/entity/vehicle/ContainerEntity.java
index 9c9a08752b54222e8ac8d9a38c7a28a775bd1164..42716cf2c864eba50628dc64c59ab29c1d51dc9b 100644
--- a/net/minecraft/world/entity/vehicle/ContainerEntity.java
+++ b/net/minecraft/world/entity/vehicle/ContainerEntity.java
@@ -161,7 +161,7 @@ public interface ContainerEntity extends Container, MenuProvider {
default void setChestVehicleItem(final int slot, final ItemStack itemStack) {
this.unpackChestVehicleLootTable(null);
this.getItemStacks().set(slot, itemStack);
- itemStack.limitSize(this.getMaxStackSize(itemStack));
+ itemStack.limitSize(this.getMaxStackLeaves(itemStack)); // Leaves - item over-stack util
}
default @Nullable SlotAccess getChestVehicleSlot(final int slot) {
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
index 4a177b4e714ba52cc18024d1233c9425afb93741..fa1f7dd22959632aaa54e72c8caf13ea072e7ca7 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -294,6 +294,14 @@ public abstract class AbstractContainerMenu {
this.sendAllDataToRemote();
}
+ // Leaves start - item over-stack util
+ public void sendSingleSlot(final int slotIndex, final ItemStack item) {
+ if (this.synchronizer != null) {
+ this.synchronizer.sendSlotChange(this, slotIndex, item);
+ }
+ }
+ // Leaves end - item over-stack util
+
private void updateDataSlotListeners(final int id, final int currentValue) {
for (ContainerListener containerListener : this.containerListeners) {
containerListener.dataChanged(this, id, currentValue);
@@ -450,7 +458,7 @@ public abstract class AbstractContainerMenu {
&& (this.quickcraftType == QUICKCRAFT_TYPE_CLONE || carriedItemStack.getCount() >= this.quickcraftSlots.size())
&& this.canDragTo(slot)) {
int carry = slot.hasItem() ? slot.getItem().getCount() : 0;
- int maxSize = Math.min(source.getMaxStackSize(), slot.getMaxStackSize(source));
+ int maxSize = Math.min(org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(source), slot.getMaxStackSize(source)); // Leaves - item over-stack util
int newCount = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots.size(), this.quickcraftType, source) + carry, maxSize);
remaining -= newCount - carry;
// slot.setByPlayer(source.copyWithCount(newCount));
@@ -558,7 +566,7 @@ public abstract class AbstractContainerMenu {
slotx.setByPlayer(carried);
}
} else if (ItemStack.isSameItemSameComponents(clicked, carried)) {
- Optional<ItemStack> newCarried = slotx.tryRemove(clicked.getCount(), carried.getMaxStackSize() - carried.getCount(), player);
+ Optional<ItemStack> newCarried = slotx.tryRemove(clicked.getCount(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(carried) - carried.getCount(), player); // Leaves - item over-stack util
newCarried.ifPresent(itemsTaken -> {
carried.grow(itemsTaken.getCount());
slotx.onTake(player, itemsTaken);
@@ -620,7 +628,7 @@ public abstract class AbstractContainerMenu {
Slot slotx = this.slots.get(slotIndex);
if (slotx.hasItem()) {
ItemStack item = slotx.getItem();
- this.setCarried(item.copyWithCount(item.getMaxStackSize()));
+ this.setCarried(item.copyWithCount(org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(item))); // Leaves - item over-stack util
}
} else if (containerInput == ContainerInput.THROW && this.getCarried().isEmpty() && slotIndex >= 0) {
Slot slotx = this.slots.get(slotIndex);
@@ -655,15 +663,15 @@ public abstract class AbstractContainerMenu {
int step = buttonNum == 0 ? 1 : -1;
for (int pass = 0; pass < 2; pass++) {
- for (int i = start; i >= 0 && i < this.slots.size() && carried.getCount() < carried.getMaxStackSize(); i += step) {
+ for (int i = start; i >= 0 && i < this.slots.size() && carried.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(carried); i += step) { // Leaves - item over-stack util
Slot target = this.slots.get(i);
if (target.hasItem()
&& canItemQuickReplace(target, carried, true)
&& target.mayPickup(player)
&& this.canTakeItemForPickAll(carried, target)) {
ItemStack itemStack = target.getItem();
- if (pass != 0 || itemStack.getCount() != itemStack.getMaxStackSize()) {
- ItemStack removed = target.safeTake(itemStack.getCount(), carried.getMaxStackSize() - carried.getCount(), player);
+ if (pass != 0 || itemStack.getCount() != org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack)) { // Leaves - item over-stack util
+ ItemStack removed = target.safeTake(itemStack.getCount(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(carried) - carried.getCount(), player); // Leaves - item over-stack util
carried.grow(removed.getCount());
}
}
@@ -770,7 +778,7 @@ public abstract class AbstractContainerMenu {
destSlot = endSlot - 1;
}
- if (itemStack.isStackable()) {
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.isStackable(itemStack)) { // Leaves - item over-stack util
while (!itemStack.isEmpty() && (backwards ? destSlot >= startSlot : destSlot < endSlot)) {
Slot slot = this.slots.get(destSlot);
ItemStack target = slot.getItem();
@@ -871,7 +879,7 @@ public abstract class AbstractContainerMenu {
public static boolean canItemQuickReplace(final @Nullable Slot slot, final ItemStack itemStack, final boolean ignoreSize) {
boolean slotIsEmpty = slot == null || !slot.hasItem();
return !slotIsEmpty && ItemStack.isSameItemSameComponents(itemStack, slot.getItem())
- ? slot.getItem().getCount() + (ignoreSize ? 0 : itemStack.getCount()) <= itemStack.getMaxStackSize()
+ ? slot.getItem().getCount() + (ignoreSize ? 0 : itemStack.getCount()) <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack) // Leaves - item over-stack util
: slotIsEmpty;
}
@@ -879,7 +887,7 @@ public abstract class AbstractContainerMenu {
return switch (quickCraftingType) {
case 0 -> Mth.floor((float)itemStack.getCount() / quickCraftSlotsSize);
case 1 -> 1;
- case 2 -> itemStack.getMaxStackSize();
+ case 2 -> org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
default -> itemStack.getCount();
};
}
@@ -902,7 +910,7 @@ public abstract class AbstractContainerMenu {
for (int i = 0; i < container.getContainerSize(); i++) {
ItemStack itemStack = container.getItem(i);
if (!itemStack.isEmpty()) {
- totalPercent += (float)itemStack.getCount() / container.getMaxStackSize(itemStack);
+ totalPercent += org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackSignalStrength(container.getMaxStackSize(), itemStack); // Leaves - item over-stack util
}
}
diff --git a/net/minecraft/world/inventory/MerchantContainer.java b/net/minecraft/world/inventory/MerchantContainer.java
index e1b1a261a5f7a3702c1788daa38e7d367195382e..cb95fa63c585b1c3859bfd3e5d4d0e5dd84c7f0d 100644
--- a/net/minecraft/world/inventory/MerchantContainer.java
+++ b/net/minecraft/world/inventory/MerchantContainer.java
@@ -108,7 +108,7 @@ public class MerchantContainer implements Container {
@Override
public void setItem(final int slot, final ItemStack itemStack) {
this.itemStacks.set(slot, itemStack);
- itemStack.limitSize(this.getMaxStackSize(itemStack));
+ itemStack.limitSize(this.getMaxStackLeaves(itemStack)); // Leaves - item over-stack util
if (this.isPaymentSlot(slot)) {
this.updateSellItem();
}
diff --git a/net/minecraft/world/inventory/Slot.java b/net/minecraft/world/inventory/Slot.java
index ee86a63c8d0d4c798ad09da87598d22c0e516840..57061d97bd368bfe934157293471fd546bb105ee 100644
--- a/net/minecraft/world/inventory/Slot.java
+++ b/net/minecraft/world/inventory/Slot.java
@@ -75,7 +75,7 @@ public class Slot {
}
public int getMaxStackSize(final ItemStack itemStack) {
- return Math.min(this.getMaxStackSize(), itemStack.getMaxStackSize());
+ return Math.min(this.getMaxStackSize(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack)); // Leaves - item over-stack util
}
public @Nullable Identifier getNoItemIcon() {
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index 65d5c766eb9bfade4d8259bda418a7f0e413edbe..b052bc0107d93cd65a6c92914d6b3d02d6cc5ccb 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -160,7 +160,7 @@ public final class ItemStack implements DataComponentHolder, ItemInstance, Chang
private int popTime;
@Deprecated
private @Nullable Holder<Item> item;
- private PatchedDataComponentMap components;
+ public PatchedDataComponentMap components; // Leaves - item over-stack util
public static DataResult<ItemStack> validateStrict(final ItemStack itemStack) {
DataResult<?> result = validateComponents(itemStack.getComponents());
@@ -185,7 +185,8 @@ public final class ItemStack implements DataComponentHolder, ItemInstance, Chang
} else {
Holder<Item> item = Item.STREAM_CODEC.decode(input);
DataComponentPatch patch = patchCodec.decode(input);
- return new ItemStack(item, count, patch);
+ ItemStack stack = new ItemStack(item, count, patch);
+ return org.leavesmc.leaves.util.ItemOverstackUtils.decodeMaxStackSize(stack); // Leaves - item over-stack util
}
}
@@ -194,17 +195,20 @@ public final class ItemStack implements DataComponentHolder, ItemInstance, Chang
if (itemStack.isEmpty() || itemStack.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem()
output.writeVarInt(0);
} else {
- output.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), itemStack, itemStack.getCount())); // Paper - potentially sanitize count
- Item.STREAM_CODEC.encode(output, itemStack.typeHolder());
+ // Leaves start - item over-stack util
+ final ItemStack encodedStack = org.leavesmc.leaves.util.ItemOverstackUtils.encodeMaxStackSize(itemStack.copy());
+ output.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), encodedStack, encodedStack.getCount())); // Paper - potentially sanitize count
+ Item.STREAM_CODEC.encode(output, encodedStack.typeHolder());
// Paper start - adventure; conditionally render translatable components
boolean prev = net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.get();
- try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.itemStack(itemStack))) { // pass the itemstack as context to the obfuscation session
+ try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.itemStack(encodedStack))) { // pass the itemstack as context to the obfuscation session
net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(true);
- patchCodec.encode(output, itemStack.components.asPatch());
+ patchCodec.encode(output, encodedStack.components.asPatch());
} finally {
net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(prev);
}
// Paper end - adventure; conditionally render translatable components
+ // Leaves end - item over-stack util
}
}
};
diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java
index 15ed625105539f402fb39275b292531fe388a7a0..2b97fd6af1c4956eb173b8c66c2a3efc8772a798 100644
--- a/net/minecraft/world/level/block/CrafterBlock.java
+++ b/net/minecraft/world/level/block/CrafterBlock.java
@@ -202,7 +202,7 @@ public class CrafterBlock extends BaseEntityBlock {
Direction direction = blockState.getValue(ORIENTATION).front();
Container into = HopperBlockEntity.getContainerAt(level, pos.relative(direction));
ItemStack remaining = results.copy();
- if (into != null && (into instanceof CrafterBlockEntity || results.getCount() > into.getMaxStackSize(results))) {
+ if (into != null && (into instanceof CrafterBlockEntity || results.getCount() > into.getMaxStackLeaves(results))) { // Leaves - item over-stack util
// CraftBukkit start - InventoryMoveItemEvent
org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(remaining);
diff --git a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index 06d55281bb782cc064255c7b56acd6cd332b9085..d926be9a0c4954746032e3e96cf50a8cba5f26b3 100644
--- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -397,7 +397,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
ItemStack oldStack = this.items.get(slot);
boolean same = !itemStack.isEmpty() && ItemStack.isSameItemSameComponents(oldStack, itemStack);
this.items.set(slot, itemStack);
- itemStack.limitSize(this.getMaxStackSize(itemStack));
+ itemStack.limitSize(this.getMaxStackLeaves(itemStack)); // Leaves - item over-stack util
if (slot == 0 && !same && this.level instanceof ServerLevel serverLevel) {
this.cookingTotalTime = getTotalCookTime(serverLevel, this, this.recipeType, this.cookSpeedMultiplier); // Paper - cook speed multiplier API
this.cookingTimer = 0;
diff --git a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
index 65ca3c97fdd60ebbdd366673c81c4375488f0cde..a7a13fb017a4c98db7639b8d672f3ad9d7814b7f 100644
--- a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
@@ -134,7 +134,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
@Override
public void setItem(final int slot, final ItemStack itemStack) {
this.getItems().set(slot, itemStack);
- itemStack.limitSize(this.getMaxStackSize(itemStack));
+ itemStack.limitSize(this.getMaxStackLeaves(itemStack)); // Leaves - item over-stack util
this.setChanged();
}
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 75a8c007ba710aa6e77ba3ed9ae5f7868894629d..d036018ee64995ee754296014888ee70c0ea5ab3 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -155,7 +155,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public void setItem(final int slot, final ItemStack itemStack) {
this.unpackLootTable(null);
this.getItems().set(slot, itemStack);
- itemStack.limitSize(this.getMaxStackSize(itemStack));
+ itemStack.limitSize(this.getMaxStackLeaves(itemStack)); // Leaves - item over-stack util
}
@Override
@@ -670,9 +670,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (current.isEmpty()) {
// Spigot start - SPIGOT-6693, SimpleContainer#setItem
ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size
- if (!itemStack.isEmpty() && itemStack.getCount() > container.getMaxStackSize()) {
+ if (!itemStack.isEmpty() && (itemStack.getCount() > container.getMaxStackSize() || itemStack.getCount() > itemStack.getMaxStackSize())) { // Leaves - item over-stack util
leftover = itemStack; // Paper - Make hoppers respect inventory max stack size
- itemStack = itemStack.split(container.getMaxStackSize());
+ itemStack = itemStack.split(Math.min(container.getMaxStackSize(), itemStack.getMaxStackSize())); // Leaves - item over-stack util
}
// Spigot end
IGNORE_TILE_UPDATES.set(Boolean.TRUE); // Paper - Perf: Optimize Hoppers // Folia - region threading
@@ -0,0 +1,177 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Fri, 11 Apr 2025 16:53:57 +0800
Subject: [PATCH] Leaves: Old raid behavior
Co-authored by: huanli233 <392352840@qq.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/bda7e406b995290234e33283a181e33467ceda38/leaves-server/minecraft-patches/features/0114-Old-raid-behavior.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/effect/BadOmenMobEffect.java b/net/minecraft/world/effect/BadOmenMobEffect.java
index f58b10c7dec0d2b7dc2b3d1198539b74d13038f3..0a838a2015526dde2cb8d9006a71610e0bf5e9dc 100644
--- a/net/minecraft/world/effect/BadOmenMobEffect.java
+++ b/net/minecraft/world/effect/BadOmenMobEffect.java
@@ -22,6 +22,11 @@ class BadOmenMobEffect extends MobEffect {
&& !player.isSpectator()
&& level.getDifficulty() != Difficulty.PEACEFUL
&& level.isVillage(player.blockPosition())) {
+ // Leaves start - Revert raid changes
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
+ return level.getRaids().createOrExtendRaid(player, player.blockPosition()) == null;
+ }
+ // Leaves end - Revert raid changes
Raid raid = level.getRaidAt(player.blockPosition());
if (raid == null || raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel()) {
player.addEffect(new MobEffectInstance(MobEffects.RAID_OMEN, 600, amplification));
diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java
index 24cc4a15731edcb701596fe7051e188637457e37..5440dc0fb8bccabb65fd9681ab368ef5028e2ca9 100644
--- a/net/minecraft/world/entity/raid/Raid.java
+++ b/net/minecraft/world/entity/raid/Raid.java
@@ -268,7 +268,7 @@ public class Raid {
}
public boolean absorbRaidOmen(final ServerPlayer player) {
- MobEffectInstance effect = player.getEffect(MobEffects.RAID_OMEN);
+ MobEffectInstance effect = player.getEffect(fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior ? MobEffects.BAD_OMEN : MobEffects.RAID_OMEN); // Leaves - old Raid Behavior
if (effect == null) {
return false;
} else {
@@ -345,7 +345,13 @@ public class Raid {
}
if (shouldTryToFindSpawnPos) {
- this.waveSpawnPos = this.getValidSpawnPos(level);
+ // Leaves Start - old FindSpawnPosition
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
+ this.waveSpawnPos = this.preCalcRavagerSpawnLocation(level, this.raidCooldownTicks < 100 ? 1 : 0);
+ } else {
+ this.waveSpawnPos = this.getValidSpawnPos(level);
+ }
+ // Leaves End - old FindSpawnPosition
}
if (this.raidCooldownTicks == 300 || this.raidCooldownTicks % 20 == 0) {
@@ -400,7 +406,14 @@ public class Raid {
int attempt = 0;
while (this.shouldSpawnGroup()) {
- BlockPos spawnPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
+ // Leaves Start - old FindSpawnPosition
+ BlockPos spawnPos;
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
+ spawnPos = this.getRavagerSpawnLocation(level, attempt, 20);
+ } else {
+ spawnPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
+ }
+ // Leaves End - old FindSpawnPosition
if (spawnPos != null) {
this.started = true;
this.spawnGroup(level, spawnPos);
@@ -412,7 +425,7 @@ public class Raid {
attempt++;
}
- if (attempt > 5) {
+ if (attempt > (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior ? 3 : 5)) { // Leaves - old FindSpawnPosition
org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(level, this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE); // CraftBukkit
this.stop();
break;
@@ -716,7 +729,7 @@ public class Raid {
int spawnX = this.center.getX() + Mth.floor(Mth.cos(angle) * 32.0F * howFar) + this.random.nextInt(3) * Mth.floor(howFar);
int spawnZ = this.center.getZ() + Mth.floor(Mth.sin(angle) * 32.0F * howFar) + this.random.nextInt(3) * Mth.floor(howFar);
int spawnY = level.getHeight(Heightmap.Types.WORLD_SURFACE, spawnX, spawnZ);
- if (Mth.abs(spawnY - this.center.getY()) <= 96) {
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior || Mth.abs(spawnY - this.center.getY()) <= 96) { // Leaves - skippable
spawnPos.set(spawnX, spawnY, spawnZ);
if (!level.isVillage(spawnPos) || secondsRemaining <= 7) {
int delta = 10;
@@ -899,4 +912,42 @@ public class Raid {
this.spawnsPerWaveBeforeBonus = spawnsPerWaveBeforeBonus;
}
}
+
+ // Leaves start - old FindSpawnPosition
+ @Nullable
+ private BlockPos getRavagerSpawnLocation(final ServerLevel serverWorld, final int proximity, final int tries) {
+ int i = proximity == 0 ? 2 : 2 - proximity;
+ BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
+ net.minecraft.world.entity.SpawnPlacementType spawnLocation = net.minecraft.world.entity.SpawnPlacements.getPlacementType(EntityType.RAVAGER);
+ for (int j = 0; j < tries; j++) {
+ float f = serverWorld.getRandom().nextFloat() * (float) (Math.PI * 2);
+ int k = this.center.getX() + Mth.floor(Mth.cos(f) * 32.0F * (float) i + serverWorld.getRandom().nextInt(5));
+ int l = this.center.getZ() + Mth.floor(Mth.sin(f) * 32.0F * (float) i + serverWorld.getRandom().nextInt(5));
+ int m = serverWorld.getHeight(Heightmap.Types.WORLD_SURFACE, k, l);
+ mutable.set(k, m, l);
+ if (serverWorld.isVillage(mutable) && proximity < 2) {
+ continue;
+ }
+ if (serverWorld.hasChunksAt(mutable.getX() - 10, mutable.getZ() - 10, mutable.getX() + 10, mutable.getZ() + 10)
+ && serverWorld.isPositionEntityTicking(mutable)
+ && (spawnLocation.isSpawnPositionOk(serverWorld, mutable, EntityType.RAVAGER)
+ || serverWorld.getBlockState(mutable.below()).is(net.minecraft.world.level.block.Blocks.SNOW)
+ && serverWorld.getBlockState(mutable).isAir())
+ ) {
+ return mutable.immutable();
+ }
+ }
+ return null;
+ }
+
+ private Optional<BlockPos> preCalcRavagerSpawnLocation(final ServerLevel serverWorld, final int proximity) {
+ for (int i = 0; i < 3; i++) {
+ BlockPos blockPos = this.getRavagerSpawnLocation(serverWorld, proximity, 1);
+ if (blockPos != null) {
+ return Optional.of(blockPos);
+ }
+ }
+ return Optional.empty();
+ }
+ // Leaves end - old FindSpawnPosition
}
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
index bc2edc48ddefaab9022029f1a913a40b72e06024..1a51da9171c13711e106731c360051d183a40893 100644
--- a/net/minecraft/world/entity/raid/Raider.java
+++ b/net/minecraft/world/entity/raid/Raider.java
@@ -128,6 +128,42 @@ public abstract class Raider extends PatrollingMonster {
raidWhenKilled.removeFromRaid(serverLevel, this, false);
}
+
+ // Leaves start - Revert raid changes
+ Entity killerEntity = source.getEntity();
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior && !this.hasActiveRaid()) {
+ ItemStack itemstack = this.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.HEAD);
+ net.minecraft.world.entity.player.Player entityhuman = null;
+ if (killerEntity instanceof net.minecraft.world.entity.player.Player player) {
+ entityhuman = player;
+ } else if (killerEntity instanceof net.minecraft.world.entity.animal.wolf.Wolf wolf) {
+ LivingEntity entityliving = wolf.getOwner();
+ if (wolf.isTame() && entityliving instanceof net.minecraft.world.entity.player.Player player) {
+ entityhuman = player;
+ }
+ }
+
+ if (entityhuman != null && !itemstack.isEmpty() && this.isPatrolLeader()) {
+ net.minecraft.world.effect.MobEffectInstance mobeffect = entityhuman.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN);
+ int amp = 1;
+
+ if (mobeffect != null) {
+ amp += mobeffect.getAmplifier();
+ entityhuman.removeEffectNoUpdate(net.minecraft.world.effect.MobEffects.BAD_OMEN);
+ } else {
+ --amp;
+ }
+
+ amp = net.minecraft.util.Mth.clamp(amp, 0, 4);
+ net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, 120000, amp, false, false, true);
+
+ if (serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.RAIDS)) {
+ entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit
+ }
+ this.setPatrolLeader(false);
+ }
+ }
+ // Leaves end - Revert raid changes
}
super.die(source);
@@ -6,15 +6,15 @@ Subject: [PATCH] Compatibility fix for Raid Revert and Cross Region Damage
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index e94687b3aa960f9c630f459fedc17bc01846eaf7..f4f4f886b6558d39d292a45665953f497f84be53 100644
index cc7b2ea7fda1326e3f9ed46373190a05f60c4d34..2bce20202b7c539bee3685741663a8ed225919ff 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -1216,6 +1216,29 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -1234,6 +1234,30 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
}
}
+ // Lophine Start - raid revert adapt Cross Region Damage trace
+ public boolean addEffect(MobEffectInstance effectInstance, EntityPotionEffectEvent.Cause cause, boolean fireEvent, boolean async) {
+ public boolean addEffect(final MobEffectInstance effectInstance, EntityPotionEffectEvent.Cause cause, boolean fireEvent, boolean async) {
+ if (!async || ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this)) {
+ return addEffect(effectInstance, this, cause, fireEvent);
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
@@ -24,31 +24,32 @@ index e94687b3aa960f9c630f459fedc17bc01846eaf7..f4f4f886b6558d39d292a45665953f49
+ return false;
+ }
+
+ private void postToAddEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) {
+ private void postToAddEffect(final MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) {
+ if (entity != null)
+ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> {
+ try {
+ if (nmsEntity.isRemoved()) return;
+ addEffect(effectInstance, nmsEntity, cause, fireEvent);
+ } catch (Throwable ex) {
+ LOGGER.error(ex.getMessage(), ex);
+ }
+ }, null, 1L );
+ }, null, 1L);
+ }
+ // Lophine End - raid revert adapt Cross Region Damage trace
+
public boolean canBeAffected(MobEffectInstance effectInstance) {
if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) {
return !effectInstance.is(MobEffects.INFESTED);
public boolean canBeAffected(final MobEffectInstance newEffect) {
if (this.is(EntityTypeTags.IMMUNE_TO_INFESTED)) {
return !newEffect.is(MobEffects.INFESTED);
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
index 2d163f3d5eb1af4d539d24c0256855bbec960de4..2cc0a7b5f088c29d9343b369b6e71c8a3ebdef75 100644
index 1a51da9171c13711e106731c360051d183a40893..7094a67959e9747b2dfa55a5f5a3e90552d35466 100644
--- a/net/minecraft/world/entity/raid/Raider.java
+++ b/net/minecraft/world/entity/raid/Raider.java
@@ -158,7 +158,7 @@ public abstract class Raider extends PatrollingMonster {
net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, 120000, i, false, false, true);
net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, 120000, amp, false, false, true);
if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DISABLE_RAIDS)) {
- entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit
+ entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true, fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled); // Lophine - raid revert adapt Cross Region Damage trace
}
this.setPatrolLeader(false);
if (serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.RAIDS)) {
- entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit
+ entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true, fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled); // CraftBukkit // Lophine - raid revert adapt Cross Region Damage trace
}
this.setPatrolLeader(false);
}
@@ -1,55 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 3 Aug 2025 15:24:01 +0800
Subject: [PATCH] Leaves: Base Protocol Core
Subject: [PATCH] Leaves: Leaves Base Protocol Core
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/ea91106ae57fc4cc14e2e0225009cf9919072f7f/leaves-server/minecraft-patches/features/0004-Leaves-Protocol-Core.patch)
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/9d2bd3f7b0a48f00df7bc8c74292338ed9c3a458/leaves-server/minecraft-patches/features/0122-Leaves-Protocol-Core.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index 8405157ec35a443e238fa6866772c839621d73d7..67f3454e6479abb241a7d94699d4f7bec22da56b 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -334,6 +334,8 @@ public final class RegionizedServer {
}
// Luminol end - Add a config to enable tick command
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleTick(); // Leaves - protocol
+
// tick connections
this.tickConnections();
diff --git a/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java b/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
index fb263fa1f30a7dfcb7ec2656abfb38e5fe88eac9..56fd1ed7ccaf96e7eedea60fbdbf7f934939d563 100644
index e9f86409bf9351e85ed31e747d9350dbf0cc441f..1f8f4d979d8766d6ba385f74cf8fcf8eea6c56c7 100644
--- a/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
+++ b/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
@@ -40,13 +40,22 @@ public interface CustomPacketPayload {
@Override
public void encode(B buffer, CustomPacketPayload value) {
public void encode(final B output, final CustomPacketPayload value) {
+ // Leaves start - protocol core
+ if (value instanceof org.leavesmc.leaves.protocol.core.LeavesCustomPayload payload) {
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.encode(buffer, payload);
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.encode(output, payload);
+ return;
+ }
+ // Leaves end - protocol core
this.writeCap(buffer, value.type(), value);
this.writeCap(output, value.type(), value);
}
@Override
public CustomPacketPayload decode(B buffer) {
ResourceLocation resourceLocation = buffer.readResourceLocation();
- return (CustomPacketPayload)this.findCodec(resourceLocation).decode(buffer);
public CustomPacketPayload decode(final B input) {
Identifier identifier = input.readIdentifier();
- return (CustomPacketPayload)this.findCodec(identifier).decode(input);
+ // Leaves start - protocol core
+ var payload = org.leavesmc.leaves.protocol.core.LeavesProtocolManager.decode(resourceLocation, buffer);
+ return java.util.Objects.requireNonNullElseGet(payload, () -> this.findCodec(resourceLocation).decode(buffer));
+ var payload = org.leavesmc.leaves.protocol.core.LeavesProtocolManager.decode(identifier, input);
+ return java.util.Objects.requireNonNullElseGet(payload, () -> (CustomPacketPayload) this.findCodec(identifier).decode(input));
+ // Leaves end - protocol core
}
};
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 99edebf474277e680df63930b51fef579b712def..3cd1a0de188db35ac9c48996a4dbe6186b69e348 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2040,6 +2040,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
profiler.popPush("server gui refresh");
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleTick(); // Leaves - protocol // Lophine - we don't have tickCount to use, remove it
+
if (false) for (Runnable tickable : this.tickables) { // Folia - region threading - TODO WTF is this?
tickable.run();
}
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
index 8150b16c196edcb226be9268ea6e0012e44517fa..c54bf0429c0ca3a35a730658c7b1b3ddc776bf9e 100644
index cf4b5e436b8d81657d1deaa5b06645016d9dc3cc..f3af5660a377e2eb823f79ec274feaf3284761cd 100644
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -57,6 +57,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -58,7 +58,7 @@ index 8150b16c196edcb226be9268ea6e0012e44517fa..c54bf0429c0ca3a35a730658c7b1b3dd
// Paper end - retain certain values
+ public final GameProfile profile; // Leaves - protocol core
public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) {
public ServerCommonPacketListenerImpl(final MinecraftServer server, final Connection connection, final CommonListenerCookie cookie) {
this.server = server;
@@ -70,6 +71,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
this.pluginMessagerChannels = cookie.channels();
@@ -68,16 +68,16 @@ index 8150b16c196edcb226be9268ea6e0012e44517fa..c54bf0429c0ca3a35a730658c7b1b3dd
}
// Paper start - configuration phase API
@@ -160,6 +162,18 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -143,6 +145,18 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@Override
public void handleCustomPayload(ServerboundCustomPayloadPacket packet) {
public void handleCustomPayload(final ServerboundCustomPayloadPacket packet) {
+ // Leaves start - protocol
+ if (packet.payload() instanceof org.leavesmc.leaves.protocol.core.LeavesCustomPayload leavesPayload) {
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePayload(org.leavesmc.leaves.protocol.core.ProtocolUtils.createSelector(this), leavesPayload);
+ return;
+ }
+ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.DiscardedPayload(net.minecraft.resources.ResourceLocation id, byte[] data)) {
+ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.DiscardedPayload(net.minecraft.resources.Identifier id, byte[] data)) {
+ if (org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleBytebuf(org.leavesmc.leaves.protocol.core.ProtocolUtils.createSelector(this), id, io.netty.buffer.Unpooled.wrappedBuffer(data))) {
+ return;
+ }
@@ -87,7 +87,7 @@ index 8150b16c196edcb226be9268ea6e0012e44517fa..c54bf0429c0ca3a35a730658c7b1b3dd
// Paper start
if (!(packet.payload() instanceof final net.minecraft.network.protocol.common.custom.DiscardedPayload discardedPayload)) {
return;
@@ -219,10 +233,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -202,6 +216,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
final String channel = new String(data, from, length, java.nio.charset.StandardCharsets.US_ASCII);
if (register) {
bridge.addChannel(channel);
@@ -95,63 +95,30 @@ index 8150b16c196edcb226be9268ea6e0012e44517fa..c54bf0429c0ca3a35a730658c7b1b3dd
} else {
bridge.removeChannel(channel);
}
- // Paper end
+ // Paper end
}
@Override
@@ -385,9 +400,9 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
net.minecraft.server.level.ServerPlayer player = serverGamePacketListener.player;
org.bukkit.event.player.PlayerKickEvent.Cause cause = disconnectionDetails.disconnectionReason().orElseThrow().game().orElse(org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN);
org.bukkit.event.player.PlayerKickEvent event = new org.bukkit.event.player.PlayerKickEvent(
- player.getBukkitEntity(),
- io.papermc.paper.adventure.PaperAdventure.asAdventure(disconnectionDetails.reason()),
- rawLeaveMessage, cause
+ player.getBukkitEntity(),
+ io.papermc.paper.adventure.PaperAdventure.asAdventure(disconnectionDetails.reason()),
+ rawLeaveMessage, cause
);
@@ -420,10 +435,10 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
private void disconnect0(DisconnectionDetails disconnectionDetails) {
this.connection
- .send(
- new ClientboundDisconnectPacket(disconnectionDetails.reason()),
- PacketSendListener.thenRun(() -> this.connection.disconnect(disconnectionDetails))
- );
+ .send(
+ new ClientboundDisconnectPacket(disconnectionDetails.reason()),
+ PacketSendListener.thenRun(() -> this.connection.disconnect(disconnectionDetails))
+ );
this.onDisconnect(disconnectionDetails);
this.connection.setReadOnly();
// CraftBukkit - Don't wait
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 4ef2816210f06082f2209c51d04aad6bb188232b..593dbcda4b497291eb1ecdc64b947a8d279f8be6 100644
index 45e5ac1e8e2ec30935e96fa20d18e77bbd0e20bd..deb029c5621f793f63447d351526c31fab5ec12c 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -423,6 +423,8 @@ public abstract class PlayerList {
//return; // Folia - region threading - must still allow the player to connect, as we must add to chunk map before handling disconnect
}
@@ -318,6 +318,8 @@ public abstract class PlayerList {
//return; // Folia - region threading - must still allow the player to connect, as we must add to chunk map before handling disconnect
}
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player);
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
+
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -605,6 +607,7 @@ public abstract class PlayerList {
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -518,6 +520,7 @@ public abstract class PlayerList {
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
}
public @Nullable net.kyori.adventure.text.Component remove(ServerPlayer player, net.kyori.adventure.text.Component leaveMessage) {
public net.kyori.adventure.text.@Nullable Component remove(final ServerPlayer player, final net.kyori.adventure.text.Component leaveMessage) {
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerLeave(player); // Leaves - protocol
// Paper end - Fix kick event leave message not being sent
ServerLevel serverLevel = player.level();
ServerLevel level = player.level();
player.awardStat(Stats.LEAVE_GAME);
@@ -1520,6 +1523,7 @@ public abstract class PlayerList {
serverPlayer.connection.send(clientboundUpdateRecipesPacket);
serverPlayer.getRecipeBook().sendInitialRecipeBook(serverPlayer);
@@ -1413,6 +1416,7 @@ public abstract class PlayerList {
player.connection.send(recipes);
player.getRecipeBook().sendInitialRecipeBook(player);
}
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleDataPackReload(); // Leaves - protocol core
}
@@ -4,14 +4,14 @@ Date: Wed, 29 Oct 2025 00:09:09 +0800
Subject: [PATCH] Leaves: Configurable trading with the void
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/9d2bd3f7b0a48f00df7bc8c74292338ed9c3a458/leaves-server/minecraft-patches/features/0088-Configurable-trading-with-the-void.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 985ddea9d74a37f58f32a27375f6f7e6af0f2192..9796c449f924b8fd9c0dd6bb02cf196641e495ed 100644
index 0f1bd15ea3b1400cc948883c92eceabcd4a4cda1..006844d6fda43f3b151899655f03b1de03f3396c 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -2901,7 +2901,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -3158,7 +3158,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
// Spigot start
if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message
// Paper start - Fix merchant inventory not closing on entity removal
@@ -21,26 +21,26 @@ index 985ddea9d74a37f58f32a27375f6f7e6af0f2192..9796c449f924b8fd9c0dd6bb02cf1966
}
// Paper end - Fix merchant inventory not closing on entity removal
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 593dbcda4b497291eb1ecdc64b947a8d279f8be6..6c1f4f943a5be5f2e43a82cca52ca76a98226915 100644
index deb029c5621f793f63447d351526c31fab5ec12c..6148e7e5978a9a5b7d7f90b58b86b0166fd16c9d 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -649,7 +649,7 @@ public abstract class PlayerList {
@@ -561,7 +561,7 @@ public abstract class PlayerList {
player.stopRiding();
rootVehicle.getPassengersAndSelf().forEach(entity -> {
vehicle.getPassengersAndSelf().forEach(e -> {
// Paper start - Fix villager boat exploit
- if (entity instanceof net.minecraft.world.entity.npc.AbstractVillager villager) {
+ if (!fun.bm.lophine.config.modules.function.OldFeatureConfig.villagerVoidTrade && entity instanceof net.minecraft.world.entity.npc.AbstractVillager villager) { // Leaves - Configurable trading with the void
- if (e instanceof net.minecraft.world.entity.npc.villager.AbstractVillager villager) {
+ if (!fun.bm.lophine.config.modules.function.OldFeatureConfig.villagerVoidTrade && e instanceof net.minecraft.world.entity.npc.villager.AbstractVillager villager) { // Leaves - Configurable trading with the void
final net.minecraft.world.entity.player.Player human = villager.getTradingPlayer();
if (human != null) {
villager.setTradingPlayer(null);
diff --git a/net/minecraft/world/inventory/MerchantMenu.java b/net/minecraft/world/inventory/MerchantMenu.java
index d59f67ffe34201c63e3d9706a4434f33b6732edb..c635c7211bff9d190b7035b284dda162334fd5c2 100644
index 1dd82dfa739957f00d51c8b987289a002815f622..85a329565119d376139a7449e538c0d83dfb079f 100644
--- a/net/minecraft/world/inventory/MerchantMenu.java
+++ b/net/minecraft/world/inventory/MerchantMenu.java
@@ -74,6 +74,7 @@ public class MerchantMenu extends AbstractContainerMenu {
@Override
public boolean stillValid(Player player) {
public boolean stillValid(final Player player) {
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.villagerVoidTrade) return this.trader.getTradingPlayer() == player; // Leaves - Configurable trading with the void
if (!checkReachable) return true; // Paper - checkReachable
return this.trader.stillValid(player);
@@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 19 May 2025 00:42:17 +0800
Subject: [PATCH] Old zombie reinforcement
diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
index 14d0758aca54d9a25e369dfa8c89c930f27946c9..1324f2c8c0d6571bac36855f08354a84e0f08b70 100644
--- a/net/minecraft/world/entity/monster/Zombie.java
+++ b/net/minecraft/world/entity/monster/Zombie.java
@@ -341,7 +341,7 @@ public class Zombie extends Monster {
int floor = Mth.floor(this.getX());
int floor1 = Mth.floor(this.getY());
int floor2 = Mth.floor(this.getZ());
- EntityType<? extends Zombie> type = this.getType();
+ EntityType<? extends Zombie> type = fun.bm.lophine.config.modules.function.OldFeatureConfig.oldZombieReinforcement ? EntityType.ZOMBIE : this.getType(); // Lophine - old zombie reinforcement
Zombie zombie = type.create(level, EntitySpawnReason.REINFORCEMENT);
if (zombie == null) {
return true;
@@ -8,10 +8,10 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/ea91106ae57fc4cc1
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/server/ServerTickRateManager.java b/net/minecraft/server/ServerTickRateManager.java
index d0d90a25a10bbecfffceee1992af88c60d14fd87..187e48e78e69c80b25710f193813335ec643957f 100644
index ca35415e152dc63cb9f4ae8da8b06766600922fd..033715812acb8f98a7c7d895d115043e232d5161 100644
--- a/net/minecraft/server/ServerTickRateManager.java
+++ b/net/minecraft/server/ServerTickRateManager.java
@@ -134,4 +134,10 @@ public class ServerTickRateManager extends TickRateManager {
@@ -139,4 +139,10 @@ public class ServerTickRateManager extends TickRateManager {
player.connection.send(ClientboundTickingStatePacket.from(this));
player.connection.send(ClientboundTickingStepPacket.from(this));
}
@@ -23,14 +23,15 @@ index d0d90a25a10bbecfffceee1992af88c60d14fd87..187e48e78e69c80b25710f193813335e
+ // Leaves end - servux
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index eb3aef1f5198592eda5dafe84b91271e861b4135..576dde41a4b48aac9079cca902f4371a31470af3 100644
index 006844d6fda43f3b151899655f03b1de03f3396c..0befa4fc81e10a23c6ba824e559f2fb4886e68ee 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -2368,6 +2368,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -2584,6 +2584,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
this.server.updateEffectiveRespawnData();
}
this.lastSpawnChunkRadius = i;
// Paper end
+
+ org.leavesmc.leaves.protocol.servux.ServuxHudDataProtocol.refreshSpawnMetadata = true; // Leaves - servux
}
public LongSet getForceLoadedChunks() {
@Override
@@ -1,828 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Sat, 30 Aug 2025 17:16:32 +0800
Subject: [PATCH] Leaves: Fakeplayer
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
index a82d84283632342bd30bc3449983431ba43583e0..f59526f6bfa1b4af5b474f0b438513c96afb491c 100644
--- a/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
+++ b/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
@@ -39,6 +39,7 @@ public abstract class SimpleCriterionTrigger<T extends SimpleCriterionTrigger.Si
}
protected void trigger(ServerPlayer player, Predicate<T> testTrigger) {
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) return; // Leaves - bot skip
PlayerAdvancements advancements = player.getAdvancements();
Set<CriterionTrigger.Listener<T>> set = (Set) advancements.criterionData.get(this); // Paper - fix PlayerAdvancements leak
if (set != null && !set.isEmpty()) {
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
index 66ec0424a46dcd49cf44467357d80b1a2d84d3b2..04ae8de63af0a8abe578f14c8ef85fd4beca0969 100644
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -96,7 +96,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@Nullable
private volatile PacketListener disconnectListener;
@Nullable
- private volatile PacketListener packetListener;
+ protected volatile PacketListener packetListener; // Leaves - private -> protected
@Nullable
private DisconnectionDetails disconnectionDetails;
private boolean encrypted;
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index b156b5c635f931a3d4abc0584591f90476d011a6..81726e5782d25ff35a2bea8820a62786e46148b1 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -347,6 +347,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
// Folia end - regionised ticking
+ private org.leavesmc.leaves.bot.BotList botList; // Leaves - fakeplayer
+
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
AtomicReference<S> atomicReference = new AtomicReference<>();
@@ -1038,6 +1040,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Folia end - region threading
public void stopServer() {
+ // Leaves end - save or remove bot
+ if (!this.getBotList().forceShutdown && !this.getBotList().removeAll()) {
+ return;
+ }
+ // Leaves end - save or remove bot
// Folia start - region threading
// halt scheduler
// don't wait, we may be on a scheduler thread
@@ -1588,7 +1595,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
int i = this.pauseWhileEmptySeconds() * 20;
this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping
if (false && i > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy
- if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping
+ if (this.playerList.getPlayerCount() == 0 && this.botList.bots.isEmpty() && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping // Leaves - fakeplayer
this.emptyTicks++;
} else {
this.emptyTicks = 0;
@@ -1912,6 +1919,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public void tickConnection() {
this.getConnection().tick();
+ this.botList.networkTick(); // Leaves - fakeplayer
}
private void synchronizeTime(ServerLevel level) {
@@ -2983,6 +2991,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return 0;
}
+ // Leaves start - fakeplayer
+ protected void setBotList(org.leavesmc.leaves.bot.BotList botList) {
+ this.botList = botList;
+ }
+
+ public org.leavesmc.leaves.bot.BotList getBotList() {
+ return botList;
+ }
+ // Leaves end - fakeplayer
+
public record ReloadableResources(CloseableResourceManager resourceManager, ReloadableServerResources managers) implements AutoCloseable {
@Override
public void close() {
diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java
index fdeca41d40705f28864ce4443d01cd872c9d51b0..5c0e338dc1b0eb5724d10a73d6fc7975f9d2e5e5 100644
--- a/net/minecraft/server/PlayerAdvancements.java
+++ b/net/minecraft/server/PlayerAdvancements.java
@@ -167,6 +167,11 @@ public class PlayerAdvancements {
}
public boolean award(AdvancementHolder advancement, String criterionKey) {
+ // Leaves start - bot can't get advancement
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ return false;
+ }
+ // Leaves end - bot can't get advancement
boolean flag = false;
AdvancementProgress orStartProgress = this.getOrStartProgress(advancement);
boolean isDone = orStartProgress.isDone();
diff --git a/net/minecraft/server/commands/BanIpCommands.java b/net/minecraft/server/commands/BanIpCommands.java
index bb5dbfeb6915a808d6f70e332bf9f0a3f9b7d19a..62f23d47b55eb59956d69153d508b5c9ab544adf 100644
--- a/net/minecraft/server/commands/BanIpCommands.java
+++ b/net/minecraft/server/commands/BanIpCommands.java
@@ -44,6 +44,12 @@ public class BanIpCommands {
return banIp(source, username, reason);
} else {
ServerPlayer playerByName = source.getServer().getPlayerList().getPlayerByName(username);
+ // Leaves start - disable ban
+ if (playerByName instanceof org.leavesmc.leaves.bot.ServerBot) {
+ source.sendFailure(Component.literal("Permission denied"));
+ return 0;
+ }
+ // Leaves end - disable ban
if (playerByName != null) {
return banIp(source, playerByName.getIpAddress(), reason);
} else {
diff --git a/net/minecraft/server/commands/BanPlayerCommands.java b/net/minecraft/server/commands/BanPlayerCommands.java
index ac3ba9d0ea344fa189912d359b718fbe05e7aa49..61a4db144f721b47ac1000df72263bceb6e38ec0 100644
--- a/net/minecraft/server/commands/BanPlayerCommands.java
+++ b/net/minecraft/server/commands/BanPlayerCommands.java
@@ -44,8 +44,16 @@ public class BanPlayerCommands {
private static int banPlayers(CommandSourceStack source, Collection<GameProfile> gameProfiles, @Nullable Component reason) throws CommandSyntaxException {
UserBanList bans = source.getServer().getPlayerList().getBans();
int i = 0;
-
+ boolean hasBot = false; // Leaves - disable kick
for (GameProfile gameProfile : gameProfiles) {
+ // Leaves start - disable ban
+ if (gameProfile instanceof org.leavesmc.leaves.bot.BotList.CustomGameProfile) {
+ source.sendFailure(Component.literal("Permission denied"));
+ hasBot = true;
+ continue;
+ }
+ // Leaves end - disable ban
+ ServerPlayer player = source.getServer().getPlayerList().getPlayer(gameProfile.getId());
if (!bans.isBanned(gameProfile)) {
UserBanListEntry userBanListEntry = new UserBanListEntry(
gameProfile, null, source.getTextName(), null, reason == null ? null : reason.getString()
@@ -55,7 +63,6 @@ public class BanPlayerCommands {
source.sendSuccess(
() -> Component.translatable("commands.ban.success", Component.literal(gameProfile.getName()), userBanListEntry.getReason()), true
);
- ServerPlayer player = source.getServer().getPlayerList().getPlayer(gameProfile.getId());
if (player != null) {
player.connection.disconnect(Component.translatable("multiplayer.disconnect.banned"), org.bukkit.event.player.PlayerKickEvent.Cause.BANNED); // Paper - kick event cause
}
@@ -63,7 +70,13 @@ public class BanPlayerCommands {
}
if (i == 0) {
- throw ERROR_ALREADY_BANNED.create();
+ // Leaves start - disable kick
+ if (hasBot) {
+ return i;
+ } else {
+ throw ERROR_ALREADY_BANNED.create();
+ }
+ // Leaves end - disable kick
} else {
return i;
}
diff --git a/net/minecraft/server/commands/KickCommand.java b/net/minecraft/server/commands/KickCommand.java
index 14e2e0fcf20c8fa875bbefb97a673be4928d099a..8af40a77dc3da1599da2793168488f88686b8785 100644
--- a/net/minecraft/server/commands/KickCommand.java
+++ b/net/minecraft/server/commands/KickCommand.java
@@ -46,9 +46,17 @@ public class KickCommand {
if (!source.getServer().isPublished()) {
throw ERROR_SINGLEPLAYER.create();
} else {
+ boolean hasBot = false; // Leaves - disable kick
int i = 0;
for (ServerPlayer serverPlayer : players) {
+ // Leaves start - disable kick
+ if (serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot) {
+ source.sendFailure(Component.literal("Permission denied"));
+ hasBot = true;
+ continue;
+ }
+ // Leaves end - disable kick
if (!source.getServer().isSingleplayerOwner(serverPlayer.getGameProfile())) {
serverPlayer.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause
source.sendSuccess(() -> Component.translatable("commands.kick.success", serverPlayer.getDisplayName(), reason), true);
@@ -57,7 +65,13 @@ public class KickCommand {
}
if (i == 0) {
- throw ERROR_KICKING_OWNER.create();
+ // Leaves start - disable kick
+ if (hasBot) {
+ return i;
+ } else {
+ throw ERROR_KICKING_OWNER.create();
+ }
+ // Leaves end - disable kick
} else {
return i;
}
diff --git a/net/minecraft/server/commands/OpCommand.java b/net/minecraft/server/commands/OpCommand.java
index f2286b96b8f40b4588f817913c42ae7b4a92340f..e6c7bbb023000b9de90c1256274ff5aba4a6478a 100644
--- a/net/minecraft/server/commands/OpCommand.java
+++ b/net/minecraft/server/commands/OpCommand.java
@@ -43,6 +43,7 @@ public class OpCommand {
int i = 0;
for (GameProfile gameProfile : gameProfiles) {
+ if (gameProfile instanceof org.leavesmc.leaves.bot.BotList.CustomGameProfile) continue; // Leaves - disable op
if (!playerList.isOp(gameProfile)) {
playerList.op(gameProfile);
i++;
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 0e278f7b9ed85ce8c3cedd9154f817b30ff1e48a..09d4b1d68c3f046ef304016a1afe7a3038dfae3e 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -162,6 +162,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
// Spigot start
+ this.setBotList(new org.leavesmc.leaves.bot.BotList(this)); // Leaves - fakeplayer
this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage));
org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings"));
org.spigotmc.SpigotConfig.registerCommands();
@@ -173,6 +174,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
// Paper end - initialize global and world-defaults configuration
me.earthme.luminol.config.ConfigManager.loadConfigFiles(); // Luminol - load config file
fun.bm.lophine.utils.ServerI18nUtil.init(); // Lophine - I18n support
+ this.getBotList().loadBotInfo(); // Leaves - load resident bot info
if (false) this.server.spark.enableEarlyIfRequested(); // Paper - spark // Luminol - Force disable builtin spark
// Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save
if (this.convertOldUsers()) {
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 70740381c6501c1a518c52b24381edd16792507f..5e31b499a894113b4be1982a1071348fcbaf9ded 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -134,7 +134,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
public final AtomicInteger tickingGenerated = new AtomicInteger(); // Paper - public
private final String storageName;
//private final PlayerMap playerMap = new PlayerMap(); // Folia - region threading
- //public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap = new Int2ObjectOpenHashMap<>(); // Folia - region threading
+ public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap = new Int2ObjectOpenHashMap<>(); // Folia - region threading
private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap();
// Paper - rewrite chunk system
public int serverViewDistance;
@@ -1309,6 +1309,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
} else if (this.seenBy.remove(player.connection)) {
this.serverEntity.removePairing(player);
+ // Leaves start - render bot
+ if (entity instanceof org.leavesmc.leaves.bot.ServerBot bot) {
+ if (bot.needSendFakeData(player)) {
+ bot.sendFakeData(player.connection, false);
+ }
+ }
+ // Leaves end - render bot
}
}
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 4f1976c47a087bf4f36687124ef29ca7b664f682..96aafe4d63446b3d212f21f14091858f72bb081f 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -207,6 +207,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private final StructureCheck structureCheck;
public final boolean tickTime; // Folia - region threading
private final RandomSequences randomSequences;
+ final List<ServerPlayer> realPlayers; // Leaves - skip
// CraftBukkit start
public final LevelStorageSource.LevelStorageAccess levelStorageAccess;
@@ -635,6 +636,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - rewrite chunk system
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
this.updateTickData(); // Folia - region threading - make sure it is initialised before ticked
+ this.realPlayers = Lists.newArrayList(); // Leaves - skip
}
// Folia start - region threading
@@ -2389,6 +2391,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
return this.players;
}
+ // Leaves start - fakeplayer skip
+ public List<ServerPlayer> realPlayers() {
+ return this.realPlayers;
+ }
+ // Leaves end - fakeplayer skip
+
@Override
public void updatePOIOnBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) {
Optional<Holder<PoiType>> optional = PoiTypes.forState(oldState);
@@ -2827,6 +2835,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true
if (entity instanceof ServerPlayer serverPlayer) {
ServerLevel.this.players.add(serverPlayer);
+ // Leaves start - skip
+ if (!(serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot)) {
+ ServerLevel.this.realPlayers.add(serverPlayer);
+ }
+ // Leaves end - skip
if (serverPlayer.isReceivingWaypoints()) {
ServerLevel.this.getWaypointManager().addPlayer(serverPlayer);
}
@@ -2914,6 +2927,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
ServerLevel.this.getChunkSource().removeEntity(entity);
if (entity instanceof ServerPlayer serverPlayer) {
ServerLevel.this.players.remove(serverPlayer);
+ // Leaves start - skip
+ if (!(serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot)) {
+ ServerLevel.this.realPlayers.remove(serverPlayer);
+ }
+ // Leaves end - skip
ServerLevel.this.getWaypointManager().removePlayer(serverPlayer);
ServerLevel.this.updateSleepingPlayerList();
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 44f0e3a675c612e9ca2bc40cc3898bdbca0f6718..4b2dba8b30b72fb3acc00957b3e19d6fc178c99e 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -219,7 +219,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private static final boolean DEFAULT_SPAWN_EXTRA_PARTICLES_ON_FALL = false;
public ServerGamePacketListenerImpl connection;
private final MinecraftServer server;
- public final ServerPlayerGameMode gameMode;
+ public ServerPlayerGameMode gameMode; // Leaves - not final
private final PlayerAdvancements advancements;
private final ServerStatsCounter stats;
private float lastRecordedHealthAndAbsorption = Float.MIN_VALUE;
@@ -232,7 +232,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private int lastSentFood = -99999999;
private boolean lastFoodSaturationZero = true;
public int lastSentExp = -99999999;
- private int spawnInvulnerableTime = 60; // Lophine - spawn invulnerable time
+ public int spawnInvulnerableTime = 60; // Lophine - spawn invulnerable time
private ChatVisiblity chatVisibility = ChatVisiblity.FULL;
public ParticleStatus particleStatus = ParticleStatus.ALL;
private boolean canChatColor = true;
@@ -241,7 +241,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private Entity camera;
public boolean isChangingDimension;
public boolean seenCredits = false;
- private final ServerRecipeBook recipeBook;
+ protected ServerRecipeBook recipeBook; // Leaves - not final and private -> protected
@Nullable
private Vec3 levitationStartPos;
private int levitationStartTime;
@@ -436,6 +436,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
// Paper start - rewrite chunk system
private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader;
private final ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.ViewDistanceHolder viewDistanceHolder = new ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.ViewDistanceHolder();
+ // Leaves start - player operation limiter
+ private int instaBreakCountPerTick = 0;
+ private int placeBlockCountPerTick = 0;
+ // Leaves end - player operation limiter
@Override
public final boolean moonrise$isRealPlayer() {
@@ -924,6 +928,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// CraftBukkit end
this.tickClientLoadTimeout();
+ this.resetOperationCountPerTick(); // Leaves - player operation limiter
this.gameMode.tick();
this.wardenSpawnTracker.tick();
if (this.spawnInvulnerableTime > 0) --this.spawnInvulnerableTime; // Lophine - spawn invulnerable time
@@ -2029,6 +2034,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.lastSentHealth = -1.0F;
this.lastSentFood = -1;
this.teleportSpectators(teleportTransition, serverLevel);
+ // Leaves start - bot support
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(this, true)); // Leaves - render bot
+ }
+ // Leaves end - bot support
// CraftBukkit start
org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), serverLevel.getWorld());
this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
@@ -3577,4 +3587,31 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
return (org.bukkit.craftbukkit.entity.CraftPlayer) super.getBukkitEntity();
}
// CraftBukkit end
+
+ // Leaves start - player operation limiter
+ protected void resetOperationCountPerTick() {
+ instaBreakCountPerTick = 0;
+ placeBlockCountPerTick = 0;
+ }
+
+ public int getInstaBreakCountPerTick() {
+ return instaBreakCountPerTick;
+ }
+
+ public int getPlaceBlockCountPerTick() {
+ return placeBlockCountPerTick;
+ }
+
+ public void addInstaBreakCountPerTick() {
+ ++instaBreakCountPerTick;
+ }
+
+ public void addPlaceBlockCountPerTick() {
+ ++placeBlockCountPerTick;
+ }
+
+ public boolean allowOperation() {
+ return (instaBreakCountPerTick == 0 || placeBlockCountPerTick == 0) && (instaBreakCountPerTick <= 1 && placeBlockCountPerTick <= 2);
+ }
+ // Leaves end - player operation limiter
}
diff --git a/net/minecraft/server/players/GameProfileCache.java b/net/minecraft/server/players/GameProfileCache.java
index 144a2644c15f276f02bb3be859dc5d05a677ac55..c6a89e8936cffa49b3de153ed3c40e3cc9b8ae61 100644
--- a/net/minecraft/server/players/GameProfileCache.java
+++ b/net/minecraft/server/players/GameProfileCache.java
@@ -125,6 +125,12 @@ public class GameProfileCache {
// Paper end
public Optional<GameProfile> get(String name) {
+ // Leaves start - fix bot
+ org.leavesmc.leaves.bot.ServerBot bot = org.leavesmc.leaves.bot.BotList.INSTANCE.getBotByName(name);
+ if (bot != null) {
+ return Optional.of(bot.getGameProfile());
+ }
+ // Leaves end - fix bot
String string = name.toLowerCase(Locale.ROOT);
boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
GameProfileCache.GameProfileInfo gameProfileInfo = this.profilesByName.get(string);
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 8e2775e873c92beed6a0e4e8ce1304ab8ca6e8d1..580f114fd99b017403c61e994d0c947d00e5115d 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -425,6 +425,19 @@ public abstract class PlayerList {
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player);
+ // Leaves start - bot support
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
+ if (bot != null) {
+ this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, true);
+ }
+ this.server.getBotList().bots.forEach(bot1 -> {
+ bot1.sendPlayerInfo(player);
+ bot1.sendFakeDataIfNeed(player, true);
+ }); // Leaves - render bot
+ }
+ // Leaves end - bot support
+
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -922,6 +935,12 @@ public abstract class PlayerList {
}
// Paper end - Add PlayerPostRespawnEvent
+ // Leaves start - bot support
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(serverPlayer, true)); // Leaves - render bot
+ }
+ // Leaves end - bot support
+
// CraftBukkit end
return serverPlayer;
@@ -1026,11 +1045,16 @@ public abstract class PlayerList {
public String[] getPlayerNamesArray() {
List<ServerPlayer> players = new java.util.ArrayList<>(this.players); // Folia - region threading
- String[] strings = new String[this.players.size()];
+ String[] strings = new String[this.players.size() + this.server.getBotList().bots.size()]; // Leaves - fakeplayer support
for (int i = 0; i < players.size(); i++) { // Folia - region threading
strings[i] = players.get(i).getGameProfile().getName(); // Folia - region threading
}
+ // Leaves start - fakeplayer support
+ for (int i = this.players.size(); i < strings.length; ++i) {
+ strings[i] = this.server.getBotList().bots.get(i - this.players.size()).getGameProfile().getName();
+ }
+ // Leaves end - fakeplayer support
return strings;
}
@@ -1141,7 +1165,14 @@ public abstract class PlayerList {
@Nullable
public ServerPlayer getPlayerByName(String username) {
- return this.playersByName.get(username.toLowerCase(java.util.Locale.ROOT)); // Spigot
+ // Leaves start - fakeplayer support
+ username = username.toLowerCase(java.util.Locale.ROOT);
+ ServerPlayer player = this.playersByName.get(username);
+ if (player == null) {
+ player = this.server.getBotList().getBotByName(username);
+ }
+ return player; // Spigot
+ // Leaves end - fakeplayer support
}
public void broadcast(@Nullable Player except, double x, double y, double z, double radius, ResourceKey<Level> dimension, Packet<?> packet) {
@@ -1482,7 +1513,13 @@ public abstract class PlayerList {
@Nullable
public ServerPlayer getPlayer(UUID playerUUID) {
- return this.playersByUUID.get(playerUUID);
+ // Leaves start - fakeplayer support
+ ServerPlayer player = this.playersByUUID.get(playerUUID);
+ if (player == null) {
+ player = this.server.getBotList().getBot(playerUUID);
+ }
+ return player;
+ // Leaves start - fakeplayer support
}
public boolean canBypassPlayerLimit(GameProfile profile) {
diff --git a/net/minecraft/server/waypoints/ServerWaypointManager.java b/net/minecraft/server/waypoints/ServerWaypointManager.java
index 52fd730998535ea071bfc99b7cc2c254b9b656d7..0abf6f0265fcb916f2c2c76fb1313bd13444f4ad 100644
--- a/net/minecraft/server/waypoints/ServerWaypointManager.java
+++ b/net/minecraft/server/waypoints/ServerWaypointManager.java
@@ -24,6 +24,11 @@ public class ServerWaypointManager implements WaypointManager<WaypointTransmitte
public void trackWaypoint(WaypointTransmitter waypoint) {
// Lophine start - unsafe waypoint bar
if (!fun.bm.lophine.config.modules.experiment.CommandConfig.waypoint) return;
+ // Leaves start - fakeplayer
+ if (waypoint instanceof org.leavesmc.leaves.bot.ServerBot bot && !bot.getConfigValue(org.leavesmc.leaves.bot.agent.Configs.ENABLE_LOCATOR_BAR)) {
+ return;
+ }
+ // Leaves end - fakeplayer
this.waypoints.add(waypoint);
for (ServerPlayer serverPlayer : this.players) {
@@ -59,6 +64,11 @@ public class ServerWaypointManager implements WaypointManager<WaypointTransmitte
// Folia - region threading
// Lophine start - unsafe waypoint bar
if (!fun.bm.lophine.config.modules.experiment.CommandConfig.waypoint) return;
+ // Leaves start - fakeplayer
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ return;
+ }
+ // Leaves end - fakeplayer
this.players.add(player);
for (WaypointTransmitter waypointTransmitter : this.waypoints) {
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 1258591aae1b926ee8085b1984d553b8d3a1df7e..365cb2aed3d0f428ba33d4debdf3c3a3c494882d 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -1225,7 +1225,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
BlockPos onPosLegacy = this.getOnPosLegacy();
BlockState blockState = this.level().getBlockState(onPosLegacy);
- if (this.isLocalInstanceAuthoritative()) {
+ if (this.isLocalInstanceAuthoritative() || this instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - ServerBot needs check fall damage
this.checkFallDamage(vec3.y, this.onGround(), blockState, onPosLegacy);
}
@@ -1539,7 +1539,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
// Paper start - optimise collisions
- private Vec3 collide(Vec3 movement) {
+ public Vec3 collide(Vec3 movement) { // Leaves - private -> public
final boolean xZero = movement.x == 0.0;
final boolean yZero = movement.y == 0.0;
final boolean zZero = movement.z == 0.0;
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index f4f4f886b6558d39d292a45665953f497f84be53..12466e0294123a5922ee7694984d4d277a390ddd 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3212,7 +3212,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
private void travelRidden(Player player, Vec3 travelVector) {
Vec3 riddenInput = this.getRiddenInput(player, travelVector);
this.tickRidden(player, riddenInput);
- if (this.canSimulateMovement()) {
+ if (this.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - Fakeplayer
this.setSpeed(this.getRiddenSpeed(player));
this.travel(riddenInput);
} else {
@@ -4062,7 +4062,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
// Paper start - lag compensate eating
// we add 1 to the expected time to avoid lag compensating when we should not
final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L));
- if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide && !usingItem.useOnRelease()) {
+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !(this instanceof org.leavesmc.leaves.bot.ServerBot) && !this.level().isClientSide && !usingItem.useOnRelease()) { // Leaves - Fakeplayer skip this check
this.useItemRemaining = 0;
// Paper end - lag compensate eating
this.completeUsingItem();
@@ -4239,6 +4239,23 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
this.stopUsingItem();
}
+ // Leaves start - Fakeplayer
+ public boolean releaseUsingItemWithResult() {
+ ItemStack itemInHand = this.getItemInHand(this.getUsedItemHand());
+ boolean result = false;
+ if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInHand, this.useItem)) {
+ this.useItem = itemInHand;
+ result = this.useItem.releaseUsingWithResult(this.level(), this, this.getUseItemRemainingTicks());
+ if (this.useItem.useOnRelease()) {
+ this.updatingUsingItem();
+ }
+ }
+
+ this.stopUsingItem();
+ return result;
+ }
+ // Leaves end - Fakeplayer
+
public void stopUsingItem() {
if (!this.level().isClientSide) {
boolean isUsingItem = this.isUsingItem();
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 6c933c27ce155eb516a9ede96fb2c3bd19251bfa..6e0784af90aab5c25100613f97d4492fa7d1b277 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -205,7 +205,7 @@ public abstract class Player extends LivingEntity {
private int lastLevelUpTime;
public GameProfile gameProfile;
private boolean reducedDebugInfo;
- private ItemStack lastItemInMainHand = ItemStack.EMPTY;
+ protected ItemStack lastItemInMainHand = ItemStack.EMPTY;
private final ItemCooldowns cooldowns = this.createItemCooldowns();
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
@Nullable
@@ -412,6 +412,12 @@ public abstract class Player extends LivingEntity {
}
}
+ // Leaves start - fakeplayer
+ protected void livingEntityTick() {
+ super.tick();
+ }
+ // Leaves end - fakeplayer
+
@Override
protected float getMaxHeadRotationRelativeToBody() {
return this.isBlocking() ? 15.0F : super.getMaxHeadRotationRelativeToBody();
@@ -714,7 +720,7 @@ public abstract class Player extends LivingEntity {
}
}
- private void touch(Entity entity) {
+ public void touch(Entity entity) { // Leaves - private -> public
entity.playerTouch(this);
}
@@ -1339,7 +1345,7 @@ public abstract class Player extends LivingEntity {
this.sweepAttack();
}
- if (target instanceof ServerPlayer && target.hurtMarked) {
+ if ((target instanceof ServerPlayer && !(target instanceof org.leavesmc.leaves.bot.ServerBot)) && target.hurtMarked) { // Leaves - bot knockback
// CraftBukkit start - Add Velocity Event
boolean cancelled = false;
org.bukkit.entity.Player player = (org.bukkit.entity.Player) target.getBukkitEntity();
diff --git a/net/minecraft/world/entity/projectile/FishingHook.java b/net/minecraft/world/entity/projectile/FishingHook.java
index 7760ab1fe365b4bf1ab6c2ff953e8659a28008a8..76f6b0932633bc5670a1cdc76ff78b3bc725401d 100644
--- a/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/net/minecraft/world/entity/projectile/FishingHook.java
@@ -58,7 +58,7 @@ public class FishingHook extends Projectile {
public static final EntityDataAccessor<Integer> DATA_HOOKED_ENTITY = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> DATA_BITING = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.BOOLEAN);
private int life;
- private int nibble;
+ public int nibble; // Leaves - private -> public
public int timeUntilLured;
public int timeUntilHooked;
public float fishAngle;
diff --git a/net/minecraft/world/entity/vehicle/AbstractBoat.java b/net/minecraft/world/entity/vehicle/AbstractBoat.java
index 91ac54fb0ae9a06945476cbd1caa20be32c4a9fe..be380db0cb2f243b4a3cf8bd1b06d38debc5f6fd 100644
--- a/net/minecraft/world/entity/vehicle/AbstractBoat.java
+++ b/net/minecraft/world/entity/vehicle/AbstractBoat.java
@@ -271,6 +271,11 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
}
this.move(MoverType.SELF, this.getDeltaMovement());
+ } else if (this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves start - Fakeplayer
+ this.floatBoat();
+ this.controlBoat();
+ this.move(MoverType.SELF, this.getDeltaMovement());
+ // Leaves end - Fakeplayer
} else {
this.setDeltaMovement(Vec3.ZERO);
}
@@ -383,6 +388,13 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
}
}
+ // Leaves start - Fakeplayer
+ @Override
+ public boolean canSimulateMovement() {
+ return super.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot;
+ }
+ // Leaves end - Fakeplayer
+
@Nullable
protected SoundEvent getPaddleSound() {
return switch (this.getStatus()) {
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
index bdc0ca1f625dc264bef6e5722ec66121ba48625a..525610be29d5077a3199287347b1b71cf9fd8abf 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -407,6 +407,7 @@ public abstract class AbstractContainerMenu {
private void doClick(int slotId, int button, ClickType clickType, Player player) {
Inventory inventory = player.getInventory();
+ if (!doClickCheck(slotId, button, clickType, player)) return; // Leaves - doClick check
if (clickType == ClickType.QUICK_CRAFT) {
int i = this.quickcraftStatus;
this.quickcraftStatus = getQuickcraftHeader(button);
@@ -685,6 +686,22 @@ public abstract class AbstractContainerMenu {
}
}
+ // Leaves start - doClick check
+ private boolean doClickCheck(int slotIndex, int button, ClickType actionType, Player player) {
+ if (slotIndex < 0) {
+ return true;
+ }
+
+ Slot slot = getSlot(slotIndex);
+ ItemStack itemStack = slot.getItem();
+ net.minecraft.world.item.component.CustomData customData = itemStack.get(net.minecraft.core.component.DataComponents.CUSTOM_DATA);
+ if (customData != null && customData.contains("Leaves.Gui.Placeholder")) {
+ return !customData.copyTag().getBoolean("Leaves.Gui.Placeholder").orElse(false);
+ }
+ return true;
+ }
+ // Leaves end - doClick check
+
private boolean tryItemClickBehaviourOverride(Player player, ClickAction action, Slot slot, ItemStack clickedItem, ItemStack carriedItem) {
FeatureFlagSet featureFlagSet = player.level().enabledFeatures();
return carriedItem.isItemEnabled(featureFlagSet) && carriedItem.overrideStackedOnOther(slot, action, player)
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index a27e1d53abc2d8b8912226add33510067e10ed52..be0a267e5564a30c16f408cb311a448f354d60b4 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -450,7 +450,7 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(serverLevel, player, hand, blocks.getFirst(), clickedPos);
}
- if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild()) && (!(player instanceof org.leavesmc.leaves.bot.ServerBot))) { // Leaves - Fakeplayer skip this check
interactionResult = InteractionResult.FAIL; // cancel placement
// PAIL: Remove this when MC-99075 fixed
player.containerMenu.forceHeldSlot(hand);
@@ -946,6 +946,20 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
}
}
+ // Leaves start - Fakeplayer
+ public boolean releaseUsingWithResult(Level level, LivingEntity livingEntity, int timeLeft) {
+ ItemStack itemStack = this.copy();
+ if (this.getItem().releaseUsing(this, level, livingEntity, timeLeft)) {
+ ItemStack itemStack1 = this.applyAfterUseComponentSideEffects(livingEntity, itemStack);
+ if (itemStack1 != this) {
+ livingEntity.setItemInHand(livingEntity.getUsedItemHand(), itemStack1);
+ }
+ return true;
+ }
+ return false;
+ }
+ // Leaves end - Fakeplayer
+
public boolean useOnRelease() {
return this.getItem().useOnRelease(this);
}
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index bff9574bece5f5581d9cc51a3f2b68b5c13c25c9..4bfe53c15c9b2effd24dddc48565efc9c102e56a 100644
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -145,7 +145,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
break;
}
- if (!(entity instanceof ServerPlayer)) {
+ if (!(entity instanceof ServerPlayer) || (entity instanceof org.leavesmc.leaves.bot.ServerBot)) { // Leaves - bot slime block
Vec3 deltaMovement = entity.getDeltaMovement();
double d1 = deltaMovement.x;
double d2 = deltaMovement.y;
diff --git a/net/minecraft/world/level/levelgen/PhantomSpawner.java b/net/minecraft/world/level/levelgen/PhantomSpawner.java
index ecfd6a04ea1bac75bbb7e88554b73fc67e7f7358..2c9a55eecf44eaa62ef57597a94d657ad0b9cfc4 100644
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -49,6 +49,11 @@ public class PhantomSpawner implements CustomSpawner {
ServerStatsCounter stats = serverPlayer.getStats();
int i = Mth.clamp(stats.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
int i1 = 24000;
+ // Leaves start - fakeplayer spawn
+ if (serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot bot && bot.getConfigValue(org.leavesmc.leaves.bot.agent.Configs.SPAWN_PHANTOM)) {
+ i1 = Math.max(bot.notSleepTicks, 1);
+ }
+ // Leaves end - fakeplayer spawn
if (randomSource.nextInt(i) >= 72000) {
BlockPos blockPos1 = blockPos.above(20 + randomSource.nextInt(15))
.east(-10 + randomSource.nextInt(21))
diff --git a/net/minecraft/world/level/storage/LevelResource.java b/net/minecraft/world/level/storage/LevelResource.java
index bef794c3f58c41d910aa0bcc63fbdeea7225fddf..a601da588e6973cc5b87d3e3eeba49b53f6d9a6d 100644
--- a/net/minecraft/world/level/storage/LevelResource.java
+++ b/net/minecraft/world/level/storage/LevelResource.java
@@ -15,7 +15,7 @@ public class LevelResource {
public static final LevelResource ROOT = new LevelResource(".");
private final String id;
- private LevelResource(String id) {
+ public LevelResource(String id) { // Leaves - private -> public
this.id = id;
}
diff --git a/net/minecraft/world/level/storage/PlayerDataStorage.java b/net/minecraft/world/level/storage/PlayerDataStorage.java
index fe44d8d17d2622b3d6021c11579af85ef96737bb..0aae211dc2048f8cd14213c2a868394d1ed16070 100644
--- a/net/minecraft/world/level/storage/PlayerDataStorage.java
+++ b/net/minecraft/world/level/storage/PlayerDataStorage.java
@@ -19,7 +19,7 @@ import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.entity.player.Player;
import org.slf4j.Logger;
-public class PlayerDataStorage {
+public class PlayerDataStorage implements org.leavesmc.leaves.bot.IPlayerDataStorage {
private static final Logger LOGGER = LogUtils.getLogger();
private final File playerDir;
protected final DataFixer fixerUpper;
@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 16 Nov 2025 17:47:48 +0800
Subject: [PATCH] LeavesHooks
diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java
index d097b889499a8e410839e8f69d99dc9adfa2488b..b97d65b81ec4b86e00b7c06341b40dc5c02b9044 100644
--- a/ca/spottedleaf/moonrise/paper/PaperHooks.java
+++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java
@@ -29,7 +29,7 @@ import net.minecraft.world.phys.AABB;
import java.util.List;
import java.util.function.Predicate;
-public final class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
+public class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger();
@@ -8,14 +8,14 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/3e96b237749a960f2
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index b3e897a4afee742b5055d652ad7047a660d8ea04..33471f3d0e2cbd54eaf095c19555f8fdaeb55878 100644
index 769dc39e11881d5f81a2405850cbcbd0842c5995..9fc97e8b01f66ada6af1fe76f4e27c9bb1a5dcfc 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -729,6 +729,7 @@ public class ServerExplosion implements Explosion {
@@ -708,6 +708,7 @@ public class ServerExplosion implements Explosion {
public boolean shouldAffectBlocklikeEntities() {
boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
boolean flag = this.source == null || this.source.getType() != EntityType.BREEZE_WIND_CHARGE && this.source.getType() != EntityType.WIND_CHARGE;
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldExplosionDamageCalculator) flag = flag && (this.source == null || !this.source.isInWater()); // Leaves - Old MC TNT wet explosion no item damage
return _boolean ? flag : this.blockInteraction.shouldAffectBlocklikeEntities() && flag;
boolean mobGriefingEnabled = this.level.getGameRules().get(GameRules.MOB_GRIEFING);
boolean isNotWindCharge = this.source == null || !this.source.is(EntityType.BREEZE_WIND_CHARGE) && !this.source.is(EntityType.WIND_CHARGE);
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldExplosionDamageCalculator) isNotWindCharge = isNotWindCharge && (this.source == null || !this.source.isInWater()); // Leaves - Old MC TNT wet explosion no item damage
return mobGriefingEnabled ? isNotWindCharge : this.blockInteraction.shouldAffectBlocklikeEntities() && isNotWindCharge;
}
@@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Fri, 3 Oct 2025 19:43:36 +0800
Subject: [PATCH] Modify merge ItemEntity logic
Add followTickSequenceMerge to modify merge items, due to Paper's modification of the merge radius, when the merge radius is large and stacks containing many items get stuck in an unexpected position, individual items may never reach their destination. This configuration option is added to fix this behavior.
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index e5e8c752129a6ebb0dd1315c9b8ec459be11ef07..dfd202a74ec7f2cdb9cdc208a6428090a110f811 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -295,7 +295,7 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
ItemStack item = this.getItem();
ItemStack item1 = itemEntity.getItem();
if (Objects.equals(this.target, itemEntity.target) && areMergable(item, item1)) {
- if (item1.getCount() < item.getCount()) {
+ if (fun.bm.lophine.config.modules.misc.ItemEntityConfig.followTickSequenceMerge || item1.getCount() < item.getCount()) { // Lophine - add follow Tick Sequence Merge, see Paper#13073
merge(this, item, itemEntity, item1);
} else {
merge(itemEntity, item1, this, item);
@@ -8,7 +8,7 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/79d9ef74c2684eb49
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/item/ShearsItem.java b/net/minecraft/world/item/ShearsItem.java
index 8cf3e51e12f9cf98836657e722edb23943f9e866..5fd5e9fd4e1a79dd1a9d62a5cf0c308805979420 100644
index 837f8c56bf5d68dd8bfbeca8ae1b66be8316ddea..1098695e646c20f47bc4739034fcb69b96909667 100644
--- a/net/minecraft/world/item/ShearsItem.java
+++ b/net/minecraft/world/item/ShearsItem.java
@@ -80,7 +80,10 @@ public class ShearsItem extends Item {
@@ -17,7 +17,7 @@ index 8cf3e51e12f9cf98836657e722edb23943f9e866..5fd5e9fd4e1a79dd1a9d62a5cf0c3088
} else {
- return super.useOn(context);
+ // Leaves start - shears wrench
+ InteractionResult result = org.leavesmc.leaves.util.ShearsWrenchUtil.tryApplyRotate(context, blockState);
+ InteractionResult result = org.leavesmc.leaves.util.ShearsWrenchUtil.tryApplyRotate(context, state);
+ return result == null ? super.useOn(context) : result;
+ // Leaves end - shears wrench
}
@@ -1,5 +1,5 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 3 Feb 2025 16:51:01 +0800
Subject: [PATCH] Leaves: Syncmatica Protocol
@@ -9,10 +9,10 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index e17f9629369f8653b484b4cc71de4874b5faa4d6..9be4bc9e78c22c12ba594b16dac6901023f0fd47 100644
index e15be199d690954d99d710de4046e721a943b3a9..0eae303f8959345571a906906ef60c6a28bba348 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -330,9 +330,12 @@ public class ServerGamePacketListenerImpl
@@ -346,9 +346,12 @@ public class ServerGamePacketListenerImpl
this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(player.getUUID(), server::enforceSecureProfile);
this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat
this.tickEndEvent = new io.papermc.paper.event.packet.ClientTickEndEvent(player.getBukkitEntity()); // Paper - add client tick end event
@@ -1,5 +1,5 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 3 Feb 2025 13:03:42 +0800
Subject: [PATCH] Leaves: BBOR Protocol
@@ -8,12 +8,12 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 29788fedd54b8411c9c8872b4d83b037874fb5f0..24af6821694768058dc0146220877ab70066b5f9 100644
index da9706f866aabee6939cacbfbcc9def01fde0326..3708f9ffc46a5b1c038c0e7b2ce84802e2b22397 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -754,6 +754,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
@@ -772,6 +772,11 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
public void setLoaded(boolean loaded) {
public void setLoaded(final boolean loaded) {
this.loaded = loaded;
+ // Leaves start - bbor
+ if (loaded) {
@@ -1,5 +1,5 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Fri, 7 Feb 2025 14:23:43 +0800
Subject: [PATCH] Leaves: Xaero Map Protocol
@@ -8,13 +8,13 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 908ec29a6e285122d1a8a43dc547b74af2697442..1bf1731e43278b71423fee5d92401c48d6dabaca 100644
index 6148e7e5978a9a5b7d7f90b58b86b0166fd16c9d..16d01fcb97aa3dbd7554bd64b3608c6e80ce3dbd 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -1247,6 +1247,7 @@ public abstract class PlayerList {
player.connection.send(new ClientboundInitializeBorderPacket(worldBorder));
player.connection.send(new ClientboundSetTimePacket(level.getGameTime(), level.getDayTime(), level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)));
player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle()));
@@ -1107,6 +1107,7 @@ public abstract class PlayerList {
//player.connection.send(new ClientboundSetChunkCacheRadiusPacket(io.papermc.paper.FeatureHooks.getViewDistance(level))); // Paper - rewrite chunk system
//player.connection.send(new ClientboundSetSimulationDistancePacket(io.papermc.paper.FeatureHooks.getSimulationDistance(level))); // Paper - rewrite chunk system
// Paper end - view distances
+ org.leavesmc.leaves.protocol.XaeroMapProtocol.onSendWorldInfo(player); // Leaves - xaero map protocol
if (level.isRaining()) {
// CraftBukkit start - handle player weather
@@ -1,5 +1,5 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 27 Mar 2025 13:04:35 +0800
Subject: [PATCH] Leaves: Support REI protocol
@@ -8,16 +8,16 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/item/crafting/SmithingTransformRecipe.java b/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
index 9bc0a9c3577d63a0ad5489bfd4c07d5006245c5f..bb2e891539b7eb49dc7925630695149aa531f672 100644
index 33f9870a4f966a887023b1debd4ab9ef9d24378f..89983e7da244434a5346b23b49c748349cd79e34 100644
--- a/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
+++ b/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
@@ -83,6 +83,12 @@ public class SmithingTransformRecipe implements SmithingRecipe {
@@ -115,6 +115,12 @@ public class SmithingTransformRecipe extends SimpleSmithingRecipe {
);
}
+ // Leaves start - REI
+ public SlotDisplay getResult() {
+ return this.result.display();
+ return new SlotDisplay.ItemStackSlotDisplay(this.result);
+ }
+ // Leaves end - REI
+
@@ -25,10 +25,10 @@ index 9bc0a9c3577d63a0ad5489bfd4c07d5006245c5f..bb2e891539b7eb49dc7925630695149a
@Override
public org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id) {
diff --git a/net/minecraft/world/item/crafting/SmithingTrimRecipe.java b/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
index c324896afc2ee28ebb4d426ce4a469ee847ce24d..d5b26ff7be916e07e1162536cb2ddf5674c82f46 100644
index f9fa7d0eaf9f32959a4bd12b82e5a49ea808a44c..2f3241563ad7e5ed5663b913671d2af056df97bb 100644
--- a/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
+++ b/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
@@ -85,6 +85,12 @@ public class SmithingTrimRecipe implements SmithingRecipe {
@@ -109,6 +109,12 @@ public class SmithingTrimRecipe extends SimpleSmithingRecipe {
return Optional.of(this.addition);
}
@@ -40,4 +40,4 @@ index c324896afc2ee28ebb4d426ce4a469ee847ce24d..d5b26ff7be916e07e1162536cb2ddf56
+
@Override
public RecipeSerializer<SmithingTrimRecipe> getSerializer() {
return RecipeSerializer.SMITHING_TRIM;
return SERIALIZER;
@@ -1,6 +1,6 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
Date: Mon, 3 Feb 2025 13:33:19 +0800
From: Bacteriawa <A3167717663@hotmail.com>
Date: Fri, 13 Feb 2026 16:17:36 +0800
Subject: [PATCH] Leaves: Jade Protocol
This patch is Powered by Jade(https://github.com/Snownee/Jade)
@@ -8,11 +8,24 @@ Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 0eae303f8959345571a906906ef60c6a28bba348..1af966cadec3dd51aae842824e432e20b700d9c9 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3902,7 +3902,7 @@ public class ServerGamePacketListenerImpl
}
@Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add PlayerLoadedWorldEvent
- private void markClientLoaded() {
+ public void markClientLoaded() { // Lophine - private -> public
// Paper start - Add PlayerLoadedWorldEvent
this.markClientLoaded(false);
}
diff --git a/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
index c1798db2972c8f2a343cf6e16fd9354ff212d906..a8d617b16ab2b2c0cdb289a0aa05fa171940cd7e 100644
index 03ec05a860781f85e58055d6f58893963781bd97..c15f0a3d419fea50d4349fa864e83bf7fee78b9f 100644
--- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java
+++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
@@ -63,7 +63,7 @@ public class Armadillo extends Animal {
@@ -72,7 +72,7 @@ public class Armadillo extends Animal {
public final AnimationState rollOutAnimationState = new AnimationState();
public final AnimationState rollUpAnimationState = new AnimationState();
public final AnimationState peekAnimationState = new AnimationState();
@@ -20,12 +33,12 @@ index c1798db2972c8f2a343cf6e16fd9354ff212d906..a8d617b16ab2b2c0cdb289a0aa05fa17
+ public int scuteTime; // Leaves - private -> public
private boolean peekReceivedClient = false;
public Armadillo(EntityType<? extends Animal> entityType, Level level) {
public Armadillo(final EntityType<? extends Animal> type, final Level level) {
diff --git a/net/minecraft/world/entity/animal/frog/Tadpole.java b/net/minecraft/world/entity/animal/frog/Tadpole.java
index 17f58246849ed407821a987b200cc765eb7943f9..ac27df3ba0ce9bbdf2f32ea87171fbb9407008d6 100644
index 3d4bfeae2fddb9ace26e7dea8870704d8309862b..d2862d2e6f599265bc319000bba05609e0bea2c3 100644
--- a/net/minecraft/world/entity/animal/frog/Tadpole.java
+++ b/net/minecraft/world/entity/animal/frog/Tadpole.java
@@ -254,7 +254,7 @@ public class Tadpole extends AbstractFish {
@@ -255,7 +255,7 @@ public class Tadpole extends AbstractFish {
}
}
@@ -35,12 +48,12 @@ index 17f58246849ed407821a987b200cc765eb7943f9..ac27df3ba0ce9bbdf2f32ea87171fbb9
}
diff --git a/net/minecraft/world/level/storage/loot/LootPool.java b/net/minecraft/world/level/storage/loot/LootPool.java
index 6901e629d941e22e64d83eed4e8cfee3165a96a1..fdc26c8d8c82c20534c57af2a0281b99998cc9f6 100644
index f08a25b76e689c2242e8ef8226c3d8c2dcec1c70..6e76e472bd1e7242f6cd7986c23ebc38d16fd46a 100644
--- a/net/minecraft/world/level/storage/loot/LootPool.java
+++ b/net/minecraft/world/level/storage/loot/LootPool.java
@@ -37,7 +37,7 @@ public class LootPool {
@@ -36,7 +36,7 @@ public class LootPool implements Validatable {
)
.apply(instance, LootPool::new)
.apply(i, LootPool::new)
);
- private final List<LootPoolEntryContainer> entries;
+ public final List<LootPoolEntryContainer> entries; // Leaves - private -> public
@@ -48,23 +61,23 @@ index 6901e629d941e22e64d83eed4e8cfee3165a96a1..fdc26c8d8c82c20534c57af2a0281b99
private final Predicate<LootContext> compositeCondition;
private final List<LootItemFunction> functions;
diff --git a/net/minecraft/world/level/storage/loot/LootTable.java b/net/minecraft/world/level/storage/loot/LootTable.java
index 8612cdf7161f8ddff60a6478cc901318b8f958ba..07a962d647baa99b0e1bf3898a07cc914e91397e 100644
index 14fc07badbd14a5a4c8e8c7d237d08a4eb6a6f12..0aaf2240a0f79b5c4aaa9c22dca7b2f0953dac49 100644
--- a/net/minecraft/world/level/storage/loot/LootTable.java
+++ b/net/minecraft/world/level/storage/loot/LootTable.java
@@ -50,7 +50,7 @@ public class LootTable {
@@ -49,7 +49,7 @@ public class LootTable implements Validatable {
public static final LootTable EMPTY = new LootTable(LootContextParamSets.EMPTY, Optional.empty(), List.of(), List.of());
private final ContextKeySet paramSet;
private final Optional<ResourceLocation> randomSequence;
private final Optional<Identifier> randomSequence;
- private final List<LootPool> pools;
+ public final List<LootPool> pools; // Leaves - private -> public
private final List<LootItemFunction> functions;
private final BiFunction<ItemStack, LootContext, ItemStack> compositeFunction;
public org.bukkit.craftbukkit.CraftLootTable craftLootTable; // CraftBukkit
diff --git a/net/minecraft/world/level/storage/loot/entries/CompositeEntryBase.java b/net/minecraft/world/level/storage/loot/entries/CompositeEntryBase.java
index eeaa49e9f70a18b5d39493aeff73f31b05ac2faa..8cd0403d7873c4c37caef75935b06b056c3d951d 100644
index 53e4375a4af610e54309f2978e59985e6ada15f5..615b533caecef09d967c615ae39ef29c80784575 100644
--- a/net/minecraft/world/level/storage/loot/entries/CompositeEntryBase.java
+++ b/net/minecraft/world/level/storage/loot/entries/CompositeEntryBase.java
@@ -16,7 +16,7 @@ public abstract class CompositeEntryBase extends LootPoolEntryContainer {
@@ -17,7 +17,7 @@ public abstract class CompositeEntryBase extends LootPoolEntryContainer {
return "Empty children list";
}
};
@@ -72,22 +85,22 @@ index eeaa49e9f70a18b5d39493aeff73f31b05ac2faa..8cd0403d7873c4c37caef75935b06b05
+ public final List<LootPoolEntryContainer> children; // Leaves - private -> public
private final ComposableEntryContainer composedChildren;
protected CompositeEntryBase(List<LootPoolEntryContainer> children, List<LootItemCondition> conditions) {
protected CompositeEntryBase(final List<LootPoolEntryContainer> children, final List<LootItemCondition> conditions) {
diff --git a/net/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer.java b/net/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer.java
index 65e27bce9e59ef97bc8b914d646fba924d0f0877..a49bdcdf37b351436e0ba6d7865f10827c4e6ab4 100644
index 83c514c213251dd5470627d0299b5858b850784d..d231f706388e6967d2e29f806a9f52e8f7f5ba61 100644
--- a/net/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer.java
+++ b/net/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer.java
@@ -14,7 +14,7 @@ import net.minecraft.world.level.storage.loot.predicates.ConditionUserBuilder;
@@ -15,7 +15,7 @@ import net.minecraft.world.level.storage.loot.predicates.ConditionUserBuilder;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
public abstract class LootPoolEntryContainer implements ComposableEntryContainer {
public abstract class LootPoolEntryContainer implements ComposableEntryContainer, Validatable {
- protected final List<LootItemCondition> conditions;
+ public final List<LootItemCondition> conditions; // Leaves - private -> public
private final Predicate<LootContext> compositeCondition;
protected LootPoolEntryContainer(List<LootItemCondition> conditions) {
protected LootPoolEntryContainer(final List<LootItemCondition> conditions) {
diff --git a/net/minecraft/world/level/storage/loot/entries/NestedLootTable.java b/net/minecraft/world/level/storage/loot/entries/NestedLootTable.java
index 141026601cd9a4561426b85fd1f8e7dc0544fbd7..a5d7ebb93c147bf0f806ac3c9b2dc4b878573944 100644
index 20520b7071f19af2882a797ee40019cddd76e378..11c4333ab28cffcfb97bcd289930b33c4baae993 100644
--- a/net/minecraft/world/level/storage/loot/entries/NestedLootTable.java
+++ b/net/minecraft/world/level/storage/loot/entries/NestedLootTable.java
@@ -29,7 +29,7 @@ public class NestedLootTable extends LootPoolSingletonContainer {
@@ -98,12 +111,12 @@ index 141026601cd9a4561426b85fd1f8e7dc0544fbd7..a5d7ebb93c147bf0f806ac3c9b2dc4b8
+ public final Either<ResourceKey<LootTable>, LootTable> contents; // Leaves - private -> public
private NestedLootTable(
Either<ResourceKey<LootTable>, LootTable> contents, int weight, int quality, List<LootItemCondition> conditions, List<LootItemFunction> functions
final Either<ResourceKey<LootTable>, LootTable> contents,
diff --git a/net/minecraft/world/level/storage/loot/predicates/CompositeLootItemCondition.java b/net/minecraft/world/level/storage/loot/predicates/CompositeLootItemCondition.java
index bae72197acc929c7ed3e964f156115d728eb2176..8f3094f42f3366a1313d70c0b27fbe5632b2082a 100644
index cb821605781050282fd0a28e3d096fa18de833b8..99624ca2e895884a5e92a965af2064803c0d3b14 100644
--- a/net/minecraft/world/level/storage/loot/predicates/CompositeLootItemCondition.java
+++ b/net/minecraft/world/level/storage/loot/predicates/CompositeLootItemCondition.java
@@ -12,7 +12,7 @@ import net.minecraft.world.level.storage.loot.LootContext;
@@ -12,7 +12,7 @@ import net.minecraft.world.level.storage.loot.Validatable;
import net.minecraft.world.level.storage.loot.ValidationContext;
public abstract class CompositeLootItemCondition implements LootItemCondition {
@@ -111,4 +124,4 @@ index bae72197acc929c7ed3e964f156115d728eb2176..8f3094f42f3366a1313d70c0b27fbe56
+ public final List<LootItemCondition> terms; // Leaves - private -> public
private final Predicate<LootContext> composedPredicate;
protected CompositeLootItemCondition(List<LootItemCondition> terms, Predicate<LootContext> composedPredicate) {
protected CompositeLootItemCondition(final List<LootItemCondition> terms, final Predicate<LootContext> composedPredicate) {
@@ -0,0 +1,98 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 3 Feb 2025 13:51:26 +0800
Subject: [PATCH] Leaves: Alternative block placement Protocol
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: MIT
This patch is Powered by
carpet-extra(https://github.com/gnembon/carpet-extra)
MasaGadget(https://github.com/plusls/MasaGadget)
litematica(https://github.com/maruohon/litematica)
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 1af966cadec3dd51aae842824e432e20b700d9c9..83c9418ea45b8d7f639c6bf5e134bad90d9ac039 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2183,7 +2183,7 @@ public class ServerGamePacketListenerImpl
if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.player.level(), pos.getX() >> 4, pos.getZ() >> 4, 8) && this.player.isWithinBlockInteractionRange(pos, 1.0)) { // Folia - do not allow players to interact with blocks outside the current region
Vec3 distance = location.subtract(Vec3.atCenterOf(pos));
double limit = 1.0000001;
- if (Math.abs(distance.x()) < 1.0000001 && Math.abs(distance.y()) < 1.0000001 && Math.abs(distance.z()) < 1.0000001) {
+ if (fun.bm.lophine.config.modules.function.protocol.AlternativeBlockPlacementProtocolConfig.needIgnoreDistance() ||Math.abs(distance.x()) < 1.0000001 && Math.abs(distance.y()) < 1.0000001 && Math.abs(distance.z()) < 1.0000001) { // Leaves - disableDistanceCheckForUseItem
Direction direction = blockHit.getDirection();
this.player.resetLastActionTime();
int maxY = level.getMaxY();
diff --git a/net/minecraft/world/item/BlockItem.java b/net/minecraft/world/item/BlockItem.java
index 3167be4b7c2c61ef725af4a832d759ab6e061af0..2e2a8af12f249ec5bd0935fd13f5acbd0a777b5f 100644
--- a/net/minecraft/world/item/BlockItem.java
+++ b/net/minecraft/world/item/BlockItem.java
@@ -136,7 +136,7 @@ public class BlockItem extends Item {
}
protected @Nullable BlockState getPlacementState(final BlockPlaceContext context) {
- BlockState stateForPlacement = this.getBlock().getStateForPlacement(context);
+ BlockState stateForPlacement = this.getBlock().getRealStateForPlacement(context); // Leaves - alternativeBlockPlacement
return stateForPlacement != null && this.canPlace(context, stateForPlacement) ? stateForPlacement : null;
}
diff --git a/net/minecraft/world/item/StandingAndWallBlockItem.java b/net/minecraft/world/item/StandingAndWallBlockItem.java
index d5d499226d0b2c2adfae7bbb4c28c96c80411c44..cb0a4a9865df69e5504a86de6c144bc4450bd19a 100644
--- a/net/minecraft/world/item/StandingAndWallBlockItem.java
+++ b/net/minecraft/world/item/StandingAndWallBlockItem.java
@@ -26,14 +26,14 @@ public class StandingAndWallBlockItem extends BlockItem {
@Override
protected @Nullable BlockState getPlacementState(final BlockPlaceContext context) {
- BlockState wallState = this.wallBlock.getStateForPlacement(context);
+ BlockState wallState = this.wallBlock.getRealStateForPlacement(context); // Leaves - alternativeBlockPlacement
BlockState stateForPlacement = null;
LevelReader level = context.getLevel();
BlockPos pos = context.getClickedPos();
for (Direction direction : context.getNearestLookingDirections()) {
if (direction != this.attachmentDirection.getOpposite()) {
- BlockState possibleState = direction == this.attachmentDirection ? this.getBlock().getStateForPlacement(context) : wallState;
+ BlockState possibleState = direction == this.attachmentDirection ? this.getBlock().getRealStateForPlacement(context) : wallState; // Leaves - alternativeBlockPlacement
if (possibleState != null && this.canPlace(level, possibleState, pos)) {
stateForPlacement = possibleState;
break;
diff --git a/net/minecraft/world/level/block/Block.java b/net/minecraft/world/level/block/Block.java
index c5f4e0570a82dfcc2ba88023f3301f69afa41cc5..30f7e8f5e3e9440713e36ee25c90150b6b93c6ff 100644
--- a/net/minecraft/world/level/block/Block.java
+++ b/net/minecraft/world/level/block/Block.java
@@ -516,6 +516,32 @@ public class Block extends BlockBehaviour implements ItemLike {
public void stepOn(final Level level, final BlockPos pos, final BlockState onState, final Entity entity) {
}
+ // Leaves start - alternativeBlockPlacement
+ public @Nullable BlockState getRealStateForPlacement(final BlockPlaceContext context) {
+ BlockState vanillaState = this.getStateForPlacement(context);
+ switch (fun.bm.lophine.config.modules.function.protocol.AlternativeBlockPlacementProtocolConfig.alternativeBlockPlacement) {
+ case fun.bm.lophine.enums.EnumAlternativePlaceType.CARPET -> {
+ BlockState tryState = org.leavesmc.leaves.protocol.CarpetAlternativeBlockPlacement.alternativeBlockPlacement(this, context);
+ if (tryState != null) {
+ return tryState;
+ }
+ }
+ case fun.bm.lophine.enums.EnumAlternativePlaceType.CARPET_FIX -> {
+ BlockState tryState = org.leavesmc.leaves.protocol.CarpetAlternativeBlockPlacement.alternativeBlockPlacementFix(this, context);
+ if (tryState != null) {
+ return tryState;
+ }
+ }
+ case fun.bm.lophine.enums.EnumAlternativePlaceType.LITEMATICA -> {
+ if (vanillaState != null) {
+ return org.leavesmc.leaves.protocol.LitematicaEasyPlaceProtocol.applyPlacementProtocol(vanillaState, context);
+ }
+ }
+ }
+ return vanillaState;
+ }
+ // Leaves end - alternativeBlockPlacement
+
public @Nullable BlockState getStateForPlacement(final BlockPlaceContext context) {
return this.defaultBlockState();
}
@@ -0,0 +1,782 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Sat, 30 Aug 2025 17:16:32 +0800
Subject: [PATCH] Leaves: Fakeplayer
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java b/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java
index dfce5ced082de0caaff8da071fb632cd6ae787c9..d5c1862ebf6066859da74f47fa0be0256ba0f653 100644
--- a/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java
+++ b/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java
@@ -41,6 +41,7 @@ public abstract class SimpleCriterionTrigger<T extends SimpleCriterionTrigger.Si
}
protected void trigger(final ServerPlayer player, final Predicate<T> matcher) {
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) return; // Leaves - bot skip
PlayerAdvancements advancements = player.getAdvancements();
Set<CriterionTrigger.Listener<T>> allListeners = (Set) advancements.criterionData.get(this); // Paper - fix PlayerAdvancements leak
if (allListeners != null && !allListeners.isEmpty()) {
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
index efbbc1a40d203a2818eeda2a4e938b9a6117f1c3..6b85a5ad9af0c57a0d4d5b55f62b82c5ff69b0e8 100644
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -74,7 +74,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public boolean preparing = true;
// Spigot end
private volatile @Nullable PacketListener disconnectListener;
- private volatile @Nullable PacketListener packetListener;
+ protected volatile @Nullable PacketListener packetListener; // Leaves - private -> protected
private @Nullable DisconnectionDetails disconnectionDetails;
private boolean encrypted;
private final java.util.concurrent.atomic.AtomicBoolean disconnectionHandled = new java.util.concurrent.atomic.AtomicBoolean(false); // Folia - region threading - may be called concurrently during configuration stage
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 3cd1a0de188db35ac9c48996a4dbe6186b69e348..9837d8388e6fe73ef87d021c7370c2a7c236c634 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -297,6 +297,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Paper - per-level scheduledEvents
private final ServerClockManager clockManager;
+ private org.leavesmc.leaves.bot.BotList botList; // Leaves - fakeplayer
+
public static <S extends MinecraftServer> S spin(final Function<Thread, S> factory) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
AtomicReference<S> serverReference = new AtomicReference<>();
@@ -1229,6 +1231,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.safeShutdown(wait, false);
}
public void safeShutdown(final boolean wait, final boolean isRestarting) {
+ // Lophine start - Folia changes
+ safeShutdown(wait, isRestarting, false);
+ }
+
+ public void safeShutdown(final boolean wait, final boolean isRestarting, boolean force) {
+ if (!force && !this.getBotList().forceShutdown && !this.getBotList().removeAll()) { // Leaves - save or remove bot
+ this.getPlayerList().broadcastSystemMessage(Component.literal("Bot Still need to save, please wait! If you want to shuntdown without bot data saving, please use /stop force"), false);
+ return;
+ }
+ // Lophine end - Folia changes
this.isRestarting = isRestarting;
this.hasLoggedStop = true; // Paper - Debugging
if (this.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
@@ -1698,7 +1710,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
int emptyTickThreshold = this.pauseWhenEmptySeconds() * 20;
this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping
if (false && emptyTickThreshold > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy
- if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping
+ if (this.playerList.getPlayerCount() == 0 && this.botList.bots.isEmpty() && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping // Leaves - fakeplayer
this.emptyTicks++;
} else {
this.emptyTicks = 0;
@@ -1830,6 +1842,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.isSaving = true;
if (playerSaveInterval > 0) {
this.playerList.saveAll(playerSaveInterval);
+ org.leavesmc.leaves.bot.BotList.INSTANCE.saveAllResumeBots(playerSaveInterval); // Leaves - resident fakeplayer
}
if (region == null && fullSave) { // Folia - region threading - don't auto save level data
this.saveGlobalData(false);
@@ -2068,6 +2081,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
protected void tickConnection() {
this.getConnection().tick();
+ this.botList.networkTick(); // Leaves - fakeplayer
}
public void forceGameTimeSynchronization() {
@@ -3273,6 +3287,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return this.debugSubscribers;
}
+ // Leaves start - fakeplayer
+ protected void setBotList(org.leavesmc.leaves.bot.BotList botList) {
+ this.botList = botList;
+ }
+
+ public org.leavesmc.leaves.bot.BotList getBotList() {
+ return botList;
+ }
+ // Leaves end - fakeplayer
+
public record ReloadableResources(CloseableResourceManager resourceManager, ReloadableServerResources managers) implements AutoCloseable {
@Override
public void close() {
diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java
index 658db8460122db271bbc3c2c0844574b8d75f044..89448eee9f135de8b406bf5f4147b3298e33ba17 100644
--- a/net/minecraft/server/PlayerAdvancements.java
+++ b/net/minecraft/server/PlayerAdvancements.java
@@ -168,6 +168,11 @@ public class PlayerAdvancements {
}
public boolean award(final AdvancementHolder holder, final String criterion) {
+ // Leaves start - bot can't get advancement
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ return false;
+ }
+ // Leaves end - bot can't get advancement
boolean result = false;
AdvancementProgress progress = this.getOrStartProgress(holder);
boolean wasDone = progress.isDone();
diff --git a/net/minecraft/server/commands/BanIpCommands.java b/net/minecraft/server/commands/BanIpCommands.java
index 36b858bfe123edc2f1c5c7861dd0e4475ef7a5f1..e52a2ad8408d9691701dc51fa702efdb51f0acbb 100644
--- a/net/minecraft/server/commands/BanIpCommands.java
+++ b/net/minecraft/server/commands/BanIpCommands.java
@@ -40,6 +40,12 @@ public class BanIpCommands {
return banIp(source, target, reason);
} else {
ServerPlayer player = source.getServer().getPlayerList().getPlayerByName(target);
+ // Leaves start - disable ban
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ source.sendFailure(Component.literal("Permission denied"));
+ return 0;
+ }
+ // Leaves end - disable ban
if (player != null) {
return banIp(source, player.getIpAddress(), reason);
} else {
diff --git a/net/minecraft/server/commands/BanPlayerCommands.java b/net/minecraft/server/commands/BanPlayerCommands.java
index c87bc86c57fde9d92e3927bdead5cdaf2e935744..950f8ed955bc09713348936ae7aa1a8b14006c2a 100644
--- a/net/minecraft/server/commands/BanPlayerCommands.java
+++ b/net/minecraft/server/commands/BanPlayerCommands.java
@@ -38,8 +38,15 @@ public class BanPlayerCommands {
private static int banPlayers(final CommandSourceStack source, final Collection<NameAndId> players, final @Nullable Component reason) throws CommandSyntaxException {
UserBanList list = source.getServer().getPlayerList().getBans();
int count = 0;
-
+ boolean hasBot = false; // Leaves - disable kick
for (NameAndId player : players) {
+ // Leaves start - disable ban
+ if (player.isBot()) {
+ source.sendFailure(Component.literal("Permission denied"));
+ hasBot = true;
+ continue;
+ }
+ // Leaves end - disable ban
if (!list.isBanned(player)) {
UserBanListEntry entry = new UserBanListEntry(player, null, source.getTextName(), null, reason == null ? null : reason.getString());
list.add(entry);
@@ -53,7 +60,13 @@ public class BanPlayerCommands {
}
if (count == 0) {
- throw ERROR_ALREADY_BANNED.create();
+ // Leaves start - disable kick
+ if (hasBot) {
+ return count;
+ } else {
+ throw ERROR_ALREADY_BANNED.create();
+ }
+ // Leaves end - disable kick
} else {
return count;
}
diff --git a/net/minecraft/server/commands/KickCommand.java b/net/minecraft/server/commands/KickCommand.java
index 0227dd63f67537d769494e122616873c18d35350..18d49018b1330cfcaa91d9b02d0d23e4ba941809 100644
--- a/net/minecraft/server/commands/KickCommand.java
+++ b/net/minecraft/server/commands/KickCommand.java
@@ -38,9 +38,17 @@ public class KickCommand {
if (!source.getServer().isPublished()) {
throw ERROR_SINGLEPLAYER.create();
} else {
+ boolean hasBot = false; // Leaves - disable kick
int count = 0;
for (ServerPlayer player : players) {
+ // Leaves start - disable kick
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ source.sendFailure(Component.literal("Permission denied"));
+ hasBot = true;
+ continue;
+ }
+ // Leaves end - disable kick
if (!source.getServer().isSingleplayerOwner(player.nameAndId())) {
player.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause
source.sendSuccess(() -> Component.translatable("commands.kick.success", player.getDisplayName(), reason), true);
@@ -49,7 +57,13 @@ public class KickCommand {
}
if (count == 0) {
- throw ERROR_KICKING_OWNER.create();
+ // Leaves start - disable kick
+ if (hasBot) {
+ return count;
+ } else {
+ throw ERROR_KICKING_OWNER.create();
+ }
+ // Leaves end - disable kick
} else {
return count;
}
diff --git a/net/minecraft/server/commands/OpCommand.java b/net/minecraft/server/commands/OpCommand.java
index 636f56bfc0e9075b257e2eb14e858975bdedd801..20cbc0e65fea3fc2d0033259c2f35e158ea81926 100644
--- a/net/minecraft/server/commands/OpCommand.java
+++ b/net/minecraft/server/commands/OpCommand.java
@@ -39,6 +39,7 @@ public class OpCommand {
int count = 0;
for (NameAndId player : players) {
+ if (player.isBot()) continue; // Leaves - disable op
if (!list.isOp(player)) {
list.op(player);
count++;
diff --git a/net/minecraft/server/commands/StopCommand.java b/net/minecraft/server/commands/StopCommand.java
index e9c9a468f046832e8eaa999bb57da261b4633604..2efe24c0378a80dd2750b10a54c1887816236c1a 100644
--- a/net/minecraft/server/commands/StopCommand.java
+++ b/net/minecraft/server/commands/StopCommand.java
@@ -11,6 +11,10 @@ public class StopCommand {
c.getSource().sendSuccess(() -> Component.translatable("commands.stop.stopping"), true);
c.getSource().getServer().halt(false);
return 1;
- }));
+ }).then(Commands.literal("force").requires(Commands.hasPermission(Commands.LEVEL_OWNERS)).executes(c -> {
+ c.getSource().sendSuccess(() -> Component.translatable("commands.stop.stopping"), true);
+ c.getSource().getServer().safeShutdown(false, false, true);
+ return 1;
+ })));
}
}
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index fcd4b4785f0d09f87fe214202468c75395157e14..09e92f20f97b374582e057b0dc7d2edc82d6f431 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -274,6 +274,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
// Spigot start
+ this.setBotList(new org.leavesmc.leaves.bot.BotList(this)); // Leaves - fakeplayer
this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage));
org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings"));
org.spigotmc.SpigotConfig.registerCommands();
@@ -295,6 +296,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
consoleThread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
if (false) this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark // Luminol - Force disable builtin spark
+ this.getBotList().loadResumeBotInfo(); // Leaves - load resident bot info
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 0dfb25ad032429a2aea7aa441dd5fd1848a6c617..215f2a40921cc8e6b181c0a34aa1bbaf843e3059 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -1388,6 +1388,13 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
}
} else {
this.removePlayer(player);
+ // Leaves start - render bot
+ if (this.entity instanceof org.leavesmc.leaves.bot.ServerBot bot) {
+ if (bot.needSendFakeData(player)) {
+ bot.sendFakeData(player.connection, false);
+ }
+ }
+ // Leaves end - render bot
}
}
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 0befa4fc81e10a23c6ba824e559f2fb4886e68ee..2ddcf6ae90aaaf98e2fcd8ab9995b6f0d7791856 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -240,6 +240,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
//public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent // Folia - region threading - move to regionised world data
//public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent // Folia - region threading - move to regionised world data
//private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current) // Folia - region threading - move to regionised world data
+ final List<ServerPlayer> realPlayers; // Leaves - skip
@Override
public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
@@ -706,6 +707,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler);
// Paper end - rewrite chunk system
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
+ this.realPlayers = Lists.newArrayList(); // Leaves - skip
this.updateTickData(); // Folia - region threading - make sure it is initialised before ticked
}
@@ -2611,6 +2613,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
return this.players;
}
+ // Leaves start - fakeplayer skip
+ public List<ServerPlayer> realPlayers() {
+ return this.realPlayers;
+ }
+ // Leaves end - fakeplayer skip
+
@Override
public void updatePOIOnBlockStateChange(final BlockPos pos, final BlockState oldState, final BlockState newState) {
Optional<Holder<PoiType>> oldType = PoiTypes.forState(oldState);
@@ -3091,6 +3099,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
// ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true
if (entity instanceof ServerPlayer player) {
ServerLevel.this.players.add(player);
+ // Leaves start - skip
+ if (!(player instanceof org.leavesmc.leaves.bot.ServerBot)) {
+ ServerLevel.this.realPlayers.add(player);
+ }
+ // Leaves end - skip
if (player.isReceivingWaypoints()) {
ServerLevel.this.getWaypointManager().addPlayer(player);
}
@@ -3172,6 +3185,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
ServerLevel.this.getChunkSource().removeEntity(entity);
if (entity instanceof ServerPlayer player) {
ServerLevel.this.players.remove(player);
+ // Leaves start - skip
+ if (!(player instanceof org.leavesmc.leaves.bot.ServerBot)) {
+ ServerLevel.this.realPlayers.remove(player);
+ }
+ // Leaves end - skip
ServerLevel.this.getWaypointManager().removePlayer(player);
ServerLevel.this.updateSleepingPlayerList();
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 295be200cb0696bd2ae2b655f89d96dd7723a541..4f6010285a5ff9cf939248c4d93043133680d383 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -229,7 +229,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private static final boolean DEFAULT_SPAWN_EXTRA_PARTICLES_ON_FALL = false;
public ServerGamePacketListenerImpl connection;
private final MinecraftServer server;
- public final ServerPlayerGameMode gameMode;
+ public ServerPlayerGameMode gameMode; // Leaves - not final
private final PlayerAdvancements advancements;
private final ServerStatsCounter stats;
private float lastRecordedHealthAndAbsorption = Float.MIN_VALUE;
@@ -250,7 +250,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private @Nullable Entity camera;
public boolean isChangingDimension;
public boolean seenCredits = false;
- private final ServerRecipeBook recipeBook;
+ protected ServerRecipeBook recipeBook; // Leaves - not final and private -> protected
private @Nullable Vec3 levitationStartPos;
private int levitationStartTime;
private boolean disconnected;
@@ -1517,7 +1517,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// Luminol End - Cross Region Damage trace
- private void tellNeutralMobsThatIDied() {
+ protected void tellNeutralMobsThatIDied() { // Leaves private -> protected
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
this.level()
.getEntitiesOfClass(Mob.class, aabb, EntitySelector.NO_SPECTATORS)
@@ -2183,6 +2183,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.lastSentHealth = -1.0F;
this.lastSentFood = -1;
this.teleportSpectators(transition, oldLevel);
+ // Leaves start - bot support
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(this, true)); // Leaves - render bot
+ }
+ // Leaves end - bot support
// CraftBukkit start
org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), oldLevel.getWorld());
this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
diff --git a/net/minecraft/server/players/CachedUserNameToIdResolver.java b/net/minecraft/server/players/CachedUserNameToIdResolver.java
index d2da9f3c5e53ceaeb85c6d3d7443e124a4d93bb8..8a96c07e6d5fd0826efc50e3fd585a42b2c9028c 100644
--- a/net/minecraft/server/players/CachedUserNameToIdResolver.java
+++ b/net/minecraft/server/players/CachedUserNameToIdResolver.java
@@ -122,6 +122,12 @@ public class CachedUserNameToIdResolver implements UserNameToIdResolver {
@Override
public Optional<NameAndId> get(final String name) {
+ // Leaves start - fix bot
+ org.leavesmc.leaves.bot.ServerBot bot = org.leavesmc.leaves.bot.BotList.INSTANCE.getBotByName(name);
+ if (bot != null) {
+ return Optional.of(bot.nameAndId());
+ }
+ // Leaves end - fix bot
String userName = name.toLowerCase(Locale.ROOT);
boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
CachedUserNameToIdResolver.GameProfileInfo profileInfo = this.profilesByName.get(userName);
diff --git a/net/minecraft/server/players/NameAndId.java b/net/minecraft/server/players/NameAndId.java
index 484714beb5f7cdf8178834c5edd4f847fb06ebb8..ba7a280aad07f36366c15cd158b36ca9768cef19 100644
--- a/net/minecraft/server/players/NameAndId.java
+++ b/net/minecraft/server/players/NameAndId.java
@@ -8,18 +8,22 @@ import java.util.UUID;
import net.minecraft.core.UUIDUtil;
import org.jspecify.annotations.Nullable;
-public record NameAndId(UUID id, String name) {
+public record NameAndId(UUID id, String name, boolean isBot) { // Leaves - fakeplayer
public static final Codec<NameAndId> CODEC = RecordCodecBuilder.create(
i -> i.group(UUIDUtil.STRING_CODEC.fieldOf("id").forGetter(NameAndId::id), Codec.STRING.fieldOf("name").forGetter(NameAndId::name))
.apply(i, NameAndId::new)
);
public NameAndId(final GameProfile profile) {
- this(profile.id(), profile.name());
+ this(profile.id(), profile.name(), com.google.common.collect.Iterables.getFirst(profile.properties().get("is_bot"), "false").equals("true")); // Leaves - fakeplayer
}
public NameAndId(final com.mojang.authlib.yggdrasil.response.NameAndId profile) {
- this(profile.id(), profile.name());
+ this(profile.id(), profile.name(), false); // Leaves - fakeplayer
+ }
+
+ public NameAndId(UUID uuid, String name) {
+ this(uuid, name, false); // Leaves - fakeplayer
}
public static @Nullable NameAndId fromJson(final JsonObject object) {
@@ -33,7 +37,7 @@ public record NameAndId(UUID id, String name) {
return null;
}
- return new NameAndId(uuid, object.get("name").getAsString());
+ return new NameAndId(uuid, object.get("name").getAsString(), false); // Leaves - fakeplayer
} else {
return null;
}
@@ -46,7 +50,7 @@ public record NameAndId(UUID id, String name) {
public static NameAndId createOffline(final String name) {
UUID id = UUIDUtil.createOfflinePlayerUUID(name);
- return new NameAndId(id, name);
+ return new NameAndId(id, name, false); // Leaves - fakeplayer
}
// Paper start - utility method for common conversion back to the game profile
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 16d01fcb97aa3dbd7554bd64b3608c6e80ce3dbd..b77968e195d1f87c825c09b2a1622b3a3ed5f772 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -320,6 +320,19 @@ public abstract class PlayerList {
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
+ // Leaves start - bot support
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
+ if (bot != null) {
+ this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
+ }
+ this.server.getBotList().bots.forEach(bot1 -> {
+ bot1.sendPlayerInfo(player);
+ bot1.sendFakeDataIfNeed(player, true);
+ }); // Leaves - render bot
+ }
+ // Leaves end - bot support
+
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -793,6 +806,11 @@ public abstract class PlayerList {
respawnReason
).callEvent();
// Paper end
+ // Leaves start - bot support
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(player, true)); // Leaves - render bot
+ }
+ // Leaves end - bot support
return player;
}
@@ -895,11 +913,16 @@ public abstract class PlayerList {
public String[] getPlayerNamesArray() {
List<ServerPlayer> players = new java.util.ArrayList<>(this.players); // Folia - region threading
- String[] names = new String[players.size()]; // Folia - region threading
+ String[] names = new String[players.size() + this.server.getBotList().bots.size()]; // Leaves - fakeplayer support
for (int i = 0; i < players.size(); i++) { // Folia - region threading
names[i] = players.get(i).getGameProfile().name(); // Folia - region threading
}
+ // Leaves start - fakeplayer support
+ for (int i = this.players.size(); i < names.length; ++i) {
+ names[i] = this.server.getBotList().bots.get(i - this.players.size()).gameProfile.name();
+ }
+ // Leaves end - fakeplayer support
return names;
}
@@ -1018,8 +1041,15 @@ public abstract class PlayerList {
|| this.allowCommandsForAllPlayers;
}
- public @Nullable ServerPlayer getPlayerByName(final String name) {
- return this.playersByName.get(name.toLowerCase(java.util.Locale.ROOT)); // Spigot
+ public @Nullable ServerPlayer getPlayerByName(String name) {
+ // Leaves start - fakeplayer support
+ name = name.toLowerCase(java.util.Locale.ROOT);
+ ServerPlayer player = this.playersByName.get(name);
+ if (player == null) {
+ player = this.server.getBotList().getBotByName(name);
+ }
+ return player; // Spigot
+ // Leaves end - fakeplayer support
}
public void broadcast(
@@ -1362,7 +1392,13 @@ public abstract class PlayerList {
}
public @Nullable ServerPlayer getPlayer(final UUID uuid) {
- return this.playersByUUID.get(uuid);
+ // Leaves start - fakeplayer support
+ ServerPlayer player = this.playersByUUID.get(uuid);
+ if (player == null) {
+ player = this.server.getBotList().getBot(uuid);
+ }
+ return player;
+ // Leaves start - fakeplayer support
}
public @Nullable ServerPlayer getPlayer(final String playerName) {
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index f090b8d77bd2731debfc61c263bd77550f52212b..03c155140da7300f6f934aff323e0daed1b63366 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -1257,7 +1257,7 @@ public abstract class Entity
BlockPos effectPos = this.getOnPosLegacy();
BlockState effectState = this.level().getBlockState(effectPos);
- if (this.isLocalInstanceAuthoritative()) {
+ if (this.isLocalInstanceAuthoritative() || this instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - ServerBot needs check fall damage
this.checkFallDamage(movement.y, this.onGround(), effectState, effectPos);
}
@@ -1602,7 +1602,7 @@ public abstract class Entity
return colliders.isEmpty() ? maxDistance : -Shapes.collide(Direction.Axis.Y, aabb, colliders, -maxDistance);
}
- private Vec3 collide(final Vec3 movement) {
+ public Vec3 collide(final Vec3 movement) { // Leaves - private -> public
// Paper start - optimise collisions
final boolean xZero = movement.x == 0.0;
final boolean yZero = movement.y == 0.0;
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 2bce20202b7c539bee3685741663a8ed225919ff..a2f44e4354f6aa1c0502cba40cadaad59193b169 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3347,7 +3347,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
private void travelRidden(final Player controller, final Vec3 selfInput) {
Vec3 riddenInput = this.getRiddenInput(controller, selfInput);
this.tickRidden(controller, riddenInput);
- if (this.canSimulateMovement()) {
+ if (this.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - Fakeplayer
this.setSpeed(this.getRiddenSpeed(controller));
this.travel(riddenInput);
} else {
@@ -4270,7 +4270,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
// Paper start - lag compensate eating
// we add 1 to the expected time to avoid lag compensating when we should not
final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L));
- if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide() && !useItem.useOnRelease()) {
+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !(this instanceof org.leavesmc.leaves.bot.ServerBot) && !this.level().isClientSide() && !useItem.useOnRelease()) {
this.useItemRemaining = 0;
// Paper end - lag compensate eating
this.completeUsingItem();
@@ -4459,6 +4459,23 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
this.stopUsingItem();
}
+ // Leaves start - Fakeplayer
+ public boolean releaseUsingItemWithResult() {
+ ItemStack itemInHand = this.getItemInHand(this.getUsedItemHand());
+ boolean result = false;
+ if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInHand, this.useItem)) {
+ this.useItem = itemInHand;
+ result = this.useItem.releaseUsingWithResult(this.level(), this, this.getUseItemRemainingTicks());
+ if (this.useItem.useOnRelease()) {
+ this.updatingUsingItem();
+ }
+ }
+
+ this.stopUsingItem();
+ return result;
+ }
+ // Leaves end - Fakeplayer
+
public void stopUsingItem() {
if (!this.level().isClientSide()) {
boolean wasUsingItem = this.isUsingItem();
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 06c6d30f3aef605bc25c42db8a6d26bbde57f40b..20a76138a8625663cf608e4ef97cc8ca4085b844 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -167,7 +167,7 @@ public abstract class Player extends Avatar implements ContainerUser {
private int lastLevelUpTime;
public GameProfile gameProfile;
private boolean reducedDebugInfo;
- private ItemStack lastItemInMainHand = ItemStack.EMPTY;
+ protected ItemStack lastItemInMainHand = ItemStack.EMPTY; // Leaves - fakeplayer
private final ItemCooldowns cooldowns = this.createItemCooldowns();
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
public me.earthme.luminol.functions.bars.TickableStatusBarList statusBarList = new me.earthme.luminol.functions.bars.TickableStatusBarList(this); // Luminol status bars
@@ -341,6 +341,12 @@ public abstract class Player extends Avatar implements ContainerUser {
this.updatePlayerPose();
}
+ // Leaves start - fakeplayer
+ protected void livingEntityTick() {
+ super.tick();
+ }
+ // Leaves end - fakeplayer
+
@Override
protected float getMaxHeadRotationRelativeToBody() {
return this.isBlocking() ? 15.0F : super.getMaxHeadRotationRelativeToBody();
@@ -566,7 +572,7 @@ public abstract class Player extends Avatar implements ContainerUser {
public void removeEntitiesOnShoulder() {
}
- private void touch(final Entity entity) {
+ public void touch(final Entity entity) { // Leaves - private -> public
entity.playerTouch(this);
}
@@ -1250,7 +1256,7 @@ public abstract class Player extends Avatar implements ContainerUser {
// Paper end - Configurable sprint interruption on attack
}
- if (entity instanceof ServerPlayer && entity.hurtMarked) {
+ if ((entity instanceof ServerPlayer && !(entity instanceof org.leavesmc.leaves.bot.ServerBot)) && entity.hurtMarked) { // Leaves - bot knockback
// CraftBukkit start - Add Velocity Event
boolean cancelled = false;
org.bukkit.entity.Player player = (org.bukkit.entity.Player) entity.getBukkitEntity();
diff --git a/net/minecraft/world/entity/projectile/FishingHook.java b/net/minecraft/world/entity/projectile/FishingHook.java
index 0c8a48988c859669cf7e38816aaf32782c245244..a554e050d0c582c441af9d5616367234caa67ab0 100644
--- a/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/net/minecraft/world/entity/projectile/FishingHook.java
@@ -58,7 +58,7 @@ public class FishingHook extends Projectile {
public static final EntityDataAccessor<Integer> DATA_HOOKED_ENTITY = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> DATA_BITING = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.BOOLEAN);
private int life;
- private int nibble;
+ public int nibble; // Leaves - private -> public
public int timeUntilLured;
public int timeUntilHooked;
public float fishAngle;
diff --git a/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java b/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
index 05176458264b110ef3280342866ace22ec5a3333..2ce33513fd8e3de912c69ca8bc558a5800784ac5 100644
--- a/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
+++ b/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
@@ -270,6 +270,11 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
}
this.move(MoverType.SELF, this.getDeltaMovement());
+ } else if (this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves start - Fakeplayer
+ this.floatBoat();
+ this.controlBoat();
+ this.move(MoverType.SELF, this.getDeltaMovement());
+ // Leaves end - Fakeplayer
} else {
this.setDeltaMovement(Vec3.ZERO);
}
@@ -380,6 +385,13 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
}
}
+ // Leaves start - Fakeplayer
+ @Override
+ public boolean canSimulateMovement() {
+ return super.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot;
+ }
+ // Leaves end - Fakeplayer
+
protected @Nullable SoundEvent getPaddleSound() {
return switch (this.getStatus()) {
case IN_WATER, UNDER_WATER, UNDER_FLOWING_WATER -> SoundEvents.BOAT_PADDLE_WATER;
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
index fa1f7dd22959632aaa54e72c8caf13ea072e7ca7..ae6056c3b6ae3eebdfb59cf54d7333dfc2cebf6a 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -407,6 +407,7 @@ public abstract class AbstractContainerMenu {
private void doClick(final int slotIndex, final int buttonNum, final ContainerInput containerInput, final Player player) {
Inventory inventory = player.getInventory();
+ if (!doClickCheck(slotIndex, buttonNum, containerInput, player)) return; // Leaves - doClick check
if (containerInput == ContainerInput.QUICK_CRAFT) {
int expectedStatus = this.quickcraftStatus;
this.quickcraftStatus = getQuickcraftHeader(buttonNum);
@@ -681,6 +682,22 @@ public abstract class AbstractContainerMenu {
}
}
+ // Leaves start - doClick check
+ private boolean doClickCheck(int slotIndex, int buttonNum, ContainerInput containerInput, Player player) {
+ if (slotIndex < 0) {
+ return true;
+ }
+
+ Slot slot = getSlot(slotIndex);
+ ItemStack itemStack = slot.getItem();
+ net.minecraft.world.item.component.CustomData customData = itemStack.get(net.minecraft.core.component.DataComponents.CUSTOM_DATA);
+ if (customData != null && customData.contains("Leaves.Gui.Placeholder")) {
+ return !customData.copyTag().getBoolean("Leaves.Gui.Placeholder").orElse(false);
+ }
+ return true;
+ }
+ // Leaves end - doClick check
+
private boolean tryItemClickBehaviourOverride(
final Player player, final ClickAction clickAction, final Slot slot, final ItemStack clicked, final ItemStack carried
) {
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index b052bc0107d93cd65a6c92914d6b3d02d6cc5ccb..fd2545f33692f964b62415178069e46e9c9d4c02 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -453,7 +453,7 @@ public final class ItemStack implements DataComponentHolder, ItemInstance, Chang
placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(level, player, hand, blocks.getFirst(), pos);
}
- if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild()) && (!(player instanceof org.leavesmc.leaves.bot.ServerBot))) { // Leaves - Fakeplayer skip this check
result = InteractionResult.FAIL; // cancel placement
// PAIL: Remove this when MC-99075 fixed
player.containerMenu.forceHeldSlot(hand);
@@ -982,6 +982,20 @@ public final class ItemStack implements DataComponentHolder, ItemInstance, Chang
}
}
+ // Leaves start - Fakeplayer
+ public boolean releaseUsingWithResult(Level level, LivingEntity livingEntity, int timeLeft) {
+ ItemStack itemStack = this.copy();
+ if (this.getItem().releaseUsing(this, level, livingEntity, timeLeft)) {
+ ItemStack itemStack1 = this.applyAfterUseComponentSideEffects(livingEntity, itemStack);
+ if (itemStack1 != this) {
+ livingEntity.setItemInHand(livingEntity.getUsedItemHand(), itemStack1);
+ }
+ return true;
+ }
+ return false;
+ }
+ // Leaves end - Fakeplayer
+
public boolean useOnRelease() {
return this.getItem().useOnRelease(this);
}
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index 282849162b88354893a15533e66d046fdd035bd6..2ecb10fe97d15954e44c61247eabc8818eb16f34 100644
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -152,7 +152,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
break;
}
- if (!(entity instanceof ServerPlayer)) {
+ if (!(entity instanceof ServerPlayer) || (entity instanceof org.leavesmc.leaves.bot.ServerBot)) { // Leaves - bot slime block
Vec3 deltaMovement = entity.getDeltaMovement();
double dx = deltaMovement.x;
double dy = deltaMovement.y;
diff --git a/net/minecraft/world/level/levelgen/PhantomSpawner.java b/net/minecraft/world/level/levelgen/PhantomSpawner.java
index 9d7238a28440ddc442c9288a617795261df767d9..142ab133d3b68eb9b88651e307653f1aafdf1de3 100644
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -49,6 +49,10 @@ public class PhantomSpawner implements CustomSpawner {
ServerStatsCounter stats = player.getStats();
int value = Mth.clamp(stats.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
int dayLength = 24000;
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot bot && bot.getConfigValue(org.leavesmc.leaves.bot.agent.Configs.SPAWN_PHANTOM)) {
+ dayLength = Math.max(bot.notSleepTicks, 1);
+ }
+ // Leaves end - fakeplayer spawn
if (random.nextInt(value) >= level.paperConfig().entities.behavior.playerInsomniaStartTicks) { // Paper - Ability to control player's insomnia and phantoms
BlockPos spawnPos = playerPos.above(20 + random.nextInt(15))
.east(-10 + random.nextInt(21))
@@ -0,0 +1,560 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 16 Nov 2025 15:48:12 +0800
Subject: [PATCH] Leaves: Replay Mod API
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves) & ReplayMod (https://github.com/ReplayMod)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
This patch is Powered by ReplayMod (https://github.com/ReplayMod)
diff --git a/net/minecraft/commands/CommandSourceStack.java b/net/minecraft/commands/CommandSourceStack.java
index 28776f3363810259f8c3bfdfd9f8c0455975be2a..0f562d7403aebf6c0907f2a33f758f4351ef282e 100644
--- a/net/minecraft/commands/CommandSourceStack.java
+++ b/net/minecraft/commands/CommandSourceStack.java
@@ -562,7 +562,7 @@ public class CommandSourceStack implements SharedSuggestionProvider, ExecutionCo
@Override
public Collection<String> getOnlinePlayerNames() {
- return this.entity instanceof ServerPlayer sourcePlayer && !sourcePlayer.getBukkitEntity().hasPermission("paper.bypass-visibility.tab-completion") ? this.getServer().getPlayerList().getPlayers().stream().filter(serverPlayer -> sourcePlayer.getBukkitEntity().canSee(serverPlayer.getBukkitEntity())).map(serverPlayer -> serverPlayer.getGameProfile().name()).toList() : Lists.newArrayList(this.server.getPlayerNames()); // Paper - Make CommandSourceStack respect hidden players
+ return this.entity instanceof ServerPlayer sourcePlayer && !(sourcePlayer instanceof org.leavesmc.leaves.replay.ServerPhotographer) && !sourcePlayer.getBukkitEntity().hasPermission("paper.bypass-visibility.tab-completion") ? this.getServer().getPlayerList().getPlayers().stream().filter(serverPlayer -> sourcePlayer.getBukkitEntity().canSee(serverPlayer.getBukkitEntity())).map(serverPlayer -> serverPlayer.getGameProfile().name()).toList() : Lists.newArrayList(this.server.getPlayerNames()); // Paper - Make CommandSourceStack respect hidden players // Leaves - only real player
}
@Override
diff --git a/net/minecraft/commands/arguments/selector/EntitySelector.java b/net/minecraft/commands/arguments/selector/EntitySelector.java
index 7e3912b8b29e40eb3347f1451b0fd3ebee2af4f1..0834e402e6af7028e08851378e15390ec6314380 100644
--- a/net/minecraft/commands/arguments/selector/EntitySelector.java
+++ b/net/minecraft/commands/arguments/selector/EntitySelector.java
@@ -142,11 +142,12 @@ public class EntitySelector {
return this.findPlayers(sender);
} else if (this.playerName != null) {
ServerPlayer result = sender.getServer().getPlayerList().getPlayerByName(this.playerName);
+ result = result instanceof org.leavesmc.leaves.replay.ServerPhotographer ? null : result; // Leaves - skip photographer
return result == null ? List.of() : List.of(result);
} else if (this.entityUUID != null) {
for (ServerLevel level : sender.getServer().getAllLevels()) {
Entity entity = level.getEntity(this.entityUUID);
- if (entity != null) {
+ if (entity != null && !(entity instanceof org.leavesmc.leaves.replay.ServerPhotographer)) {
if (entity.getType().isEnabled(sender.enabledFeatures())) {
return List.of(entity);
}
@@ -160,7 +161,7 @@ public class EntitySelector {
AABB absoluteAabb = this.getAbsoluteAabb(pos);
if (this.currentEntity) {
Predicate<Entity> predicate = this.getPredicate(pos, absoluteAabb, null);
- return sender.getEntity() != null && predicate.test(sender.getEntity()) ? List.of(sender.getEntity()) : List.of();
+ return sender.getEntity() != null && !(sender.getEntity() instanceof org.leavesmc.leaves.replay.ServerPhotographer) && predicate.test(sender.getEntity()) ? List.of(sender.getEntity()) : List.of(); // Leaves - skip photographer
} else {
Predicate<Entity> predicate = this.getPredicate(pos, absoluteAabb, sender.enabledFeatures());
List<Entity> result = new ObjectArrayList<>();
@@ -171,6 +172,7 @@ public class EntitySelector {
this.addEntities(result, levelx, absoluteAabb, predicate);
}
}
+ result.removeIf(entity -> entity instanceof org.leavesmc.leaves.replay.ServerPhotographer); // Leaves - skip photographer
return this.sortAndLimit(pos, result);
}
@@ -206,9 +208,11 @@ public class EntitySelector {
this.checkPermissions(sender);
if (this.playerName != null) {
ServerPlayer result = sender.getServer().getPlayerList().getPlayerByName(this.playerName);
+ result = result instanceof org.leavesmc.leaves.replay.ServerPhotographer ? null : result; // Leaves - skip photographer
return result == null ? List.of() : List.of(result);
} else if (this.entityUUID != null) {
ServerPlayer result = sender.getServer().getPlayerList().getPlayer(this.entityUUID);
+ result = result instanceof org.leavesmc.leaves.replay.ServerPhotographer ? null : result; // Leaves - skip photographer
return result == null ? List.of() : List.of(result);
} else {
Vec3 pos = this.position.apply(sender.getPosition());
@@ -220,11 +224,11 @@ public class EntitySelector {
int limit = this.getResultLimit();
List<ServerPlayer> result;
if (this.isWorldLimited()) {
- result = sender.getLevel().getPlayers(predicate, limit);
+ result = sender.getLevel().getPlayers((player -> !(player instanceof org.leavesmc.leaves.replay.ServerPhotographer) && predicate.test(player)), limit); // Leaves - skip photographer
} else {
result = new ObjectArrayList<>();
- for (ServerPlayer player : sender.getServer().getPlayerList().getPlayers()) {
+ for (ServerPlayer player : sender.getServer().getPlayerList().realPlayers) { // Leaves - only real players
if (predicate.test(player)) {
result.add(player);
if (result.size() >= limit) {
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 9837d8388e6fe73ef87d021c7370c2a7c236c634..5889aa815ab02261f26048c5ef43f5bdfa2939fc 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1933,7 +1933,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
private ServerStatus.Players buildPlayerStatus() {
- List<ServerPlayer> players = new java.util.ArrayList<>(this.playerList.getPlayers()); // Folia - region threading
+ List<ServerPlayer> players = new java.util.ArrayList<>(this.playerList.realPlayers); // Folia - region threading // Leaves - only real player
int maxPlayers = this.getMaxPlayers();
if (this.hidesOnlinePlayers()) {
return new ServerStatus.Players(maxPlayers, players.size(), List.of());
@@ -2154,7 +2154,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@Override
public int getPlayerCount() {
- return this.playerList.getPlayerCount();
+ return this.playerList.realPlayers.size(); // Leaves - only real player
}
public String[] getPlayerNames() {
@@ -2366,7 +2366,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
} else {
int count = 0;
- for (ServerPlayer player : this.getPlayerList().getPlayers()) {
+ for (ServerPlayer player : this.getPlayerList().realPlayers) { // Leaves - only real player
player.getBukkitEntity().taskScheduler.schedule((ServerPlayer updatedPlayer) -> { // Folia - region threading
// Paper start - Expand PlayerGameModeChangeEvent
org.bukkit.event.player.PlayerGameModeChangeEvent event = updatedPlayer.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); // Folia - region threading
@@ -2553,7 +2553,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (Thread.currentThread() != this.serverThread) return; // Paper
// Paper start - we don't need to save everything, just advancements
// this.getPlayerList().saveAll();
- for (final ServerPlayer player : this.getPlayerList().getPlayers()) {
+ for (final ServerPlayer player : this.getPlayerList().realPlayers) { // Leaves - only real players
player.getAdvancements().save();
}
// Paper end - we don't need to save everything, just advancements
@@ -2689,7 +2689,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
PlayerList playerList = this.getPlayerList();
UserWhiteList whiteList = playerList.getWhiteList();
- for (ServerPlayer player : Lists.newArrayList(playerList.getPlayers())) {
+ for (ServerPlayer player : Lists.newArrayList(playerList.realPlayers)) { // Leaves - only real player
if (!whiteList.isWhiteListed(player.nameAndId()) && !this.getPlayerList().isOp(player.nameAndId())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420)
player.connection.disconnect(net.kyori.adventure.text.Component.text(org.spigotmc.SpigotConfig.whitelistMessage), org.bukkit.event.player.PlayerKickEvent.Cause.WHITELIST); // Paper - use configurable message & kick event cause
}
diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java
index 89448eee9f135de8b406bf5f4147b3298e33ba17..b286aefc7d328bc7a7f44ce93615392075d9fef7 100644
--- a/net/minecraft/server/PlayerAdvancements.java
+++ b/net/minecraft/server/PlayerAdvancements.java
@@ -169,7 +169,7 @@ public class PlayerAdvancements {
public boolean award(final AdvancementHolder holder, final String criterion) {
// Leaves start - bot can't get advancement
- if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot || player instanceof org.leavesmc.leaves.replay.ServerPhotographer) { // Leaves - and photographer
return false;
}
// Leaves end - bot can't get advancement
diff --git a/net/minecraft/server/ServerScoreboard.java b/net/minecraft/server/ServerScoreboard.java
index 9bf09b888425e491072864265c8de3885154a0ba..97a8fee8280061312a28013a5400e835db2eb474 100644
--- a/net/minecraft/server/ServerScoreboard.java
+++ b/net/minecraft/server/ServerScoreboard.java
@@ -245,7 +245,7 @@ public class ServerScoreboard extends Scoreboard {
public void startTrackingObjective(final Objective objective) {
List<Packet<?>> packets = this.getStartTrackingPackets(objective);
- for (ServerPlayer player : this.server.getPlayerList().getPlayers()) {
+ for (ServerPlayer player : this.server.getPlayerList().realPlayers) { // Leaves - only real players
if (player.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board
for (Packet<?> packet : packets) {
player.connection.send(packet);
@@ -271,7 +271,7 @@ public class ServerScoreboard extends Scoreboard {
public void stopTrackingObjective(final Objective objective) {
List<Packet<?>> packets = this.getStopTrackingPackets(objective);
- for (ServerPlayer player : this.server.getPlayerList().getPlayers()) {
+ for (ServerPlayer player : this.server.getPlayerList().realPlayers) { // Leaves - only real players
if (player.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board
for (Packet<?> packet : packets) {
player.connection.send(packet);
diff --git a/net/minecraft/server/commands/ListPlayersCommand.java b/net/minecraft/server/commands/ListPlayersCommand.java
index b850c908a594f839ce124c6bd01762d31cc3aa1e..b2240fd3f5ace03168fd679932675a72c09e81d7 100644
--- a/net/minecraft/server/commands/ListPlayersCommand.java
+++ b/net/minecraft/server/commands/ListPlayersCommand.java
@@ -33,7 +33,7 @@ public class ListPlayersCommand {
private static int format(final CommandSourceStack source, final Function<ServerPlayer, Component> formatter) {
PlayerList playerList = source.getServer().getPlayerList();
// CraftBukkit start
- List<ServerPlayer> playersTemp = playerList.getPlayers();
+ List<ServerPlayer> playersTemp = playerList.realPlayers;
if (source.getBukkitSender() instanceof org.bukkit.entity.Player) {
org.bukkit.entity.Player sender = (org.bukkit.entity.Player) source.getBukkitSender();
playersTemp = playersTemp.stream().filter((ep) -> sender.canSee(ep.getBukkitEntity())).collect(java.util.stream.Collectors.toList());
diff --git a/net/minecraft/server/commands/OpCommand.java b/net/minecraft/server/commands/OpCommand.java
index 20cbc0e65fea3fc2d0033259c2f35e158ea81926..6bcd09b8d39333bd5f2c0d7c0a9a91bb52f9314d 100644
--- a/net/minecraft/server/commands/OpCommand.java
+++ b/net/minecraft/server/commands/OpCommand.java
@@ -25,7 +25,8 @@ public class OpCommand {
(c, p) -> {
PlayerList list = c.getSource().getServer().getPlayerList();
return SharedSuggestionProvider.suggest(
- list.getPlayers().stream().filter(player -> !list.isOp(player.nameAndId())).map(pl -> pl.getGameProfile().name()), p
+ list.realPlayers // Leaves - only real player
+ .stream().filter(player -> !list.isOp(player.nameAndId())).map(pl -> pl.getGameProfile().name()), p
);
}
)
diff --git a/net/minecraft/server/commands/ParticleCommand.java b/net/minecraft/server/commands/ParticleCommand.java
index a14f82a1587e175030d4cd806726456831008dea..563d897a70f402d556cabd3e02131aaf22ff8d1e 100644
--- a/net/minecraft/server/commands/ParticleCommand.java
+++ b/net/minecraft/server/commands/ParticleCommand.java
@@ -36,7 +36,7 @@ public class ParticleCommand {
0.0F,
0,
false,
- c.getSource().getServer().getPlayerList().getPlayers()
+ c.getSource().getServer().getPlayerList().realPlayers // Leaves - only real player
)
)
.then(
@@ -50,7 +50,7 @@ public class ParticleCommand {
0.0F,
0,
false,
- c.getSource().getServer().getPlayerList().getPlayers()
+ c.getSource().getServer().getPlayerList().realPlayers // Leaves - only real player
)
)
.then(
@@ -68,7 +68,7 @@ public class ParticleCommand {
FloatArgumentType.getFloat(c, "speed"),
IntegerArgumentType.getInteger(c, "count"),
false,
- c.getSource().getServer().getPlayerList().getPlayers()
+ c.getSource().getServer().getPlayerList().realPlayers // Leaves - only real player
)
)
.then(
@@ -82,7 +82,7 @@ public class ParticleCommand {
FloatArgumentType.getFloat(c, "speed"),
IntegerArgumentType.getInteger(c, "count"),
true,
- c.getSource().getServer().getPlayerList().getPlayers()
+ c.getSource().getServer().getPlayerList().realPlayers // Leaves - only real player
)
)
.then(
@@ -112,7 +112,7 @@ public class ParticleCommand {
FloatArgumentType.getFloat(c, "speed"),
IntegerArgumentType.getInteger(c, "count"),
false,
- c.getSource().getServer().getPlayerList().getPlayers()
+ c.getSource().getServer().getPlayerList().realPlayers // Leaves - only real player
)
)
.then(
diff --git a/net/minecraft/server/commands/TeamMsgCommand.java b/net/minecraft/server/commands/TeamMsgCommand.java
index d04fd8ab5f8e3c1697af5448c320838a822dbf1f..f46abe413e9b30f219fa1f7fc485de4c8859be90 100644
--- a/net/minecraft/server/commands/TeamMsgCommand.java
+++ b/net/minecraft/server/commands/TeamMsgCommand.java
@@ -40,7 +40,7 @@ public class TeamMsgCommand {
} else {
List<ServerPlayer> receivers = source.getServer()
.getPlayerList()
- .getPlayers()
+ .realPlayers // Leaves - only real players
.stream()
.filter(receiver -> receiver == entity || receiver.getTeam() == team)
.toList();
diff --git a/net/minecraft/server/commands/WhitelistCommand.java b/net/minecraft/server/commands/WhitelistCommand.java
index 907d1304503a80c6d0fd064bf1aaf4e081e9f85b..e0c1ee55888261bca42bbadec8812da2a36dded8 100644
--- a/net/minecraft/server/commands/WhitelistCommand.java
+++ b/net/minecraft/server/commands/WhitelistCommand.java
@@ -44,7 +44,7 @@ public class WhitelistCommand {
(c, p) -> {
PlayerList list = c.getSource().getServer().getPlayerList();
return SharedSuggestionProvider.suggest(
- list.getPlayers()
+ list.realPlayers // Leaves - only real player
.stream()
.map(Player::nameAndId)
.filter(nameAndId -> !list.getWhiteList().isWhiteListed(nameAndId))
diff --git a/net/minecraft/server/gui/PlayerListComponent.java b/net/minecraft/server/gui/PlayerListComponent.java
index 37c9f983ae89c497f44a1b7967d741abf909e0a0..d7fb2505f2a86ca0d81f144624ef2e1a4b4bddbb 100644
--- a/net/minecraft/server/gui/PlayerListComponent.java
+++ b/net/minecraft/server/gui/PlayerListComponent.java
@@ -17,8 +17,8 @@ public class PlayerListComponent extends JList<String> {
if (this.tickCount++ % 20 == 0) {
Vector<String> players = new Vector<>();
- for (int i = 0; i < this.server.getPlayerList().getPlayers().size(); i++) {
- players.add(this.server.getPlayerList().getPlayers().get(i).getGameProfile().name());
+ for (int i = 0; i < this.server.getPlayerList().realPlayers.size(); i++) { // Leaves - only real players
+ players.add(this.server.getPlayerList().realPlayers.get(i).getGameProfile().name()); // Leaves - only real players
}
this.setListData(players);
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 2ddcf6ae90aaaf98e2fcd8ab9995b6f0d7791856..a7cebb797973cde399dc30c696b064efd40874f2 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -3100,7 +3100,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
if (entity instanceof ServerPlayer player) {
ServerLevel.this.players.add(player);
// Leaves start - skip
- if (!(player instanceof org.leavesmc.leaves.bot.ServerBot)) {
+ if (!(player instanceof org.leavesmc.leaves.bot.ServerBot) && !(player instanceof org.leavesmc.leaves.replay.ServerPhotographer)) { // and photographer
ServerLevel.this.realPlayers.add(player);
}
// Leaves end - skip
@@ -3186,7 +3186,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
if (entity instanceof ServerPlayer player) {
ServerLevel.this.players.remove(player);
// Leaves start - skip
- if (!(player instanceof org.leavesmc.leaves.bot.ServerBot)) {
+ if (!(player instanceof org.leavesmc.leaves.bot.ServerBot) && !(player instanceof org.leavesmc.leaves.replay.ServerPhotographer)) { // and photographer
ServerLevel.this.realPlayers.remove(player);
}
// Leaves end - skip
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index b77968e195d1f87c825c09b2a1622b3a3ed5f772..c95c7b9a3968fc34a900a613b65b5d3e1abb24bf 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -130,6 +130,7 @@ public abstract class PlayerList {
private int simulationDistance;
private boolean allowCommandsForAllPlayers;
private int sendAllPlayerInfoIn;
+ public final List<ServerPlayer> realPlayers = new java.util.concurrent.CopyOnWriteArrayList<>(); // Leaves - replay api
// CraftBukkit start
private org.bukkit.craftbukkit.CraftServer cserver;
@@ -192,6 +193,7 @@ public abstract class PlayerList {
private boolean countConnection(Connection conn, int limit) {
synchronized (this.connectionsStateLock) {
+ if (conn instanceof org.leavesmc.leaves.bot.ServerBotPacketListenerImpl.BotConnection) return true;
int count = this.usersCountedAgainstLimit.size();
if (count >= limit) {
return false;
@@ -222,6 +224,124 @@ public abstract class PlayerList {
abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor
+ // Leaves start - replay mod api
+ public void placeNewPhotographer(Connection connection, org.leavesmc.leaves.replay.ServerPhotographer player, ServerLevel worldserver) {
+ player.isRealPlayer = true; // Paper
+ player.loginTime = System.currentTimeMillis(); // Paper
+
+ ServerLevel worldserver1 = worldserver;
+
+ player.setServerLevel(worldserver1);
+ player.spawnIn(worldserver1);
+ player.gameMode.setLevel(player.level());
+
+ LevelData worlddata = worldserver1.getLevelData();
+
+ ServerGamePacketListenerImpl playerconnection = new ServerGamePacketListenerImpl(this.server, connection, player, CommonListenerCookie.createInitial(player.gameProfile, false));
+ GameRules gamerules = worldserver1.getGameRules();
+ boolean flag = gamerules.get(GameRules.IMMEDIATE_RESPAWN);
+ boolean flag1 = gamerules.get(GameRules.REDUCED_DEBUG_INFO);
+ boolean flag2 = gamerules.get(GameRules.LIMITED_CRAFTING);
+
+ playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), this.server.levelKeys(), this.getMaxPlayers(), io.papermc.paper.FeatureHooks.getViewDistance(worldserver1), io.papermc.paper.FeatureHooks.getSimulationDistance(worldserver1), flag1, !flag, flag2, player.createCommonSpawnInfo(worldserver1), this.server.enforceSecureProfile()));
+ player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit
+ playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked()));
+ playerconnection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities()));
+ playerconnection.send(new ClientboundSetHeldSlotPacket(player.getInventory().getSelectedSlot()));
+ RecipeManager craftingmanager = this.server.getRecipeManager();
+ playerconnection.send(new ClientboundUpdateRecipesPacket(craftingmanager.getSynchronizedItemProperties(), craftingmanager.getSynchronizedStonecutterRecipes()));
+
+ this.sendPlayerPermissionLevel(player);
+ player.getStats().markAllDirty();
+ player.getRecipeBook().sendInitialRecipeBook(player);
+ this.updateEntireScoreboard(worldserver1.getScoreboard(), player);
+ this.server.invalidateStatus();
+
+ playerconnection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot());
+ ServerStatus serverping = this.server.getStatus();
+
+ if (serverping != null) {
+ player.sendServerStatus(serverping);
+ }
+
+ this.players.add(player);
+ this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); // Spigot
+ this.playersByUUID.put(player.getUUID(), player);
+
+ player.suppressTrackerForLogin = true;
+ worldserver1.addNewPlayer(player);
+ this.server.getCustomBossEvents().onPlayerConnect(player);
+ org.bukkit.craftbukkit.entity.CraftPlayer bukkitPlayer = player.getBukkitEntity();
+
+ player.containerMenu.transferTo(player.containerMenu, bukkitPlayer);
+ if (!player.connection.isAcceptingMessages()) {
+ return;
+ }
+
+ // org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
+
+ // Leaves start - bot support
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
+ if (bot != null) {
+ this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
+ }
+ this.server.getBotList().bots.forEach(bot1 -> {
+ bot1.sendPlayerInfo(player);
+ bot1.sendFakeDataIfNeed(player, true);
+ }); // Leaves - render bot
+ }
+ // Leaves end - bot support
+
+ final List<ServerPlayer> onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1);
+ for (int i = 0; i < this.players.size(); ++i) {
+ ServerPlayer entityplayer1 = this.players.get(i);
+
+ if (entityplayer1 == player || !bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) {
+ continue;
+ }
+
+ // Leaves start - skip photographer
+ if (entityplayer1 instanceof org.leavesmc.leaves.replay.ServerPhotographer) {
+ continue;
+ }
+ // Leaves end - skip photographer
+
+ onlinePlayers.add(entityplayer1);
+ }
+ if (!onlinePlayers.isEmpty()) {
+ player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers, player));
+ }
+
+ player.sentListPacket = true;
+ player.suppressTrackerForLogin = false;
+ ((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player);
+
+ this.sendLevelInfo(player, worldserver1);
+
+ if (player.level() == worldserver1 && !worldserver1.players().contains(player)) {
+ worldserver1.addNewPlayer(player);
+ this.server.getCustomBossEvents().onPlayerConnect(player);
+ }
+
+ worldserver1 = player.level();
+ java.util.Iterator<net.minecraft.world.effect.MobEffectInstance> iterator = player.getActiveEffects().iterator();
+ while (iterator.hasNext()) {
+ MobEffectInstance mobeffect = iterator.next();
+ playerconnection.send(new ClientboundUpdateMobEffectPacket(player.getId(), mobeffect, false));
+ }
+
+ if (player.isDeadOrDying()) {
+ net.minecraft.core.Holder<net.minecraft.world.level.biome.Biome> plains = worldserver1.registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME)
+ .getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
+ new net.minecraft.world.level.chunk.EmptyLevelChunk(worldserver1, player.chunkPosition(), plains),
+ worldserver1.getLightEngine(), null, null, false)
+ );
+ }
+ }
+ // Leaves end - replay mod api
+
public void placeNewPlayer(final Connection connection, final ServerPlayer player, final CommonListenerCookie cookie) {
player.isRealPlayer = true; // Paper
player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
@@ -295,6 +415,7 @@ public abstract class PlayerList {
// player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players)); // CraftBukkit - replaced with loop below
this.players.add(player);
+ this.realPlayers.add(player); // Leaves - replay api
this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); // Spigot
this.playersByUUID.put(player.getUUID(), player);
// this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player))); // CraftBukkit - replaced with loop below
@@ -514,6 +635,7 @@ public abstract class PlayerList {
}
protected void save(final ServerPlayer player) {
+ if (player instanceof org.leavesmc.leaves.replay.ServerPhotographer) return; // Leaves - skip photographer
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
player.lastSave = System.nanoTime(); // Folia - region threading - changed to nanoTime tracking
this.playerIo.save(player);
@@ -528,6 +650,47 @@ public abstract class PlayerList {
}
}
+ // Leaves start - replay mod api
+ public void removePhotographer(org.leavesmc.leaves.replay.ServerPhotographer entityplayer) {
+ ServerLevel worldserver = entityplayer.level();
+
+ entityplayer.awardStat(Stats.LEAVE_GAME);
+
+ if (entityplayer.containerMenu != entityplayer.inventoryMenu) {
+ entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT);
+ }
+
+ if (server.isSameThread()) entityplayer.doTick();
+
+ if (this.collideRuleTeamName != null) {
+ final net.minecraft.world.scores.Scoreboard scoreBoard = this.server.getLevel(Level.OVERWORLD).getScoreboard();
+ final PlayerTeam team = scoreBoard.getPlayersTeam(this.collideRuleTeamName);
+ if (entityplayer.getTeam() == team && team != null) {
+ scoreBoard.removePlayerFromTeam(entityplayer.getScoreboardName(), team);
+ }
+ }
+
+ worldserver.removePlayerImmediately(entityplayer, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
+ entityplayer.retireScheduler();
+ entityplayer.getAdvancements().stopListening();
+ this.players.remove(entityplayer);
+ // Leaves - guard name removal so a photographer sharing a real player's name won't evict the real player's mapping
+ final String nameKey = entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT);
+ if (this.playersByName.get(nameKey) == entityplayer) {
+ this.playersByName.remove(nameKey);
+ }
+ this.server.getCustomBossEvents().onPlayerDisconnect(entityplayer);
+ UUID uuid = entityplayer.getUUID();
+ ServerPlayer entityplayer1 = this.playersByUUID.get(uuid);
+
+ if (entityplayer1 == entityplayer) {
+ this.playersByUUID.remove(uuid);
+ }
+
+ this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity());
+ }
+ // Leaves end - replay mod api
+
public net.kyori.adventure.text.@Nullable Component remove(final ServerPlayer player) { // CraftBukkit - return string // Paper - return Component
// Paper start - Fix kick event leave message not being sent
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
@@ -601,6 +764,7 @@ public abstract class PlayerList {
player.getBukkitEntity().packetProcessor.close(); // Folia - region threading
player.getAdvancements().stopListening();
this.players.remove(player);
+ this.realPlayers.remove(player); // Leaves - replay api
this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
if (me.earthme.luminol.config.modules.misc.UsernameCheckConfig.allowOldPlayersJoin) this.playedPlayers.remove(player.getGameProfile().name()); // Leaf - Configurable vanilla username check
this.server.getCustomBossEvents().onPlayerDisconnect(player);
@@ -912,15 +1076,15 @@ public abstract class PlayerList {
}
public String[] getPlayerNamesArray() {
- List<ServerPlayer> players = new java.util.ArrayList<>(this.players); // Folia - region threading
- String[] names = new String[players.size() + this.server.getBotList().bots.size()]; // Leaves - fakeplayer support
+ List<ServerPlayer> players = new java.util.ArrayList<>(this.realPlayers); // Folia - region threading // Lophine - fakeplayer support
+ String[] names = new String[this.realPlayers.size() + this.server.getBotList().bots.size()]; // Leaves - fakeplayer support
- for (int i = 0; i < players.size(); i++) { // Folia - region threading
- names[i] = players.get(i).getGameProfile().name(); // Folia - region threading
+ for (int i = 0; i < this.realPlayers.size(); i++) { // Folia - region threading // Leaves - only real players
+ names[i] = this.realPlayers.get(i).getGameProfile().name(); // Folia - region threading // Leaves - only real players
}
// Leaves start - fakeplayer support
- for (int i = this.players.size(); i < names.length; ++i) {
- names[i] = this.server.getBotList().bots.get(i - this.players.size()).gameProfile.name();
+ for (int i = this.realPlayers.size(); i < names.length; ++i) { // Leaves - only real players
+ names[i] = this.server.getBotList().bots.get(i - this.realPlayers.size()).gameProfile.name(); // Leaves - only real players
}
// Leaves end - fakeplayer support
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index a2f44e4354f6aa1c0502cba40cadaad59193b169..a3c19d725e03c07de6708f3c2d092e0b9aea69c2 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -261,7 +261,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
public int useItemRemaining;
protected int fallFlyTicks;
private long lastKineticHitFeedbackTime = -2147483648L;
- private BlockPos lastPos;
+ protected BlockPos lastPos;
private Optional<BlockPos> lastClimbablePos = Optional.empty();
private @Nullable DamageSource lastDamageSource;
private long lastDamageStamp = Long.MIN_VALUE; // Folia - region threading
@@ -0,0 +1,144 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 8 Mar 2026 23:56:06 +0800
Subject: [PATCH] Leaves: Creative fly no clip
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/da12a58e8d3bd3cd13b52a60676d5a1e03acd30a/leaves-server/minecraft-patches/features/0049-Creative-fly-no-clip.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/entity/ExperienceOrb.java b/net/minecraft/world/entity/ExperienceOrb.java
index e302c6198d71782b524391329aa5c89d2b3e0ccf..2312803297321f66c9057bc54ce56dd17ecb6f1f 100644
--- a/net/minecraft/world/entity/ExperienceOrb.java
+++ b/net/minecraft/world/entity/ExperienceOrb.java
@@ -199,7 +199,7 @@ public class ExperienceOrb extends Entity {
Player prevTarget = this.followingPlayer; // CraftBukkit - store old target
if (this.followingPlayer == null || this.followingPlayer.isSpectator() || this.followingPlayer.distanceToSqr(this) > 64.0) {
Player nearestPlayer = this.level().getNearestPlayer(this, 8.0);
- if (nearestPlayer != null && !nearestPlayer.isSpectator() && !nearestPlayer.isDeadOrDying()) {
+ if (nearestPlayer != null && !nearestPlayer.isCreativeFlyOrSpectator() && !nearestPlayer.isDeadOrDying()) { // Leaves - creative no clip
this.followingPlayer = nearestPlayer;
} else {
this.followingPlayer = null;
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 20a76138a8625663cf608e4ef97cc8ca4085b844..97057675369875ed71c228a87f5a4d3c3489dded 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -280,8 +280,8 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.cullTask != null) this.cullTask.requestCullSignal(); // Luminol - Ray tracing entity tracker
// Luminol end
- this.noPhysics = this.isSpectator();
- if (this.isSpectator() || this.isPassenger()) {
+ this.noPhysics = this.isCreativeFlyOrSpectator(); // Leaves - creative no clip
+ if (this.isCreativeFlyOrSpectator() || this.isPassenger()) { // Leaves - creative no clip
this.setOnGround(false);
}
@@ -407,7 +407,7 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) {
Pose desiredPose = this.getDesiredPose();
Pose actualPose;
- if (this.isSpectator() || this.isPassenger() || this.canPlayerFitWithinBlocksAndEntitiesWhen(desiredPose)) {
+ if (this.isCreativeFlyOrSpectator() || this.isPassenger() || this.canPlayerFitWithinBlocksAndEntitiesWhen(desiredPose)) { // Leaves - creative no clip
actualPose = desiredPose;
} else if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.CROUCHING)) {
actualPose = Pose.CROUCHING;
@@ -536,7 +536,7 @@ public abstract class Player extends Avatar implements ContainerUser {
this.updateSwingTime();
this.yHeadRot = this.getYRot();
this.setSpeed((float)this.getAttributeValue(Attributes.MOVEMENT_SPEED));
- if (this.getHealth() > 0.0F && !this.isSpectator()) {
+ if (this.getHealth() > 0.0F && !this.isCreativeFlyOrSpectator()) { // Leaves - creative no clip
AABB pickupArea;
if (this.isPassenger() && !this.getVehicle().isRemoved()) {
pickupArea = this.getBoundingBox().minmax(this.getVehicle().getBoundingBox()).inflate(1.0, 0.0, 1.0);
@@ -1849,6 +1849,26 @@ public abstract class Player extends Avatar implements ContainerUser {
return this.gameMode() == GameType.SPECTATOR;
}
+ // Leaves start - creative no clip
+ public boolean isCreativeFlyOrSpectator() {
+ return isSpectator() || (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeNoClip && isCreative() && getAbilities().flying);
+ }
+
+ public boolean canSpectatingPlace(final net.minecraft.world.level.LevelReader world, final BlockState state, final BlockPos pos, final net.minecraft.world.phys.shapes.CollisionContext context) {
+ if (this.isCreativeFlyOrSpectator()) {
+ net.minecraft.world.phys.shapes.VoxelShape voxelShape = state.getCollisionShape(world, pos, context);
+ return voxelShape.isEmpty() || world.isUnobstructed(this, voxelShape.move(pos.getX(), pos.getY(), pos.getZ()));
+ } else {
+ return world.isUnobstructed(state, pos, context);
+ }
+ }
+
+ @Override
+ public boolean isCollidable(final boolean ignoreClimbing) {
+ return !isCreativeFlyOrSpectator() && super.isCollidable(ignoreClimbing);
+ }
+ // Leaves end - creative no clip
+
@Override
public boolean isPickable() {
return !this.isSpectator() && super.isPickable();
diff --git a/net/minecraft/world/item/BlockItem.java b/net/minecraft/world/item/BlockItem.java
index 2e2a8af12f249ec5bd0935fd13f5acbd0a777b5f..07b84bd0144e133d13e8e033a8998f3cf674f746 100644
--- a/net/minecraft/world/item/BlockItem.java
+++ b/net/minecraft/world/item/BlockItem.java
@@ -158,8 +158,9 @@ public class BlockItem extends Item {
Player player = context.getPlayer();
// CraftBukkit start
Level world = context.getLevel(); // Paper - Cancel hit for vanished players
+ CollisionContext collisionContext = player == null ? CollisionContext.empty() : CollisionContext.placementContext(player); // Leaves - creative no clip
boolean canBuild = (!this.mustSurvive() || stateForPlacement.canSurvive(world, context.getClickedPos()))
- && world.checkEntityCollision(stateForPlacement, player, CollisionContext.placementContext(player), context.getClickedPos(), true); // Paper - Cancel hit for vanished players
+ && ((fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeNoClip && context.getPlayer() != null) ? context.getPlayer().canSpectatingPlace(world, stateForPlacement, context.getClickedPos(), collisionContext) : world.checkEntityCollision(stateForPlacement, player, collisionContext, context.getClickedPos(), true)); // Paper - Cancel hit for vanished players // Leaves - creative no clip
org.bukkit.entity.Player bukkitPlayer = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null;
org.bukkit.event.block.BlockCanBuildEvent event = new org.bukkit.event.block.BlockCanBuildEvent(
diff --git a/net/minecraft/world/item/StandingAndWallBlockItem.java b/net/minecraft/world/item/StandingAndWallBlockItem.java
index cb0a4a9865df69e5504a86de6c144bc4450bd19a..596fb91fccb4c8d6854fa859f9ee357c6d22a81e 100644
--- a/net/minecraft/world/item/StandingAndWallBlockItem.java
+++ b/net/minecraft/world/item/StandingAndWallBlockItem.java
@@ -44,7 +44,7 @@ public class StandingAndWallBlockItem extends BlockItem {
// return stateForPlacement != null && level.isUnobstructed(stateForPlacement, pos, CollisionContext.empty()) ? stateForPlacement : null;
// CraftBukkit start
if (stateForPlacement != null) {
- boolean defaultReturn = level.isUnobstructed(stateForPlacement, pos, CollisionContext.empty());
+ boolean defaultReturn = (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeNoClip && context.getPlayer() != null) ? context.getPlayer().canSpectatingPlace(level, stateForPlacement, pos, CollisionContext.empty()) : level.isUnobstructed(stateForPlacement, pos, CollisionContext.empty()); // Leaves - creative no clip
org.bukkit.entity.Player player = (context.getPlayer() instanceof net.minecraft.server.level.ServerPlayer serverPlayer) ? serverPlayer.getBukkitEntity() : null;
org.bukkit.event.block.BlockCanBuildEvent event = new org.bukkit.event.block.BlockCanBuildEvent(org.bukkit.craftbukkit.block.CraftBlock.at(context.getLevel(), pos), player, stateForPlacement.asBlockData(), defaultReturn, org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand())); // Paper - Expose hand in BlockCanBuildEvent
diff --git a/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java b/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java
index 6205f52ecad24f80d21b924945c5ff06c6704aca..d84159df4d2a0379ffbb6bdb0807b4a02dbec71e 100644
--- a/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java
@@ -153,7 +153,7 @@ public class ShulkerBoxBlockEntity extends RandomizableContainerBlockEntity impl
List<Entity> entities = level.getEntities(null, aabb);
if (!entities.isEmpty()) {
for (Entity entity : entities) {
- if (entity.getPistonPushReaction() != PushReaction.IGNORE) {
+ if (entity.getPistonPushReaction() != PushReaction.IGNORE && !(entity instanceof net.minecraft.world.entity.player.Player player && player.isCreativeFlyOrSpectator())) { // Leaves - creative no clip
entity.move(
MoverType.SHULKER_BOX,
new Vec3(
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index 2ecb10fe97d15954e44c61247eabc8818eb16f34..22663ad55f669081b43644ad2cf1bd4aac48b745 100644
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -168,7 +168,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
dz = movement.getStepZ();
}
- entity.setDeltaMovement(dx, dy, dz);
+ if (!(entity instanceof net.minecraft.world.entity.player.Player player) || !player.isCreativeFlyOrSpectator()) entity.setDeltaMovement(dx, dy, dz); // Leaves - creative no clip
// Paper - EAR items stuck in slime pushed by a piston
entity.activatedTick = Math.max(entity.activatedTick, io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + 10); // Folia - region threading
entity.activatedImmunityTick = Math.max(entity.activatedImmunityTick, io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + 10); // Folia - region threading
@@ -204,6 +204,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
}
private static void moveEntityByPiston(final Direction pistonDirection, final Entity entity, final double delta, final Direction movement) {
+ if (entity instanceof net.minecraft.world.entity.player.Player player && player.isCreativeFlyOrSpectator()) return; // Leaves - creative no clip
NOCLIP.set(pistonDirection);
Vec3 previousPos = entity.position();
entity.move(MoverType.PISTON, new Vec3(delta * movement.getStepX(), delta * movement.getStepY(), delta * movement.getStepZ()));
@@ -10,20 +10,20 @@ Licensed under: MIT
This patch is Powered by fabric-carpet(https://github.com/gnembon/fabric-carpet)
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index d4fe03fd766caca1d7693a5317460ca1a9b9fa4f..a821deaa5c076151336762d17a8da45abb4c43cd 100644
index d036018ee64995ee754296014888ee70c0ea5ab3..aa782c6441cdce3eb39aefb28d40f3b1970d4e62 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -232,8 +232,30 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
flag |= validator.getAsBoolean(); // Paper - note: this is not a validator, it's what adds/sucks in items
@@ -239,8 +239,30 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
changed |= action.getAsBoolean(); // Paper - note: this is not a validator, it's what adds/sucks in items
}
+ // Leaves start - Wool hopper counter
+ if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled()) {
+ net.minecraft.world.item.DyeColor woolColor = org.leavesmc.leaves.util.WoolUtils.getWoolColorAtPosition(level, blockEntity.getBlockPos().relative(state.getValue(HopperBlock.FACING)));
+ net.minecraft.world.item.DyeColor woolColor = org.leavesmc.leaves.util.WoolUtils.getWoolColorAtPosition(level, entity.getBlockPos().relative(state.getValue(HopperBlock.FACING)));
+ if (woolColor != null) {
+ for (int i = 0; i < Short.MAX_VALUE; i++) {
+ flag |= suckInItems(level, blockEntity);
+ if (!flag) {
+ changed |= suckInItems(level, entity);
+ if (!changed) {
+ break;
+ } else {
+ woolHopperCounter(level, pos, state, HopperBlockEntity.getContainerAt(level, pos));
@@ -33,32 +33,32 @@ index d4fe03fd766caca1d7693a5317460ca1a9b9fa4f..a821deaa5c076151336762d17a8da45a
+ }
+ // Leaves end - Wool hopper counter
+
if (flag) {
blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
if (changed) {
entity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
+ // Leaves start - Wool hopper counter
+ if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && woolHopperCounter(level, pos, state, HopperBlockEntity.getContainerAt(level, pos))) {
+ blockEntity.setCooldown(0);
+ entity.setCooldown(0);
+ return true;
+ }
+ // Leaves end - Wool hopper counter
setChanged(level, pos, state);
// Leaves start - Lithium Sleeping Block Entity
if (me.earthme.luminol.config.modules.optimizations.LeavesSleepingBlockEntityConfig.enabled
@@ -465,6 +487,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -491,6 +513,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
// Paper end - Perf: Optimize Hoppers
private static boolean ejectItems(Level level, BlockPos pos, HopperBlockEntity blockEntity) {
private static boolean ejectItems(final Level level, final BlockPos blockPos, final HopperBlockEntity self) {
+ // Leaves start - hopper counter
+ if (org.leavesmc.leaves.util.HopperCounter.isEnabled()) {
+ if (woolHopperCounter(level, pos, level.getBlockState(pos), HopperBlockEntity.getContainerAt(level, pos))) {
+ if (woolHopperCounter(level, blockPos, level.getBlockState(blockPos), HopperBlockEntity.getContainerAt(level, blockPos))) {
+ return true;
+ }
+ }
+ // Leaves end - hopper counter
Container attachedContainer = me.earthme.luminol.config.modules.optimizations.LeavesSleepingBlockEntityConfig.enabled ? blockEntity.getInsertInventory(level) : getAttachedContainer(level, pos, blockEntity); // Leaves - Lithium Sleeping Block Entity
if (attachedContainer == null) {
Container container = me.earthme.luminol.config.modules.optimizations.LeavesSleepingBlockEntityConfig.enabled ? self.getInsertInventory(level) : getAttachedContainer(level, blockPos, self); // Leaves - Lithium Sleeping Block Entity
if (container == null) {
return false;
@@ -541,6 +570,26 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -512,6 +541,26 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
}
@@ -72,7 +72,7 @@ index d4fe03fd766caca1d7693a5317460ca1a9b9fa4f..a821deaa5c076151336762d17a8da45a
+ for (int i = 0; i < container.getContainerSize(); ++i) {
+ if (!container.getItem(i).isEmpty()) {
+ ItemStack itemstack = container.getItem(i);
+ org.leavesmc.leaves.util.HopperCounter.getCounter(woolColor).add(level, itemstack);
+ org.leavesmc.leaves.util.HopperCounter.getCounter(woolColor).add(level.getServer(), itemstack);
+ container.setItem(i, ItemStack.EMPTY);
+ }
+ }
@@ -82,14 +82,14 @@ index d4fe03fd766caca1d7693a5317460ca1a9b9fa4f..a821deaa5c076151336762d17a8da45a
+ }
+ // Leaves end - hopper counter
+
private static int[] getSlots(Container container, Direction direction) {
private static int[] getSlots(final Container container, final Direction direction) {
if (container instanceof WorldlyContainer worldlyContainer) {
return worldlyContainer.getSlotsForFace(direction);
@@ -683,6 +732,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -606,6 +655,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
public static boolean addItem(Container container, ItemEntity item) {
+ if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && item.isRemoved()) return false; // Leaves - Wool hopper counter
boolean flag = false;
public static boolean addItem(final Container container, final ItemEntity entity) {
+ if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && entity.isRemoved()) return false; // Leaves - Wool hopper counter
boolean changed = false;
// CraftBukkit start
if (org.bukkit.event.inventory.InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
@@ -0,0 +1,223 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 3 Dec 2025 16:28:34 +0800
Subject: [PATCH] Global Entities Counter
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
index eedbeb005d3c8090333c36b9857c837dfb75dbd4..7ea91dbfb988aff3215a91cf62c9beae94461484 100644
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
@@ -558,6 +558,9 @@ public final class RegionizedWorldData {
public final Map<Long, ChunkSectionItemEntityMovementTracker> itemEntityMovementTrackerMap = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>();
// Luminol end
+ public int uniqueId = -1; // Lophine - Global Entities Counter
+ public boolean underGlobalEntitiesCounter = false; // Lophine - Global Entities Counter
+
public final TickRegions.TickRegionData regionData;
public RegionizedWorldData(final ServerLevel world, final TickRegions.TickRegionData regionData) {
@@ -570,6 +573,15 @@ public final class RegionizedWorldData {
this.turbo = new io.papermc.paper.redstone.RedstoneWireTurbo((RedStoneWireBlock)Blocks.REDSTONE_WIRE);
this.regionData = regionData;
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ uniqueId = fun.bm.lophine.utils.EntitiesCounterUtil.generateUniqueId();
+ fun.bm.lophine.utils.EntitiesCounterUtil.reportAreaMap(world, spawnChunkTracker, uniqueId);
+ if (!fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(world, loadedEntities, uniqueId);
+ underGlobalEntitiesCounter = true;
+ }
+ // Lophine end - Global Entities Counter
+
// tasks may be drained before the region ticks, so we must set up the tick data early just in case
this.updateTickData();
}
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index 27389ff98942e27c2a877ea5b671caa31353d18c..76fa17ce0afc7ff1c0b2b84aa2baddd2ba18c1a5 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -513,6 +513,26 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
this.chunkMap.tick(haveTime);
profiler.pop();
this.clearCache();
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.level.getCurrentWorldData();
+ if (regionizedWorldData != null) {
+ if (regionizedWorldData.underGlobalEntitiesCounter) {
+ if (regionizedWorldData.getLocalPlayers().isEmpty()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onWorldDataUnload(level, regionizedWorldData.uniqueId);
+ regionizedWorldData.underGlobalEntitiesCounter = false;
+ }
+ } else {
+ if (!regionizedWorldData.getLocalPlayers().isEmpty()) {
+ regionizedWorldData.uniqueId = fun.bm.lophine.utils.EntitiesCounterUtil.generateUniqueId();
+ fun.bm.lophine.utils.EntitiesCounterUtil.reportAreaMap(level, regionizedWorldData.spawnChunkTracker, regionizedWorldData.uniqueId);
+ fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(level, (ca.spottedleaf.moonrise.common.list.ReferenceList<Entity>) regionizedWorldData.getLoadedEntities(), regionizedWorldData.uniqueId);
+ regionizedWorldData.underGlobalEntitiesCounter = true;
+ }
+ }
+ }
+ }
+ // Lophine end - Global Entities Counter
}
private void tickChunks() {
@@ -577,7 +597,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
}
spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, null, true); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
} else {
- spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ spawnCookie = fun.bm.lophine.utils.EntitiesCounterUtil.createSpawnState(level, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
+ } else {
+ spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
+ }
+ // Lophine end - Global Entities Counter
}
} finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.MOB_SPAWN_ENTITY_COUNT); } // Folia - profiler
// Paper end - Optional per player mob spawns
@@ -585,7 +611,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
boolean doMobSpawning = this.level.getGameRules().get(GameRules.SPAWN_MOBS) && !this.level.getLocalPlayers().isEmpty(); // CraftBukkit // Folia - region threading
int tickSpeed = this.level.getGameRules().get(GameRules.RANDOM_TICK_SPEED);
List<MobCategory> spawningCategories;
- if (doMobSpawning && (this.spawnEnemies || this.spawnFriendlies)) { // Paper
+ if (spawnCookie != null && doMobSpawning && (this.spawnEnemies || this.spawnFriendlies)) { // Paper // Lophine - Global Entities Counter
// Paper start - PlayerNaturallySpawnCreaturesEvent
for (ServerPlayer player : this.level.getLocalPlayers()) { // Folia - region threading
int chunkRange = Math.min(level.spigotConfig.mobSpawnRange, player.getBukkitEntity().getViewDistance());
@@ -645,7 +671,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
this.level.tickThunder(chunk);
}
- if (!spawningCategories.isEmpty()) {
+ if (spawnCookie != null && !spawningCategories.isEmpty()) { // Lophine - Global Entities Counter
if (this.level.getWorldBorder().isWithinBounds(chunkPos)) { // Paper - rewrite chunk system
NaturalSpawner.spawnForChunk(this.level, chunk, spawnCookie, spawningCategories);
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index a7cebb797973cde399dc30c696b064efd40874f2..1d60c20649b2a6469bfceb5b44c38bfd133e21eb 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -808,6 +808,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
public void tick(BooleanSupplier haveTime, final io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ if (fun.bm.lophine.utils.EntitiesCounterUtil.canRunNewTask(this)) fun.bm.lophine.utils.EntitiesCounterUtil.tick(this);
+ }
+ // Lophine end - Global Entities Counter
final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - regionised ticking
final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle foliaProfiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler
ProfilerFiller profiler = Profiler.get();
@@ -2902,6 +2907,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public void close() throws IOException {
super.close();
//this.entityManager.close(); // Paper - rewrite chunk system
+ // Lophine start - Precise mob cap
+ if (!fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onWorldUnload(this);
+ }
+ // Lophine end - Precise mob cap
}
@Override
@@ -3136,6 +3146,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
entity.inWorld = true; // CraftBukkit - Mark entity as in world
entity.valid = true; // CraftBukkit
ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server
+ // Lophine start - Precise mob cap
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled() && !fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onEntityTrackingStart(ServerLevel.this, entity);
+ }
+ // Lophine end - Precise mob cap
// Paper start - Entity origin API
if (entity.origin == null) {
entity.origin = entity.position();
@@ -3151,6 +3166,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public void onTrackingEnd(final Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot
+ // Lophine start - Precise mob cap
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled() && !fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onEntityTrackingEnd(ServerLevel.this, entity);
+ }
+ // Lophine end - Precise mob cap
ServerLevel.this.getCurrentWorldData().removeLoadedEntity(entity); // Folia - region threading
// Spigot start // TODO I don't think this is needed anymore
if (entity instanceof Player player) {
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
index fc29654dd7ee3329edf1ccf705f45631d0ecc079..042f026f707e1a75b4ec7dc231e0eeb1b5afacc3 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -813,6 +813,44 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs
}
}
} else {
+ // Lophine start - fix some bug if player is cross scheduler >> to remove monster if the region don't have any valid player
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ List<net.minecraft.server.level.ServerPlayer> playerList = this.level().getServer().getPlayerList().getPlayers();
+ if (!playerList.isEmpty()) {
+ double d = -1.0;
+ Vec3 vec3 = null;
+ for (net.minecraft.server.level.ServerPlayer player1 : playerList) {
+ if (player1.level() != this.level()) continue;
+ double d1 = player1.distanceToSqr(this.position());
+ if (d == -1.0 || d1 < d) {
+ d = d1;
+ vec3 = player1.position();
+ }
+ }
+ if (vec3 != null) {
+ // copy from PaperMC
+ // Paper start - Configurable despawn distances
+ final io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = this.level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory());
+ final io.papermc.paper.configuration.type.DespawnRange.Shape shape = this.level().paperConfig().entities.spawning.despawnRangeShape;
+ final double dy = Math.abs(vec3.y - this.getY());
+ final double dySqr = Mth.square(dy);
+ final double dxSqr = Mth.square(vec3.x - this.getX());
+ final double dzSqr = Mth.square(vec3.z - this.getZ());
+ final double distanceSquared = dxSqr + dzSqr + dySqr;
+ // Despawn if hard/soft limit is exceeded
+ if (despawnRangePair.hard().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy) && this.removeWhenFarAway(distanceSquared)) {
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
+ }
+
+ if (despawnRangePair.soft().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy)) {
+ if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && this.removeWhenFarAway(distanceSquared)) {
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
+ }
+ }
+ }
+ }
+ }
+ // Lophine end - fix some bug if player is cross scheduler >> to remove monster if the region don't have any valid player
this.noActionTime = 0;
}
}
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index b3b8160927147468c1dd4a30fac51f96a9d60c9a..cd20d10ee4cd2fe98131c9a93367ae133f96b8d4 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -121,7 +121,7 @@ public final class NaturalSpawner {
return new NaturalSpawner.SpawnState(spawnableChunkCount, mobCounts, spawnPotential, localMobCapCalculator);
}
- private static Biome getRoughBiome(final BlockPos pos, final ChunkAccess chunk) {
+ public static Biome getRoughBiome(final BlockPos pos, final ChunkAccess chunk) { // Lophine - protected -> public
return chunk.getNoiseBiome(QuartPos.fromBlock(pos.getX()), QuartPos.fromBlock(pos.getY()), QuartPos.fromBlock(pos.getZ())).value();
}
@@ -628,7 +628,7 @@ public final class NaturalSpawner {
private @Nullable EntityType<?> lastCheckedType;
private double lastCharge;
- private SpawnState(
+ public SpawnState( // Lophine - protected -> public
final int spawnableChunkCount,
final Object2IntOpenHashMap<MobCategory> mobCategoryCounts,
final PotentialCalculator spawnPotential,
@@ -0,0 +1,237 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Sat, 7 Feb 2026 23:57:50 +0800
Subject: [PATCH] Leaves: Catch update suppression crash
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/network/PacketProcessor.java b/net/minecraft/network/PacketProcessor.java
index 24f5b890b0126fc817863f99b676da1a548f7608..a25bc31c04778bf12e3b6301ffcfb2275fcc2d90 100644
--- a/net/minecraft/network/PacketProcessor.java
+++ b/net/minecraft/network/PacketProcessor.java
@@ -106,7 +106,23 @@ public class PacketProcessor implements AutoCloseable {
final int packetTimerId = profiler.getOrCreateTimerAndStart(() -> "Packet Handler: ".concat(ListenerAndPacket.this.packet.getClass().getName())); try { // Folia - profiler
this.packet.handle(this.listener);
} finally { profiler.stopTimer(packetTimerId); } // Folia - profiler
+ // Lophine start - catch update suppression crash
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ if (this.listener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) {
+ exception.providePlayer(gamePacketListener.player);
+ }
+ exception.consume();
+ // Lophine end - catch update suppression crash
} catch (Exception var3) {
+ // Lophine start - catch update suppression crash
+ if (var3.getCause() instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ if (this.listener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) {
+ exception.providePlayer(gamePacketListener.player);
+ }
+ exception.consume();
+ }
+
+ // Lophine end - catch update suppression crash
if (var3 instanceof ReportedException re && re.getCause() instanceof OutOfMemoryError) {
throw PacketUtils.makeReportedException(var3, this.packet, this.listener);
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 5889aa815ab02261f26048c5ef43f5bdfa2939fc..af245af0fba14892095961a71925f3a53ce3d477 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2022,11 +2022,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
try {
foliaProfiler.startTimer(level.tickTimerId); try { // Folia - profiler
level.tick(haveTime, region); // Folia - region threading
+ // Lophine start - catch update suppression crash
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ exception.provideLevel(level);
+ exception.consume();
+ // Lophine end - catch update suppression crash
} finally { foliaProfiler.stopTimer(level.tickTimerId); } // Folia - profiler
} catch (Throwable var7) {
- CrashReport report = CrashReport.forThrowable(var7, "Exception ticking world");
- level.fillReportDetails(report);
- throw new ReportedException(report);
+ // Lophine start - catch update suppression crash
+ org.leavesmc.leaves.util.UpdateSuppressionException updateSuppressionException = null;
+ if (var7 instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ updateSuppressionException = exception;
+ } else if (var7.getCause() instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ updateSuppressionException = exception;
+ }
+
+ if (updateSuppressionException != null) {
+ updateSuppressionException.provideLevel(level);
+ updateSuppressionException.consume();
+ } else {
+ CrashReport report = CrashReport.forThrowable(var7, "Exception ticking world");
+ level.fillReportDetails(report);
+ throw new ReportedException(report);
+ }
+ // Lophine end - catch update suppression crash
}
profiler.pop();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 1d60c20649b2a6469bfceb5b44c38bfd133e21eb..b884e06a5e9d6a93c548820a99e5d05157e9d128 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -967,7 +967,18 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
// Kaiiju end
profiler.push("tick");
- this.guardEntityTick(this::tickNonPassenger, entity);
+ // Lophine start - catch update suppression crash
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.mergedUpdateSuppressionCrashEnabled()) {
+ try {
+ this.guardEntityTick(this::tickNonPassenger, entity);
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ exception.provideLevel(this);
+ exception.consume();
+ }
+ } else {
+ this.guardEntityTick(this::tickNonPassenger, entity);
+ }
+ // Lophine end - catch update suppression crash
profiler.pop();
}
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 4f6010285a5ff9cf939248c4d93043133680d383..020b2fcb5213a618b557f0578a7d44db5a8dc109 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1133,6 +1133,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
// Folia - region threading - move to main tick loop where we can detect duplicates
// CraftBukkit end
+ // Lophine start - catch update suppression crash
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ exception.providePlayer(this);
+ exception.provideLevel(this.level());
+ exception.consume();
+ // Lophine end - catch update suppression crash
} catch (Throwable var4) {
CrashReport report = CrashReport.forThrowable(var4, "Ticking player");
CrashReportCategory category = report.addCategory("Player being ticked");
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 03c155140da7300f6f934aff323e0daed1b63366..ee84484ca5aac03b9f321398c4d85311632b5697 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -1459,7 +1459,17 @@ public abstract class Entity
}
if (shouldVibrate) {
- this.level().gameEvent(GameEvent.STEP, this.position(), GameEvent.Context.of(this, blockState));
+ // Lophine start - catch update suppression crash
+ try {
+ this.level().gameEvent(GameEvent.STEP, this.position(), GameEvent.Context.of(this, blockState));
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ exception.provideBlock(level, pos, blockState.getBlock());
+ if (this instanceof net.minecraft.server.level.ServerPlayer player) {
+ exception.providePlayer(player);
+ }
+ exception.consume();
+ }
+ // Lophine end - catch update suppression crash
}
return true;
diff --git a/net/minecraft/world/level/block/ShulkerBoxBlock.java b/net/minecraft/world/level/block/ShulkerBoxBlock.java
index 08ad9f418fbe733b788ec27e13b61994c3a5f09d..f9dacc278200b05acb385e1f1cbf858e43d0d9f4 100644
--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
@@ -181,7 +181,16 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
@Override
protected int getAnalogOutputSignal(final BlockState state, final Level level, final BlockPos pos, final Direction direction) {
- return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
+ // Lophine start - catch update suppression crash
+ try {
+ return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
+ } catch (ClassCastException ex) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.mergedUpdateSuppressionCrashEnabled()) {
+ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, null, this, null, ex);
+ }
+ throw ex;
+ }
+ // Lophine end - catch update suppression crash
}
public @Nullable DyeColor getColor() {
diff --git a/net/minecraft/world/level/block/state/StateHolder.java b/net/minecraft/world/level/block/state/StateHolder.java
index b72861c0164ebb13b6fc3e78cd7ce0a2c484f22d..5bf43973c8de8c2f33d384f28fdd06864cdf9319 100644
--- a/net/minecraft/world/level/block/state/StateHolder.java
+++ b/net/minecraft/world/level/block/state/StateHolder.java
@@ -118,7 +118,16 @@ public abstract class StateHolder<O, S> implements ca.spottedleaf.moonrise.patch
if (ret != null) {
return ret;
}
- throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner);
+ // Lophine start - catch update suppression crash
+ IllegalArgumentException iae = new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner);
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.mergedUpdateSuppressionCrashEnabled()) {
+ org.leavesmc.leaves.util.UpdateSuppressionException exception = new org.leavesmc.leaves.util.UpdateSuppressionException(null, null, null, null, iae);
+ if (exception.getStackTrace()[1].getClassName().startsWith("net.minecraft")) {
+ throw exception;
+ }
+ }
+ throw iae;
+ // Lophine end - catch update suppression crash
// Paper end - optimise blockstate property access
}
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 3708f9ffc46a5b1c038c0e7b2ce84802e2b22397..241c43170b5020c1521f43d349813586ba1f69a5 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -400,6 +400,8 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
return null;
} else {
Block newBlock = state.getBlock();
+ // Lophine start - catch update suppression crash
+ try {
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(localX, y, localZ, state);
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(localX, y, localZ, state);
this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(localX, y, localZ, state);
@@ -468,6 +470,11 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
this.markUnsaved();
return oldState;
}
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ exception.provideBlock(this.level, pos, newBlock);
+ throw exception;
+ }
+ // Lophine end - catch update suppression crash
}
}
}
diff --git a/net/minecraft/world/level/redstone/NeighborUpdater.java b/net/minecraft/world/level/redstone/NeighborUpdater.java
index 9b8d63f69ed1101f1b7b2728690e35165b9aeb99..6358787f3c7dcfa599b2949613236fa8de025096 100644
--- a/net/minecraft/world/level/redstone/NeighborUpdater.java
+++ b/net/minecraft/world/level/redstone/NeighborUpdater.java
@@ -87,9 +87,24 @@ public interface NeighborUpdater {
} finally { if (levelChunk != null) levelChunk.getChunkHot().stopTickingAndCount(); } // KioCG
// Spigot start
} catch (StackOverflowError ex) {
+ // Lophine start - catch update suppression crash
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.mergedUpdateSuppressionCrashEnabled()) {
+ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, level, changedBlock, null, ex);
+ }
+ // Lophine end - catch update suppression crash
level.lastPhysicsProblem = pos.immutable();
// Spigot end
} catch (Throwable var9) {
+ // Lophine start - catch update suppression crash
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.mergedUpdateSuppressionCrashEnabled()) {
+ if (var9 instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ exception.provideBlock(level, pos, changedBlock);
+ throw exception;
+ }
+ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, level, changedBlock, null, var9);
+ }
+
+ // Lophine end - catch update suppression crash
CrashReport report = CrashReport.forThrowable(var9, "Exception while updating neighbours");
CrashReportCategory category = report.addCategory("Block being updated");
category.setDetail(
@@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Sat, 15 Nov 2025 01:12:39 +0800
Subject: [PATCH] Leaves: CCE update suppression
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/level/block/ShulkerBoxBlock.java b/net/minecraft/world/level/block/ShulkerBoxBlock.java
index f9dacc278200b05acb385e1f1cbf858e43d0d9f4..722ce78461b2303f99493c309345697cfc98fb99 100644
--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
@@ -183,7 +183,11 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
protected int getAnalogOutputSignal(final BlockState state, final Level level, final BlockPos pos, final Direction direction) {
// Lophine start - catch update suppression crash
try {
- return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
+ // Lophine start - configurable shulker CCE
+ return fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.shulkerBoxCCEReintroduced
+ ? AbstractContainerMenu.getRedstoneSignalFromContainer((net.minecraft.world.Container)level.getBlockEntity(pos))
+ : AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
+ // Lophine end - configurable shulker CCE
} catch (ClassCastException ex) {
if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.mergedUpdateSuppressionCrashEnabled()) {
throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, null, this, null, ex);
@@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Wed, 14 Jun 2023 12:07:07 +0800
Subject: [PATCH] Leaves: Redstone ignore upwards update
(Carpet: dustTrapdoorReintroduced)
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/level/block/ComparatorBlock.java b/net/minecraft/world/level/block/ComparatorBlock.java
index 45e11737bc2558a4ebfffe133d43111f45dd7d16..db80f0b400c7356c5524ea799354e6c44de14700 100644
--- a/net/minecraft/world/level/block/ComparatorBlock.java
+++ b/net/minecraft/world/level/block/ComparatorBlock.java
@@ -59,6 +59,11 @@ public class ComparatorBlock extends DiodeBlock implements EntityBlock {
final BlockState neighbourState,
final RandomSource random
) {
+ // Lophine start - redstone ignore upwards update
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.dustTrapdoorReintroduced && directionToNeighbour == Direction.DOWN) {
+ return state;
+ }
+ // Lophine end - redstone ignore upwards update
return directionToNeighbour == Direction.DOWN && !this.canSurviveOn(level, neighbourPos, neighbourState)
? Blocks.AIR.defaultBlockState()
: super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random);
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
index 759eb347299813c20226cc2fc5dc7718d12b7f56..30a7208a698a8bd3ba8a08ace6f23b206d90f6a3 100644
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -179,7 +179,11 @@ public class RedStoneWireBlock extends Block {
final RandomSource random
) {
if (directionToNeighbour == Direction.DOWN) {
- return !this.canSurviveOn(level, neighbourPos, neighbourState) ? Blocks.AIR.defaultBlockState() : state;
+ // Lophine start - redstone ignore upwards update
+ return fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.dustTrapdoorReintroduced
+ ? state
+ : !this.canSurviveOn(level, neighbourPos, neighbourState) ? Blocks.AIR.defaultBlockState() : state;
+ // Lophine end - redstone ignore upwards update
} else if (directionToNeighbour == Direction.UP) {
return this.getConnectionState(level, state, pos);
} else {
@@ -243,7 +247,10 @@ public class RedStoneWireBlock extends Block {
BlockPos relativePos = pos.relative(direction);
BlockState relativeState = level.getBlockState(relativePos);
if (canConnectUp) {
- boolean isPlaceableAbove = relativeState.getBlock() instanceof TrapDoorBlock || this.canSurviveOn(level, relativePos, relativeState);
+ // Lophine start - redstone ignore upwards update
+ boolean isPlaceableAbove = (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.dustTrapdoorReintroduced && relativeState.getBlock() instanceof TrapDoorBlock)
+ || this.canSurviveOn(level, relativePos, relativeState);
+ // Lophine end - redstone ignore upwards update
if (isPlaceableAbove && shouldConnectTo(level.getBlockState(relativePos.above()))) {
if (relativeState.isFaceSturdy(level, relativePos, direction.getOpposite())) {
return RedstoneSide.UP;
diff --git a/net/minecraft/world/level/block/RepeaterBlock.java b/net/minecraft/world/level/block/RepeaterBlock.java
index d301ca4c91e75d715998aa7ed155fd44ccd64785..1985602b11a584fc70b1bb9ca4c643757d4c0ed3 100644
--- a/net/minecraft/world/level/block/RepeaterBlock.java
+++ b/net/minecraft/world/level/block/RepeaterBlock.java
@@ -70,6 +70,11 @@ public class RepeaterBlock extends DiodeBlock {
final BlockState neighbourState,
final RandomSource random
) {
+ // Lophine start - redstone ignore upwards update
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.dustTrapdoorReintroduced && directionToNeighbour == Direction.DOWN) {
+ return state;
+ }
+ // Lophine end - redstone ignore upwards update
if (directionToNeighbour == Direction.DOWN && !this.canSurviveOn(level, neighbourPos, neighbourState)) {
return Blocks.AIR.defaultBlockState();
} else {
@@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 17 Nov 2025 18:41:08 +0800
Subject: [PATCH] Instant Block Updater
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
index 7ea91dbfb988aff3215a91cf62c9beae94461484..491d108cc8e440653746f20fc5b5bca3b791eb88 100644
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
@@ -506,7 +506,7 @@ public final class RegionizedWorldData {
public long lastMidTickExecuteFailure;
// From Level
public boolean populating;
- public final CollectingNeighborUpdater neighborUpdater;
+ public final net.minecraft.world.level.redstone.NeighborUpdater neighborUpdater; // Lophine - Instant Block Updater
public boolean captureBlockStates = false;
public boolean captureTreeGeneration = false;
public final Map<BlockPos, CraftBlockState> capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper
@@ -567,7 +567,11 @@ public final class RegionizedWorldData {
this.world = world;
this.blockLevelTicks = new LevelTicks<>(world::isPositionTickingWithEntitiesLoaded, world, true);
this.fluidLevelTicks = new LevelTicks<>(world::isPositionTickingWithEntitiesLoaded, world, false);
- this.neighborUpdater = new CollectingNeighborUpdater(world, world.neighbourUpdateMax);
+ // Lophine start - Instant Block Updater
+ this.neighborUpdater = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.instantBlockUpdaterReintroduced
+ ? new net.minecraft.world.level.redstone.InstantNeighborUpdater(world)
+ : new CollectingNeighborUpdater(world, world.neighbourUpdateMax);
+ // Lophine end - Instant Block Updater
this.nearbyPlayers = new NearbyPlayers(world);
this.wireHandler = new alternate.current.wire.WireHandler(world);
this.turbo = new io.papermc.paper.redstone.RedstoneWireTurbo((RedStoneWireBlock)Blocks.REDSTONE_WIRE);
@@ -896,4 +900,4 @@ public final class RegionizedWorldData {
public int getChunkCount() {
return this.chunks.size();
}
-}
\ No newline at end of file
+}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index b884e06a5e9d6a93c548820a99e5d05157e9d128..cb449a5063f7944551c2e66b603c0f910d84e50f 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1001,11 +1001,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
// Paper - rewrite chunk system
profiler.pop();
profiler.push("debugSynchronizers");
- if (this.debugSynchronizers.hasAnySubscriberFor(DebugSubscriptions.NEIGHBOR_UPDATES)) {
- regionizedWorldData.neighborUpdater // Folia - region threading
- .setDebugListener(blockPos -> this.debugSynchronizers.broadcastEventToTracking(blockPos, DebugSubscriptions.NEIGHBOR_UPDATES, blockPos));
- } else {
- regionizedWorldData.neighborUpdater.setDebugListener(null); // Folia - region threading
+ // Lophine start - Instant Block Updater
+ if (regionizedWorldData.neighborUpdater instanceof net.minecraft.world.level.redstone.CollectingNeighborUpdater neighborUpdater) {
+ if (this.debugSynchronizers.hasAnySubscriberFor(DebugSubscriptions.NEIGHBOR_UPDATES)) {
+ neighborUpdater // Folia - region threading
+ .setDebugListener(blockPos -> this.debugSynchronizers.broadcastEventToTracking(blockPos, DebugSubscriptions.NEIGHBOR_UPDATES, blockPos));
+ } else {
+ neighborUpdater.setDebugListener(null); // Folia - region threading
+ }
+ // Lophine end - Instant Block Updater
}
this.debugSynchronizers.tick(this.server.debugSubscribers());
@@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 18 Nov 2025 00:24:32 +0800
Subject: [PATCH] Revert TrapDoorBlock changes form Paper
diff --git a/net/minecraft/world/level/block/TrapDoorBlock.java b/net/minecraft/world/level/block/TrapDoorBlock.java
index cfc8b668980e0cba74b3f0d42c4902eb6aa8b01e..f01894c230b1ae4add3e20329e8dc87571d2c793 100644
--- a/net/minecraft/world/level/block/TrapDoorBlock.java
+++ b/net/minecraft/world/level/block/TrapDoorBlock.java
@@ -133,31 +133,7 @@ public class TrapDoorBlock extends HorizontalDirectionalBlock implements SimpleW
if (!level.isClientSide()) {
boolean signal = level.hasNeighborSignal(pos);
if (signal != state.getValue(POWERED)) {
- // Paper start - Call BlockRedstoneEvent
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) {
- return;
- }
- // Paper end - Call BlockRedstoneEvent
- // Paper start - break redstone on trapdoors early
- boolean open = state.getValue(TrapDoorBlock.OPEN) != signal;
- // note: this must run before any state for this block/its neighbours are written to the world
- // we allow the redstone event to fire so that plugins can block
- if (signal && open) { // if we are now powered and it caused the trap door to open
- // in this case, first check for the redstone on top first
- BlockPos abovePos = pos.above();
- BlockState above = level.getBlockState(abovePos);
- if (above.getBlock() instanceof RedStoneWireBlock) {
- level.setBlock(abovePos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_NEIGHBORS);
- Block.popResource(level, abovePos, new ItemStack(net.minecraft.world.item.Items.REDSTONE));
- // now check that this didn't change our state
- if (level.getBlockState(pos) != state) {
- // our state was changed, so we cannot propagate this update
- return;
- }
- }
- }
- if (open) {
- // Paper end - break redstone on trapdoors early
+ if (state.getValue(OPEN) != signal) { // Lophine - revert Paper trapdoor redstone handling
state = state.setValue(OPEN, signal);
this.playSound(null, level, pos, signal);
}
@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 18 Nov 2025 00:35:13 +0800
Subject: [PATCH] Leaves: Prevent loss of item drops due to update suppression
when breaking blocks
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/ea91106ae57fc4cc14e2e0225009cf9919072f7f/leaves-server/minecraft-patches/features/0090-Servux-Protocol.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
index e1de10e1a0ec221a1109a03d86fddf47b1c06a5f..71cc37515c268abd698896d514b66cb49859691c 100644
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -392,7 +392,18 @@ public class ServerPlayerGameMode {
this.level.getCurrentWorldData().captureDrops = new java.util.ArrayList<>(); // Folia - region threading
// CraftBukkit end
BlockState adjustedState = block.playerWillDestroy(this.level, pos, state, this.player);
- boolean changed = this.level.removeBlock(pos, false);
+ // Lophine start - preserve drops before update suppression
+ boolean changed;
+ org.leavesmc.leaves.util.UpdateSuppressionException updateSuppressionException = null;
+ try {
+ changed = this.level.removeBlock(pos, false);
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
+ updateSuppressionException = exception;
+ updateSuppressionException.provideBlock(this.level, pos, block);
+ updateSuppressionException.providePlayer(this.player);
+ changed = false;
+ }
+ // Lophine end - preserve drops before update suppression
if (SharedConstants.DEBUG_BLOCK_BREAK) {
LOGGER.info("server broke {} {} -> {}", pos, adjustedState, this.level.getBlockState(pos));
}
@@ -424,6 +435,11 @@ public class ServerPlayerGameMode {
if (event.isDropItems()) {
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, bState, this.player, itemsToDrop); // Paper - capture all item additions to the world
}
+ // Lophine start - preserve drops before update suppression
+ if (updateSuppressionException != null) {
+ throw updateSuppressionException;
+ }
+ // Lophine end - preserve drops before update suppression
// Drop event experience
if (changed) {
@@ -0,0 +1,52 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 18 Nov 2025 23:26:27 +0800
Subject: [PATCH] Leaves: Do not reset placed block on exception & Do not
prevent block entity and entity crash at LevelChunk
Co-authored by: MC_XiaoHei <xiaohei.xor7@outlook.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/item/BlockItem.java b/net/minecraft/world/item/BlockItem.java
index 07b84bd0144e133d13e8e033a8998f3cf674f746..9c016e7d93e4c44ddf2df520e5c57d92a0e085b3 100644
--- a/net/minecraft/world/item/BlockItem.java
+++ b/net/minecraft/world/item/BlockItem.java
@@ -69,20 +69,8 @@ public class BlockItem extends Item {
BlockState placedState = level.getBlockState(pos);
if (placedState.is(placementState.getBlock())) {
placedState = this.updateBlockStateFromTag(pos, level, itemStack, placedState);
- // Paper start - Reset placed block on exception
- try {
this.updateCustomBlockEntityTag(pos, level, player, itemStack, placedState);
updateBlockEntityComponents(level, pos, itemStack);
- } catch (Exception ex) {
- ((org.bukkit.craftbukkit.block.CraftBlockState) previousState).revertPlace();
- if (player instanceof ServerPlayer serverPlayer) {
- net.minecraft.server.MinecraftServer.LOGGER.warn("Player {} tried placing invalid block", player.getScoreboardName(), ex);
- serverPlayer.connection.disconnect(net.minecraft.network.chat.Component.literal("Packet processing error"));
- return InteractionResult.FAIL;
- }
- throw ex; // Rethrow exception if not placed by a player
- }
- // Paper end - Reset placed block on exception
placedState.getBlock().setPlacedBy(level, pos, placedState, player, itemStack);
// CraftBukkit start - special case for handling block placement with water lilies, frog spawn and snow buckets
if (player != null && (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem)) {
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 241c43170b5020c1521f43d349813586ba1f69a5..316b8d45b0902b1bf01a77307e24fc9a47d1283b 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1017,12 +1017,6 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
profiler.pop();
} catch (Throwable var5) {
- // Paper start - Prevent block entity and entity crashes
- final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", io.papermc.paper.util.MCUtil.getLevelName(LevelChunk.this.getLevel()), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
- net.minecraft.server.MinecraftServer.LOGGER.error(msg, var5);
- net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, var5))); // Paper - ServerExceptionEvent
- LevelChunk.this.removeBlockEntity(this.getPos());
- // Paper end - Prevent block entity and entity crashes
}
}
}
@@ -0,0 +1,843 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Tue, 18 Nov 2025 23:11:26 +0800
Subject: [PATCH] Leaves: Old Block remove behaviour
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/Containers.java b/net/minecraft/world/Containers.java
index 1311d4936f84652c5ffc51544f99cb98fc293906..3a62831838a60776159dcb1ca783d3f00e6cd35e 100644
--- a/net/minecraft/world/Containers.java
+++ b/net/minecraft/world/Containers.java
@@ -51,4 +51,16 @@ public class Containers {
public static void updateNeighboursAfterDestroy(final BlockState state, final Level level, final BlockPos pos) {
level.updateNeighbourForOutputSignal(pos, state.getBlock());
}
+
+
+ // Leaves start - behaviour 1.21.1-
+ public static void dropContentsOnDestroy(BlockState state, BlockState newState, Level level, BlockPos pos) {
+ if (!state.is(newState.getBlock())) {
+ if (level.getBlockEntity(pos) instanceof Container container) {
+ dropContents(level, pos, container);
+ level.updateNeighbourForOutputSignal(pos, state.getBlock());
+ }
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
}
diff --git a/net/minecraft/world/level/block/AbstractFurnaceBlock.java b/net/minecraft/world/level/block/AbstractFurnaceBlock.java
index 98561dcc465ca9d5394e58b05ad3e8dc59773ebc..72e3d6c1ce3389972df21d5ff6e4d74bcf2ad300 100644
--- a/net/minecraft/world/level/block/AbstractFurnaceBlock.java
+++ b/net/minecraft/world/level/block/AbstractFurnaceBlock.java
@@ -53,6 +53,27 @@ public abstract class AbstractFurnaceBlock extends BaseEntityBlock {
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ BlockEntity blockEntity = level.getBlockEntity(pos);
+ if (blockEntity instanceof AbstractFurnaceBlockEntity) {
+ if (level instanceof ServerLevel) {
+ Containers.dropContents(level, pos, (AbstractFurnaceBlockEntity)blockEntity);
+ ((AbstractFurnaceBlockEntity)blockEntity).getRecipesToAwardAndPopExperience((ServerLevel)level, net.minecraft.world.phys.Vec3.atCenterOf(pos));
+ }
+
+ super.onRemove(state, level, pos, newState, isMoving);
+ level.updateNeighbourForOutputSignal(pos, this);
+ } else {
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/BarrelBlock.java b/net/minecraft/world/level/block/BarrelBlock.java
index 5332fd32fa7a0d3fc3be1b0a7c2ca5dee8e402c6..37667a8e512bdba385c563e950d8c5d5cdd18832 100644
--- a/net/minecraft/world/level/block/BarrelBlock.java
+++ b/net/minecraft/world/level/block/BarrelBlock.java
@@ -51,6 +51,15 @@ public class BarrelBlock extends BaseEntityBlock {
return InteractionResult.SUCCESS;
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ Containers.dropContentsOnDestroy(state, newState, level, pos);
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/BasePressurePlateBlock.java b/net/minecraft/world/level/block/BasePressurePlateBlock.java
index c2fbf44e93e44c36423465d406b5e4d3db029a80..a28a453f139295834c77aa908027c74c8dfd7aba 100644
--- a/net/minecraft/world/level/block/BasePressurePlateBlock.java
+++ b/net/minecraft/world/level/block/BasePressurePlateBlock.java
@@ -133,6 +133,20 @@ public abstract class BasePressurePlateBlock extends Block {
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!isMoving && !state.is(newState.getBlock())) {
+ if (this.getSignalForState(state) > 0) {
+ this.updateNeighbours(level, pos);
+ }
+
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (!movedByPiston && this.getSignalForState(state) > 0) {
diff --git a/net/minecraft/world/level/block/BaseRailBlock.java b/net/minecraft/world/level/block/BaseRailBlock.java
index bc79a7c2cb18237dad15432ae7e1238125108696..5ef16955c69f0e0fecc772067a0fb006e6413011 100644
--- a/net/minecraft/world/level/block/BaseRailBlock.java
+++ b/net/minecraft/world/level/block/BaseRailBlock.java
@@ -123,6 +123,24 @@ public abstract class BaseRailBlock extends Block implements SimpleWaterloggedBl
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!isMoving) {
+ super.onRemove(state, level, pos, newState, isMoving);
+ if (state.getValue(this.getShapeProperty()).isSlope()) {
+ level.updateNeighborsAt(pos.above(), this);
+ }
+
+ if (this.isStraight) {
+ level.updateNeighborsAt(pos, this);
+ level.updateNeighborsAt(pos.below(), this);
+ }
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (!movedByPiston) {
diff --git a/net/minecraft/world/level/block/BrewingStandBlock.java b/net/minecraft/world/level/block/BrewingStandBlock.java
index aea12aad3270b966eed7779eaf77d26052f8a21f..6c39edf98f33df437880a77450557082ea9b0f6c 100644
--- a/net/minecraft/world/level/block/BrewingStandBlock.java
+++ b/net/minecraft/world/level/block/BrewingStandBlock.java
@@ -80,6 +80,15 @@ public class BrewingStandBlock extends BaseEntityBlock {
level.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0, 0.0, 0.0);
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ Containers.dropContentsOnDestroy(state, newState, level, pos);
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/ButtonBlock.java b/net/minecraft/world/level/block/ButtonBlock.java
index 86f4dcd959bb83247c6d2c5e947c79230aed3189..1b0223f1d533d1a8db5497ab9104052bc799f691 100644
--- a/net/minecraft/world/level/block/ButtonBlock.java
+++ b/net/minecraft/world/level/block/ButtonBlock.java
@@ -131,6 +131,20 @@ public class ButtonBlock extends FaceAttachedHorizontalDirectionalBlock {
return pressed ? this.type.buttonClickOn() : this.type.buttonClickOff();
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!isMoving && !state.is(newState.getBlock())) {
+ if (state.getValue(POWERED)) {
+ this.updateNeighbours(state, level, pos);
+ }
+
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (!movedByPiston && state.getValue(POWERED)) {
diff --git a/net/minecraft/world/level/block/CampfireBlock.java b/net/minecraft/world/level/block/CampfireBlock.java
index 8b706b34914326c039b761387f25e488f30fe6c8..b816594fcd83d26037734ec051f2c5d7f7dbde9f 100644
--- a/net/minecraft/world/level/block/CampfireBlock.java
+++ b/net/minecraft/world/level/block/CampfireBlock.java
@@ -111,6 +111,21 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB
return InteractionResult.TRY_WITH_EMPTY_HAND;
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ BlockEntity blockEntity = level.getBlockEntity(pos);
+ if (blockEntity instanceof CampfireBlockEntity) {
+ net.minecraft.world.Containers.dropContents(level, pos, ((CampfireBlockEntity)blockEntity).getItems());
+ }
+
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void entityInside(
final BlockState state,
diff --git a/net/minecraft/world/level/block/ChestBlock.java b/net/minecraft/world/level/block/ChestBlock.java
index d3f0680d59ec87990b54dc3dbce27706bfadf5f1..b5595d87339e4d313c5691a06c2b1b3d1b40b6de 100644
--- a/net/minecraft/world/level/block/ChestBlock.java
+++ b/net/minecraft/world/level/block/ChestBlock.java
@@ -257,6 +257,15 @@ public class ChestBlock extends AbstractChestBlock<ChestBlockEntity> implements
return this.chestCanConnectTo(state) && state.getValue(TYPE) == ChestType.SINGLE ? state.getValue(FACING) : null;
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ Containers.dropContentsOnDestroy(state, newState, level, pos);
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/ChiseledBookShelfBlock.java b/net/minecraft/world/level/block/ChiseledBookShelfBlock.java
index 0682acaae12650549eea3c291d8cde7bb17766bd..ac12ef0c99c82d771e5275ec7ced7f76c76f5938 100644
--- a/net/minecraft/world/level/block/ChiseledBookShelfBlock.java
+++ b/net/minecraft/world/level/block/ChiseledBookShelfBlock.java
@@ -168,6 +168,28 @@ public class ChiseledBookShelfBlock extends BaseEntityBlock implements Selectabl
SLOT_OCCUPIED_PROPERTIES.forEach(property -> builder.add(property));
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ if (!state.is(newState.getBlock())) {
+ if (level.getBlockEntity(pos) instanceof ChiseledBookShelfBlockEntity chiseledBookShelfBlockEntity && !chiseledBookShelfBlockEntity.isEmpty()) {
+ for (int i = 0; i < 6; i++) {
+ ItemStack item = chiseledBookShelfBlockEntity.getItem(i);
+ if (!item.isEmpty()) {
+ Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), item);
+ }
+ }
+
+ chiseledBookShelfBlockEntity.clearContent();
+ level.updateNeighbourForOutputSignal(pos, this);
+ }
+
+ super.onRemove(state, level, pos, newState, movedByPiston);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java
index 2b97fd6af1c4956eb173b8c66c2a3efc8772a798..90326fe95673edbf5ed8c1a5d9020735fdd4d53e 100644
--- a/net/minecraft/world/level/block/CrafterBlock.java
+++ b/net/minecraft/world/level/block/CrafterBlock.java
@@ -130,6 +130,15 @@ public class CrafterBlock extends BaseEntityBlock {
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ Containers.dropContentsOnDestroy(state, newState, level, pos);
+ super.onRemove(state, level, pos, newState, movedByPiston);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/CreakingHeartBlock.java b/net/minecraft/world/level/block/CreakingHeartBlock.java
index 3dd5f8c20ad68e0bd6222c8ba1687df0b2ad3b0d..b2e1e78cd70e20dd1c17ef0199059fc2b4e513b5 100644
--- a/net/minecraft/world/level/block/CreakingHeartBlock.java
+++ b/net/minecraft/world/level/block/CreakingHeartBlock.java
@@ -152,6 +152,17 @@ public class CreakingHeartBlock extends BaseEntityBlock {
builder.add(AXIS, STATE, NATURAL);
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ if (level.getBlockEntity(pos) instanceof CreakingHeartBlockEntity creakingHeartBlockEntity) {
+ creakingHeartBlockEntity.removeProtector(null);
+ }
+ super.onRemove(state, level, pos, newState, movedByPiston);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/DecoratedPotBlock.java b/net/minecraft/world/level/block/DecoratedPotBlock.java
index 3ce41ce3f9d2bf7a79e4b9811e043a69e0dedb13..2856b4081cddb38bac5c1d7199649a7531ef077f 100644
--- a/net/minecraft/world/level/block/DecoratedPotBlock.java
+++ b/net/minecraft/world/level/block/DecoratedPotBlock.java
@@ -172,6 +172,15 @@ public class DecoratedPotBlock extends BaseEntityBlock implements SimpleWaterlog
return new DecoratedPotBlockEntity(worldPosition, blockState);
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ Containers.dropContentsOnDestroy(state, newState, level, pos);
+ super.onRemove(state, level, pos, newState, movedByPiston);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/DiodeBlock.java b/net/minecraft/world/level/block/DiodeBlock.java
index 3457a1fa8f5efc4bf173bf155165ab5e5ae9f303..1342607e3bf28ca085f51ade22efaf34f19da170 100644
--- a/net/minecraft/world/level/block/DiodeBlock.java
+++ b/net/minecraft/world/level/block/DiodeBlock.java
@@ -180,6 +180,17 @@ public abstract class DiodeBlock extends HorizontalDirectionalBlock {
if (me.earthme.luminol.config.modules.optimizations.LeavesSleepingBlockEntityConfig.enabled && this instanceof ComparatorBlock && !oldState.is(Blocks.COMPARATOR)) org.leavesmc.leaves.lithium.common.block.entity.inventory_comparator_tracking.ComparatorTracking.notifyNearbyBlockEntitiesAboutNewComparator(level, pos); // Leaves - Lithium Sleeping Block Entity
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!isMoving && !state.is(newState.getBlock())) {
+ super.onRemove(state, level, pos, newState, isMoving);
+ this.updateNeighborsInFront(level, pos, state);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (!movedByPiston) {
diff --git a/net/minecraft/world/level/block/DispenserBlock.java b/net/minecraft/world/level/block/DispenserBlock.java
index dca954bd076fa917512af91e0b93d449eb5cac6d..7f880ba7cdd08be392dd4fe5a06fffbf6962318b 100644
--- a/net/minecraft/world/level/block/DispenserBlock.java
+++ b/net/minecraft/world/level/block/DispenserBlock.java
@@ -159,6 +159,15 @@ public class DispenserBlock extends BaseEntityBlock {
return this.defaultBlockState().setValue(FACING, context.getNearestLookingDirection().getOpposite());
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ Containers.dropContentsOnDestroy(state, newState, level, pos);
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/HopperBlock.java b/net/minecraft/world/level/block/HopperBlock.java
index 88606b84ea3a33ffbb0cfa6e073eb8f59d7188d0..c3ccebd7f27fd4d313cbcd616d58180a70f5f574 100644
--- a/net/minecraft/world/level/block/HopperBlock.java
+++ b/net/minecraft/world/level/block/HopperBlock.java
@@ -139,6 +139,15 @@ public class HopperBlock extends BaseEntityBlock implements org.leavesmc.leaves.
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ Containers.dropContentsOnDestroy(state, newState, level, pos);
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/JukeboxBlock.java b/net/minecraft/world/level/block/JukeboxBlock.java
index a9e46a66ffc868c3b4ef2bb6257f23a20f12b1a6..cee96a825f0e0e740ede8df0bf6dc5256b9fb8d3 100644
--- a/net/minecraft/world/level/block/JukeboxBlock.java
+++ b/net/minecraft/world/level/block/JukeboxBlock.java
@@ -82,6 +82,20 @@ public class JukeboxBlock extends BaseEntityBlock {
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ if (level.getBlockEntity(pos) instanceof JukeboxBlockEntity jukeboxBlockEntity) {
+ jukeboxBlockEntity.popOutTheItem();
+ }
+
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/LecternBlock.java b/net/minecraft/world/level/block/LecternBlock.java
index 75660fb19c25444e35dbbe58cd20f9b3d3f7ad32..196051c80baa489f43065a11a61f22a8c61251e7 100644
--- a/net/minecraft/world/level/block/LecternBlock.java
+++ b/net/minecraft/world/level/block/LecternBlock.java
@@ -200,6 +200,37 @@ public class LecternBlock extends BaseEntityBlock {
changePowered(level, pos, state, false);
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ if (state.getValue(HAS_BOOK)) {
+ this.popBook(state, level, pos);
+ }
+
+ if (state.getValue(POWERED)) {
+ updateBelow(level, pos, state);
+ }
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+
+ private void popBook(BlockState state, Level level, BlockPos pos) {
+ if (level.getBlockEntity(pos) instanceof LecternBlockEntity lecternBlockEntity) { // CraftBukkit - don't validate, type may be changed already // Leaves - the method with validate arg already removed by paper...
+ Direction direction = state.getValue(FACING);
+ ItemStack itemStack = lecternBlockEntity.getBook().copy();
+ if (itemStack.isEmpty()) return; // CraftBukkit - SPIGOT-5500
+ float f = 0.25F * direction.getStepX();
+ float f1 = 0.25F * direction.getStepZ();
+ net.minecraft.world.entity.item.ItemEntity itemEntity = new net.minecraft.world.entity.item.ItemEntity(level, pos.getX() + 0.5 + f, pos.getY() + 1, pos.getZ() + 0.5 + f1, itemStack);
+ itemEntity.setDefaultPickUpDelay();
+ level.addFreshEntity(itemEntity);
+ lecternBlockEntity.clearContent();
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (state.getValue(POWERED)) {
diff --git a/net/minecraft/world/level/block/LeverBlock.java b/net/minecraft/world/level/block/LeverBlock.java
index 341960ef67a689f660d0dcf61aaf5bf52bdc9074..6fc372e782f2a34a34a9ef1faed41ace6db5ec1b 100644
--- a/net/minecraft/world/level/block/LeverBlock.java
+++ b/net/minecraft/world/level/block/LeverBlock.java
@@ -127,6 +127,20 @@ public class LeverBlock extends FaceAttachedHorizontalDirectionalBlock {
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!isMoving && !state.is(newState.getBlock())) {
+ if (state.getValue(POWERED)) {
+ this.updateNeighbours(state, level, pos);
+ }
+
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (!movedByPiston && state.getValue(POWERED)) {
diff --git a/net/minecraft/world/level/block/LightningRodBlock.java b/net/minecraft/world/level/block/LightningRodBlock.java
index 47ca45518df306cc4368983eefb89294e56b015a..31be8864aa28eff804b507efdab614b35e3fea6f 100644
--- a/net/minecraft/world/level/block/LightningRodBlock.java
+++ b/net/minecraft/world/level/block/LightningRodBlock.java
@@ -123,6 +123,19 @@ public class LightningRodBlock extends RodBlock implements SimpleWaterloggedBloc
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ if (!state.is(newState.getBlock())) {
+ if (state.getValue(POWERED)) {
+ this.updateNeighbours(state, level, pos);
+ }
+ super.onRemove(state, level, pos, newState, movedByPiston);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (state.getValue(POWERED)) {
diff --git a/net/minecraft/world/level/block/ObserverBlock.java b/net/minecraft/world/level/block/ObserverBlock.java
index 6a3413ca875ce78f48cd8d3ce2cfe7798be1a19e..be572eff561ffdd961a9602eaa6136761c4d48a4 100644
--- a/net/minecraft/world/level/block/ObserverBlock.java
+++ b/net/minecraft/world/level/block/ObserverBlock.java
@@ -128,6 +128,18 @@ public class ObserverBlock extends DirectionalBlock {
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ if (state.getValue(POWERED) && level.getBlockTicks().hasScheduledTick(pos, this)) {
+ this.updateNeighborsInFront(level, pos, state.setValue(POWERED, Boolean.FALSE));
+ }
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (state.getValue(POWERED) && level.getBlockTicks().hasScheduledTick(pos, this)) {
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
index 30a7208a698a8bd3ba8a08ace6f23b206d90f6a3..7f5b77cd9cb78e693bbe1efd3d5fd7256d7700c5 100644
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -382,6 +382,28 @@ public class RedStoneWireBlock extends Block {
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!isMoving && !state.is(newState.getBlock())) {
+ super.onRemove(state, level, pos, newState, isMoving);
+ for (Direction direction : Direction.values()) {
+ level.updateNeighborsAt(pos.relative(direction), this);
+ }
+
+ // Paper start - optimize redstone - replace call to updatePowerStrength
+ if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ level.getWireHandler().onWireRemoved(pos, state); // Alternate Current
+ } else {
+ this.updateSurroundingRedstone(level, pos, state, null, false); // Vanilla/Eigencraft
+ }
+ // Paper end - optimize redstone
+ this.updateNeighborsOfNeighboringWires(level, pos);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (!movedByPiston) {
diff --git a/net/minecraft/world/level/block/RedstoneTorchBlock.java b/net/minecraft/world/level/block/RedstoneTorchBlock.java
index 0d0b5443c5c56825e88fd64c02c993eca6044d45..e2e5552008547fa1782b0a5ed3129162e94647c9 100644
--- a/net/minecraft/world/level/block/RedstoneTorchBlock.java
+++ b/net/minecraft/world/level/block/RedstoneTorchBlock.java
@@ -54,6 +54,16 @@ public class RedstoneTorchBlock extends BaseTorchBlock {
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!isMoving) {
+ this.notifyNeighbors(level, pos, state);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (!movedByPiston) {
diff --git a/net/minecraft/world/level/block/SculkSensorBlock.java b/net/minecraft/world/level/block/SculkSensorBlock.java
index 2bbce50d9dd0ca65f9e3bc90c8de098473039bc5..9a9fcb593c4b5f2bb0c57f9268dfdc9eb21d38ea 100644
--- a/net/minecraft/world/level/block/SculkSensorBlock.java
+++ b/net/minecraft/world/level/block/SculkSensorBlock.java
@@ -129,6 +129,19 @@ public class SculkSensorBlock extends BaseEntityBlock implements SimpleWaterlogg
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ if (!state.is(newState.getBlock())) {
+ if (getPhase(state) == SculkSensorPhase.ACTIVE) {
+ updateNeighbours(level, pos, state);
+ }
+ super.onRemove(state, level, pos, newState, movedByPiston);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (getPhase(state) == SculkSensorPhase.ACTIVE) {
diff --git a/net/minecraft/world/level/block/SculkShriekerBlock.java b/net/minecraft/world/level/block/SculkShriekerBlock.java
index d7e5ec23c64b60c47ab6b54cbf282e88c3a4a045..037aa3592a963bbb142465d31040f60e95cb146e 100644
--- a/net/minecraft/world/level/block/SculkShriekerBlock.java
+++ b/net/minecraft/world/level/block/SculkShriekerBlock.java
@@ -68,6 +68,17 @@ public class SculkShriekerBlock extends BaseEntityBlock implements SimpleWaterlo
super.stepOn(level, pos, onState, entity);
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ if (level instanceof ServerLevel serverLevel && state.getValue(SHRIEKING) && !state.is(newState.getBlock())) {
+ serverLevel.getBlockEntity(pos, BlockEntityType.SCULK_SHRIEKER).ifPresent(sculkShrieker -> sculkShrieker.tryRespond(serverLevel));
+ }
+ super.onRemove(state, level, pos, newState, movedByPiston);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) {
if (state.getValue(SHRIEKING)) {
diff --git a/net/minecraft/world/level/block/ShulkerBoxBlock.java b/net/minecraft/world/level/block/ShulkerBoxBlock.java
index 722ce78461b2303f99493c309345697cfc98fb99..45dc3e8484842265b26d387d518831ff23da4b5e 100644
--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
@@ -150,6 +150,20 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
// Paper end - re-set loot table if it was cleared
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ BlockEntity blockEntity = level.getBlockEntity(pos);
+ if (blockEntity instanceof ShulkerBoxBlockEntity) {
+ level.updateNeighbourForOutputSignal(pos, state.getBlock());
+ }
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
Containers.updateNeighboursAfterDestroy(state, level, pos);
diff --git a/net/minecraft/world/level/block/TripWireBlock.java b/net/minecraft/world/level/block/TripWireBlock.java
index 04e5995409a3532947dfab1c8ef05bd546a6f66d..6bf811477a27bbbeeeba6c9d768d33fc677ea5e7 100644
--- a/net/minecraft/world/level/block/TripWireBlock.java
+++ b/net/minecraft/world/level/block/TripWireBlock.java
@@ -107,6 +107,17 @@ public class TripWireBlock extends Block {
}
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating
+ if (!isMoving && !state.is(newState.getBlock())) {
+ this.updateSource(level, pos, state.setValue(POWERED, Boolean.TRUE));
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating
diff --git a/net/minecraft/world/level/block/TripWireHookBlock.java b/net/minecraft/world/level/block/TripWireHookBlock.java
index fd808353181e05f2fc527a391ce7bb990f61b4c7..836eae0c3e0891a3e3309b684f15d65f891215cf 100644
--- a/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -248,6 +248,26 @@ public class TripWireHookBlock extends Block {
level.updateNeighborsAt(pos.relative(front), block, orientation);
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!isMoving && !state.is(newState.getBlock())) {
+ boolean attachedValue = state.getValue(ATTACHED);
+ boolean poweredValue = state.getValue(POWERED);
+ if (attachedValue || poweredValue) {
+ calculateState(level, pos, state, true, false, -1, null);
+ }
+
+ if (poweredValue) {
+ notifyNeighbors(this, level, pos, state.getValue(FACING));
+ }
+
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
if (!movedByPiston) {
diff --git a/net/minecraft/world/level/block/entity/BlockEntityType.java b/net/minecraft/world/level/block/entity/BlockEntityType.java
index ac58bbed01edaf5dfe4839c89649ca865c339c8a..caead1012ff3b5b5f78c24a3baf20b7d00b84cf6 100644
--- a/net/minecraft/world/level/block/entity/BlockEntityType.java
+++ b/net/minecraft/world/level/block/entity/BlockEntityType.java
@@ -301,7 +301,7 @@ public class BlockEntityType<T extends BlockEntity> {
}
public boolean isValid(final BlockState state) {
- return this.validBlocks.contains(state.getBlock());
+ return fun.bm.lophine.config.modules.experiment.RedStoneConfig.oldBlockRemoveBehaviour || this.validBlocks.contains(state.getBlock()); // Leaves - behaviour 1.21.1-
}
@Deprecated
diff --git a/net/minecraft/world/level/block/piston/MovingPistonBlock.java b/net/minecraft/world/level/block/piston/MovingPistonBlock.java
index 2b6ad989e1e1424d0283bae39e5dae33eba44923..0f47fb528422d591bd03434a089ea69c7f27bf8c 100644
--- a/net/minecraft/world/level/block/piston/MovingPistonBlock.java
+++ b/net/minecraft/world/level/block/piston/MovingPistonBlock.java
@@ -70,6 +70,19 @@ public class MovingPistonBlock extends BaseEntityBlock {
return createTickerHelper(type, BlockEntityType.PISTON, PistonMovingBlockEntity::tick);
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ BlockEntity blockEntity = level.getBlockEntity(pos);
+ if (blockEntity instanceof PistonMovingBlockEntity) {
+ ((PistonMovingBlockEntity)blockEntity).finalTick();
+ }
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
public void destroy(final LevelAccessor level, final BlockPos pos, final BlockState state) {
BlockPos relative = pos.relative(state.getValue(FACING).getOpposite());
diff --git a/net/minecraft/world/level/block/piston/PistonHeadBlock.java b/net/minecraft/world/level/block/piston/PistonHeadBlock.java
index f8caa0b3c21766dbad73c524c1680346e4257188..b658d602953ade618d89c02745eb46be5d0175dd 100644
--- a/net/minecraft/world/level/block/piston/PistonHeadBlock.java
+++ b/net/minecraft/world/level/block/piston/PistonHeadBlock.java
@@ -78,6 +78,20 @@ public class PistonHeadBlock extends DirectionalBlock {
return super.playerWillDestroy(level, pos, state, player);
}
+ // Leaves start - behaviour 1.21.1-
+ @Override
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ super.onRemove(state, level, pos, newState, isMoving);
+ BlockPos blockPos = pos.relative(state.getValue(FACING).getOpposite());
+ if (this.isFittingBase(state, level.getBlockState(blockPos))) {
+ level.destroyBlock(blockPos, true);
+ }
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
@Override
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
BlockPos basePos = pos.relative(state.getValue(FACING).getOpposite());
diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java
index 0fbdf810c785c8a596d461e7651361fdedbb6217..ff1471f40b73582df68efbf2996a854c6aa37d65 100644
--- a/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -174,6 +174,16 @@ public abstract class BlockBehaviour implements FeatureElement, org.leavesmc.lea
org.spigotmc.AsyncCatcher.catchOp("block onPlace"); // Spigot
}
+ // Leaves start - behaviour 1.21.1-
+ protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ org.spigotmc.AsyncCatcher.catchOp("block remove"); // Spigot
+ if (state.hasBlockEntity() && !state.is(newState.getBlock())) {
+ level.removeBlockEntity(pos);
+ }
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
protected void affectNeighborsAfterRemoval(final BlockState state, final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
}
@@ -889,6 +899,13 @@ public abstract class BlockBehaviour implements FeatureElement, org.leavesmc.lea
// CraftBukkit end
}
+ // Leaves start - behaviour 1.21.1-
+ public void onRemove(Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
+ this.getBlock().onRemove(this.asState(), level, pos, newState, movedByPiston);
+ }
+ // Leaves end - behaviour 1.21.1-
+
+
public void affectNeighborsAfterRemoval(final ServerLevel level, final BlockPos pos, final boolean movedByPiston) {
this.getBlock().affectNeighborsAfterRemoval(this.asState(), level, pos, movedByPiston);
}
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 316b8d45b0902b1bf01a77307e24fc9a47d1283b..9b3775b0cbca782964e03935331d1bfdd1af140d 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -424,22 +424,28 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
boolean blockChanged = !oldState.is(newBlock);
boolean movedByPiston = (flags & Block.UPDATE_MOVE_BY_PISTON) != 0;
boolean sideEffects = (flags & Block.UPDATE_SKIP_BLOCK_ENTITY_SIDEEFFECTS) == 0;
- if (blockChanged && oldState.hasBlockEntity() && !state.shouldChangedStateKeepBlockEntity(oldState)) {
- if (!this.level.isClientSide() && sideEffects) {
- BlockEntity blockEntity = this.level.getBlockEntity(pos);
- if (blockEntity != null) {
- blockEntity.preRemoveSideEffects(pos, oldState);
+ // Leaves start - behaviour 1.21.1-
+ if (!fun.bm.lophine.config.modules.experiment.RedStoneConfig.oldBlockRemoveBehaviour) {
+ if (blockChanged && oldState.hasBlockEntity() && !state.shouldChangedStateKeepBlockEntity(oldState)) {
+ if (!this.level.isClientSide() && sideEffects) {
+ BlockEntity blockEntity = this.level.getBlockEntity(pos);
+ if (blockEntity != null) {
+ blockEntity.preRemoveSideEffects(pos, oldState);
+ }
}
- }
- this.removeBlockEntity(pos);
- }
+ this.removeBlockEntity(pos);
+ }
- if ((blockChanged || newBlock instanceof BaseRailBlock)
- && this.level instanceof ServerLevel serverLevel
- && ((flags & Block.UPDATE_NEIGHBORS) != 0 || movedByPiston)) {
- oldState.affectNeighborsAfterRemoval(serverLevel, pos, movedByPiston);
+ if ((blockChanged || newBlock instanceof BaseRailBlock)
+ && this.level instanceof ServerLevel serverLevel
+ && ((flags & Block.UPDATE_NEIGHBORS) != 0 || movedByPiston)) {
+ oldState.affectNeighborsAfterRemoval(serverLevel, pos, movedByPiston);
+ }
+ } else {
+ oldState.onRemove(this.level, pos, state, movedByPiston);
}
+ // Leaves end - behaviour 1.21.1-
if (!section.getBlockState(localX, localY, localZ).is(newBlock)) {
return null;
@@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Wed, 3 Jun 2026 02:20:00 +0800
Subject: [PATCH] MiniTweaks mob fire and explosion rules
diff --git a/net/minecraft/world/entity/monster/Creeper.java b/net/minecraft/world/entity/monster/Creeper.java
index 5005f2b923aa94dbc38fb75d5b6f58344888c895..0d4ba81c82b683c32addf6441de3843abf462c3c 100644
--- a/net/minecraft/world/entity/monster/Creeper.java
+++ b/net/minecraft/world/entity/monster/Creeper.java
@@ -250,7 +250,8 @@ public class Creeper extends Monster {
if (!event.isCancelled()) {
// CraftBukkit end
this.dead = true;
- level.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this)
+ Level.ExplosionInteraction explosionInteraction = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.noCreeperBlockBreaking ? Level.ExplosionInteraction.NONE : Level.ExplosionInteraction.MOB; // Lophine - MiniTweaks noCreeperBlockBreaking
+ level.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), explosionInteraction); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this)
this.spawnLingeringCloud();
this.triggerOnDeathMobEffects(level, Entity.RemovalReason.KILLED);
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
diff --git a/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java b/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java
index 711b97aa9e49b7edee34c91d77b1005be4fa96bd..1d9232c9061bde9c545e3ee25bc9c6b0417b9ece 100644
--- a/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java
+++ b/net/minecraft/world/entity/projectile/hurtingprojectile/LargeFireball.java
@@ -37,7 +37,9 @@ public class LargeFireball extends Fireball {
// CraftBukkit start - fire ExplosionPrimeEvent
org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity());
if (event.callEvent()) {
- this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB);
+ Level.ExplosionInteraction explosionInteraction = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.noGhastBlockBreaking ? Level.ExplosionInteraction.NONE : Level.ExplosionInteraction.MOB; // Lophine - MiniTweaks noGhastBlockBreaking
+ boolean createFire = event.getFire() && !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.disableGhastFire; // Lophine - MiniTweaks disableGhastFire
+ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), createFire, explosionInteraction);
}
// CraftBukkit end - fire ExplosionPrimeEvent
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
diff --git a/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java b/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java
index 1a72ee1559f75660796a9cbc1a9d9cdd6883dc90..480042d9401b6d7618fc2f36f16145606414d475 100644
--- a/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java
+++ b/net/minecraft/world/entity/projectile/hurtingprojectile/SmallFireball.java
@@ -63,7 +63,7 @@ public class SmallFireball extends Fireball {
super.onHitBlock(hitResult);
if (this.level() instanceof ServerLevel serverLevel) {
Entity owner = this.getOwner();
- if (this.isIncendiary) { // CraftBukkit
+ if (this.isIncendiary && (!(owner instanceof Mob) || !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.disableBlazeFire)) { // CraftBukkit // Lophine - MiniTweaks disableBlazeFire
BlockPos pos = hitResult.getBlockPos().relative(hitResult.getDirection());
if (this.level().isEmptyBlock(pos) && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), pos, this).isCancelled()) { // CraftBukkit
this.level().setBlockAndUpdate(pos, BaseFireBlock.getState(this.level(), pos));
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,142 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 21 Jan 2026 21:28:21 +0800
Subject: [PATCH] Carpet Features Compatible
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index 4bd923b42d1c98ce7178e05f9324f46d99ffc933..55bd9581c8c4bd3b1b7ba75cc80c94cf7548638a 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -340,7 +340,7 @@ public final class RegionizedServer {
final long tickStartNanos = System.nanoTime(); // Lophine - Carpet features
++this.tickCount;
// Luminol start - Add a config to enable tick command
- if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
MinecraftServer.getServer().tickRateManager().tick();
}
// Luminol end - Add a config to enable tick command
@@ -531,7 +531,7 @@ public final class RegionizedServer {
}
private void tickTime(final ServerLevel world, final long tickCount) {
- if ((!me.earthme.luminol.config.modules.experiment.CommandConfig.tick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command
+ if ((!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command // Lophine - redirect
world.serverLevelData.setGameTime(world.serverLevelData.getGameTime() + tickCount);
}
}
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
index a37f392146ccc0319cf56ee0058ae8782b598fe3..2223f0b38e8f628af64d1c916fb2310c4704a407 100644
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
@@ -576,7 +576,7 @@ public final class TickRegionScheduler {
// next start isn't updated until the end of this tick
this.tickRegion(tickCount, tickStart, scheduledEnd);
// Luminol start - Add a config to enable tick command
- if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
MinecraftServer.getServer().tickRateManager().endTickWork();
}
// Luminol end - Add a config to enable tick command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 74ef76058e5a410d12f88aa09450e7d90f63b5e6..1761167da363cd074a26499caadeaeb916461706 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -268,7 +268,7 @@ public class Commands {
TellRawCommand.register(this.dispatcher, context);
//TestCommand.register(this.dispatcher, context); // Folia - region threading
// Luminol start - Add a config to enable tick command
- if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
TickCommand.register(this.dispatcher); // Folia - region threading - TODO later
}
// Luminol end - Add a config to enable tick command
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 5e70e4e8a67e50a067dff1e592d617ca6a0426a9..63300acdcb1cdab2bf080c4939abb256fe05efa1 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2191,7 +2191,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.lastSentFood = -1;
this.teleportSpectators(transition, oldLevel);
// Leaves start - bot support
- if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled()) {
this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(this, true)); // Leaves - render bot
}
// Leaves end - bot support
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index c95c7b9a3968fc34a900a613b65b5d3e1abb24bf..64779d7b28e61c91897db5226158d65c32bfc835 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -281,7 +281,7 @@ public abstract class PlayerList {
// org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
// Leaves start - bot support
- if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled()) {
org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
if (bot != null) {
this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
@@ -442,7 +442,7 @@ public abstract class PlayerList {
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
// Leaves start - bot support
- if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled()) {
org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
if (bot != null) {
this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
@@ -971,7 +971,7 @@ public abstract class PlayerList {
).callEvent();
// Paper end
// Leaves start - bot support
- if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled()) {
this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(player, true)); // Leaves - render bot
}
// Leaves end - bot support
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index ac5b419169f8574f92ff7195bfa76c9978bc8a63..8066cdcaba8d2fcfa2e9ba3b040a2867dbbc6978 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -240,7 +240,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
// Leaves start - Wool hopper counter
- if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled()) {
+ if (fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig.hopperCountersUnlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled()) {
net.minecraft.world.item.DyeColor woolColor = org.leavesmc.leaves.util.WoolUtils.getWoolColorAtPosition(level, entity.getBlockPos().relative(state.getValue(HopperBlock.FACING)));
if (woolColor != null) {
for (int i = 0; i < Short.MAX_VALUE; i++) {
@@ -258,7 +258,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (changed) {
entity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
// Leaves start - Wool hopper counter
- if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && woolHopperCounter(level, pos, state, HopperBlockEntity.getContainerAt(level, pos))) {
+ if (fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig.hopperCountersUnlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && woolHopperCounter(level, pos, state, HopperBlockEntity.getContainerAt(level, pos))) {
entity.setCooldown(0);
return true;
}
@@ -668,7 +668,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
public static boolean addItem(final Container container, final ItemEntity entity) {
- if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && entity.isRemoved()) return false; // Leaves - Wool hopper counter
+ if (fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig.hopperCountersUnlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && entity.isRemoved()) return false; // Leaves - Wool hopper counter
boolean changed = false;
// CraftBukkit start
if (org.bukkit.event.inventory.InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
diff --git a/net/minecraft/world/level/dimension/end/EnderDragonFight.java b/net/minecraft/world/level/dimension/end/EnderDragonFight.java
index 5ca008b3dca83c00f2ae86a608d726972a8d9f9d..125d5f59bdfdee5aa4bae2aa4756db363ee17f4b 100644
--- a/net/minecraft/world/level/dimension/end/EnderDragonFight.java
+++ b/net/minecraft/world/level/dimension/end/EnderDragonFight.java
@@ -323,7 +323,7 @@ public class EnderDragonFight extends SavedData {
private int cachePortalOriginIteratorY = -1;
public BlockPattern.@Nullable BlockPatternMatch findExitPortal() {
- if (me.earthme.luminol.config.modules.optimizations.OptimizedDragonRespawnConfig.optimizedRespawn) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.optimizedDragonRespawn) { // Lophine - Carpet Features Compatible
int i, j;
for (i = cachePortalChunkIteratorX; i <= 8; ++i) {
for (j = cachePortalChunkIteratorZ; j <= 8; ++j) {
@@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Tue, 23 Jun 2026 02:32:14 +0800
Subject: [PATCH] PCA sync protocol
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/252a16955f6e1e31aac85d222b093b0797d392f8/leaves-server/minecraft-patches/features/0027-PCA-sync-protocol.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/SimpleContainer.java b/net/minecraft/world/SimpleContainer.java
index 049c6ab6472415479435f2caab0444c3cbd33902..d9bb641c07e2e8d3780fadac44ff5e3ee0e35c8b 100644
--- a/net/minecraft/world/SimpleContainer.java
+++ b/net/minecraft/world/SimpleContainer.java
@@ -199,6 +199,11 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled && this.getOwner() instanceof org.bukkit.craftbukkit.entity.CraftEntity entity) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(entity.getHandle());
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java b/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
index 8da479d04c04366561549617c477b0811a9b3d7c..345f63ccac2579acf4cf4ee9507c231da12b03ba 100644
--- a/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
+++ b/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
@@ -140,6 +140,11 @@ public abstract class AbstractChestBoat extends AbstractBoat implements HasCusto
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
index d2c4b47b2f95c8e6bafc93e436041143e68ffa4f..12938642aa58b6b64d7536575712dc3eadfb6e13 100644
--- a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
+++ b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
@@ -66,6 +66,11 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java
index 5e7612ad30c218fcbb7c9cdd66ecb69d78d8875d..0fa8f720e3b386a5466b3a94d18d5dbbd0d48836 100644
--- a/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -256,6 +256,14 @@ public abstract class BlockEntity implements DebugValueSource, TypedInstance<Blo
if (!blockState.isAir()) {
level.updateNeighbourForOutputSignal(worldPosition, blockState.getBlock());
}
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled && !level.isClientSide()) {
+ BlockEntity blockEntity = level.getBlockEntity(worldPosition);
+ if (blockEntity != null) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(blockEntity);
+ }
+ }
+ // Leaves end - PCA sync protocol
}
public BlockPos getBlockPos() {
@@ -0,0 +1,256 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Tue, 23 Jun 2026 03:06:41 +0800
Subject: [PATCH] Add Vanilla-like experience Config
diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java
index b97d65b81ec4b86e00b7c06341b40dc5c02b9044..d997e4f7ae6ee4e81f5fffe874f2895dda314df9 100644
--- a/ca/spottedleaf/moonrise/paper/PaperHooks.java
+++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java
@@ -204,6 +204,11 @@ public class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
@Override
public int configMaxAutoSavePerTick(final ServerLevel world) {
+ // Lophine start - Vanilla-like experience
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled) {
+ return 200;
+ }
+ // Lophine end - Vanilla-like experience
return world.paperConfig().chunks.maxAutoSaveChunksPerTick;
}
@@ -308,4 +313,4 @@ public class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
public boolean addTicketForEnderPearls(final ServerLevel world) {
return !world.paperConfig().misc.legacyEnderPearlBehavior;
}
-}
\ No newline at end of file
+}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 63300acdcb1cdab2bf080c4939abb256fe05efa1..99e61bbe15430a72096489777a4e417ec5125337 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2390,7 +2390,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
public boolean isInvulnerableTo(final ServerLevel level, final DamageSource source) {
// Paper start - disable player cramming
return (super.isInvulnerableTo(level, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.connection.hasClientLoaded())
- || (!this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING));
+ || (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING)); // Lophine - Vanilla-like experience
// Paper end - disable player cramming
}
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 0bd4d786c8e957a31811f52514a992543a0cee92..31212878ac31a8d9849b471b103b95553b274501 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3993,7 +3993,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
// Paper start - Cap entity collisions
this.numCollisions = Math.max(0, this.numCollisions - this.level().paperConfig().collisions.maxEntityCollisions);
for (Entity entityx : pushableEntities) {
- if (this.numCollisions >= this.level().paperConfig().collisions.maxEntityCollisions) {
+ if (this.numCollisions >= (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled ? Integer.MAX_VALUE : this.level().paperConfig().collisions.maxEntityCollisions)) { // Lophine - Vanilla-like experience
break;
}
diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java
index c3f1f875b1adc75f9e9747e148f214e4623a0b4f..04c264611273872a9a33fe2a4d1e2a041e6e78d2 100644
--- a/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -383,7 +383,7 @@ public class FallingBlockEntity extends Entity {
ResourceKey<Level> oldDimension = this.level().dimension();
boolean fromOrToEnd = (oldDimension == Level.END || newDimension == Level.END) && oldDimension != newDimension;
Entity newEntity = super.teleport(transition);
- this.forceTickAfterTeleportToDuplicate = newEntity != null && fromOrToEnd && (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation || me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled); // Paper // Luminol - Unsafe teleportation
+ this.forceTickAfterTeleportToDuplicate = newEntity != null && fromOrToEnd && (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation || me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled || fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled); // Paper // Luminol - Unsafe teleportation // Lophine - Vanilla-like experience
return newEntity;
}
}
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index 679a941a2af886697fbfcbc7f21e5f4e0ec77dc3..1d4856c477441dd3dc57432c7129fc7f54b528bd 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -259,7 +259,7 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
if (this.isMergable()) {
double radius = this.level().spigotConfig.itemMerge; // Spigot
for (ItemEntity entity : this.level()
- .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, this.level().paperConfig().entities.behavior.onlyMergeItemsHorizontally ? 0 : radius - 0.5D, radius), other -> other != this && other.isMergable())) { // Spigot // Paper - configuration to only merge items horizontally
+ .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled ? radius : (this.level().paperConfig().entities.behavior.onlyMergeItemsHorizontally ? 0 : radius - 0.5D), radius), other -> other != this && other.isMergable())) { // Spigot // Paper - configuration to only merge items horizontally // Lophine - Vanilla-like experience
if (entity.isMergable()) {
// Paper start - Fix items merging through walls
if (this.level().paperConfig().fixes.fixItemsMergingThroughWalls) {
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
index 5b5717a886dab57b2fe9ad926a8ae7b3d4f30155..05d8ba6e5a984660be2fba97f9022393bb84f62b 100644
--- a/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
@@ -107,7 +107,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
@Override
public void tick() {
- if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().getCurrentWorldData().currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot // Folia - region threading
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().getCurrentWorldData().currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot // Folia - region threading // Lophine - Vanilla-like experience
//this.handlePortal(); // Folia - region threading
this.applyGravity();
this.move(MoverType.SELF, this.getDeltaMovement());
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
index 61ca77cceeacf0c4ebecf3bb66c4eb99c62033d2..fb3651bb6ebc4b75c17c2443dc9f95caeea98ef0 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
@@ -259,7 +259,7 @@ public class Phantom extends Mob implements Enemy {
for (Player player : players) {
if (Phantom.this.canAttack(level, player, TargetingConditions.DEFAULT)) {
- if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls
+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls // Lophine - Vanilla-like experience
Phantom.this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit - reason
return true;
} // Paper - Add phantom creative and insomniac controls
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index c99c66563192629e399d1d904cb654c624fe9837..04e4e03399e5484bdbe8695fc2da5e5df152ba34 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -90,7 +90,8 @@ public final class NaturalSpawner {
MobCategory category = entity.getType().getCategory();
if (category != MobCategory.MISC) {
// Paper start - Only count natural spawns
- if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && // Lophine - Vanilla-like experience
+ !entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index 69d436268492183ae41fb9a60e61ed1f58a674d9..27e99cdd3a20c8c9177ccf8daa8fdf6984d51318 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -451,7 +451,7 @@ public class ServerExplosion implements Explosion {
if (this.fire || !cachedBlock.blockState.isAir()) {
ret.add(cachedBlock.immutablePos);
// Paper start - prevent headless pistons from forming
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == net.minecraft.world.level.block.Blocks.MOVING_PISTON) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == net.minecraft.world.level.block.Blocks.MOVING_PISTON) { // Lophine - Vanilla-like experience
net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(cachedBlock.immutablePos); // Paper - optimise collisions
if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) {
net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING);
diff --git a/net/minecraft/world/level/block/Block.java b/net/minecraft/world/level/block/Block.java
index 30f7e8f5e3e9440713e36ee25c90150b6b93c6ff..8527e46cab53ce6e67319cb87e9dcdda6b729de5 100644
--- a/net/minecraft/world/level/block/Block.java
+++ b/net/minecraft/world/level/block/Block.java
@@ -116,7 +116,7 @@ public class Block extends BlockBehaviour implements ItemLike {
private BlockState defaultBlockState;
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
public final boolean isDestroyable() {
- return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
+ return fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || // Lophine - Vanilla-like experience
this != Blocks.BARRIER &&
this != Blocks.BEDROCK &&
this != Blocks.END_PORTAL_FRAME &&
diff --git a/net/minecraft/world/level/block/TripWireHookBlock.java b/net/minecraft/world/level/block/TripWireHookBlock.java
index 836eae0c3e0891a3e3309b684f15d65f891215cf..a0fe40351ebb95fd5207bc63be82dbb887baebef 100644
--- a/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -188,7 +188,7 @@ public class TripWireHookBlock extends Block {
if (!cancelledEmitterHook) { // Paper - Call BlockRedstoneEvent
emitState(level, pos, attached, powered, wasAttached, wasPowered);
if (!isBeingDestroyed) {
- if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipTripwireHookPlacementValidation || level.getBlockState(pos).is(Blocks.TRIPWIRE_HOOK)) // Paper - Validate tripwire hook placement before update
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipTripwireHookPlacementValidation || level.getBlockState(pos).is(Blocks.TRIPWIRE_HOOK)) // Paper - Validate tripwire hook placement before update // Lophine - Vanilla-like experience
level.setBlock(pos, newState.setValue(FACING, direction), Block.UPDATE_ALL);
if (canUpdate) {
notifyNeighbors(block, level, pos, direction);
diff --git a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
index 62d7a44f139c28a38b14833380e2ec2bf84f3a75..12af97b9ffcf7c0f9e815ccbd81f99a80c6a5819 100644
--- a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
@@ -332,7 +332,7 @@ public class BeehiveBlockEntity extends BlockEntity {
iterator.remove();
}
// Paper start - Fix bees aging inside; use exitTickCounter to keep actual bee life
- else if (level.paperConfig().entities.behavior.cooldownFailedBeehiveReleases) {
+ else if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && level.paperConfig().entities.behavior.cooldownFailedBeehiveReleases) { // Lophine - Vanilla-like experience
data.exitTickCounter = data.occupant.minTicksInHive / 2;
}
// Paper end - Fix bees aging inside; use exitTickCounter to keep actual bee life
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 8066cdcaba8d2fcfa2e9ba3b040a2867dbbc6978..c904e35d49a36e2722295490a5a6aea67f29826e 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -346,7 +346,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
origItemStack.setCount(originalItemCount);
}
}
- if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
+ if (foundItem && !fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown // Lophine - Vanilla-like experience
hopper.setCooldown(level.spigotConfig.hopperTransfer);
}
return false;
diff --git a/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index a4d8ed890fc6bea1e961df814c00d22ae147734f..da037fbc38b4e605890711f4497ac8755a4f76f0 100644
--- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -152,7 +152,7 @@ public class PistonBaseBlock extends DirectionalBlock {
Direction direction = state.getValue(FACING);
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
Direction directionQueuedAs = Direction.from3DDataValue(b1 & 7); // Paper - copied from below
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && direction != directionQueuedAs) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && direction != directionQueuedAs) { // Lophine - Vanilla-like experience
return false;
}
// Paper end - Protect Bedrock and End Portal/Frames from being destroyed
@@ -237,7 +237,7 @@ public class PistonBaseBlock extends DirectionalBlock {
} else {
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed; fix headless pistons breaking blocks
BlockPos headPos = pos.relative(direction);
- if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || level.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, direction)) { // double check to make sure we're not a headless piston
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || level.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, direction)) { // double check to make sure we're not a headless piston // Lophine - Vanilla-like experience
level.removeBlock(headPos, false);
} else {
((ServerLevel) level).getChunkSource().blockChanged(headPos); // ... fix client desync
@@ -379,7 +379,7 @@ public class PistonBaseBlock extends DirectionalBlock {
for (int i = toPush.size() - 1; i >= 0; i--) {
// Paper start - fix a variety of piston desync dupes
- boolean allowDesync = !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntDupingFix;
+ boolean allowDesync = fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntDupingFix; // Lophine - Vanilla-like experience
BlockPos oldPos = toPush.get(i);
BlockPos pos = oldPos;
BlockState blockState = allowDesync ? level.getBlockState(oldPos) : null;
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index 22663ad55f669081b43644ad2cf1bd4aac48b745..0d79157ac9b7d099c29a933c171fe87718f34f8e 100644
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -334,7 +334,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
if (level.getBlockState(pos).is(Blocks.MOVING_PISTON)) {
BlockState newState = Block.updateFromNeighbourShapes(entity.movedState, level, pos);
if (newState.isAir()) {
- level.setBlock(pos, entity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE | (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 0 : Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air
+ level.setBlock(pos, entity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE | ((fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication) ? 0 : Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air // Lophine - Vanilla-like experience
Block.updateOrDestroy(entity.movedState, newState, level, pos, Block.UPDATE_ALL);
} else {
if (newState.hasProperty(BlockStateProperties.WATERLOGGED) && newState.getValue(BlockStateProperties.WATERLOGGED)) {
diff --git a/net/minecraft/world/level/levelgen/PhantomSpawner.java b/net/minecraft/world/level/levelgen/PhantomSpawner.java
index 142ab133d3b68eb9b88651e307653f1aafdf1de3..6061ac704e504d53492f405e92c17b6a4b44716f 100644
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -41,7 +41,7 @@ public class PhantomSpawner implements CustomSpawner {
// Paper end - Ability to control player's insomnia and phantoms
if (level.getSkyDarken() >= 5 || !level.dimensionType().hasSkyLight()) {
for (ServerPlayer player : level.getLocalPlayers()) { // Folia - region threading
- if (!player.isSpectator() && (!level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !player.isCreative())) { // Paper - Add phantom creative and insomniac controls
+ if (!player.isSpectator() && (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || !level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !player.isCreative())) { // Paper - Add phantom creative and insomniac controls // Lophine - Vanilla-like experience
BlockPos playerPos = player.blockPosition();
if (!level.dimensionType().hasSkyLight() || playerPos.getY() >= level.getSeaLevel() && level.canSeeSky(playerPos)) {
DifficultyInstance difficulty = level.getCurrentDifficultyAt(playerPos);
diff --git a/net/minecraft/world/level/portal/PortalForcer.java b/net/minecraft/world/level/portal/PortalForcer.java
index 4e4903d38d705dca6ff16418e54a7a367074aa08..b61259024c167f951d0fad292f40d2a814f6b8a5 100644
--- a/net/minecraft/world/level/portal/PortalForcer.java
+++ b/net/minecraft/world/level/portal/PortalForcer.java
@@ -233,7 +233,7 @@ public class PortalForcer {
origin, direction.getStepX() * width + clockWise.getStepX() * offset, height, direction.getStepZ() * width + clockWise.getStepZ() * offset
);
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) { // Lophine - Vanilla-like experience
if (!this.level.getBlockState(mutable).isDestroyable()) {
return false;
}
@@ -0,0 +1,219 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Wed, 24 Jun 2026 00:00:00 +0800
Subject: [PATCH] Restore vanilla ender pearl loading
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 99e61bbe15430a72096489777a4e417ec5125337..3b76045aa0b4cd97f7b104921a7fa8e29234e1d3 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -272,7 +272,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private @Nullable BlockPos raidOmenPosition;
private Vec3 lastKnownClientMovement = Vec3.ZERO;
private Input lastClientInput = Input.EMPTY;
- private final Set<ThrownEnderpearl> enderPearls = new HashSet<>();
+ private final Set<ThrownEnderpearl> enderPearls = java.util.concurrent.ConcurrentHashMap.newKeySet(); // Lophine - restore vanilla ender pearl loading on Folia
private long timeEntitySatOnShoulder;
private CompoundTag shoulderEntityLeft = new CompoundTag();
private CompoundTag shoulderEntityRight = new CompoundTag();
@@ -796,18 +796,20 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private void saveEnderPearls(final ValueOutput playerOutput) {
if (!this.enderPearls.isEmpty()) {
- ValueOutput.ValueOutputList pearlsOutput = playerOutput.childrenList("ender_pearls");
-
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ ValueOutput.TypedOutputList<CompoundTag> pearlsOutput = null;
for (ThrownEnderpearl enderPearl : this.enderPearls) {
- if (enderPearl.level().paperConfig().misc.legacyEnderPearlBehavior) continue; // Paper - Allow using old ender pearl behavior
- if (enderPearl.isRemoved()) {
- LOGGER.warn("Trying to save removed ender pearl, skipping");
+ CompoundTag pearlTag = enderPearl.getLastSavedEnderPearlTag();
+ if (pearlTag == null) {
+ LOGGER.warn("Trying to save ender pearl without a region-owned snapshot, skipping");
} else {
- ValueOutput pearlTag = pearlsOutput.addChild();
- enderPearl.save(pearlTag);
- pearlTag.store("ender_pearl_dimension", Level.RESOURCE_KEY_CODEC, enderPearl.level().dimension());
+ if (pearlsOutput == null) {
+ pearlsOutput = playerOutput.list(ServerPlayer.ENDER_PEARLS_TAG, CompoundTag.CODEC);
+ }
+ pearlsOutput.add(pearlTag);
}
}
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
}
@@ -3598,11 +3600,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
public void registerEnderPearl(final ThrownEnderpearl enderPearl) {
- //this.enderPearls.add(enderPearl); // Folia - region threading - do not track ender pearls
+ this.enderPearls.add(enderPearl); // Lophine - restore vanilla ender pearl loading on Folia
}
public void deregisterEnderPearl(final ThrownEnderpearl enderPearl) {
- //this.enderPearls.remove(enderPearl); // Folia - region threading - do not track ender pearls
+ this.enderPearls.remove(enderPearl); // Lophine - restore vanilla ender pearl loading on Folia
}
public Set<ThrownEnderpearl> getEnderPearls() {
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 64779d7b28e61c91897db5226158d65c32bfc835..f665ff0bc9068aaca6d6719ef6f7d87592f39816 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -752,11 +752,13 @@ public abstract class PlayerList {
player.unRide();
for (ThrownEnderpearl enderpearl : player.getEnderPearls()) {
- // Paper start - Allow using old ender pearl behavior
- if (!enderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) {
- enderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause
- }
- // Paper end - Allow using old ender pearl behavior
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ enderpearl.getBukkitEntity().taskScheduler.scheduleOrExecute((Entity pearl) -> {
+ if (!pearl.isRemoved()) {
+ pearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause
+ }
+ });
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
level.removePlayerImmediately(player, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
diff --git a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
index dc135f1a5d1ec33195e9ac897aa7acee4cbd13c6..bc9ca4680c18f28b97c4d1afe202cc2fff320daf 100644
--- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
+++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
@@ -29,7 +29,11 @@ import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
public class ThrownEnderpearl extends ThrowableItemProjectile {
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Lophine - restore vanilla ender pearl loading on Folia
private long ticketTimer = 0L;
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ private volatile net.minecraft.nbt.@Nullable CompoundTag lastSavedEnderPearlTag;
+ // Lophine end - restore vanilla ender pearl loading on Folia
public ThrownEnderpearl(final EntityType<? extends ThrownEnderpearl> type, final Level level) {
super(type, level);
@@ -37,6 +41,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
public ThrownEnderpearl(final Level level, final LivingEntity mob, final ItemStack itemStack) {
super(EntityType.ENDER_PEARL, mob, level, itemStack);
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
@Override
@@ -49,21 +56,73 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
this.deregisterFromCurrentOwner();
super.setOwner(owner);
this.registerToCurrentOwner();
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
private void deregisterFromCurrentOwner() {
- // Folia - region threading - we remove the registration logic, we do not need to fetch the owner
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ if (this.owner != null && this.level() instanceof ServerLevel serverLevel && serverLevel.getServer().getPlayerList().getPlayer(this.owner.getUUID()) instanceof ServerPlayer serverPlayer) {
+ serverPlayer.deregisterEnderPearl(this);
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
private void registerToCurrentOwner() {
- // Folia - region threading - we remove the registration logic, we do not need to fetch the owner
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ if (this.owner != null
+ && this.level() instanceof ServerLevel serverLevel
+ && !serverLevel.paperConfig().misc.legacyEnderPearlBehavior
+ && serverLevel.getServer().getPlayerList().getPlayer(this.owner.getUUID()) instanceof ServerPlayer serverPlayer) {
+ serverPlayer.registerEnderPearl(this);
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ public net.minecraft.nbt.@Nullable CompoundTag getLastSavedEnderPearlTag() {
+ net.minecraft.nbt.CompoundTag tag = this.lastSavedEnderPearlTag;
+ return tag == null ? null : tag.copy();
+ }
+
+ public void updateLastSavedEnderPearlTag() {
+ if (this.owner == null || this.isRemoved() || !(this.level() instanceof ServerLevel serverLevel) || serverLevel.paperConfig().misc.legacyEnderPearlBehavior) {
+ this.lastSavedEnderPearlTag = null;
+ return;
+ }
+ try (net.minecraft.util.ProblemReporter.ScopedCollector problemReporter = new net.minecraft.util.ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) {
+ net.minecraft.world.level.storage.TagValueOutput pearlOutput = net.minecraft.world.level.storage.TagValueOutput.createWithContext(problemReporter, this.registryAccess());
+ if (this.save(pearlOutput)) {
+ pearlOutput.store(ServerPlayer.ENDER_PEARL_DIMENSION_TAG, Level.RESOURCE_KEY_CODEC, this.level().dimension());
+ this.lastSavedEnderPearlTag = pearlOutput.buildResult();
+ } else {
+ this.lastSavedEnderPearlTag = null;
+ }
+ }
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
+
@Override
public @Nullable Entity getOwner() {
return this.owner != null && this.level() instanceof ServerLevel serverLevel ? this.owner.getEntity(serverLevel, Entity.class) : super.getOwner();
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ @Override
+ protected void readAdditionalSaveData(final net.minecraft.world.level.storage.ValueInput input) {
+ super.readAdditionalSaveData(input);
+ this.updateLastSavedEnderPearlTag();
+ }
+
+ @Override
+ public void restoreFrom(final Entity oldEntity) {
+ super.restoreFrom(oldEntity);
+ this.registerToCurrentOwner();
+ this.updateLastSavedEnderPearlTag();
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
+
private static @Nullable Entity findOwnerIncludingDeadPlayer(final ServerLevel serverLevel, final UUID uuid) {
Entity owner = serverLevel.getEntityInAnyDimension(uuid);
return (Entity)(owner != null ? owner : serverLevel.getServer().getPlayerList().getPlayer(uuid));
@@ -281,6 +340,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
&& owner instanceof ServerPlayer serverPlayer) {
this.ticketTimer = serverPlayer.registerAndUpdateEnderPearlTicket(this);
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
} else {
super.tick();
@@ -328,6 +390,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
public void onRemoval(final Entity.RemovalReason reason) {
if (reason != Entity.RemovalReason.UNLOADED_WITH_PLAYER) {
this.deregisterFromCurrentOwner();
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.lastSavedEnderPearlTag = null;
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
super.onRemoval(reason);
diff --git a/net/minecraft/world/item/EnderpearlItem.java b/net/minecraft/world/item/EnderpearlItem.java
index 17a005321601b0fef71604e4468134f1e98cd974..a270b4ca7d65b91ffcf292ff80f3a23124cd595c 100644
--- a/net/minecraft/world/item/EnderpearlItem.java
+++ b/net/minecraft/world/item/EnderpearlItem.java
@@ -27,6 +27,7 @@ public class EnderpearlItem extends Item {
final Projectile.Delayed<ThrownEnderpearl> thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemStack, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F);
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity());
if (event.callEvent() && thrownEnderpearl.attemptSpawn()) {
+ thrownEnderpearl.projectile().updateLastSavedEnderPearlTag(); // Lophine - restore vanilla ender pearl loading on Folia
if (event.shouldConsume()) {
itemStack.consume(1, player);
} else {
@@ -8,7 +8,7 @@ Helvetica Volubi <suisuroru@blue-millennium.fun>
bdlvl <bdlvl@blendreams.cn>
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
index 22c038e6556d9911e1eaedf71d7b86843af89c16..f5574eb883b1ee8747acc42832bc88ae03e27b67 100644
index fcdfd4f6de5e1c2d5e80c7f3d8cb0b33a62d257d..6eaa4e9bd1ecbfa531313ce1f470d55edf31b467 100644
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
@@ -593,7 +593,7 @@ public class Metrics {
@@ -35,29 +35,22 @@ index 22c038e6556d9911e1eaedf71d7b86843af89c16..f5574eb883b1ee8747acc42832bc88ae
metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
index 22125dbe1765f930fe10fe420be1c275ec553139..d5b070d1a3d84e228960dacd614e0f1abe968e79 100644
index 45611868dfdfee05380c390a11e8041685a76a19..f6df01c381c7f8bb3c2da6d8833adc9c9f24bd37 100644
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -35,7 +35,7 @@ public class PaperVersionFetcher implements VersionFetcher {
private static final Logger LOGGER = LogUtils.getClassLogger();
@@ -40,8 +40,8 @@ public class PaperVersionFetcher implements VersionFetcher {
private static final ComponentLogger COMPONENT_LOGGER = ComponentLogger.logger(LogManager.getRootLogger().getName());
private static final int DISTANCE_ERROR = -1;
private static final int DISTANCE_UNKNOWN = -2;
- private static final String DOWNLOAD_PAGE = "https://github.com/LuminolMC/Luminol"; //Luminol
+ private static final String DOWNLOAD_PAGE = "https://github.com/LuminolMC/Lophine"; //Luminol // Lophine
@Override
public long getCacheTime() {
@@ -49,7 +49,7 @@ public class PaperVersionFetcher implements VersionFetcher {
if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
updateMessage = text("You are running a development version without access to version information", color(0xFF5300));
} else {
- updateMessage = getUpdateStatusMessage("LuminolMC/Luminol", build); // Folia // Luminol
+ updateMessage = getUpdateStatusMessage("LuminolMC/Lophine", build); // Folia // Luminol // Lophine
}
final @Nullable Component history = this.getHistory();
- private static final String DOWNLOAD_PAGE = "https://github.com/LuminolMC/Luminol"; // Luminol
- private static final String REPOSITORY = "LuminolMC/Luminol"; // Luminol
+ private static final String DOWNLOAD_PAGE = "https://github.com/LuminolMC/Lophine"; // Luminol // Lophine
+ private static final String REPOSITORY = "LuminolMC/Lophine"; // Luminol // Lophine
private static final ServerBuildInfo BUILD_INFO = ServerBuildInfo.buildInfo();
private static final String USER_AGENT = BUILD_INFO.brandName() + "/" + BUILD_INFO.asString(VERSION_SIMPLE) + " (https://papermc.io)";
private static final Gson GSON = new Gson();
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
index 4ada790812957657d580cb748077c4961987d0cb..3a539df860305e777e85ed6dc72b5effe76734b4 100644
index 4ada790812957657d580cb748077c4961987d0cb..ddf3ad20e7ce967d9e096345f99c55abf066c3b3 100644
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
@@ -31,7 +31,7 @@ public record ServerBuildInfoImpl(
@@ -65,7 +58,7 @@ index 4ada790812957657d580cb748077c4961987d0cb..3a539df860305e777e85ed6dc72b5eff
private static final String BRAND_PAPER_NAME = "Paper";
- private static final String BRAND_LUMINOL_NAME = "Luminol";
+ private static final String BRAND_LOPHINE_NAME = "Lophine";
+ private static final String BRAND_LOPHINE_NAME = "Lophine"; // Lophine - Rebrand to Lophine
private static final String BUILD_DEV = "DEV";
@@ -90,19 +83,6 @@ index 4ada790812957657d580cb748077c4961987d0cb..3a539df860305e777e85ed6dc72b5eff
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
index 9699d7dcca5cf67f50ad05c0e875de424a4e00c5..2c546d470013d4daf3ddf427ab4bda1b51d6e641 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
@@ -11,7 +11,7 @@ public final class Versioning {
public static String getBukkitVersion() {
String result = "Unknown-Version";
- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/me.earthme.luminol/luminol-api/pom.properties"); // Folia //Luminol
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/fun.bm.lophine/lophine-api/pom.properties"); // Folia //Luminol
Properties properties = new Properties();
if (stream != null) {
diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png
index 2b6037aab645e303df6edbbc8af34dc4b4a55bc5..76ea89f23e6d2a42806c5d5d29b415d325e1ee82 100644
GIT binary patch
@@ -1,11 +1,11 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Suisuroru <qwertyuiop14077@qq.com>
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 20 Feb 2025 01:00:29 +0800
Subject: [PATCH] Purpur: Barrels and enderchests 6 rows
Co-authored by: William Blake Galbreath <Blake.Galbreath@GMail.com>
As part of: Purpur (https://github.com/PurpurMC/Purpur/blob/09f547de09fc5d886f18f6d99ff389289766ec9d/purpur-server/paper-patches/features/0003-Barrels-and-enderchests-6-rows.patch)
Licensed under: MIT (https://github.com/PurpurMC/Purpur/blob/09f547de09fc5d886f18f6d99ff389289766ec9d/LICENSE)
Co-authored by: William Blake Galbreath <blake.galbreath@gmail.com>
As part of: Purpur (https://github.com/PurpurMC/Purpur/blob/dc46f46d28dcdcaf33bb533f9571a107db98c1d7/purpur-server/paper-patches/features/0003-Barrels-and-enderchests-6-rows.patch)
Licensed under: MIT (https://github.com/PurpurMC/Purpur/blob/dc46f46d28dcdcaf33bb533f9571a107db98c1d7/LICENSE)
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
index 2f41a92465b9da28e026297cc3528898bb1c8412..168301a2f1c3081ae15d3695c2dcc72b4538cdfb 100644
@@ -41,15 +41,15 @@ index 2f41a92465b9da28e026297cc3528898bb1c8412..168301a2f1c3081ae15d3695c2dcc72b
case DROPPER:
this.delegate = new DispenserMenu(windowId, bottom, top);
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
index f850e6cea92edc87ed54cf54488b5ebb606913ed..f4db38de4348fb03db0b769bd5b5993184dd4abb 100644
index 9d5fe6fc727948955d89f9ed5e181185393a9611..5e5a4e48b2a96c355256b8f8bfcc09225d562944 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
@@ -84,7 +84,7 @@ public class CraftInventory implements Inventory {
@@ -85,7 +85,7 @@ public class CraftInventory implements Inventory {
@Override
public void setContents(ItemStack[] items) {
- Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize());
+ // Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize()); // Purpur - Barrels and enderchests 6 rows
+ // Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize()); // Purpur - Barrels and enderchests 6 rows
for (int i = 0; i < this.getSize(); i++) {
if (i >= items.length) {
@@ -0,0 +1,102 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sat, 22 Nov 2025 01:43:26 +0800
Subject: [PATCH] Add cancel task by task id in FoliaGlobalRegionScheduler
diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java
index 14ffbcb66006878eacf310547dad53718f8308eb..f20f2735fbb4d1e38d576eafe18a0054a45aa59e 100644
--- a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java
+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java
@@ -16,6 +16,8 @@ public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
private long tickCount = 0L;
private final Object stateLock = new Object();
private final Long2ObjectOpenHashMap<List<GlobalScheduledTask>> tasksByDeadline = new Long2ObjectOpenHashMap<>();
+ private int lastTaskId = 1; // Lophine - add task id
+ private final Object stateLockForTaskId = new Object(); // Lophine - add task id
public void tick() {
final List<GlobalScheduledTask> run;
@@ -64,7 +66,7 @@ public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
throw new IllegalPluginAccessException("Plugin attempted to register task while disabled");
}
- final GlobalScheduledTask ret = new GlobalScheduledTask(plugin, -1, task);
+ final GlobalScheduledTask ret = new GlobalScheduledTask(plugin, -1, task, this.getNextTaskId()); // Lophine - add task id
this.scheduleInternal(ret, delayTicks);
@@ -91,7 +93,7 @@ public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
throw new IllegalPluginAccessException("Plugin attempted to register task while disabled");
}
- final GlobalScheduledTask ret = new GlobalScheduledTask(plugin, periodTicks, task);
+ final GlobalScheduledTask ret = new GlobalScheduledTask(plugin, periodTicks, task, this.getNextTaskId()); // Lophine - add task id
this.scheduleInternal(ret, initialDelayTicks);
@@ -133,7 +135,34 @@ public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
}
}
- private final class GlobalScheduledTask implements ScheduledTask, Runnable {
+ // Lophine start - add cancel task by task id
+ @Override
+ public void cancelTask(final int taskId) {
+ synchronized (this.stateLock) {
+ for (final List<GlobalScheduledTask> tasks : this.tasksByDeadline.values()) {
+ for (final GlobalScheduledTask task : tasks) {
+ if (task.getTaskId() == taskId) {
+ task.cancel();
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private int getNextTaskId() {
+ synchronized (this.stateLockForTaskId) {
+ if (this.lastTaskId == Integer.MAX_VALUE) {
+ this.lastTaskId = 1;
+ } else {
+ ++this.lastTaskId;
+ }
+ }
+ return this.lastTaskId;
+ }
+ // Lophine end - add cancel task by task id
+
+ public final class GlobalScheduledTask implements ScheduledTask, Runnable { // Lophine - private -> public
private static final int STATE_IDLE = 0;
private static final int STATE_EXECUTING = 1;
@@ -145,13 +174,15 @@ public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
private final long repeatDelay; // in ticks
private Consumer<ScheduledTask> run;
private volatile int state;
+ private final int taskId; // Lophine - add task id
private static final VarHandle STATE_HANDLE = ConcurrentUtil.getVarHandle(GlobalScheduledTask.class, "state", int.class);
- private GlobalScheduledTask(final Plugin plugin, final long repeatDelay, final Consumer<ScheduledTask> run) {
+ private GlobalScheduledTask(final Plugin plugin, final long repeatDelay, final Consumer<ScheduledTask> run, int taskId) { // Lophine - add task id
this.plugin = plugin;
this.repeatDelay = repeatDelay;
this.run = run;
+ this.taskId = taskId; // Lophine - add task id
}
private final int getStateVolatile() {
@@ -262,5 +293,11 @@ public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
}
}
}
+
+ // Lophine start - add task id
+ public int getTaskId() {
+ return taskId;
+ }
+ // Lophine end - add task id
}
}
@@ -1,17 +1,17 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 3 Aug 2025 15:57:08 +0800
Subject: [PATCH] Leaves: Leaves Protocol Core
Subject: [PATCH] Leaves: Leaves Base Protocol Core
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/ea91106ae57fc4cc14e2e0225009cf9919072f7f/leaves-server/paper-patches/features/0004-Leaves-Protocol-Core.patch)
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/3e7f4a313ff0d2469dd7feae36304f0c8994cba1/leaves-server/paper-patches/features/0004-Leaves-Protocol-Core.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 4dde33c872d463bf17ba03e926de90e6988444b2..de72f36bd22e2c7452b9c3ee40657f6119ca70b3 100644
index f19ad4f317f911eb50802c325bcfce829d98524e..75ef8eab6665401bb2a9603de89172e341f8a2c4 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -497,6 +497,7 @@ public final class CraftServer implements Server {
@@ -483,6 +483,7 @@ public final class CraftServer implements Server {
this.potionBrewer = new io.papermc.paper.potion.PaperPotionBrewer(console); // Paper - custom potion mixes
datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper
if (false) this.spark = new io.papermc.paper.SparksFly(this); // Paper - spark // Luminol - Force disable builtin spark
@@ -19,7 +19,7 @@ index 4dde33c872d463bf17ba03e926de90e6988444b2..de72f36bd22e2c7452b9c3ee40657f61
}
public boolean getCommandBlockOverride(String command) {
@@ -1115,6 +1116,7 @@ public final class CraftServer implements Server {
@@ -1057,6 +1058,7 @@ public final class CraftServer implements Server {
if (false) this.spark.registerCommandBeforePlugins(this); // Paper - spark // Luminol - Force disable builtin spark
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
@@ -0,0 +1,13 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 16 Nov 2025 17:47:42 +0800
Subject: [PATCH] LeavesHooks
diff --git a/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks b/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks
index e57c3ca79677b1dfe7cf3db36f0406de7ea5bd0a..86edd824ec42e550dd1419fd57d93a21fe2d648d 100644
--- a/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks
+++ b/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks
@@ -1 +1 @@
-ca.spottedleaf.moonrise.paper.PaperHooks
+org.leavesmc.leaves.region.LeavesHooks
@@ -8,7 +8,7 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
index 9180f23529a31b6b0a5b38bb7cda3e32d487f691..e1f456b31ffda9370b63e51f343847d6f9f62263 100644
index 9180f23529a31b6b0a5b38bb7cda3e32d487f691..d0b763f07aee56f69a67c87d7dd15a44b6f44db7 100644
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
@@ -36,6 +36,15 @@ class PaperEventManager {
@@ -16,7 +16,7 @@ index 9180f23529a31b6b0a5b38bb7cda3e32d487f691..e1f456b31ffda9370b63e51f343847d6
// SimplePluginManager
public void callEvent(@NotNull Event event) {
+ // Leaves start - process bot load/save
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable && fun.bm.lophine.config.modules.function.FakeplayerConfig.canResident) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled() && fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig.fakePlayerResident) {
+ if (event instanceof org.bukkit.event.world.WorldLoadEvent worldLoadEvent) {
+ org.leavesmc.leaves.bot.BotList.INSTANCE.loadResume(worldLoadEvent.getWorld().getUID().toString());
+ } else if (event instanceof org.bukkit.event.world.WorldUnloadEvent worldUnloadEvent) {
@@ -41,22 +41,22 @@ index 9180f23529a31b6b0a5b38bb7cda3e32d487f691..e1f456b31ffda9370b63e51f343847d6
if (!registration.getPlugin().isEnabled()) {
continue;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index 0a10f49ee410d93e95ceb90108200a1a9d12b54b..d2eee37d810a6d5cf514bc71dea66a4d2b0d09e2 100644
index 5339ff469a38d35e72ea7227503a84395462f84a..d75b4ecb24f2ea42afc82ac255775d8f35121fe5 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -423,6 +423,7 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
@@ -373,6 +373,7 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
@SuppressWarnings("unchecked")
public <T extends Entity> T addEntity(T entity) {
Preconditions.checkArgument(!entity.isInWorld(), "Entity has already been added to a world");
+ Preconditions.checkState(!(entity instanceof org.leavesmc.leaves.entity.bot.CraftBot), "[Leaves] Fakeplayers do not support changing world, Please use leaves fakeplayer-api instead!");
net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle();
if (nmsEntity.level() != this.getHandle().getLevel()) {
nmsEntity = nmsEntity.teleport(new TeleportTransition(this.getHandle().getLevel(), nmsEntity, TeleportTransition.DO_NOTHING));
throw new IllegalArgumentException(entity + " wasn't created with this world, you must create the entity with the world you want to add it to.");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index de72f36bd22e2c7452b9c3ee40657f6119ca70b3..0a96721797b9bbc643f68677bbb1d10c3c89e815 100644
index 75ef8eab6665401bb2a9603de89172e341f8a2c4..42df6c661ec5ab18387b12743771bdb156a98e93 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -316,6 +316,7 @@ public final class CraftServer implements Server {
@@ -303,6 +303,7 @@ public final class CraftServer implements Server {
private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer;
public io.papermc.paper.SparksFly spark; // Paper - spark // Luminol - Force disable builtin spark
private final ServerConfiguration serverConfig = new PaperServerConfiguration();
@@ -64,7 +64,7 @@ index de72f36bd22e2c7452b9c3ee40657f6119ca70b3..0a96721797b9bbc643f68677bbb1d10c
// Paper start - Folia region threading API
private final io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler(); // Folia - region threading
@@ -498,6 +499,7 @@ public final class CraftServer implements Server {
@@ -484,6 +485,7 @@ public final class CraftServer implements Server {
datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper
if (false) this.spark = new io.papermc.paper.SparksFly(this); // Paper - spark // Luminol - Force disable builtin spark
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.init(); // Leaves - protocol
@@ -72,7 +72,7 @@ index de72f36bd22e2c7452b9c3ee40657f6119ca70b3..0a96721797b9bbc643f68677bbb1d10c
}
public boolean getCommandBlockOverride(String command) {
@@ -1482,7 +1484,7 @@ public final class CraftServer implements Server {
@@ -1377,7 +1379,7 @@ public final class CraftServer implements Server {
return false;
}
@@ -81,9 +81,9 @@ index de72f36bd22e2c7452b9c3ee40657f6119ca70b3..0a96721797b9bbc643f68677bbb1d10c
return false;
}
@@ -3260,6 +3262,13 @@ public final class CraftServer implements Server {
this.console.addPluginAllowingSleep(plugin.getName(), value);
@@ -3117,6 +3119,13 @@ public final class CraftServer implements Server {
}
// Leaves end - Feature API
+ // Leaves start - Bot API
+ @Override
@@ -96,10 +96,10 @@ index de72f36bd22e2c7452b9c3ee40657f6119ca70b3..0a96721797b9bbc643f68677bbb1d10c
/**
* Gets the TPS from the region which owns the specified location, or {@code null} if no region owns
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 9b9eea4babcd67a088e9400b369d168d11c06ac1..3177db282013e6dc3c7215fc2a851e2630a29409 100644
index 03ad9254c4b5556119fe73d533ceac7073b8fe74..fd2e24b6219219fa1fe7d2ba1d877ee4c24676ca 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -249,7 +249,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@@ -255,7 +255,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public int getPlayerCount() {
@@ -108,7 +108,7 @@ index 9b9eea4babcd67a088e9400b369d168d11c06ac1..3177db282013e6dc3c7215fc2a851e26
}
@Override
@@ -1279,9 +1279,9 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@@ -1126,9 +1126,9 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public List<Player> getPlayers() {
@@ -120,7 +120,7 @@ index 9b9eea4babcd67a088e9400b369d168d11c06ac1..3177db282013e6dc3c7215fc2a851e26
HumanEntity bukkitEntity = human.getBukkitEntity();
if ((bukkitEntity != null) && (bukkitEntity instanceof Player)) {
@@ -1988,7 +1988,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@@ -1628,7 +1628,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
public void playSound(final net.kyori.adventure.sound.Sound sound) {
org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper
final long seed = sound.seed().orElseGet(this.world.getRandom()::nextLong);
@@ -129,7 +129,7 @@ index 9b9eea4babcd67a088e9400b369d168d11c06ac1..3177db282013e6dc3c7215fc2a851e26
player.connection.send(io.papermc.paper.adventure.PaperAdventure.asSoundPacket(sound, player.getX(), player.getY(), player.getZ(), seed, null));
}
}
@@ -2016,7 +2016,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@@ -1656,7 +1656,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper
final long seed = sound.seed().orElseGet(this.getHandle().getRandom()::nextLong);
if (emitter == net.kyori.adventure.sound.Sound.Emitter.self()) {
@@ -138,20 +138,20 @@ index 9b9eea4babcd67a088e9400b369d168d11c06ac1..3177db282013e6dc3c7215fc2a851e26
player.connection.send(io.papermc.paper.adventure.PaperAdventure.asSoundPacket(sound, player, seed, null));
}
} else if (emitter instanceof CraftEntity craftEntity) {
@@ -2248,7 +2248,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@@ -1779,7 +1779,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
Preconditions.checkArgument(particle.getDataType().isInstance(data), "data (%s) should be %s", data.getClass(), particle.getDataType());
}
this.getHandle().sendParticlesSource(
- receivers == null ? this.getHandle().players() : receivers.stream().map(player -> ((CraftPlayer) player).getHandle()).collect(java.util.stream.Collectors.toList()), // Paper - Particle API
+ receivers == null ? this.getHandle().realPlayers() : receivers.stream().map(player -> ((CraftPlayer) player).getHandle()).collect(java.util.stream.Collectors.toList()), // Paper - Particle API // Leaves - skip
- receivers == null ? this.getHandle().players() : Lists.transform(receivers, player -> ((CraftPlayer) player).getHandle()), // Paper - Particle API
+ receivers == null ? this.getHandle().realPlayers() : Lists.transform(receivers, player -> ((CraftPlayer) player).getHandle()), // Paper - Particle API // Leaves - skip
sender != null ? ((CraftPlayer) sender).getHandle() : null, // Sender // Paper - Particle API
CraftParticle.createParticleParam(particle, data), // Particle
force,
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 852e1ffef6a022caad7c8eff34091e50112a2290..8eb5d014d9ed688ffebaffb4ce0bb40896961a04 100644
index d43b1a6e6a8ac2a21b0a048e838115b0403170dd..42c2c6a05645e5aef26e9d3a91ad93563a297ca3 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -126,6 +126,8 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
@@ -127,6 +127,8 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return new CraftHumanEntity(server, (net.minecraft.world.entity.player.Player) entity);
}
@@ -161,10 +161,10 @@ index 852e1ffef6a022caad7c8eff34091e50112a2290..8eb5d014d9ed688ffebaffb4ce0bb408
if (entity instanceof EnderDragonPart complexPart) {
if (complexPart.parentMob instanceof EnderDragon) {
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 317837a2a9b3b511b5cac4df4db248d4652816dc..a8253d1a3129c8258e9ead7c430e1bcf82f735d7 100644
index 23882dbe5fdfe9f0cf98a13791f70fe83393639d..41cf8145a6a5f1542e06af522201fccef1d5f07d 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -897,7 +897,11 @@ public class CraftEventFactory {
@@ -1004,7 +1004,11 @@ public class CraftEventFactory {
event.setKeepInventory(keepInventory);
event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel
populateFields(victim, event); // Paper - make cancellable
@@ -0,0 +1,106 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 16 Nov 2025 15:55:47 +0800
Subject: [PATCH] Leaves: Replay Mod API
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
index d0b763f07aee56f69a67c87d7dd15a44b6f44db7..bd301425f4c3cdf2b2bd22c1775b7ca9be1d4248 100644
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
@@ -57,7 +57,7 @@ class PaperEventManager {
}
// Leaves start - skip bot
- if (event instanceof org.bukkit.event.player.PlayerEvent playerEvent && playerEvent.getPlayer() instanceof org.leavesmc.leaves.entity.bot.Bot) {
+ if (event instanceof org.bukkit.event.player.PlayerEvent playerEvent && (playerEvent.getPlayer() instanceof org.leavesmc.leaves.entity.bot.Bot || playerEvent.getPlayer() instanceof org.leavesmc.leaves.entity.photographer.Photographer)) { // Leaves - and photographer
return;
}
// Leaves end - skip bot
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 42df6c661ec5ab18387b12743771bdb156a98e93..feccf57b61200aead73fe97b897c1ad0fad563fb 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -304,6 +304,7 @@ public final class CraftServer implements Server {
public io.papermc.paper.SparksFly spark; // Paper - spark // Luminol - Force disable builtin spark
private final ServerConfiguration serverConfig = new PaperServerConfiguration();
private final org.leavesmc.leaves.entity.bot.CraftBotManager botManager; // Leaves
+ private final org.leavesmc.leaves.entity.photographer.CraftPhotographerManager photographerManager = new org.leavesmc.leaves.entity.photographer.CraftPhotographerManager(); // Leaves
// Paper start - Folia region threading API
private final io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler(); // Folia - region threading
@@ -398,7 +399,7 @@ public final class CraftServer implements Server {
public CraftServer(DedicatedServer console, PlayerList playerList) {
this.console = console;
this.playerList = (DedicatedPlayerList) playerList;
- this.playerView = Collections.unmodifiableList(Lists.transform(playerList.players, new Function<ServerPlayer, CraftPlayer>() {
+ this.playerView = Collections.unmodifiableList(Lists.transform(playerList.realPlayers, new Function<ServerPlayer, CraftPlayer>() { // Leaves - replay api
@Override
public CraftPlayer apply(ServerPlayer player) {
return player.getBukkitEntity();
@@ -3190,4 +3191,11 @@ public final class CraftServer implements Server {
}
}
// Folia end - region TPS API
+
+ // Leaves start - replay mod api
+ @Override
+ public org.leavesmc.leaves.entity.photographer.CraftPhotographerManager getPhotographerManager() {
+ return photographerManager;
+ }
+ // Leaves end - replay mod api
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 42c2c6a05645e5aef26e9d3a91ad93563a297ca3..759d54f1f012461fc322d452bb26f7fd6e601039 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -128,6 +128,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
}
if (entity instanceof org.leavesmc.leaves.bot.ServerBot bot) { return new org.leavesmc.leaves.entity.bot.CraftBot(server, bot); }
+ if (entity instanceof org.leavesmc.leaves.replay.ServerPhotographer photographer) { return new org.leavesmc.leaves.entity.photographer.CraftPhotographer(server, photographer); }
// Special case complex part, since there is no extra entity type for them
if (entity instanceof EnderDragonPart complexPart) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 59e3a15cce0ed34aa3b75b92db9e349c9fe481fa..044f3168583b23542e18fe14853d3b98bad3fa4d 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2086,7 +2086,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa
@Override
public boolean canSee(Player player) {
- return this.canSee((org.bukkit.entity.Entity) player);
+ return !(player instanceof org.leavesmc.leaves.entity.photographer.Photographer) && this.canSee((org.bukkit.entity.Entity) player); // Leaves - skip photographer
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index fa3e2bf2b31ca5173d71082e93eb7eaa4faa2816..bd3c4eb10489f13562b31f4b809e80b19717bc25 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -347,7 +347,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
Bukkit.getLogger().log(Level.SEVERE, "Error saving advancement " + key, ex);
}
- MinecraftServer.getServer().getPlayerList().getPlayers().forEach(player -> {
+ net.minecraft.server.MinecraftServer.getServer().getPlayerList().realPlayers.forEach(player -> { // Leaves - only real players
player.getAdvancements().reload(MinecraftServer.getServer().getAdvancements());
player.getAdvancements().flushDirty(player, false);
});
diff --git a/src/main/java/org/bukkit/craftbukkit/util/LazyPlayerSet.java b/src/main/java/org/bukkit/craftbukkit/util/LazyPlayerSet.java
index 25aae550dcdcef2df268d0dd99bdcc9bbd49fcf8..83af50de50a03e164d572f3c3466b6d0b42ed138 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/LazyPlayerSet.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/LazyPlayerSet.java
@@ -23,7 +23,7 @@ public class LazyPlayerSet extends LazyHashSet<Player> {
}
public static Set<Player> makePlayerSet(final MinecraftServer server) {
- List<ServerPlayer> players = server.getPlayerList().players;
+ List<ServerPlayer> players = server.getPlayerList().realPlayers; // Leaves - only real players
Set<Player> reference = new HashSet<>(players.size());
for (ServerPlayer player : players) {
reference.add(player.getBukkitEntity());
@@ -0,0 +1,8 @@
package fun.bm.lophine;
import com.mojang.logging.LogUtils;
import org.slf4j.Logger;
public class LophineLogger {
public static final Logger LOGGER = LogUtils.getLogger();
}
@@ -0,0 +1,42 @@
package fun.bm.lophine.carpet;
import fun.bm.lophine.carpet.config.modules.GeneralCompatConfig;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.objecthunter.exp4j.ExpressionBuilder;
import java.math.BigDecimal;
public final class CarpetCalculatorCompatHelper {
public static boolean handleChat(ServerPlayer player, String rawMessage) {
if (!GeneralCompatConfig.simpleInGameCalculator || !rawMessage.startsWith("=")) {
return false;
}
String expression = rawMessage.substring(1).trim();
if (expression.isEmpty()) {
return false;
}
Component response;
try {
double result = new ExpressionBuilder(expression).build().evaluate();
response = Component.literal(expression + " = " + formatNumber(result)).withStyle(ChatFormatting.YELLOW);
} catch (RuntimeException exception) {
response = Component.literal("Calculator error: " + exception.getMessage()).withStyle(ChatFormatting.RED);
}
Component scheduledResponse = response;
player.getBukkitEntity().taskScheduler.schedule((ServerPlayer scheduledPlayer) -> scheduledPlayer.sendSystemMessage(scheduledResponse), null, 1L);
return true;
}
private static String formatNumber(double value) {
if (Double.isFinite(value) && Math.rint(value) == value && value >= Long.MIN_VALUE && value <= Long.MAX_VALUE) {
return Long.toString((long) value);
}
return BigDecimal.valueOf(value).stripTrailingZeros().toPlainString();
}
}
@@ -0,0 +1,107 @@
package fun.bm.lophine.carpet;
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
import fun.bm.lophine.carpet.config.modules.GeneralCompatConfig;
import fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig;
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
import fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig;
import fun.bm.lophine.protocol.CarpetLoggerProtocol;
import org.leavesmc.leaves.protocol.CarpetServerProtocol;
import java.util.List;
// WARNING: THIS FILE NEED TO FULLY REWRITTEN
public final class CarpetCompatSync {
private static boolean init = false;
public static void apply() {
CarpetLoggerProtocol.refreshConfiguredDefaults(!init);
registerProtocolRules();
init = true;
}
private static List<String> sanitizeDefaultLoggers(List<String> configuredLoggers) {
return configuredLoggers == null ? List.of() : List.copyOf(configuredLoggers);
}
private static void registerProtocolRules() {
CarpetServerProtocol.CarpetRules.beginBatch();
try {
CarpetServerProtocol.CarpetRules.clear();
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "language", GeneralCompatConfig.language));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "amsUpdateSuppressionCrashFix", GeneralCompatConfig.amsUpdateSuppressionCrashFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetUpdateSuppressionCrash", GeneralCompatConfig.yeetUpdateSuppressionCrash));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "dustTrapdoorReintroduced", GeneralCompatConfig.dustTrapdoorReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "shulkerBoxCCEReintroduced", GeneralCompatConfig.shulkerBoxCCEReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "instantBlockUpdaterReintroduced", GeneralCompatConfig.instantBlockUpdaterReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandTick", GeneralCompatConfig.commandTick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "creativeNoClip", GeneralCompatConfig.creativeNoClip));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedDragonRespawn", GeneralCompatConfig.optimizedDragonRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "antiSpamDisabled", GeneralCompatConfig.antiSpamDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "blockPlacementIgnoreEntity", GeneralCompatConfig.blockPlacementIgnoreEntity));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeOpenContainerForcibly", GeneralCompatConfig.creativeOpenContainerForcibly));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "creativeOneHitKill", GeneralCompatConfig.creativeOneHitKill));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "observerNoDetection", GeneralCompatConfig.observerNoDetection));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "bambooModelNoOffset", GeneralCompatConfig.bambooModelNoOffset));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeNoItemCooldown", GeneralCompatConfig.creativeNoItemCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "ctrlQCraftingFix", GeneralCompatConfig.ctrlQCraftingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "carpetAlwaysSetDefault", GeneralCompatConfig.carpetAlwaysSetDefault));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "placementRotationFix", GeneralCompatConfig.placementRotationFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntDoNotUpdate", GeneralCompatConfig.tntDoNotUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "totallyNoBlockUpdate", GeneralCompatConfig.totallyNoBlockUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tiscmNetworkProtocol", GeneralCompatConfig.tiscmNetworkProtocol));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "hopperNoItemCost", GeneralCompatConfig.hopperNoItemCost));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "explosionNoBlockDamage", GeneralCompatConfig.explosionNoBlockDamage));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedTNTHighPriority", GeneralCompatConfig.optimizedTNTHighPriority));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntPrimerMomentumRemoved", GeneralCompatConfig.tntPrimerMomentumRemoved));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntIgnoreRedstoneSignal", GeneralCompatConfig.tntIgnoreRedstoneSignal));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntDupingFix", GeneralCompatConfig.tntDupingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "interactionUpdates", GeneralCompatConfig.interactionUpdates));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "xpNoCooldown", GeneralCompatConfig.xpNoCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "powerfulExpMending", GeneralCompatConfig.powerfulExpMending));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "clientSettingsLostOnRespawnFix", GeneralCompatConfig.clientSettingsLostOnRespawnFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "sensibleEnderman", GeneralCompatConfig.sensibleEnderman));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "entityInstantDeathRemoval", GeneralCompatConfig.entityInstantDeathRemoval));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "farmlandTrampledDisabled", GeneralCompatConfig.farmlandTrampledDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "shulkerGolem", GeneralCompatConfig.shulkerGolem));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "preventEndSpikeRespawn", GeneralCompatConfig.preventEndSpikeRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetOutOfOrderChatKick", GeneralCompatConfig.yeetOutOfOrderChatKick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableBoneBlock", GeneralCompatConfig.betterCraftableBoneBlock));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableDispenser", GeneralCompatConfig.betterCraftableDispenser));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "viewDistance", GeneralCompatConfig.viewDistance));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickCommandPermission", GeneralCompatConfig.normalizedTickCommandPermission()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickFreezeCommandToggleable", GeneralCompatConfig.tickFreezeCommandToggleable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "syncServerMsptMetricsData", GeneralCompatConfig.syncServerMsptMetricsData));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "simpleInGameCalculator", GeneralCompatConfig.simpleInGameCalculator));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "microTiming", GeneralCompatConfig.microTiming));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "fastRedstoneDust", GeneralCompatConfig.fastRedstoneDust));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "lagFreeSpawning", GeneralCompatConfig.lagFreeSpawning));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedFastEntityMovement", GeneralCompatConfig.optimizedFastEntityMovement));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedHardHitBoxEntityCollision", GeneralCompatConfig.optimizedHardHitBoxEntityCollision));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntFuseDuration", GeneralCompatConfig.normalizedTntFuseDuration()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "defaultLoggers", CarpetLoggerProtocol.serializeConfiguredDefaults(sanitizeDefaultLoggers(GeneralCompatConfig.defaultLoggers))));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "commandBot", FakeplayerConfig.enable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandPlayer", FakePlayerCompatConfig.commandPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerResident", FakePlayerCompatConfig.fakePlayerResident));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "openFakePlayerInventory", FakePlayerCompatConfig.openFakePlayerInventory));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "fakePlayerTicksLikeRealPlayer", FakePlayerCompatConfig.fakePlayerTicksLikeRealPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerDefaultSurvivalMode", FakePlayerCompatConfig.fakePlayerDefaultSurvivalMode));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerInteractLikeClient", FakePlayerCompatConfig.fakePlayerInteractLikeClient));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplaceTool", FakePlayerCompatConfig.fakePlayerAutoReplaceTool));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplenishment", FakePlayerCompatConfig.fakePlayerAutoReplenishment));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerAutoReplenishmentFormShulkerBox", FakePlayerCompatConfig.fakePlayerAutoReplenishmentFormShulkerBox));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoFish", FakePlayerCompatConfig.fakePlayerAutoFish));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerReloadAction", FakePlayerCompatConfig.fakePlayerReloadAction));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "hopperCounters", WoolHopperCounterConfig.hopperCounters));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "hopperCountersUnlimitedSpeed", WoolHopperCounterConfig.hopperCountersUnlimitedSpeed));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("pca", "pcaSyncProtocol", PcaSyncProtocolConfig.enabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("pca", "pcaSyncPlayerEntity", PcaSyncProtocolConfig.syncPlayerEntity));
} finally {
CarpetServerProtocol.CarpetRules.endBatch();
}
}
}

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