Compare commits

...

22 Commits

Author SHA1 Message Date
Helvetica Volubi 41e24e8f91 Fakeplayer Action Gui - Stage 1 (#161)
Still needs some tweaks to fit Leaves' changes

* pre add gui (not implemented)

* fallback one change in Actions

* pre for new structure of gui register

* Enhance GUI node structure with item support and command handling

* feat: update GUI node handling in bot actions

* feat: enhance command building logic in GUI nodes

* fix a bug

* feat: implement GUI navigation and command execution in BotAction GUI

* feat: refactor GuiNode and related classes to use Item instead of ItemStack

* feat: update command building logic to include additional action parameters

* feat: simplify command syntax in BotAction GUI and update inventory view handling

* feat: add ActionType enum and implement action confirmation in BotAction GUI

* feat: enhance ActionType handling and selection in BotAction GUI

* feat: integrate GUI data handling in bot actions and enhance navigation

* fix up

* because of tmp move to new org, rebrand

* Implement pagination for bot action GUI and enhance action stop functionality

* ci updates

* replace boarder item

* fix https://github.com/LophineCraft/Lophine/pull/161#issuecomment-5012127501 issues - 1

* fix https://github.com/LophineCraft/Lophine/pull/161#issuecomment-5012127501 issues - 2

* fix index

* replace some items

* feat: use the same item shown for stop & start action

* remove 2 todos, we wouldn't provide them

* refactor: simplify rendering methods in BotActionGuiContainer

* feat: add empty action placeholder and simplify item rendering

* fix: remove extra suggestions

* fix: update GUI icons for jump, move, and swap actions

* fix: update comment in open action gui

* set release mode to true

---------

Co-authored-by: xiaoxijun <A3167717663@hotmail.com>
2026-07-22 13:12:47 +00:00
Helvetica Volubi feec643a0e [ci skip] update some information 2026-07-22 01:00:09 +08:00
Helvetica Volubi 1861578557 [ci skip] fix docs 2026-07-20 03:14:23 +08:00
Helvetica Volubi 3f3618850b fix: fallback night-config version to fix config save problem 2026-07-19 17:33:23 +08:00
Helvetica Volubi 46771456de patches from 26.2
origin patches from Camellia
2026-07-19 16:50:46 +08:00
Helvetica Volubi f67b68e4b7 [ci skip] some info update 2026-07-12 21:35:03 +08:00
Helvetica Volubi 4bb5b6c3da [ci skip] fix ci for update 2026-07-12 16:23:14 +08:00
Helvetica Volubi 40aaa5f824 [ci skip] ci updates 2026-07-11 01:21:37 +08:00
Helvetica Volubi cefaa4a712 fix: some fix for bot action
fix stop command could stop all the same type of action when a stop action called

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

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

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

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

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

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

* Add Vanilla-like experience config and updates

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

* Restore vanilla ender pearl loading on Folia

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

* Restore vanilla ender pearl loading

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

* remove extra import

* Add Precise mob cap and adjust ender pearl patch

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

* remove extra import

* pre merge config

* transform config

* merge config

* rebuild patches

* fix a bug in new counter

* simplify code

---------

Co-authored-by: Helvetica Volubi <suisuroru@blue-millennium.fun>
Co-authored-by: Helvetica Volubi <88063803+Suisuroru@users.noreply.github.com>
2026-07-02 18:11:12 +08:00
Helvetica Volubi 37c22202ab [ci skip] oops 2026-06-28 04:18:47 +08:00
Helvetica Volubi 2e67f978ec Update Luminol 2026-06-28 03:16:11 +08:00
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
110 changed files with 3383 additions and 442 deletions
+1 -1
View File
@@ -11,4 +11,4 @@ issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
custom: https://afdian.com/a/Luminol
custom: [https://afdian.com/a/bm0721, https://afdian.com/a/Luminol] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+3 -3
View File
@@ -47,7 +47,7 @@ jobs:
run: chmod +x gradlew
- name: Configure Git User Details
run: git config --global user.email "ci@luminolmc.com" && git config --global user.name "LuminolMC CI"
run: git config --global user.email "ci@lophinelabs.com" && git config --global user.name "LophineLabsCI"
- name: Apply All Patches
run: ./gradlew --refresh-dependencies applyAllPatches
@@ -124,7 +124,7 @@ jobs:
tag: ${{ env.tag }}
name: ${{ env.project_id_b }} ${{ env.mcversion }} - ${{ env.commit_id }}${{ env.release_count }}
body: |
📦Version: `${{ env.mcversion }}` | Commit ${{ env.commit_id }} [![download](https://img.shields.io/github/downloads/LuminolMC/${{ env.project_id }}/${{ env.tag }}/total?color=red&style=flat-square)](https://github.com/LuminolMC/${{ env.project_id }}/releases/download/${{ env.tag }}/${{ env.jar }})
📦Version: `${{ env.mcversion }}` | Commit ${{ env.commit_id }} [![download](https://img.shields.io/github/downloads/LophineLabs/${{ env.project_id }}/${{ env.tag }}/total?color=red&style=flat-square)](https://github.com/LophineLabs/${{ env.project_id }}/releases/download/${{ env.tag }}/${{ env.jar }})
This release is automatically compiled by GitHub Actions
### Branch Info
> ${{ github.ref_name }}
@@ -143,7 +143,7 @@ jobs:
tag: ${{ env.tag }}
name: ${{ env.project_id_b }} ${{ env.mcversion }} - ${{ env.commit_id }}${{ env.release_count }}
body: |
📦Version: `${{ env.mcversion }}` | Commit ${{ env.commit_id }} [![download](https://img.shields.io/github/downloads/LuminolMC/${{ env.project_id }}/${{ env.tag }}/total?color=red&style=flat-square)](https://github.com/LuminolMC/${{ env.project_id }}/releases/download/${{ env.tag }}/${{ env.jar }})
📦Version: `${{ env.mcversion }}` | Commit ${{ env.commit_id }} [![download](https://img.shields.io/github/downloads/LophineLabs/${{ env.project_id }}/${{ env.tag }}/total?color=red&style=flat-square)](https://github.com/LophineLabs/${{ env.project_id }}/releases/download/${{ env.tag }}/${{ env.jar }})
This release is automatically compiled by GitHub Actions
### Comments
> ${{ inputs.comments }}
+16 -46
View File
@@ -5,15 +5,15 @@
*Lophine 是一个基于Luminol的分支,具有许多有用的优化和可配置的原版特性,目标是在Folia上实现更多生电的内容(请注意,完整生电请使用Fabric)*
![Created At](https://img.shields.io/github/created-at/LuminolMC/Lophine?style=for-the-badge&color=blue)
[![License](https://img.shields.io/github/license/LuminolMC/Lophine?style=for-the-badge&color=green)](LICENSE.md)
[![Issues](https://img.shields.io/github/issues/LuminolMC/Lophine?style=for-the-badge&color=orange)](https://github.com/LuminolMC/Lophine/issues)
![Created At](https://img.shields.io/github/created-at/LophineLabs/Lophine?style=for-the-badge&color=blue)
[![License](https://img.shields.io/github/license/LophineLabs/Lophine?style=for-the-badge&color=green)](LICENSE.md)
[![Issues](https://img.shields.io/github/issues/LophineLabs/Lophine?style=for-the-badge&color=orange)](https://github.com/LophineLabs/Lophine/issues)
![Commit Activity](https://img.shields.io/github/commit-activity/w/LuminolMC/Lophine?style=for-the-badge&color=purple)
![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/LuminolMC/Lophine?style=for-the-badge&color=yellow)
![GitHub all releases](https://img.shields.io/github/downloads/LuminolMC/Lophine/total?style=for-the-badge&color=red)
![Commit Activity](https://img.shields.io/github/commit-activity/w/LophineLabs/Lophine?style=for-the-badge&color=purple)
![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/LophineLabs/Lophine?style=for-the-badge&color=yellow)
![GitHub all releases](https://img.shields.io/github/downloads/LophineLabs/Lophine/total?style=for-the-badge&color=red)
![Repo contributors](https://img.shields.io/github/contributors/LuminolMC/Lophine?style=for-the-badge&color=brightgreen)
![Repo contributors](https://img.shields.io/github/contributors/LophineLabs/Lophine?style=for-the-badge&color=brightgreen)
[English](./README_EN.md) | **中文**
</div>
@@ -32,7 +32,7 @@
## 📥 下载
### 稳定版本
所有发布版本都可以在 [Releases](https://github.com/LuminolMC/Lophine/releases) 页面找到。
所有发布版本都可以在 [Releases](https://github.com/LophineLabs/Lophine/releases) 页面找到。
### 开发版本
如果您想体验最新功能,可以通过以下步骤自行构建。
@@ -41,7 +41,7 @@
```bash
# 克隆项目
git clone https://github.com/LuminolMC/Lophine.git
git clone https://github.com/LophineLabs/Lophine.git
cd Lophine
# 应用补丁并构建 Paperclip JAR
@@ -57,7 +57,7 @@ cd Lophine
```kotlin
repositories {
maven {
url = "https://repo.menthamc.org/repository/maven-public/"
url = "https://repo.bacteriawa.com/repository/maven-public/"
}
}
@@ -71,8 +71,8 @@ dependencies {
```xml
<repositories>
<repository>
<id>menthamc</id>
<url>https://repo.menthamc.org/repository/maven-public/</url>
<id>repository</id>
<url>https://repo.bacteriawa.com/repository/maven-public/</url>
</repository>
</repositories>
@@ -91,15 +91,13 @@ dependencies {
### 加入我们的社区
- **QQ群**: [1015048616](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=QML5kIVsniPi1PlZvnjHQT_02EHsZ5Jc&authKey=%2FTCJsZC7JFQ9sxAroPCKuYnlV57Z5fyqp36ewXZk3Sn4iJ9p4MB1JKdc%2FFcX3HOM&noverify=0&group_code=1015048616)
- **QQ频道**: [点击加入](https://pd.qq.com/s/eq9krf9j)
- **Telegram**: [点击加入](https://t.me/LuminolMinecraft)
- **Discord**: [点击加入](https://discord.gg/Qd7m3V6eDx)
- **QQ群**: [1020403749](https://qm.qq.com/cgi-bin/qm/qr?k=y_MA9UaN7PM9e9J1LIs9Eea3LK8C0h6J&jump_from=webapi&authKey=ap5f8MlbeezXYtnmpnT5ZOFljDuOyV6OAb2PIcViQ+Ilr60Ycq63FDDTsJOZDYtj)
- **Discord**: [点击加入](https://discord.gg/UXSgPZczcy)
### 获取帮助
- 📋 [提交 Issue](https://github.com/LuminolMC/Lophine/issues)
- 💬 [GitHub Discussions](https://github.com/LuminolMC/Lophine/discussions)
- 📋 [提交 Issue](https://github.com/LophineLabs/Lophine/issues)
- 💬 [GitHub Discussions](https://github.com/LophineLabs/Lophine/discussions)
- 📖 [项目文档](./docs/)
## 🐛 问题反馈
@@ -124,34 +122,6 @@ dependencies {
![bStats](https://bstats.org/signatures/server-implementation/Lophine.svg "bStats")
## 🎉 特别感谢
### 项目赞助商
<div align="center">
<b>感谢 <a href="https://github.com/LegacyLands">LegacyLands</a> 对本项目的赞助</b>
<br>
<i>如果你想开发跨 Folia/非 Folia 平台的插件,<a href="https://github.com/LegacyLands/legacy-lands-library/">legacy-lands-library</a> 将会是个不错的选择</i>
<br><br>
<img src="public/image/legacy-lands-logo.png" alt="LegacyLands Logo" width="200">
</div>
---
## ⭐ 请给我们一个 Star
> 你的每一个免费的 ⭐Star 就是我们每一个前进的动力。
### Star 历史
<a href="https://star-history.com/#LuminolMC/Luminol&LuminolMC/LightingLuminol&LuminolMC/Lophine&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=LuminolMC/Luminol%2CLuminolMC/LightingLuminol%2CLuminolMC/Lophine&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=LuminolMC/Luminol%2CLuminolMC/LightingLuminol%2CLuminolMC/Lophine&type=Date" />
<img alt="Star历史表" src="https://api.star-history.com/svg?repos=LuminolMC/Luminol%2CLuminolMC/LightingLuminol%2CLuminolMC/Lophine&type=Date" />
</picture>
</a>
<div align="center">
<b>如果这个项目对您有帮助,请不要忘记给我们一个 ⭐Star!</b>
</div>
+16 -46
View File
@@ -5,15 +5,15 @@
*Lophine is a Luminol fork with many useful optimizations and configurable vanilla features, aims to provide more function for survival-usable circuit on folia (Please note that Fabric should be used for complete survival-usable)*
![Created At](https://img.shields.io/github/created-at/LuminolMC/Lophine?style=for-the-badge&color=blue)
[![License](https://img.shields.io/github/license/LuminolMC/Lophine?style=for-the-badge&color=green)](LICENSE.md)
[![Issues](https://img.shields.io/github/issues/LuminolMC/Lophine?style=for-the-badge&color=orange)](https://github.com/LuminolMC/Lophine/issues)
![Created At](https://img.shields.io/github/created-at/LophineLabs/Lophine?style=for-the-badge&color=blue)
[![License](https://img.shields.io/github/license/LophineLabs/Lophine?style=for-the-badge&color=green)](LICENSE.md)
[![Issues](https://img.shields.io/github/issues/LophineLabs/Lophine?style=for-the-badge&color=orange)](https://github.com/LophineLabs/Lophine/issues)
![Commit Activity](https://img.shields.io/github/commit-activity/w/LuminolMC/Lophine?style=for-the-badge&color=purple)
![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/LuminolMC/Lophine?style=for-the-badge&color=yellow)
![GitHub all releases](https://img.shields.io/github/downloads/LuminolMC/Lophine/total?style=for-the-badge&color=red)
![Commit Activity](https://img.shields.io/github/commit-activity/w/LophineLabs/Lophine?style=for-the-badge&color=purple)
![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/LophineLabs/Lophine?style=for-the-badge&color=yellow)
![GitHub all releases](https://img.shields.io/github/downloads/LophineLabs/Lophine/total?style=for-the-badge&color=red)
![Repo contributors](https://img.shields.io/github/contributors/LuminolMC/Lophine?style=for-the-badge&color=brightgreen)
![Repo contributors](https://img.shields.io/github/contributors/LophineLabs/Lophine?style=for-the-badge&color=brightgreen)
**English** | [中文](./README.md)
</div>
@@ -32,7 +32,7 @@
## 📥 Download
### Stable Releases
All release versions can be found on the [Releases](https://github.com/LuminolMC/Lophine/releases) page.
All release versions can be found on the [Releases](https://github.com/LophineLabs/Lophine/releases) page.
### Development Builds
If you want to experience the latest features, you can build it yourself following the steps below.
@@ -41,7 +41,7 @@ If you want to experience the latest features, you can build it yourself followi
```bash
# Clone the project
git clone https://github.com/LuminolMC/Lophine.git
git clone https://github.com/LophineLabs/Lophine.git
cd Lophine
# Apply patches and build Paperclip JAR
@@ -57,7 +57,7 @@ After building, you can find the generated JAR file in the `lophine-server/build
```kotlin
repositories {
maven {
url = "https://repo.menthamc.org/repository/maven-public/"
url = "https://repo.bacteriawa.com/repository/maven-public/"
}
}
@@ -71,8 +71,8 @@ dependencies {
```xml
<repositories>
<repository>
<id>menthamc</id>
<url>https://repo.menthamc.org/repository/maven-public/</url>
<id>repository</id>
<url>https://repo.bacteriawa.com/repository/maven-public/</url>
</repository>
</repositories>
@@ -92,15 +92,13 @@ dependencies {
### Join Our Community
- **QQ Group**: [1015048616](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=QML5kIVsniPi1PlZvnjHQT_02EHsZ5Jc&authKey=%2FTCJsZC7JFQ9sxAroPCKuYnlV57Z5fyqp36ewXZk3Sn4iJ9p4MB1JKdc%2FFcX3HOM&noverify=0&group_code=1015048616)
- **QQ Channel**: [Join Here](https://pd.qq.com/s/eq9krf9j)
- **Telegram**: [Join Here](https://t.me/LuminolMinecraft)
- **Discord**: [Join Here](https://discord.gg/Qd7m3V6eDx)
- **QQ Group**: [1020403749](https://qm.qq.com/cgi-bin/qm/qr?k=y_MA9UaN7PM9e9J1LIs9Eea3LK8C0h6J&jump_from=webapi&authKey=ap5f8MlbeezXYtnmpnT5ZOFljDuOyV6OAb2PIcViQ+Ilr60Ycq63FDDTsJOZDYtj)
- **Discord**: [Join Here](https://discord.gg/UXSgPZczcy)
### Get Help
- 📋 [Submit Issues](https://github.com/LuminolMC/Lophine/issues)
- 💬 [GitHub Discussions](https://github.com/LuminolMC/Lophine/discussions)
- 📋 [Submit Issues](https://github.com/LophineLabs/Lophine/issues)
- 💬 [GitHub Discussions](https://github.com/LophineLabs/Lophine/discussions)
- 📖 [Project Documentation](./docs/)
## 🐛 Bug Reports
@@ -125,34 +123,6 @@ We welcome community contributions! For detailed contribution guidelines, please
![bStats](https://bstats.org/signatures/server-implementation/Lophine.svg "bStats")
## 🎉 Special Thanks
### Project Sponsors
<div align="center">
<b>Thanks to <a href="https://github.com/LegacyLands">LegacyLands</a> for sponsoring this project</b>
<br>
<i>If you want to develop cross-Folia/non-Folia platform plugins, <a href="https://github.com/LegacyLands/legacy-lands-library/">legacy-lands-library</a> would be a great choice</i>
<br><br>
<img src="public/image/legacy-lands-logo.png" alt="LegacyLands Logo" width="200">
</div>
---
## ⭐ Give Us a Star!
> Every free ⭐Star you give is the motivation for our every step forward.
### Star History
<a href="https://star-history.com/#LuminolMC/Luminol&LuminolMC/LightingLuminol&LuminolMC/Lophine&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=LuminolMC/Luminol%2CLuminolMC/LightingLuminol%2CLuminolMC/Lophine&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=LuminolMC/Luminol%2CLuminolMC/LightingLuminol%2CLuminolMC/Lophine&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=LuminolMC/Luminol%2CLuminolMC/LightingLuminol%2CLuminolMC/Lophine&type=Date" />
</picture>
</a>
<div align="center">
<b>If this project helps you, please don't forget to give us a ⭐Star!</b>
</div>
+5 -5
View File
@@ -9,7 +9,7 @@ plugins {
paperweight {
filterPatches = false
upstreams.register("luminol") {
repo = github("LuminolMC", "Luminol")
repo = github("LuminolCustomArchive", "Luminol")
ref = providers.gradleProperty("luminolRef")
println("Upstream commit ref: " + ref.get())
@@ -44,7 +44,7 @@ paperweight {
}
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
val menthaMavenPublicUrl = "https://repo.menthamc.org/repository/maven-public/";
val bacteriawaMavenPublicUrl = "https://repo.bacteriawa.com/repository/maven-public/";
subprojects {
apply(plugin = "java-library")
@@ -59,7 +59,7 @@ subprojects {
repositories {
mavenCentral()
maven(paperMavenPublicUrl)
maven(menthaMavenPublicUrl)
maven(bacteriawaMavenPublicUrl)
}
dependencies {
@@ -91,8 +91,8 @@ subprojects {
extensions.configure<PublishingExtension> {
repositories {
maven("https://repo.menthamc.org/repository/maven-snapshots/") {
name = "MenthaMC"
maven("https://repo.bacteriawa.com/repository/maven-releases/") {
name = "Bacteriawa"
credentials(PasswordCredentials::class) {
username = System.getenv("PRIVATE_MAVEN_REPO_USERNAME")
password = System.getenv("PRIVATE_MAVEN_REPO_PASSWORD")
+1 -1
View File
@@ -9,7 +9,7 @@ release=true
# true for push to repo, false for skip push repo, auto for detect by release value
pushRepo=auto
luminolRef=7de90e841ed4a8c5aaeea394328604165b7a4b7b
luminolRef=b796645fdaae7d6b3d3c84fd79f9c090a6458a48
org.gradle.configuration-cache=true
org.gradle.caching=true
@@ -0,0 +1,46 @@
package org.leavesmc.leaves.event.bot;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.entity.bot.Bot;
public class BotActionGuiOpenEvent extends BotEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Player player;
private boolean cancel = false;
public BotActionGuiOpenEvent(@NotNull Bot who, @Nullable Player player) {
super(who);
this.player = player;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancel;
}
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Nullable
public Player getOpenPlayer() {
return player;
}
@Override
public @NotNull HandlerList getHandlers() {
return handlers;
}
}
+6 -2
View File
@@ -42,7 +42,7 @@
}
}
val log4jPlugins = sourceSets.create("log4jPlugins") {
@@ -158,7 +_,7 @@
@@ -158,10 +_,10 @@
}
dependencies {
@@ -50,7 +50,11 @@
+ implementation(project(":lophine-api"))
// Luminol start - Dependenices insert
implementation("net.objecthunter:exp4j:0.4.8")
implementation("com.electronwill.night-config:toml:3.9.0") // Night config
- implementation("com.electronwill.night-config:toml:3.9.0") // Night config
+ implementation("com.electronwill.night-config:toml:3.8.4") // Night config
implementation("com.github.luben:zstd-jni:1.5.4-1")
implementation("net.openhft:zero-allocation-hashing:0.16")
implementation("io.github.classgraph:classgraph:4.8.158")
@@ -234,14 +_,14 @@
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
attributes(
@@ -5,14 +5,14 @@ Subject: [PATCH] Rebrand to Lophine
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index a2f5a99ee45a0810fd338ccf6f71df3a077ca62b..05e1aa84586284ac0389e7023f975bfb08438535 100644
index 3b700b214ac6818cd75c34b207aa1436f52231e7..315c137cb9dbac51a8ac0d63f0ae0127e57c6c9f 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -24,6 +24,7 @@ public class ConfigManager {
@@ -25,6 +25,7 @@ public class ConfigManager {
public static void initConfigs() {
registerConfig("luminol", ConfigsInstance.of("luminol", "me.earthme.luminol.config.modules"));
+ registerConfig("lophine", ConfigsInstance.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
registerConfig("luminol", builder.of("luminol", "me.earthme.luminol.config.modules"));
+ registerConfig("lophine", builder.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
preLoad();
}
@@ -5,10 +5,10 @@ Subject: [PATCH] Leaves: Fakeplayer
diff --git a/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java b/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
index 0a20c6f03625391201e5ced167707e54ed27daa1..dc983bcb8d2e90ad27a693dfcd6debb4b2c2b86b 100644
index a4c188f71564fc77a9fa22b4cae032e1919d06f2..019266803f1452cb1e76350da8edae10a77020ac 100644
--- a/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
+++ b/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
@@ -46,6 +46,12 @@ public class FoliaServerWaypointManager implements WaypointManager<@NotNull Wayp
@@ -54,6 +54,12 @@ public class FoliaServerWaypointManager extends ServerWaypointManager {
return;
}
@@ -21,16 +21,15 @@ index 0a20c6f03625391201e5ced167707e54ed27daa1..dc983bcb8d2e90ad27a693dfcd6debb4
this.waypoints.add(waypoint);
for (ServerPlayer toCreateFor : this.trackingPlayers) {
@@ -101,6 +107,12 @@ public class FoliaServerWaypointManager implements WaypointManager<@NotNull Wayp
scheduleIfOffTarget(player, () -> {
this.trackingPlayers.add(player);
@@ -110,6 +116,11 @@ public class FoliaServerWaypointManager extends ServerWaypointManager {
this.trackingPlayers.add(player);
scheduleIfOffTarget(player, () -> {
+ // Leaves start - fakeplayer
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
+ return;
+ }
+ // Leaves end - fakeplayer
+
for (WaypointTransmitter transmitter : this.waypoints) {
this.createConnection(player, transmitter);
}
@@ -5,15 +5,15 @@ Subject: [PATCH] Carpet features
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index 05e1aa84586284ac0389e7023f975bfb08438535..5a8c94337e42584ddaf25ef289327777e7ac675e 100644
index 315c137cb9dbac51a8ac0d63f0ae0127e57c6c9f..2a2d6aff636ad960638b357d224a631c89d23d33 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -25,6 +25,15 @@ public class ConfigManager {
@@ -26,6 +26,15 @@ public class ConfigManager {
public static void initConfigs() {
registerConfig("luminol", ConfigsInstance.of("luminol", "me.earthme.luminol.config.modules"));
registerConfig("lophine", ConfigsInstance.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
registerConfig("luminol", builder.of("luminol", "me.earthme.luminol.config.modules"));
registerConfig("lophine", builder.of("lophine", "fun.bm.lophine.config.modules")); // add lophine global config
+ // Lophine start - add carpet config
+ registerConfig("lophine_carpet", ConfigsInstance.of(
+ registerConfig("lophine_carpet", builder.of(
+ new java.io.File("lophine_config"),
+ "lophine_carpet",
+ "lophine_carpet_config.toml",
@@ -7,10 +7,10 @@ Subject: [PATCH] TEMP: Temporarily transform config between different config
Should be removed in Minecraft 26.2 Update
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index 5a8c94337e42584ddaf25ef289327777e7ac675e..b652525f243c23e09c4e13f67617e99a3ce0db04 100644
index 2a2d6aff636ad960638b357d224a631c89d23d33..536e8d7df4ce9de1dbe587c1af6b2474a530a165 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -64,6 +64,12 @@ public class ConfigManager {
@@ -65,6 +65,12 @@ public class ConfigManager {
CompletableFuture.allOf(futures).join();
CommandRegister.register(); // register command after config loaded to enable some command didn't depend on config files
initialized = true;
@@ -39,7 +39,7 @@ index 143ad4e342b184aa02b6fbbe81508e244eebc7a2..89be42b8519522398920eb424c894fd2
String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck();
if (awtException != null) {
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 3707b03b6d7ebdf47a38f4feff5b738eb41f38e1..1bc1e9a77dca7acfe5f989f6439f185d0d2e20a6 100644
index dfac07850b02abba160f8f143eba4569172ab9e9..fcd4b4785f0d09f87fe214202468c75395157e14 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -283,6 +283,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -5,10 +5,10 @@ Subject: [PATCH] Fix datapack command save function
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 83178b9a0b017c8945c0f41981838f40263c9a12..ef898f5b60219be00471f9ea227103dfcea5b202 100644
index e7eec08a4d8943b35a76173e39529498c348140c..61983a80191e64942bfdac74c6d2f23cf781484d 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2472,6 +2472,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2475,6 +2475,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return this.reloadResources(packsToEnable, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN);
}
@@ -8,10 +8,10 @@ As part of: Purpur (https://github.com/PurpurMC/Purpur/blob/dc46f46d28dcdcaf33bb
Licensed under: MIT (https://github.com/PurpurMC/Purpur/blob/dc46f46d28dcdcaf33bb533f9571a107db98c1d7/LICENSE)
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 63b81f30b8d813a7986ae72842fdc2d3097fa103..527c495bb4f6007aee760b99cc0e9aa589931f4b 100644
index c9d3b000a328fe3583a7053a94c72dc003c1e10c..45e5ac1e8e2ec30935e96fa20d18e77bbd0e20bd 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -961,6 +961,10 @@ public abstract class PlayerList {
@@ -963,6 +963,10 @@ public abstract class PlayerList {
player.getBukkitEntity().recalculatePermissions(); // CraftBukkit
this.server.getCommands().sendCommands(player);
} // Paper - Add sendOpLevel API
@@ -23,10 +23,10 @@ index 63b81f30b8d813a7986ae72842fdc2d3097fa103..527c495bb4f6007aee760b99cc0e9aa5
// Paper start - whitelist verify event / login event
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 1413286ddc63c5978e745eb26f6012230e4b1cd6..234124cc64e5175c20f9e9f0f482c9c677bca563 100644
index 592ce8beb28ebe8aaac2ed167abb24148afb0bc3..ce8ab4b7eee5e0715e780d189d2f6554c5a9dc3c 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -174,6 +174,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -175,6 +175,7 @@ public abstract class Player extends Avatar implements ContainerUser {
public float hurtDir;
public boolean affectsSpawning = true; // Paper - Affects Spawning API
public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage
@@ -5,10 +5,10 @@ Subject: [PATCH] Add config to enable cross region damage trace
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 1d17ab4775916bcd820666259e840e98eb9aa792..37956ca0f114657347ba53cfde50f8e8591b2571 100644
index ad50feba5cbc5fe904850e6da06a866eeb23b519..f7869f06ab29e4bbd003c807176345dec9e9e5ab 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1464,6 +1464,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1467,6 +1467,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.awardStat(Stats.ENTITY_KILLED_BY.get(killer.getType()));
killer.awardKillScore(this, source);
this.createWitherRose(killer);
@@ -22,7 +22,7 @@ index 1d17ab4775916bcd820666259e840e98eb9aa792..37956ca0f114657347ba53cfde50f8e8
}
this.level().broadcastEntityEvent(this, EntityEvent.DEATH);
@@ -1487,6 +1494,24 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1490,6 +1497,24 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// Leaves end - exp fix
@@ -48,7 +48,7 @@ index 1d17ab4775916bcd820666259e840e98eb9aa792..37956ca0f114657347ba53cfde50f8e8
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 0a403e859169e0dcc4b0fd6fde7bd8bd7037e8b3..ad25bd7ce12ceedae38d1db5008be52efa807b14 100644
index cd2fb9e2110d0dba1358daa283af767db3f4e80a..cc7b2ea7fda1326e3f9ed46373190a05f60c4d34 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -1961,6 +1961,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -48,10 +48,10 @@ index 89f61f5715942d2b521e04b9fdc8b1b379c0c957..2c2487e1c1c65438119a13bd705a9e44
SaveOnCommand.register(this.dispatcher);
SetPlayerIdleTimeoutCommand.register(this.dispatcher);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index ef898f5b60219be00471f9ea227103dfcea5b202..4991b8a925d9431d80f42a4480d76d6602a85347 100644
index 61983a80191e64942bfdac74c6d2f23cf781484d..99edebf474277e680df63930b51fef579b712def 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1683,6 +1683,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1686,6 +1686,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Folia start - region threading
public void tickServer(final long startTime, final long scheduledEnd, final long targetBuffer,
final io.papermc.paper.threadedregions.TickRegions.TickRegionData region) {
@@ -96,10 +96,10 @@ index cb0a52dc3795e1cf54069bcbe82abf7877a658b8..0d743a01ae70baa789cd0e0bb9abd4c4
public EntityType(
final EntityType.EntityFactory<T> factory,
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 234124cc64e5175c20f9e9f0f482c9c677bca563..b45481f781f3556001af89704b718d6291ba1f66 100644
index ce8ab4b7eee5e0715e780d189d2f6554c5a9dc3c..06c6d30f3aef605bc25c42db8a6d26bbde57f40b 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -185,6 +185,25 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -186,6 +186,25 @@ public abstract class Player extends Avatar implements ContainerUser {
return (org.bukkit.craftbukkit.entity.CraftHumanEntity) super.getBukkitEntity();
}
// CraftBukkit end
@@ -125,7 +125,7 @@ index 234124cc64e5175c20f9e9f0f482c9c677bca563..b45481f781f3556001af89704b718d62
public Player(final Level level, final GameProfile gameProfile) {
super(EntityType.PLAYER, level);
@@ -240,6 +259,26 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -241,6 +260,26 @@ public abstract class Player extends Avatar implements ContainerUser {
@Override
public void tick() {
@@ -152,7 +152,7 @@ index 234124cc64e5175c20f9e9f0f482c9c677bca563..b45481f781f3556001af89704b718d62
this.noPhysics = this.isSpectator();
if (this.isSpectator() || this.isPassenger()) {
this.setOnGround(false);
@@ -1352,6 +1391,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1355,6 +1394,7 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.hasContainerOpen()) {
this.doCloseContainer();
}
@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 2 Jul 2026 18:49:40 +0800
Subject: [PATCH] Old leader zombie health logic
diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
index 2734ffc103ee4760d3521609fdd090ab99df675b..a99683d341f52139003dfa5190ee118d5b06f59f 100644
--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
+++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
@@ -597,7 +597,7 @@ public class Zombie extends Monster {
.addOrReplacePermanentModifier(
new AttributeModifier(LEADER_ZOMBIE_BONUS_ID, this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)
);
- if (spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) {
+ if (!fun.bm.lophine.config.modules.function.OldFeatureConfig.oldLeaderZombieHealth && spawnReason != EntitySpawnReason.CONVERSION && spawnReason != EntitySpawnReason.LOAD && spawnReason != EntitySpawnReason.DIMENSION_TRAVEL) { // Lophine - Configurable option to disable health boost for leader zombies
this.setHealth(this.getMaxHealth());
}
@@ -5,7 +5,7 @@ Subject: [PATCH] Spawn invulnerable time
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 37956ca0f114657347ba53cfde50f8e8591b2571..eb461febb88f4135be14397d0d5e96fd3483e4e2 100644
index f7869f06ab29e4bbd003c807176345dec9e9e5ab..295be200cb0696bd2ae2b655f89d96dd7723a541 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -242,6 +242,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -16,7 +16,7 @@ index 37956ca0f114657347ba53cfde50f8e8591b2571..eb461febb88f4135be14397d0d5e96fd
private ChatVisiblity chatVisibility = ChatVisiblity.FULL;
public ParticleStatus particleStatus = ParticleStatus.ALL;
private boolean canChatColor = true;
@@ -920,6 +921,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -923,6 +924,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.connection.tickClientLoadTimeout();
this.gameMode.tick();
this.wardenSpawnTracker.tick();
@@ -24,7 +24,7 @@ index 37956ca0f114657347ba53cfde50f8e8591b2571..eb461febb88f4135be14397d0d5e96fd
if (this.invulnerableTime > 0) {
this.invulnerableTime--;
}
@@ -1556,6 +1558,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1559,6 +1561,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
if (this.isInvulnerableTo(level, source)) {
return false;
} else {
@@ -6,7 +6,7 @@ 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 ad25bd7ce12ceedae38d1db5008be52efa807b14..a4f5c0585c2353c39c4c991138d838a724d2eae2 100644
index cc7b2ea7fda1326e3f9ed46373190a05f60c4d34..2bce20202b7c539bee3685741663a8ed225919ff 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -1234,6 +1234,30 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -36,10 +36,10 @@ index e9f86409bf9351e85ed31e747d9350dbf0cc441f..1f8f4d979d8766d6ba385f74cf8fcf8e
};
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 4991b8a925d9431d80f42a4480d76d6602a85347..9e290fa626caffac148920c54479a75ad0919e70 100644
index 99edebf474277e680df63930b51fef579b712def..3cd1a0de188db35ac9c48996a4dbe6186b69e348 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2037,6 +2037,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2040,6 +2040,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
profiler.popPush("server gui refresh");
@@ -96,10 +96,10 @@ index cf4b5e436b8d81657d1deaa5b06645016d9dc3cc..f3af5660a377e2eb823f79ec274feaf3
bridge.removeChannel(channel);
}
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 527c495bb4f6007aee760b99cc0e9aa589931f4b..e6987eaf6e4d36d43cee4ece3ce22d31052a2a2a 100644
index 45e5ac1e8e2ec30935e96fa20d18e77bbd0e20bd..deb029c5621f793f63447d351526c31fab5ec12c 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -317,6 +317,8 @@ public abstract class PlayerList {
@@ -318,6 +318,8 @@ public abstract class PlayerList {
//return; // Folia - region threading - must still allow the player to connect, as we must add to chunk map before handling disconnect
}
@@ -108,7 +108,7 @@ index 527c495bb4f6007aee760b99cc0e9aa589931f4b..e6987eaf6e4d36d43cee4ece3ce22d31
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -517,6 +519,7 @@ public abstract class PlayerList {
@@ -518,6 +520,7 @@ public abstract class PlayerList {
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
}
public net.kyori.adventure.text.@Nullable Component remove(final ServerPlayer player, final net.kyori.adventure.text.Component leaveMessage) {
@@ -116,7 +116,7 @@ index 527c495bb4f6007aee760b99cc0e9aa589931f4b..e6987eaf6e4d36d43cee4ece3ce22d31
// Paper end - Fix kick event leave message not being sent
ServerLevel level = player.level();
player.awardStat(Stats.LEAVE_GAME);
@@ -1411,6 +1414,7 @@ public abstract class PlayerList {
@@ -1413,6 +1416,7 @@ public abstract class PlayerList {
player.connection.send(recipes);
player.getRecipeBook().sendInitialRecipeBook(player);
}
@@ -8,7 +8,7 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/9d2bd3f7b0a48f00d
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 047c605eb087667e10da557864ad931dadebd274..e9547fb9be40c3e999a9172acb48037595439396 100644
index 0f1bd15ea3b1400cc948883c92eceabcd4a4cda1..006844d6fda43f3b151899655f03b1de03f3396c 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -3158,7 +3158,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -21,10 +21,10 @@ index 047c605eb087667e10da557864ad931dadebd274..e9547fb9be40c3e999a9172acb480375
}
// Paper end - Fix merchant inventory not closing on entity removal
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index e6987eaf6e4d36d43cee4ece3ce22d31052a2a2a..168702a5ae51a2bc42c5761e13cb14008a8162c4 100644
index deb029c5621f793f63447d351526c31fab5ec12c..6148e7e5978a9a5b7d7f90b58b86b0166fd16c9d 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -560,7 +560,7 @@ public abstract class PlayerList {
@@ -561,7 +561,7 @@ public abstract class PlayerList {
player.stopRiding();
vehicle.getPassengersAndSelf().forEach(e -> {
// Paper start - Fix villager boat exploit
@@ -23,7 +23,7 @@ index ca35415e152dc63cb9f4ae8da8b06766600922fd..033715812acb8f98a7c7d895d115043e
+ // Leaves end - servux
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index e9547fb9be40c3e999a9172acb48037595439396..0ff635e6956a9935ad6d11e5c7bac189c51244b6 100644
index 006844d6fda43f3b151899655f03b1de03f3396c..0befa4fc81e10a23c6ba824e559f2fb4886e68ee 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -2584,6 +2584,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -8,10 +8,10 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 168702a5ae51a2bc42c5761e13cb14008a8162c4..ebd2f2887780d9c6c3c44983bac23eab732cf43f 100644
index 6148e7e5978a9a5b7d7f90b58b86b0166fd16c9d..16d01fcb97aa3dbd7554bd64b3608c6e80ce3dbd 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -1105,6 +1105,7 @@ public abstract class PlayerList {
@@ -1107,6 +1107,7 @@ public abstract class PlayerList {
//player.connection.send(new ClientboundSetChunkCacheRadiusPacket(io.papermc.paper.FeatureHooks.getViewDistance(level))); // Paper - rewrite chunk system
//player.connection.send(new ClientboundSetSimulationDistancePacket(io.papermc.paper.FeatureHooks.getSimulationDistance(level))); // Paper - rewrite chunk system
// Paper end - view distances
@@ -33,7 +33,7 @@ index efbbc1a40d203a2818eeda2a4e938b9a6117f1c3..6b85a5ad9af0c57a0d4d5b55f62b82c5
private boolean encrypted;
private final java.util.concurrent.atomic.AtomicBoolean disconnectionHandled = new java.util.concurrent.atomic.AtomicBoolean(false); // Folia - region threading - may be called concurrently during configuration stage
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 9e290fa626caffac148920c54479a75ad0919e70..75d93d7d8bc6077dd80e499cd43327a4afe58f51 100644
index 3cd1a0de188db35ac9c48996a4dbe6186b69e348..9837d8388e6fe73ef87d021c7370c2a7c236c634 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -297,6 +297,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -45,7 +45,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..75d93d7d8bc6077dd80e499cd43327a4
public static <S extends MinecraftServer> S spin(final Function<Thread, S> factory) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
AtomicReference<S> serverReference = new AtomicReference<>();
@@ -1226,6 +1228,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1229,6 +1231,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.safeShutdown(wait, false);
}
public void safeShutdown(final boolean wait, final boolean isRestarting) {
@@ -62,7 +62,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..75d93d7d8bc6077dd80e499cd43327a4
this.isRestarting = isRestarting;
this.hasLoggedStop = true; // Paper - Debugging
if (this.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
@@ -1695,7 +1707,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1698,7 +1710,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
int emptyTickThreshold = this.pauseWhenEmptySeconds() * 20;
this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping
if (false && emptyTickThreshold > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy
@@ -71,7 +71,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..75d93d7d8bc6077dd80e499cd43327a4
this.emptyTicks++;
} else {
this.emptyTicks = 0;
@@ -1827,6 +1839,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1830,6 +1842,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.isSaving = true;
if (playerSaveInterval > 0) {
this.playerList.saveAll(playerSaveInterval);
@@ -79,7 +79,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..75d93d7d8bc6077dd80e499cd43327a4
}
if (region == null && fullSave) { // Folia - region threading - don't auto save level data
this.saveGlobalData(false);
@@ -2065,6 +2078,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2068,6 +2081,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
protected void tickConnection() {
this.getConnection().tick();
@@ -87,7 +87,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..75d93d7d8bc6077dd80e499cd43327a4
}
public void forceGameTimeSynchronization() {
@@ -3270,6 +3284,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -3273,6 +3287,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return this.debugSubscribers;
}
@@ -239,7 +239,7 @@ index e9c9a468f046832e8eaa999bb57da261b4633604..2efe24c0378a80dd2750b10a54c18878
}
}
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 1bc1e9a77dca7acfe5f989f6439f185d0d2e20a6..1790e8c141a8d3f7ccf4b11f9a28b3582325e317 100644
index fcd4b4785f0d09f87fe214202468c75395157e14..09e92f20f97b374582e057b0dc7d2edc82d6f431 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -274,6 +274,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -277,7 +277,7 @@ index 0dfb25ad032429a2aea7aa441dd5fd1848a6c617..215f2a40921cc8e6b181c0a34aa1bbaf
}
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 0ff635e6956a9935ad6d11e5c7bac189c51244b6..8bfb2afd7199b2739ccfbab4ad68e030e722db7e 100644
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
@@ -334,7 +334,7 @@ index 0ff635e6956a9935ad6d11e5c7bac189c51244b6..8bfb2afd7199b2739ccfbab4ad68e030
ServerLevel.this.updateSleepingPlayerList();
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index eb461febb88f4135be14397d0d5e96fd3483e4e2..c38c098bf4db3d8fb09ba9f102dbddfb57faca06 100644
index 295be200cb0696bd2ae2b655f89d96dd7723a541..4f6010285a5ff9cf939248c4d93043133680d383 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -229,7 +229,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -355,7 +355,7 @@ index eb461febb88f4135be14397d0d5e96fd3483e4e2..c38c098bf4db3d8fb09ba9f102dbddfb
private @Nullable Vec3 levitationStartPos;
private int levitationStartTime;
private boolean disconnected;
@@ -1514,7 +1514,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1517,7 +1517,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// Luminol End - Cross Region Damage trace
@@ -364,7 +364,7 @@ index eb461febb88f4135be14397d0d5e96fd3483e4e2..c38c098bf4db3d8fb09ba9f102dbddfb
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
this.level()
.getEntitiesOfClass(Mob.class, aabb, EntitySelector.NO_SPECTATORS)
@@ -2180,6 +2180,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -2183,6 +2183,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.lastSentHealth = -1.0F;
this.lastSentFood = -1;
this.teleportSpectators(transition, oldLevel);
@@ -377,7 +377,7 @@ index eb461febb88f4135be14397d0d5e96fd3483e4e2..c38c098bf4db3d8fb09ba9f102dbddfb
org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), oldLevel.getWorld());
this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
diff --git a/net/minecraft/server/players/CachedUserNameToIdResolver.java b/net/minecraft/server/players/CachedUserNameToIdResolver.java
index 50c64f4be138f08e8a57fb10888dbfbc364c91af..382fc20df48d7d554833715a9c9f62ea7464a25d 100644
index d2da9f3c5e53ceaeb85c6d3d7443e124a4d93bb8..8a96c07e6d5fd0826efc50e3fd585a42b2c9028c 100644
--- a/net/minecraft/server/players/CachedUserNameToIdResolver.java
+++ b/net/minecraft/server/players/CachedUserNameToIdResolver.java
@@ -122,6 +122,12 @@ public class CachedUserNameToIdResolver implements UserNameToIdResolver {
@@ -442,10 +442,10 @@ index 484714beb5f7cdf8178834c5edd4f847fb06ebb8..ba7a280aad07f36366c15cd158b36ca9
// Paper start - utility method for common conversion back to the game profile
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f0da2047c 100644
index 16d01fcb97aa3dbd7554bd64b3608c6e80ce3dbd..b77968e195d1f87c825c09b2a1622b3a3ed5f772 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -319,6 +319,19 @@ public abstract class PlayerList {
@@ -320,6 +320,19 @@ public abstract class PlayerList {
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
@@ -465,7 +465,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -791,6 +804,11 @@ public abstract class PlayerList {
@@ -793,6 +806,11 @@ public abstract class PlayerList {
respawnReason
).callEvent();
// Paper end
@@ -477,7 +477,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
return player;
}
@@ -893,11 +911,16 @@ public abstract class PlayerList {
@@ -895,11 +913,16 @@ public abstract class PlayerList {
public String[] getPlayerNamesArray() {
List<ServerPlayer> players = new java.util.ArrayList<>(this.players); // Folia - region threading
@@ -495,7 +495,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
return names;
}
@@ -1016,8 +1039,15 @@ public abstract class PlayerList {
@@ -1018,8 +1041,15 @@ public abstract class PlayerList {
|| this.allowCommandsForAllPlayers;
}
@@ -513,7 +513,7 @@ index ebd2f2887780d9c6c3c44983bac23eab732cf43f..14be3d21cc1a613b1d9164ecc699073f
}
public void broadcast(
@@ -1360,7 +1390,13 @@ public abstract class PlayerList {
@@ -1362,7 +1392,13 @@ public abstract class PlayerList {
}
public @Nullable ServerPlayer getPlayer(final UUID uuid) {
@@ -551,7 +551,7 @@ index f090b8d77bd2731debfc61c263bd77550f52212b..03c155140da7300f6f934aff323e0dae
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 a4f5c0585c2353c39c4c991138d838a724d2eae2..a5b80dec06e906886b1d4fbee64d556a9a0402bd 100644
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
@@ -597,7 +597,7 @@ index a4f5c0585c2353c39c4c991138d838a724d2eae2..a5b80dec06e906886b1d4fbee64d556a
if (!this.level().isClientSide()) {
boolean wasUsingItem = this.isUsingItem();
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index b45481f781f3556001af89704b718d6291ba1f66..2135ea645131c27b9bec5534431199f9d55134d8 100644
index 06c6d30f3aef605bc25c42db8a6d26bbde57f40b..20a76138a8625663cf608e4ef97cc8ca4085b844 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -167,7 +167,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -608,8 +608,8 @@ index b45481f781f3556001af89704b718d6291ba1f66..2135ea645131c27b9bec5534431199f9
+ protected ItemStack lastItemInMainHand = ItemStack.EMPTY; // Leaves - fakeplayer
private final ItemCooldowns cooldowns = this.createItemCooldowns();
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
public @Nullable FishingHook fishing;
@@ -340,6 +340,12 @@ public abstract class Player extends Avatar implements ContainerUser {
public me.earthme.luminol.functions.bars.TickableStatusBarList statusBarList = new me.earthme.luminol.functions.bars.TickableStatusBarList(this); // Luminol status bars
@@ -341,6 +341,12 @@ public abstract class Player extends Avatar implements ContainerUser {
this.updatePlayerPose();
}
@@ -622,7 +622,7 @@ index b45481f781f3556001af89704b718d6291ba1f66..2135ea645131c27b9bec5534431199f9
@Override
protected float getMaxHeadRotationRelativeToBody() {
return this.isBlocking() ? 15.0F : super.getMaxHeadRotationRelativeToBody();
@@ -565,7 +571,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -566,7 +572,7 @@ public abstract class Player extends Avatar implements ContainerUser {
public void removeEntitiesOnShoulder() {
}
@@ -631,7 +631,7 @@ index b45481f781f3556001af89704b718d6291ba1f66..2135ea645131c27b9bec5534431199f9
entity.playerTouch(this);
}
@@ -1247,7 +1253,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1250,7 +1256,7 @@ public abstract class Player extends Avatar implements ContainerUser {
// Paper end - Configurable sprint interruption on attack
}
@@ -84,10 +84,10 @@ index 7e3912b8b29e40eb3347f1451b0fd3ebee2af4f1..0834e402e6af7028e08851378e15390e
result.add(player);
if (result.size() >= limit) {
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 75d93d7d8bc6077dd80e499cd43327a4afe58f51..3b9a4f4b5794faa4955018858c94fd5c2d6ada3d 100644
index 9837d8388e6fe73ef87d021c7370c2a7c236c634..5889aa815ab02261f26048c5ef43f5bdfa2939fc 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1930,7 +1930,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1933,7 +1933,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
private ServerStatus.Players buildPlayerStatus() {
@@ -96,7 +96,7 @@ index 75d93d7d8bc6077dd80e499cd43327a4afe58f51..3b9a4f4b5794faa4955018858c94fd5c
int maxPlayers = this.getMaxPlayers();
if (this.hidesOnlinePlayers()) {
return new ServerStatus.Players(maxPlayers, players.size(), List.of());
@@ -2151,7 +2151,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2154,7 +2154,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@Override
public int getPlayerCount() {
@@ -105,7 +105,7 @@ index 75d93d7d8bc6077dd80e499cd43327a4afe58f51..3b9a4f4b5794faa4955018858c94fd5c
}
public String[] getPlayerNames() {
@@ -2363,7 +2363,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2366,7 +2366,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
} else {
int count = 0;
@@ -114,7 +114,7 @@ index 75d93d7d8bc6077dd80e499cd43327a4afe58f51..3b9a4f4b5794faa4955018858c94fd5c
player.getBukkitEntity().taskScheduler.schedule((ServerPlayer updatedPlayer) -> { // Folia - region threading
// Paper start - Expand PlayerGameModeChangeEvent
org.bukkit.event.player.PlayerGameModeChangeEvent event = updatedPlayer.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); // Folia - region threading
@@ -2550,7 +2550,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2553,7 +2553,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (Thread.currentThread() != this.serverThread) return; // Paper
// Paper start - we don't need to save everything, just advancements
// this.getPlayerList().saveAll();
@@ -123,7 +123,7 @@ index 75d93d7d8bc6077dd80e499cd43327a4afe58f51..3b9a4f4b5794faa4955018858c94fd5c
player.getAdvancements().save();
}
// Paper end - we don't need to save everything, just advancements
@@ -2686,7 +2686,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2689,7 +2689,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
PlayerList playerList = this.getPlayerList();
UserWhiteList whiteList = playerList.getWhiteList();
@@ -285,7 +285,7 @@ index 37c9f983ae89c497f44a1b7967d741abf909e0a0..d7fb2505f2a86ca0d81f144624ef2e1a
this.setListData(players);
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 8bfb2afd7199b2739ccfbab4ad68e030e722db7e..8d6a5d2ab4589f81abdd4ae939f197051e9523fc 100644
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
@@ -307,7 +307,7 @@ index 8bfb2afd7199b2739ccfbab4ad68e030e722db7e..8d6a5d2ab4589f81abdd4ae939f19705
}
// Leaves end - skip
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1f82c9279 100644
index b77968e195d1f87c825c09b2a1622b3a3ed5f772..c95c7b9a3968fc34a900a613b65b5d3e1abb24bf 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -130,6 +130,7 @@ public abstract class PlayerList {
@@ -318,7 +318,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
// CraftBukkit start
private org.bukkit.craftbukkit.CraftServer cserver;
@@ -191,6 +192,7 @@ public abstract class PlayerList {
@@ -192,6 +193,7 @@ public abstract class PlayerList {
private boolean countConnection(Connection conn, int limit) {
synchronized (this.connectionsStateLock) {
@@ -326,7 +326,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
int count = this.usersCountedAgainstLimit.size();
if (count >= limit) {
return false;
@@ -221,6 +223,124 @@ public abstract class PlayerList {
@@ -222,6 +224,124 @@ public abstract class PlayerList {
abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor
@@ -451,7 +451,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
public void placeNewPlayer(final Connection connection, final ServerPlayer player, final CommonListenerCookie cookie) {
player.isRealPlayer = true; // Paper
player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
@@ -294,6 +414,7 @@ public abstract class PlayerList {
@@ -295,6 +415,7 @@ public abstract class PlayerList {
// player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players)); // CraftBukkit - replaced with loop below
this.players.add(player);
@@ -459,7 +459,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); // Spigot
this.playersByUUID.put(player.getUUID(), player);
// this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player))); // CraftBukkit - replaced with loop below
@@ -513,6 +634,7 @@ public abstract class PlayerList {
@@ -514,6 +635,7 @@ public abstract class PlayerList {
}
protected void save(final ServerPlayer player) {
@@ -467,7 +467,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
player.lastSave = System.nanoTime(); // Folia - region threading - changed to nanoTime tracking
this.playerIo.save(player);
@@ -527,6 +649,47 @@ public abstract class PlayerList {
@@ -528,6 +650,47 @@ public abstract class PlayerList {
}
}
@@ -515,15 +515,15 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
public net.kyori.adventure.text.@Nullable Component remove(final ServerPlayer player) { // CraftBukkit - return string // Paper - return Component
// Paper start - Fix kick event leave message not being sent
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
@@ -600,6 +763,7 @@ public abstract class PlayerList {
@@ -601,6 +764,7 @@ public abstract class PlayerList {
player.getBukkitEntity().packetProcessor.close(); // Folia - region threading
player.getAdvancements().stopListening();
this.players.remove(player);
+ this.realPlayers.remove(player); // Leaves - replay api
this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
if (me.earthme.luminol.config.modules.misc.UsernameCheckConfig.allowOldPlayersJoin) this.playedPlayers.remove(player.getGameProfile().name()); // Leaf - Configurable vanilla username check
this.server.getCustomBossEvents().onPlayerDisconnect(player);
UUID uuid = player.getUUID();
@@ -910,15 +1074,15 @@ public abstract class PlayerList {
@@ -912,15 +1076,15 @@ public abstract class PlayerList {
}
public String[] getPlayerNamesArray() {
@@ -546,7 +546,7 @@ index 14be3d21cc1a613b1d9164ecc699073f0da2047c..baa295f3dd8cf10bf7347ee4d1c249b1
// Leaves end - fakeplayer support
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index a5b80dec06e906886b1d4fbee64d556a9a0402bd..5389f974eb688021f131f73d6d74f989906ef3d4 100644
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
@@ -21,10 +21,10 @@ index e302c6198d71782b524391329aa5c89d2b3e0ccf..2312803297321f66c9057bc54ce56dd1
} else {
this.followingPlayer = null;
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 2135ea645131c27b9bec5534431199f9d55134d8..5e7e99410c7597ec5330cc82e441fa30c53c9532 100644
index 20a76138a8625663cf608e4ef97cc8ca4085b844..97057675369875ed71c228a87f5a4d3c3489dded 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -279,8 +279,8 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -280,8 +280,8 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.cullTask != null) this.cullTask.requestCullSignal(); // Luminol - Ray tracing entity tracker
// Luminol end
@@ -35,7 +35,7 @@ index 2135ea645131c27b9bec5534431199f9d55134d8..5e7e99410c7597ec5330cc82e441fa30
this.setOnGround(false);
}
@@ -406,7 +406,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -407,7 +407,7 @@ public abstract class Player extends Avatar implements ContainerUser {
if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) {
Pose desiredPose = this.getDesiredPose();
Pose actualPose;
@@ -44,7 +44,7 @@ index 2135ea645131c27b9bec5534431199f9d55134d8..5e7e99410c7597ec5330cc82e441fa30
actualPose = desiredPose;
} else if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.CROUCHING)) {
actualPose = Pose.CROUCHING;
@@ -535,7 +535,7 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -536,7 +536,7 @@ public abstract class Player extends Avatar implements ContainerUser {
this.updateSwingTime();
this.yHeadRot = this.getYRot();
this.setSpeed((float)this.getAttributeValue(Attributes.MOVEMENT_SPEED));
@@ -53,7 +53,7 @@ index 2135ea645131c27b9bec5534431199f9d55134d8..5e7e99410c7597ec5330cc82e441fa30
AABB pickupArea;
if (this.isPassenger() && !this.getVehicle().isRemoved()) {
pickupArea = this.getBoundingBox().minmax(this.getVehicle().getBoundingBox()).inflate(1.0, 0.0, 1.0);
@@ -1846,6 +1846,26 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1849,6 +1849,26 @@ public abstract class Player extends Avatar implements ContainerUser {
return this.gameMode() == GameType.SPECTATOR;
}
@@ -5,7 +5,7 @@ Subject: [PATCH] Global Entities Counter
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
index 0cf5815672ac62d8caf7f18165be1f0f8e067aed..64d407c5a6140a7e5dc47a8e304b4c00602e2bdd 100644
index eedbeb005d3c8090333c36b9857c837dfb75dbd4..7ea91dbfb988aff3215a91cf62c9beae94461484 100644
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
@@ -558,6 +558,9 @@ public final class RegionizedWorldData {
@@ -23,10 +23,10 @@ index 0cf5815672ac62d8caf7f18165be1f0f8e067aed..64d407c5a6140a7e5dc47a8e304b4c00
this.regionData = regionData;
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ uniqueId = fun.bm.lophine.utils.EntitiesCounterUtil.generateUniqueId();
+ fun.bm.lophine.utils.EntitiesCounterUtil.reportAreaMap(world, spawnChunkTracker, uniqueId);
+ fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(world, loadedEntities, uniqueId);
+ if (!fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(world, loadedEntities, uniqueId);
+ underGlobalEntitiesCounter = true;
+ }
+ // Lophine end - Global Entities Counter
@@ -35,15 +35,15 @@ index 0cf5815672ac62d8caf7f18165be1f0f8e067aed..64d407c5a6140a7e5dc47a8e304b4c00
this.updateTickData();
}
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f824ad7df2 100644
index 27389ff98942e27c2a877ea5b671caa31353d18c..76fa17ce0afc7ff1c0b2b84aa2baddd2ba18c1a5 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -513,6 +513,25 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -513,6 +513,26 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
this.chunkMap.tick(haveTime);
profiler.pop();
this.clearCache();
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.level.getCurrentWorldData();
+ if (regionizedWorldData != null) {
+ if (regionizedWorldData.underGlobalEntitiesCounter) {
@@ -53,6 +53,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
+ }
+ } else {
+ if (!regionizedWorldData.getLocalPlayers().isEmpty()) {
+ regionizedWorldData.uniqueId = fun.bm.lophine.utils.EntitiesCounterUtil.generateUniqueId();
+ fun.bm.lophine.utils.EntitiesCounterUtil.reportAreaMap(level, regionizedWorldData.spawnChunkTracker, regionizedWorldData.uniqueId);
+ fun.bm.lophine.utils.EntitiesCounterUtil.addDataToLoaded(level, (ca.spottedleaf.moonrise.common.list.ReferenceList<Entity>) regionizedWorldData.getLoadedEntities(), regionizedWorldData.uniqueId);
+ regionizedWorldData.underGlobalEntitiesCounter = true;
@@ -64,14 +65,14 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
}
private void tickChunks() {
@@ -577,7 +596,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -577,7 +597,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
}
spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, null, true); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
} else {
- spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ spawnCookie = fun.bm.lophine.utils.EntitiesCounterUtil.runRemainingTasks(level, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ spawnCookie = fun.bm.lophine.utils.EntitiesCounterUtil.createSpawnState(level, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
+ } else {
+ spawnCookie = NaturalSpawner.createState(chunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all
+ }
@@ -79,7 +80,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
}
} finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.MOB_SPAWN_ENTITY_COUNT); } // Folia - profiler
// Paper end - Optional per player mob spawns
@@ -585,7 +610,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -585,7 +611,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
boolean doMobSpawning = this.level.getGameRules().get(GameRules.SPAWN_MOBS) && !this.level.getLocalPlayers().isEmpty(); // CraftBukkit // Folia - region threading
int tickSpeed = this.level.getGameRules().get(GameRules.RANDOM_TICK_SPEED);
List<MobCategory> spawningCategories;
@@ -88,7 +89,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
// Paper start - PlayerNaturallySpawnCreaturesEvent
for (ServerPlayer player : this.level.getLocalPlayers()) { // Folia - region threading
int chunkRange = Math.min(level.spigotConfig.mobSpawnRange, player.getBukkitEntity().getViewDistance());
@@ -645,7 +670,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -645,7 +671,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
this.level.tickThunder(chunk);
}
@@ -98,7 +99,7 @@ index 27389ff98942e27c2a877ea5b671caa31353d18c..e9e5f929d638d3ddf279423d3e23b3f8
NaturalSpawner.spawnForChunk(this.level, chunk, spawnCookie, spawningCategories);
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 8d6a5d2ab4589f81abdd4ae939f197051e9523fc..54011666a2f358fe38ca03bc39d68d122011c796 100644
index a7cebb797973cde399dc30c696b064efd40874f2..1d60c20649b2a6469bfceb5b44c38bfd133e21eb 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -808,6 +808,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -106,15 +107,51 @@ index 8d6a5d2ab4589f81abdd4ae939f197051e9523fc..54011666a2f358fe38ca03bc39d68d12
public void tick(BooleanSupplier haveTime, final io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking
+ // Lophine start - Global Entities Counter
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ if (fun.bm.lophine.utils.EntitiesCounterUtil.canRunNewTask(this)) fun.bm.lophine.utils.EntitiesCounterUtil.tick(this);
+ }
+ // Lophine end - Global Entities Counter
final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - regionised ticking
final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle foliaProfiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler
ProfilerFiller profiler = Profiler.get();
@@ -2902,6 +2907,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public void close() throws IOException {
super.close();
//this.entityManager.close(); // Paper - rewrite chunk system
+ // Lophine start - Precise mob cap
+ if (!fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onWorldUnload(this);
+ }
+ // Lophine end - Precise mob cap
}
@Override
@@ -3136,6 +3146,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
entity.inWorld = true; // CraftBukkit - Mark entity as in world
entity.valid = true; // CraftBukkit
ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server
+ // Lophine start - Precise mob cap
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled() && !fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onEntityTrackingStart(ServerLevel.this, entity);
+ }
+ // Lophine end - Precise mob cap
// Paper start - Entity origin API
if (entity.origin == null) {
entity.origin = entity.position();
@@ -3151,6 +3166,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public void onTrackingEnd(final Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot
+ // Lophine start - Precise mob cap
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled() && !fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isDefaultModule()) {
+ fun.bm.lophine.utils.EntitiesCounterUtil.onEntityTrackingEnd(ServerLevel.this, entity);
+ }
+ // Lophine end - Precise mob cap
ServerLevel.this.getCurrentWorldData().removeLoadedEntity(entity); // Folia - region threading
// Spigot start // TODO I don't think this is needed anymore
if (entity instanceof Player player) {
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
index fc29654dd7ee3329edf1ccf705f45631d0ecc079..9b8ee2df5a0b6d76d9bfc747187f6cd51bb4a520 100644
index fc29654dd7ee3329edf1ccf705f45631d0ecc079..042f026f707e1a75b4ec7dc231e0eeb1b5afacc3 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -813,6 +813,44 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs
@@ -122,7 +159,7 @@ index fc29654dd7ee3329edf1ccf705f45631d0ecc079..9b8ee2df5a0b6d76d9bfc747187f6cd5
}
} else {
+ // Lophine start - fix some bug if player is cross scheduler >> to remove monster if the region don't have any valid player
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.enabled) {
+ if (fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter.isEnabled()) {
+ List<net.minecraft.server.level.ServerPlayer> playerList = this.level().getServer().getPlayerList().getPlayers();
+ if (!playerList.isEmpty()) {
+ double d = -1.0;
@@ -36,10 +36,10 @@ index 24f5b890b0126fc817863f99b676da1a548f7608..a25bc31c04778bf12e3b6301ffcfb227
throw PacketUtils.makeReportedException(var3, this.packet, this.listener);
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 3b9a4f4b5794faa4955018858c94fd5c2d6ada3d..0b7e704210c4bc01797a33a9c0da609a844d8489 100644
index 5889aa815ab02261f26048c5ef43f5bdfa2939fc..af245af0fba14892095961a71925f3a53ce3d477 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2019,11 +2019,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2022,11 +2022,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
try {
foliaProfiler.startTimer(level.tickTimerId); try { // Folia - profiler
level.tick(haveTime, region); // Folia - region threading
@@ -74,7 +74,7 @@ index 3b9a4f4b5794faa4955018858c94fd5c2d6ada3d..0b7e704210c4bc01797a33a9c0da609a
profiler.pop();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 54011666a2f358fe38ca03bc39d68d122011c796..3f7b3a07a6f65b231de16d5bc1e68d5b90f41311 100644
index 1d60c20649b2a6469bfceb5b44c38bfd133e21eb..b884e06a5e9d6a93c548820a99e5d05157e9d128 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -967,7 +967,18 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -98,10 +98,10 @@ index 54011666a2f358fe38ca03bc39d68d122011c796..3f7b3a07a6f65b231de16d5bc1e68d5b
}
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index c38c098bf4db3d8fb09ba9f102dbddfb57faca06..627af751fcd905c60f2d09eb066ac53dba607d85 100644
index 4f6010285a5ff9cf939248c4d93043133680d383..020b2fcb5213a618b557f0578a7d44db5a8dc109 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1130,6 +1130,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1133,6 +1133,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
// Folia - region threading - move to main tick loop where we can detect duplicates
// CraftBukkit end
@@ -5,7 +5,7 @@ Subject: [PATCH] Instant Block Updater
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
index 64d407c5a6140a7e5dc47a8e304b4c00602e2bdd..9911c70d89cfb43b803cab9bbe6eedd1142f59d6 100644
index 7ea91dbfb988aff3215a91cf62c9beae94461484..491d108cc8e440653746f20fc5b5bca3b791eb88 100644
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
@@ -506,7 +506,7 @@ public final class RegionizedWorldData {
@@ -38,7 +38,7 @@ index 64d407c5a6140a7e5dc47a8e304b4c00602e2bdd..9911c70d89cfb43b803cab9bbe6eedd1
\ No newline at end of file
+}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 3f7b3a07a6f65b231de16d5bc1e68d5b90f41311..ad36f4bace2bf6eaf28f3ca26bf07369eddbfe38 100644
index b884e06a5e9d6a93c548820a99e5d05157e9d128..cb449a5063f7944551c2e66b603c0f910d84e50f 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1001,11 +1001,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -128,7 +128,7 @@ index 1a2b57a100c997b39f8f25ad3da121e04700d5d2..6b0d0a2c0067065b4a995a9f12791066
// Paper start - fix converting txt to json file; moved from constructor
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 627af751fcd905c60f2d09eb066ac53dba607d85..be948a57431dcd4bb3b23a742e71957be58cee2d 100644
index 020b2fcb5213a618b557f0578a7d44db5a8dc109..5e70e4e8a67e50a067dff1e592d617ca6a0426a9 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -257,6 +257,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -139,7 +139,7 @@ index 627af751fcd905c60f2d09eb066ac53dba607d85..be948a57431dcd4bb3b23a742e71957b
private @Nullable Vec3 startingToFallPosition;
private @Nullable Vec3 enteredNetherPosition;
private @Nullable Vec3 enteredLavaOnVehiclePosition;
@@ -2828,6 +2829,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -2831,6 +2832,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.setShoulderEntityRight(oldPlayer.getShoulderEntityRight());
this.setLastDeathLocation(oldPlayer.getLastDeathLocation());
this.waypointIcon().copyFrom(oldPlayer.waypointIcon());
@@ -151,7 +151,7 @@ index 627af751fcd905c60f2d09eb066ac53dba607d85..be948a57431dcd4bb3b23a742e71957b
}
private void transferInventoryXpAndScore(final Player oldPlayer) {
@@ -3111,6 +3117,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -3114,6 +3120,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.particleStatus = information.particleStatus();
this.getEntityData().set(DATA_PLAYER_MODE_CUSTOMISATION, (byte)information.modelCustomisation());
this.getEntityData().set(DATA_PLAYER_MAIN_HAND, information.mainHand());
@@ -384,7 +384,7 @@ index 2312803297321f66c9057bc54ce56dd17ecb6f1f..27163558d967eed2035fd167fa515420
return this.entityData.get(DATA_VALUE);
}
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 5389f974eb688021f131f73d6d74f989906ef3d4..cabf724eb0a2521bda329d8cfc042dcee3da81f3 100644
index a3c19d725e03c07de6708f3c2d092e0b9aea69c2..0bd4d786c8e957a31811f52514a992543a0cee92 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -601,7 +601,10 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -481,10 +481,10 @@ index 459a05ca83583538f995f45c4d2c977c6d6fcd00..35a275ff953a271a2769a18af8163e81
}
}
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 5e7e99410c7597ec5330cc82e441fa30c53c9532..f34631cd7d5d1c76f2b1522200e5c9f6bf5406f5 100644
index 97057675369875ed71c228a87f5a4d3c3489dded..79bc1c2320ffd7b7017b664b5fe376566968c265 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -555,7 +555,15 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -556,7 +556,15 @@ public abstract class Player extends Avatar implements ContainerUser {
}
if (!orbs.isEmpty()) {
@@ -501,7 +501,7 @@ index 5e7e99410c7597ec5330cc82e441fa30c53c9532..f34631cd7d5d1c76f2b1522200e5c9f6
}
}
@@ -1066,6 +1074,28 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1069,6 +1077,28 @@ public abstract class Player extends Avatar implements ContainerUser {
if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable.
// Paper end - PlayerAttackEntityEvent
@@ -530,7 +530,7 @@ index 5e7e99410c7597ec5330cc82e441fa30c53c9532..f34631cd7d5d1c76f2b1522200e5c9f6
float baseDamage = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE);
ItemStack attackingItemStack = this.getWeaponItem();
DamageSource damageSource = this.createAttackSource(attackingItemStack); final DamageSource dmgSourceFinal = damageSource; // Paper - damage events
@@ -1123,6 +1153,18 @@ public abstract class Player extends Avatar implements ContainerUser {
@@ -1126,6 +1156,18 @@ public abstract class Player extends Avatar implements ContainerUser {
}
}
@@ -676,10 +676,10 @@ index 298908003d5422b8b58de631145fad381e8294c1..2e5519813260033daff127fef2598cd1
public void addRecipe(RecipeHolder<?> holder) {
org.spigotmc.AsyncCatcher.catchOp("Recipe Add"); // Spigot
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index f0ae87545bd38c38cffbc2217acb9008a4183531..95ec0e3b78a8740dd593c80d5dd8f1bf693c35af 100644
index 8c051d7322d8efc1ae2e151964fd0124740fd04d..d419d9e3c8f7af424a1b4783f7e7a015bbf541b0 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1176,6 +1176,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -1175,6 +1175,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
BlockState state = newState;
BlockState blockState = oldState;
BlockState blockState1 = currentState;
@@ -692,7 +692,7 @@ index f0ae87545bd38c38cffbc2217acb9008a4183531..95ec0e3b78a8740dd593c80d5dd8f1bf
if (blockState1 == state) {
if (blockState != blockState1) {
this.setBlocksDirty(pos, blockState, blockState1);
@@ -1192,7 +1198,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -1191,7 +1197,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
}
}
@@ -53,10 +53,10 @@ index 74ef76058e5a410d12f88aa09450e7d90f63b5e6..1761167da363cd074a26499caadeaeb9
}
// Luminol end - Add a config to enable tick command
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index be948a57431dcd4bb3b23a742e71957be58cee2d..d3b24d2f94b1edeb02a4bd4fb2271093c7597a09 100644
index 5e70e4e8a67e50a067dff1e592d617ca6a0426a9..63300acdcb1cdab2bf080c4939abb256fe05efa1 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2188,7 +2188,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -2191,7 +2191,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.lastSentFood = -1;
this.teleportSpectators(transition, oldLevel);
// Leaves start - bot support
@@ -66,10 +66,10 @@ index be948a57431dcd4bb3b23a742e71957be58cee2d..d3b24d2f94b1edeb02a4bd4fb2271093
}
// Leaves end - bot support
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index baa295f3dd8cf10bf7347ee4d1c249b1f82c9279..1d5376650d0f5eeb23fde8d7116b47cfae37576f 100644
index c95c7b9a3968fc34a900a613b65b5d3e1abb24bf..64779d7b28e61c91897db5226158d65c32bfc835 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -280,7 +280,7 @@ public abstract class PlayerList {
@@ -281,7 +281,7 @@ public abstract class PlayerList {
// org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
// Leaves start - bot support
@@ -78,7 +78,7 @@ index baa295f3dd8cf10bf7347ee4d1c249b1f82c9279..1d5376650d0f5eeb23fde8d7116b47cf
org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
if (bot != null) {
this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
@@ -441,7 +441,7 @@ public abstract class PlayerList {
@@ -442,7 +442,7 @@ public abstract class PlayerList {
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
// Leaves start - bot support
@@ -87,7 +87,7 @@ index baa295f3dd8cf10bf7347ee4d1c249b1f82c9279..1d5376650d0f5eeb23fde8d7116b47cf
org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
if (bot != null) {
this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
@@ -969,7 +969,7 @@ public abstract class PlayerList {
@@ -971,7 +971,7 @@ public abstract class PlayerList {
).callEvent();
// Paper end
// Leaves start - bot support
@@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Tue, 23 Jun 2026 02:32:14 +0800
Subject: [PATCH] PCA sync protocol
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/252a16955f6e1e31aac85d222b093b0797d392f8/leaves-server/minecraft-patches/features/0027-PCA-sync-protocol.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/SimpleContainer.java b/net/minecraft/world/SimpleContainer.java
index 049c6ab6472415479435f2caab0444c3cbd33902..d9bb641c07e2e8d3780fadac44ff5e3ee0e35c8b 100644
--- a/net/minecraft/world/SimpleContainer.java
+++ b/net/minecraft/world/SimpleContainer.java
@@ -199,6 +199,11 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled && this.getOwner() instanceof org.bukkit.craftbukkit.entity.CraftEntity entity) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(entity.getHandle());
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java b/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
index 8da479d04c04366561549617c477b0811a9b3d7c..345f63ccac2579acf4cf4ee9507c231da12b03ba 100644
--- a/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
+++ b/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java
@@ -140,6 +140,11 @@ public abstract class AbstractChestBoat extends AbstractBoat implements HasCusto
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
index d2c4b47b2f95c8e6bafc93e436041143e68ffa4f..12938642aa58b6b64d7536575712dc3eadfb6e13 100644
--- a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
+++ b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecartContainer.java
@@ -66,6 +66,11 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
@Override
public void setChanged() {
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this);
+ }
+ // Leaves end - PCA sync protocol
}
@Override
diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java
index 5e7612ad30c218fcbb7c9cdd66ecb69d78d8875d..0fa8f720e3b386a5466b3a94d18d5dbbd0d48836 100644
--- a/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -256,6 +256,14 @@ public abstract class BlockEntity implements DebugValueSource, TypedInstance<Blo
if (!blockState.isAir()) {
level.updateNeighbourForOutputSignal(worldPosition, blockState.getBlock());
}
+ // Leaves start - PCA sync protocol
+ if (fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig.enabled && !level.isClientSide()) {
+ BlockEntity blockEntity = level.getBlockEntity(worldPosition);
+ if (blockEntity != null) {
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(blockEntity);
+ }
+ }
+ // Leaves end - PCA sync protocol
}
public BlockPos getBlockPos() {
@@ -0,0 +1,256 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Tue, 23 Jun 2026 03:06:41 +0800
Subject: [PATCH] Add Vanilla-like experience Config
diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java
index b97d65b81ec4b86e00b7c06341b40dc5c02b9044..d997e4f7ae6ee4e81f5fffe874f2895dda314df9 100644
--- a/ca/spottedleaf/moonrise/paper/PaperHooks.java
+++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java
@@ -204,6 +204,11 @@ public class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
@Override
public int configMaxAutoSavePerTick(final ServerLevel world) {
+ // Lophine start - Vanilla-like experience
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled) {
+ return 200;
+ }
+ // Lophine end - Vanilla-like experience
return world.paperConfig().chunks.maxAutoSaveChunksPerTick;
}
@@ -308,4 +313,4 @@ public class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
public boolean addTicketForEnderPearls(final ServerLevel world) {
return !world.paperConfig().misc.legacyEnderPearlBehavior;
}
-}
\ No newline at end of file
+}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 63300acdcb1cdab2bf080c4939abb256fe05efa1..99e61bbe15430a72096489777a4e417ec5125337 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2390,7 +2390,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
public boolean isInvulnerableTo(final ServerLevel level, final DamageSource source) {
// Paper start - disable player cramming
return (super.isInvulnerableTo(level, source) || this.isChangingDimension() && !source.is(DamageTypes.ENDER_PEARL) || !this.connection.hasClientLoaded())
- || (!this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING));
+ || (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !this.level().paperConfig().collisions.allowPlayerCrammingDamage && source.is(DamageTypes.CRAMMING)); // Lophine - Vanilla-like experience
// Paper end - disable player cramming
}
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 0bd4d786c8e957a31811f52514a992543a0cee92..31212878ac31a8d9849b471b103b95553b274501 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3993,7 +3993,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
// Paper start - Cap entity collisions
this.numCollisions = Math.max(0, this.numCollisions - this.level().paperConfig().collisions.maxEntityCollisions);
for (Entity entityx : pushableEntities) {
- if (this.numCollisions >= this.level().paperConfig().collisions.maxEntityCollisions) {
+ if (this.numCollisions >= (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled ? Integer.MAX_VALUE : this.level().paperConfig().collisions.maxEntityCollisions)) { // Lophine - Vanilla-like experience
break;
}
diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java
index c3f1f875b1adc75f9e9747e148f214e4623a0b4f..04c264611273872a9a33fe2a4d1e2a041e6e78d2 100644
--- a/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -383,7 +383,7 @@ public class FallingBlockEntity extends Entity {
ResourceKey<Level> oldDimension = this.level().dimension();
boolean fromOrToEnd = (oldDimension == Level.END || newDimension == Level.END) && oldDimension != newDimension;
Entity newEntity = super.teleport(transition);
- this.forceTickAfterTeleportToDuplicate = newEntity != null && fromOrToEnd && (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation || me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled); // Paper // Luminol - Unsafe teleportation
+ this.forceTickAfterTeleportToDuplicate = newEntity != null && fromOrToEnd && (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowUnsafeEndPortalTeleportation || me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled || fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled); // Paper // Luminol - Unsafe teleportation // Lophine - Vanilla-like experience
return newEntity;
}
}
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index 679a941a2af886697fbfcbc7f21e5f4e0ec77dc3..1d4856c477441dd3dc57432c7129fc7f54b528bd 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -259,7 +259,7 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
if (this.isMergable()) {
double radius = this.level().spigotConfig.itemMerge; // Spigot
for (ItemEntity entity : this.level()
- .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, this.level().paperConfig().entities.behavior.onlyMergeItemsHorizontally ? 0 : radius - 0.5D, radius), other -> other != this && other.isMergable())) { // Spigot // Paper - configuration to only merge items horizontally
+ .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled ? radius : (this.level().paperConfig().entities.behavior.onlyMergeItemsHorizontally ? 0 : radius - 0.5D), radius), other -> other != this && other.isMergable())) { // Spigot // Paper - configuration to only merge items horizontally // Lophine - Vanilla-like experience
if (entity.isMergable()) {
// Paper start - Fix items merging through walls
if (this.level().paperConfig().fixes.fixItemsMergingThroughWalls) {
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
index 5b5717a886dab57b2fe9ad926a8ae7b3d4f30155..05d8ba6e5a984660be2fba97f9022393bb84f62b 100644
--- a/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
@@ -107,7 +107,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
@Override
public void tick() {
- if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().getCurrentWorldData().currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot // Folia - region threading
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().getCurrentWorldData().currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot // Folia - region threading // Lophine - Vanilla-like experience
//this.handlePortal(); // Folia - region threading
this.applyGravity();
this.move(MoverType.SELF, this.getDeltaMovement());
diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java
index 61ca77cceeacf0c4ebecf3bb66c4eb99c62033d2..fb3651bb6ebc4b75c17c2443dc9f95caeea98ef0 100644
--- a/net/minecraft/world/entity/monster/Phantom.java
+++ b/net/minecraft/world/entity/monster/Phantom.java
@@ -259,7 +259,7 @@ public class Phantom extends Mob implements Enemy {
for (Player player : players) {
if (Phantom.this.canAttack(level, player, TargetingConditions.DEFAULT)) {
- if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls
+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls // Lophine - Vanilla-like experience
Phantom.this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit - reason
return true;
} // Paper - Add phantom creative and insomniac controls
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index c99c66563192629e399d1d904cb654c624fe9837..04e4e03399e5484bdbe8695fc2da5e5df152ba34 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -90,7 +90,8 @@ public final class NaturalSpawner {
MobCategory category = entity.getType().getCategory();
if (category != MobCategory.MISC) {
// Paper start - Only count natural spawns
- if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && // Lophine - Vanilla-like experience
+ !entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index 69d436268492183ae41fb9a60e61ed1f58a674d9..27e99cdd3a20c8c9177ccf8daa8fdf6984d51318 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -451,7 +451,7 @@ public class ServerExplosion implements Explosion {
if (this.fire || !cachedBlock.blockState.isAir()) {
ret.add(cachedBlock.immutablePos);
// Paper start - prevent headless pistons from forming
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == net.minecraft.world.level.block.Blocks.MOVING_PISTON) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowHeadlessPistons && iblockdata.getBlock() == net.minecraft.world.level.block.Blocks.MOVING_PISTON) { // Lophine - Vanilla-like experience
net.minecraft.world.level.block.entity.BlockEntity extension = this.level.getBlockEntity(cachedBlock.immutablePos); // Paper - optimise collisions
if (extension instanceof net.minecraft.world.level.block.piston.PistonMovingBlockEntity blockEntity && blockEntity.isSourcePiston()) {
net.minecraft.core.Direction direction = iblockdata.getValue(net.minecraft.world.level.block.piston.PistonHeadBlock.FACING);
diff --git a/net/minecraft/world/level/block/Block.java b/net/minecraft/world/level/block/Block.java
index 30f7e8f5e3e9440713e36ee25c90150b6b93c6ff..8527e46cab53ce6e67319cb87e9dcdda6b729de5 100644
--- a/net/minecraft/world/level/block/Block.java
+++ b/net/minecraft/world/level/block/Block.java
@@ -116,7 +116,7 @@ public class Block extends BlockBehaviour implements ItemLike {
private BlockState defaultBlockState;
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
public final boolean isDestroyable() {
- return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
+ return fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || // Lophine - Vanilla-like experience
this != Blocks.BARRIER &&
this != Blocks.BEDROCK &&
this != Blocks.END_PORTAL_FRAME &&
diff --git a/net/minecraft/world/level/block/TripWireHookBlock.java b/net/minecraft/world/level/block/TripWireHookBlock.java
index 836eae0c3e0891a3e3309b684f15d65f891215cf..a0fe40351ebb95fd5207bc63be82dbb887baebef 100644
--- a/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -188,7 +188,7 @@ public class TripWireHookBlock extends Block {
if (!cancelledEmitterHook) { // Paper - Call BlockRedstoneEvent
emitState(level, pos, attached, powered, wasAttached, wasPowered);
if (!isBeingDestroyed) {
- if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipTripwireHookPlacementValidation || level.getBlockState(pos).is(Blocks.TRIPWIRE_HOOK)) // Paper - Validate tripwire hook placement before update
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipTripwireHookPlacementValidation || level.getBlockState(pos).is(Blocks.TRIPWIRE_HOOK)) // Paper - Validate tripwire hook placement before update // Lophine - Vanilla-like experience
level.setBlock(pos, newState.setValue(FACING, direction), Block.UPDATE_ALL);
if (canUpdate) {
notifyNeighbors(block, level, pos, direction);
diff --git a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
index 62d7a44f139c28a38b14833380e2ec2bf84f3a75..12af97b9ffcf7c0f9e815ccbd81f99a80c6a5819 100644
--- a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
@@ -332,7 +332,7 @@ public class BeehiveBlockEntity extends BlockEntity {
iterator.remove();
}
// Paper start - Fix bees aging inside; use exitTickCounter to keep actual bee life
- else if (level.paperConfig().entities.behavior.cooldownFailedBeehiveReleases) {
+ else if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && level.paperConfig().entities.behavior.cooldownFailedBeehiveReleases) { // Lophine - Vanilla-like experience
data.exitTickCounter = data.occupant.minTicksInHive / 2;
}
// Paper end - Fix bees aging inside; use exitTickCounter to keep actual bee life
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 8066cdcaba8d2fcfa2e9ba3b040a2867dbbc6978..c904e35d49a36e2722295490a5a6aea67f29826e 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -346,7 +346,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
origItemStack.setCount(originalItemCount);
}
}
- if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
+ if (foundItem && !fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown // Lophine - Vanilla-like experience
hopper.setCooldown(level.spigotConfig.hopperTransfer);
}
return false;
diff --git a/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index a4d8ed890fc6bea1e961df814c00d22ae147734f..da037fbc38b4e605890711f4497ac8755a4f76f0 100644
--- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -152,7 +152,7 @@ public class PistonBaseBlock extends DirectionalBlock {
Direction direction = state.getValue(FACING);
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
Direction directionQueuedAs = Direction.from3DDataValue(b1 & 7); // Paper - copied from below
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && direction != directionQueuedAs) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && direction != directionQueuedAs) { // Lophine - Vanilla-like experience
return false;
}
// Paper end - Protect Bedrock and End Portal/Frames from being destroyed
@@ -237,7 +237,7 @@ public class PistonBaseBlock extends DirectionalBlock {
} else {
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed; fix headless pistons breaking blocks
BlockPos headPos = pos.relative(direction);
- if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || level.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, direction)) { // double check to make sure we're not a headless piston
+ if (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || level.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, direction)) { // double check to make sure we're not a headless piston // Lophine - Vanilla-like experience
level.removeBlock(headPos, false);
} else {
((ServerLevel) level).getChunkSource().blockChanged(headPos); // ... fix client desync
@@ -379,7 +379,7 @@ public class PistonBaseBlock extends DirectionalBlock {
for (int i = toPush.size() - 1; i >= 0; i--) {
// Paper start - fix a variety of piston desync dupes
- boolean allowDesync = !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntDupingFix;
+ boolean allowDesync = fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntDupingFix; // Lophine - Vanilla-like experience
BlockPos oldPos = toPush.get(i);
BlockPos pos = oldPos;
BlockState blockState = allowDesync ? level.getBlockState(oldPos) : null;
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index 22663ad55f669081b43644ad2cf1bd4aac48b745..0d79157ac9b7d099c29a933c171fe87718f34f8e 100644
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -334,7 +334,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
if (level.getBlockState(pos).is(Blocks.MOVING_PISTON)) {
BlockState newState = Block.updateFromNeighbourShapes(entity.movedState, level, pos);
if (newState.isAir()) {
- level.setBlock(pos, entity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE | (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 0 : Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air
+ level.setBlock(pos, entity.movedState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_KNOWN_SHAPE | ((fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication) ? 0 : Block.UPDATE_CLIENTS)); // Paper - fix a variety of piston desync dupes; force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air // Lophine - Vanilla-like experience
Block.updateOrDestroy(entity.movedState, newState, level, pos, Block.UPDATE_ALL);
} else {
if (newState.hasProperty(BlockStateProperties.WATERLOGGED) && newState.getValue(BlockStateProperties.WATERLOGGED)) {
diff --git a/net/minecraft/world/level/levelgen/PhantomSpawner.java b/net/minecraft/world/level/levelgen/PhantomSpawner.java
index 142ab133d3b68eb9b88651e307653f1aafdf1de3..6061ac704e504d53492f405e92c17b6a4b44716f 100644
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -41,7 +41,7 @@ public class PhantomSpawner implements CustomSpawner {
// Paper end - Ability to control player's insomnia and phantoms
if (level.getSkyDarken() >= 5 || !level.dimensionType().hasSkyLight()) {
for (ServerPlayer player : level.getLocalPlayers()) { // Folia - region threading
- if (!player.isSpectator() && (!level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !player.isCreative())) { // Paper - Add phantom creative and insomniac controls
+ if (!player.isSpectator() && (fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled || !level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !player.isCreative())) { // Paper - Add phantom creative and insomniac controls // Lophine - Vanilla-like experience
BlockPos playerPos = player.blockPosition();
if (!level.dimensionType().hasSkyLight() || playerPos.getY() >= level.getSeaLevel() && level.canSeeSky(playerPos)) {
DifficultyInstance difficulty = level.getCurrentDifficultyAt(playerPos);
diff --git a/net/minecraft/world/level/portal/PortalForcer.java b/net/minecraft/world/level/portal/PortalForcer.java
index 4e4903d38d705dca6ff16418e54a7a367074aa08..b61259024c167f951d0fad292f40d2a814f6b8a5 100644
--- a/net/minecraft/world/level/portal/PortalForcer.java
+++ b/net/minecraft/world/level/portal/PortalForcer.java
@@ -233,7 +233,7 @@ public class PortalForcer {
origin, direction.getStepX() * width + clockWise.getStepX() * offset, height, direction.getStepZ() * width + clockWise.getStepZ() * offset
);
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) {
+ if (!fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig.enabled && !io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) { // Lophine - Vanilla-like experience
if (!this.level.getBlockState(mutable).isDestroyable()) {
return false;
}
@@ -0,0 +1,219 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Wed, 24 Jun 2026 00:00:00 +0800
Subject: [PATCH] Restore vanilla ender pearl loading
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 99e61bbe15430a72096489777a4e417ec5125337..3b76045aa0b4cd97f7b104921a7fa8e29234e1d3 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -272,7 +272,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private @Nullable BlockPos raidOmenPosition;
private Vec3 lastKnownClientMovement = Vec3.ZERO;
private Input lastClientInput = Input.EMPTY;
- private final Set<ThrownEnderpearl> enderPearls = new HashSet<>();
+ private final Set<ThrownEnderpearl> enderPearls = java.util.concurrent.ConcurrentHashMap.newKeySet(); // Lophine - restore vanilla ender pearl loading on Folia
private long timeEntitySatOnShoulder;
private CompoundTag shoulderEntityLeft = new CompoundTag();
private CompoundTag shoulderEntityRight = new CompoundTag();
@@ -796,18 +796,20 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private void saveEnderPearls(final ValueOutput playerOutput) {
if (!this.enderPearls.isEmpty()) {
- ValueOutput.ValueOutputList pearlsOutput = playerOutput.childrenList("ender_pearls");
-
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ ValueOutput.TypedOutputList<CompoundTag> pearlsOutput = null;
for (ThrownEnderpearl enderPearl : this.enderPearls) {
- if (enderPearl.level().paperConfig().misc.legacyEnderPearlBehavior) continue; // Paper - Allow using old ender pearl behavior
- if (enderPearl.isRemoved()) {
- LOGGER.warn("Trying to save removed ender pearl, skipping");
+ CompoundTag pearlTag = enderPearl.getLastSavedEnderPearlTag();
+ if (pearlTag == null) {
+ LOGGER.warn("Trying to save ender pearl without a region-owned snapshot, skipping");
} else {
- ValueOutput pearlTag = pearlsOutput.addChild();
- enderPearl.save(pearlTag);
- pearlTag.store("ender_pearl_dimension", Level.RESOURCE_KEY_CODEC, enderPearl.level().dimension());
+ if (pearlsOutput == null) {
+ pearlsOutput = playerOutput.list(ServerPlayer.ENDER_PEARLS_TAG, CompoundTag.CODEC);
+ }
+ pearlsOutput.add(pearlTag);
}
}
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
}
@@ -3598,11 +3600,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
public void registerEnderPearl(final ThrownEnderpearl enderPearl) {
- //this.enderPearls.add(enderPearl); // Folia - region threading - do not track ender pearls
+ this.enderPearls.add(enderPearl); // Lophine - restore vanilla ender pearl loading on Folia
}
public void deregisterEnderPearl(final ThrownEnderpearl enderPearl) {
- //this.enderPearls.remove(enderPearl); // Folia - region threading - do not track ender pearls
+ this.enderPearls.remove(enderPearl); // Lophine - restore vanilla ender pearl loading on Folia
}
public Set<ThrownEnderpearl> getEnderPearls() {
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 64779d7b28e61c91897db5226158d65c32bfc835..f665ff0bc9068aaca6d6719ef6f7d87592f39816 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -752,11 +752,13 @@ public abstract class PlayerList {
player.unRide();
for (ThrownEnderpearl enderpearl : player.getEnderPearls()) {
- // Paper start - Allow using old ender pearl behavior
- if (!enderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) {
- enderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause
- }
- // Paper end - Allow using old ender pearl behavior
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ enderpearl.getBukkitEntity().taskScheduler.scheduleOrExecute((Entity pearl) -> {
+ if (!pearl.isRemoved()) {
+ pearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, org.bukkit.event.entity.EntityRemoveEvent.Cause.PLAYER_QUIT); // CraftBukkit - add Bukkit remove cause
+ }
+ });
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
level.removePlayerImmediately(player, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
diff --git a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
index dc135f1a5d1ec33195e9ac897aa7acee4cbd13c6..bc9ca4680c18f28b97c4d1afe202cc2fff320daf 100644
--- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
+++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
@@ -29,7 +29,11 @@ import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
public class ThrownEnderpearl extends ThrowableItemProjectile {
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Lophine - restore vanilla ender pearl loading on Folia
private long ticketTimer = 0L;
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ private volatile net.minecraft.nbt.@Nullable CompoundTag lastSavedEnderPearlTag;
+ // Lophine end - restore vanilla ender pearl loading on Folia
public ThrownEnderpearl(final EntityType<? extends ThrownEnderpearl> type, final Level level) {
super(type, level);
@@ -37,6 +41,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
public ThrownEnderpearl(final Level level, final LivingEntity mob, final ItemStack itemStack) {
super(EntityType.ENDER_PEARL, mob, level, itemStack);
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
@Override
@@ -49,21 +56,73 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
this.deregisterFromCurrentOwner();
super.setOwner(owner);
this.registerToCurrentOwner();
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
private void deregisterFromCurrentOwner() {
- // Folia - region threading - we remove the registration logic, we do not need to fetch the owner
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ if (this.owner != null && this.level() instanceof ServerLevel serverLevel && serverLevel.getServer().getPlayerList().getPlayer(this.owner.getUUID()) instanceof ServerPlayer serverPlayer) {
+ serverPlayer.deregisterEnderPearl(this);
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
private void registerToCurrentOwner() {
- // Folia - region threading - we remove the registration logic, we do not need to fetch the owner
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ if (this.owner != null
+ && this.level() instanceof ServerLevel serverLevel
+ && !serverLevel.paperConfig().misc.legacyEnderPearlBehavior
+ && serverLevel.getServer().getPlayerList().getPlayer(this.owner.getUUID()) instanceof ServerPlayer serverPlayer) {
+ serverPlayer.registerEnderPearl(this);
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ public net.minecraft.nbt.@Nullable CompoundTag getLastSavedEnderPearlTag() {
+ net.minecraft.nbt.CompoundTag tag = this.lastSavedEnderPearlTag;
+ return tag == null ? null : tag.copy();
+ }
+
+ public void updateLastSavedEnderPearlTag() {
+ if (this.owner == null || this.isRemoved() || !(this.level() instanceof ServerLevel serverLevel) || serverLevel.paperConfig().misc.legacyEnderPearlBehavior) {
+ this.lastSavedEnderPearlTag = null;
+ return;
+ }
+ try (net.minecraft.util.ProblemReporter.ScopedCollector problemReporter = new net.minecraft.util.ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) {
+ net.minecraft.world.level.storage.TagValueOutput pearlOutput = net.minecraft.world.level.storage.TagValueOutput.createWithContext(problemReporter, this.registryAccess());
+ if (this.save(pearlOutput)) {
+ pearlOutput.store(ServerPlayer.ENDER_PEARL_DIMENSION_TAG, Level.RESOURCE_KEY_CODEC, this.level().dimension());
+ this.lastSavedEnderPearlTag = pearlOutput.buildResult();
+ } else {
+ this.lastSavedEnderPearlTag = null;
+ }
+ }
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
+
@Override
public @Nullable Entity getOwner() {
return this.owner != null && this.level() instanceof ServerLevel serverLevel ? this.owner.getEntity(serverLevel, Entity.class) : super.getOwner();
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ @Override
+ protected void readAdditionalSaveData(final net.minecraft.world.level.storage.ValueInput input) {
+ super.readAdditionalSaveData(input);
+ this.updateLastSavedEnderPearlTag();
+ }
+
+ @Override
+ public void restoreFrom(final Entity oldEntity) {
+ super.restoreFrom(oldEntity);
+ this.registerToCurrentOwner();
+ this.updateLastSavedEnderPearlTag();
+ }
+ // Lophine end - restore vanilla ender pearl loading on Folia
+
private static @Nullable Entity findOwnerIncludingDeadPlayer(final ServerLevel serverLevel, final UUID uuid) {
Entity owner = serverLevel.getEntityInAnyDimension(uuid);
return (Entity)(owner != null ? owner : serverLevel.getServer().getPlayerList().getPlayer(uuid));
@@ -281,6 +340,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
&& owner instanceof ServerPlayer serverPlayer) {
this.ticketTimer = serverPlayer.registerAndUpdateEnderPearlTicket(this);
}
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.updateLastSavedEnderPearlTag();
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
} else {
super.tick();
@@ -328,6 +390,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
public void onRemoval(final Entity.RemovalReason reason) {
if (reason != Entity.RemovalReason.UNLOADED_WITH_PLAYER) {
this.deregisterFromCurrentOwner();
+ // Lophine start - restore vanilla ender pearl loading on Folia
+ this.lastSavedEnderPearlTag = null;
+ // Lophine end - restore vanilla ender pearl loading on Folia
}
super.onRemoval(reason);
diff --git a/net/minecraft/world/item/EnderpearlItem.java b/net/minecraft/world/item/EnderpearlItem.java
index 17a005321601b0fef71604e4468134f1e98cd974..a270b4ca7d65b91ffcf292ff80f3a23124cd595c 100644
--- a/net/minecraft/world/item/EnderpearlItem.java
+++ b/net/minecraft/world/item/EnderpearlItem.java
@@ -27,6 +27,7 @@ public class EnderpearlItem extends Item {
final Projectile.Delayed<ThrownEnderpearl> thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemStack, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F);
com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity());
if (event.callEvent() && thrownEnderpearl.attemptSpawn()) {
+ thrownEnderpearl.projectile().updateLastSavedEnderPearlTag(); // Lophine - restore vanilla ender pearl loading on Folia
if (event.shouldConsume()) {
itemStack.consume(1, player);
} else {
@@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrHua269 <mrhua269@gmail.com>
Date: Wed, 8 Jul 2026 21:37:19 +0800
Subject: [PATCH] Camellia: Fix teleport missing original rotation and velocity
diff --git a/io/papermc/paper/threadedregions/TeleportUtils.java b/io/papermc/paper/threadedregions/TeleportUtils.java
index 2a64a5b2cf049661fe3f5a22ddfa39979624f5ec..335e9775e0d9a61f0e9641aba691a3bdf3ac7f2b 100644
--- a/io/papermc/paper/threadedregions/TeleportUtils.java
+++ b/io/papermc/paper/threadedregions/TeleportUtils.java
@@ -41,7 +41,7 @@ public final class TeleportUtils {
return;
}
(useFromRootVehicle ? realFrom.getRootVehicle() : realFrom).teleportAsync(
- ((CraftWorld)loc.getWorld()).getHandle(), pos, null, null, null,
+ ((CraftWorld)loc.getWorld()).getHandle(), pos, yaw, pitch, null, // Camellia - Fix teleport missing original rotation and velocity
cause, teleportFlags, onComplete
);
},
diff --git a/net/minecraft/server/commands/TeleportCommand.java b/net/minecraft/server/commands/TeleportCommand.java
index f3b697eda0f47a2d1c64d7978ccdfb77fa226929..f657cda7c3856623f60f00f9fa44367ea771133c 100644
--- a/net/minecraft/server/commands/TeleportCommand.java
+++ b/net/minecraft/server/commands/TeleportCommand.java
@@ -247,10 +247,8 @@ public class TeleportCommand {
// Folia start - region threading
if (true) {
Vec3 posFinal = new Vec3(x, y, z);
- //Float yawFinal = Float.valueOf(newYRot); // Luminol - fix teleport yaw issue
- //Float pitchFinal = Float.valueOf(newXRot); // Luminol - fix teleport yaw issue
- Float yawFinal = Float.valueOf(newYRot + victim.getYRot()); // Luminol - fix teleport yaw issue
- Float pitchFinal = Float.valueOf(newXRot + victim.getXRot()); // Luminol - fix teleport pitch issue
+ Float yawFinal = Float.valueOf(newYRot + victim.getYRot()); // Camellia - Fix teleport missing original rotation and velocity
+ Float pitchFinal = Float.valueOf(newXRot + victim.getXRot()); // Camellia - Fix teleport missing original rotation and velocity
victim.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> {
nmsEntity.stopRiding();
nmsEntity.teleportAsync(
diff --git a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
index bc9ca4680c18f28b97c4d1afe202cc2fff320daf..08c3b8ee0ed015572823bb0218ac7522ec8945b3 100644
--- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
+++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
@@ -156,7 +156,7 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
}
entity.teleportAsync(
- checkWorld, to, null, null, null,
+ checkWorld, to, null, null, entity.getDeltaMovement(), // Camellia - Fix teleport missing original rotation and velocity
org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.ENDER_PEARL,
// chunk could have been unloaded
Entity.TELEPORT_FLAG_TELEPORT_PASSENGERS | Entity.TELEPORT_FLAG_LOAD_CHUNK,
@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NanaChiyo0721 <nanachiyo0721@163.com>
Date: Mon, 13 Jul 2026 23:10:31 +0800
Subject: [PATCH] Camellia: Replace packet processing queue with mt-queue
diff --git a/net/minecraft/network/PacketProcessor.java b/net/minecraft/network/PacketProcessor.java
index a25bc31c04778bf12e3b6301ffcfb2275fcc2d90..b91c669438dc4692144143c8eef0d3450a824969 100644
--- a/net/minecraft/network/PacketProcessor.java
+++ b/net/minecraft/network/PacketProcessor.java
@@ -11,7 +11,7 @@ import org.slf4j.Logger;
public class PacketProcessor implements AutoCloseable {
private static final Logger LOGGER = LogUtils.getLogger();
- private final Queue<PacketProcessor.ListenerAndPacket<?>> packetsToBeHandled = Queues.newConcurrentLinkedQueue();
+ private final Queue<PacketProcessor.ListenerAndPacket<?>> packetsToBeHandled = new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>(); // Camellia - Replace packet processing queue with mt-queue
private final Thread runningThread;
private boolean closed;
@@ -35,7 +35,7 @@ index fcdfd4f6de5e1c2d5e80c7f3d8cb0b33a62d257d..6eaa4e9bd1ecbfa531313ce1f470d55e
metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
index a5f2e4454258886536251288c3694f58386c7420..28371ecf31d5fc280aaa03ed9a86f5b565cf32f6 100644
index 45611868dfdfee05380c390a11e8041685a76a19..0219692014bd5d7b52afcb847c5cd39c4dc63ff2 100644
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -40,8 +40,8 @@ public class PaperVersionFetcher implements VersionFetcher {
@@ -44,8 +44,8 @@ index a5f2e4454258886536251288c3694f58386c7420..28371ecf31d5fc280aaa03ed9a86f5b5
private static final int DISTANCE_UNKNOWN = -2;
- private static final String DOWNLOAD_PAGE = "https://github.com/LuminolMC/Luminol"; // Luminol
- private static final String REPOSITORY = "LuminolMC/Luminol"; // Luminol
+ private static final String DOWNLOAD_PAGE = "https://github.com/LuminolMC/Lophine"; // Luminol // Lophine
+ private static final String REPOSITORY = "LuminolMC/Lophine"; // Luminol // Lophine
+ private static final String DOWNLOAD_PAGE = "https://github.com/LophineLabs/Lophine"; // Luminol // Lophine
+ private static final String REPOSITORY = "LophineLabs/Lophine"; // Luminol // Lophine
private static final ServerBuildInfo BUILD_INFO = ServerBuildInfo.buildInfo();
private static final String USER_AGENT = BUILD_INFO.brandName() + "/" + BUILD_INFO.asString(VERSION_SIMPLE) + " (https://papermc.io)";
private static final Gson GSON = new Gson();
@@ -8,7 +8,7 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/3e7f4a313ff0d2469
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index ba0779211405b8b83f7c7e7b1c55b3e4846029a3..5f685b07878443bfe5f63147a0728df0708d79ad 100644
index f19ad4f317f911eb50802c325bcfce829d98524e..75ef8eab6665401bb2a9603de89172e341f8a2c4 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -483,6 +483,7 @@ public final class CraftServer implements Server {
@@ -53,7 +53,7 @@ index 5339ff469a38d35e72ea7227503a84395462f84a..d75b4ecb24f2ea42afc82ac255775d8f
if (nmsEntity.level() != this.getHandle().getLevel()) {
throw new IllegalArgumentException(entity + " wasn't created with this world, you must create the entity with the world you want to add it to.");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 5f685b07878443bfe5f63147a0728df0708d79ad..0eb89fc127738e02e8d4d49418b83baaffe00cbd 100644
index 75ef8eab6665401bb2a9603de89172e341f8a2c4..42df6c661ec5ab18387b12743771bdb156a98e93 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -303,6 +303,7 @@ public final class CraftServer implements Server {
@@ -81,7 +81,7 @@ index 5f685b07878443bfe5f63147a0728df0708d79ad..0eb89fc127738e02e8d4d49418b83baa
return false;
}
@@ -3113,6 +3115,13 @@ public final class CraftServer implements Server {
@@ -3117,6 +3119,13 @@ public final class CraftServer implements Server {
}
// Leaves end - Feature API
@@ -21,7 +21,7 @@ index d0b763f07aee56f69a67c87d7dd15a44b6f44db7..bd301425f4c3cdf2b2bd22c1775b7ca9
}
// Leaves end - skip bot
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0eb89fc127738e02e8d4d49418b83baaffe00cbd..53e49df883ec0fab984f2329d044d12ed6b1edff 100644
index 42df6c661ec5ab18387b12743771bdb156a98e93..feccf57b61200aead73fe97b897c1ad0fad563fb 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -304,6 +304,7 @@ public final class CraftServer implements Server {
@@ -41,7 +41,7 @@ index 0eb89fc127738e02e8d4d49418b83baaffe00cbd..53e49df883ec0fab984f2329d044d12e
@Override
public CraftPlayer apply(ServerPlayer player) {
return player.getBukkitEntity();
@@ -3186,4 +3187,11 @@ public final class CraftServer implements Server {
@@ -3190,4 +3191,11 @@ public final class CraftServer implements Server {
}
}
// Folia end - region TPS API
@@ -66,7 +66,7 @@ index 42c2c6a05645e5aef26e9d3a91ad93563a297ca3..759d54f1f012461fc322d452bb26f7fd
// Special case complex part, since there is no extra entity type for them
if (entity instanceof EnderDragonPart complexPart) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 47926ff2fba43bb83e2d9747420a526cce8ebe65..e72cd3c9919978a0ed91614d51d018bfb2cdb900 100644
index 59e3a15cce0ed34aa3b75b92db9e349c9fe481fa..044f3168583b23542e18fe14853d3b98bad3fa4d 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2086,7 +2086,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa
@@ -0,0 +1,759 @@
package fun.bm.lophine.bot;
import fun.bm.lophine.bot.action.gui.ActionType;
import fun.bm.lophine.bot.action.gui.GuiNode;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.item.component.ItemLore;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.agent.actions.AbstractBotAction;
import org.leavesmc.leaves.entity.bot.CraftBot;
import org.leavesmc.leaves.entity.bot.action.BotAction;
import org.leavesmc.leaves.entity.bot.actions.CraftBotAction;
import java.util.*;
public class BotActionGuiContainer extends SimpleContainer {
private static final Map<String, GuiRootNode> GUI_ROOT_NODE_MAP = new LinkedHashMap<>();
private static final int CONTAINER_SIZE = 54;
private static final int[] BORDER_SLOTS = {
0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 17,
18, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53
};
public static final int[] CONTENT_SLOTS = {
10, 11, 12, 13, 14, 15, 16,
19, 20, 21, 22, 23, 24, 25
};
private static final int BACK_BUTTON_SLOT = 38;
private static final int COMMAND_BUILDER_SLOT = 40;
private static final int HOME_BUTTON_SLOT = 42;
private static final int PREV_PAGE_SLOT = 39;
private static final int NEXT_PAGE_SLOT = 41;
private static final ItemStack boarder = new ItemStack(Items.WHITE_STAINED_GLASS_PANE);
private static final ItemStack emptyActionPlaceholder = createEmptyActionPlaceholder();
private final CraftBot bot;
private final CraftPlayer player;
private final Deque<GuiNode> navigationStack = new ArrayDeque<>();
private final Deque<Boolean> fromRootLevelStack = new ArrayDeque<>(); // Track if we came from root level
private GuiNode currentNode = null;
// New state for action type selection flow
private ActionType selectedActionType = null;
private boolean isSelectingActionType = false;
// Pagination state
private int currentPage = 0;
public static void registerGuiRootNode(GuiRootNode guiRootNode) {
if (!GUI_ROOT_NODE_MAP.containsKey(guiRootNode.getName())) {
GUI_ROOT_NODE_MAP.put(guiRootNode.getName(), guiRootNode);
}
}
public static void unregisterGuiRootNode(String name) {
GUI_ROOT_NODE_MAP.remove(name);
}
public static GuiRootNode getGuiRootNode(String name) {
return GUI_ROOT_NODE_MAP.get(name);
}
public static Map<String, GuiRootNode> getGuiRootNodes() {
return new LinkedHashMap<>(GUI_ROOT_NODE_MAP);
}
public BotActionGuiContainer(@NotNull CraftBot bot, CraftPlayer player) {
super(CONTAINER_SIZE, player);
this.bot = bot;
this.player = player;
this.showActionTypes();
}
public boolean isCommandBuilderSlot(int id) {
return id == COMMAND_BUILDER_SLOT;
}
private void fillBorder() {
for (int slot : BORDER_SLOTS) {
this.setItem(slot, boarder);
}
}
private void showActionTypes() {
this.clearContent();
this.fillBorder();
this.currentNode = null;
this.navigationStack.clear();
this.fromRootLevelStack.clear();
this.selectedActionType = null;
this.isSelectingActionType = true;
this.currentPage = 0;
this.renderActionTypes();
this.addNavigationButtons();
}
private void showRootNodes() {
this.clearContent();
this.fillBorder();
this.currentNode = null;
this.navigationStack.clear();
this.fromRootLevelStack.clear();
this.isSelectingActionType = false;
this.currentPage = 0;
List<GuiRootNode> allNodes = new ArrayList<>(GUI_ROOT_NODE_MAP.values());
if (allNodes.isEmpty()) {
// No root nodes, go back to action type selection
this.showActionTypes();
return;
}
this.renderRootNodes();
this.addNavigationButtons();
}
public void navigateToChild(GuiNode node) {
if (node == null) {
return;
}
// If we're at root level (currentNode is null but not selecting action type),
// we need to track that we came from root nodes level
if (this.currentNode != null) {
this.navigationStack.push(this.currentNode);
this.fromRootLevelStack.push(false);
} else if (!this.isSelectingActionType && this.selectedActionType != null) {
// We're at root nodes level, mark that we should return to root nodes
this.fromRootLevelStack.push(true);
}
this.currentNode = node;
this.currentPage = 0;
this.refreshContainer();
}
public boolean navigateBack() {
// If we're at root node level (no navigation stack), go back to action type selection
if (this.navigationStack.isEmpty() && this.fromRootLevelStack.isEmpty()) {
// If we have a selected action type, we're at the root nodes level
if (!this.isSelectingActionType && this.selectedActionType != null) {
this.showActionTypes();
return true;
}
// Already at action type selection
return false;
}
// Check if we should return to root nodes level
boolean fromRootLevel = !this.fromRootLevelStack.isEmpty() && this.fromRootLevelStack.pop();
if (fromRootLevel) {
// Return to root nodes level
this.currentNode = null;
this.showRootNodes();
} else if (!this.navigationStack.isEmpty()) {
// Pop from navigation stack and refresh
this.currentNode = this.navigationStack.pop();
this.refreshContainer();
}
return true;
}
public void navigateHome() {
this.showActionTypes();
}
private void refreshContainer() {
this.clearContent();
this.fillBorder();
Set<GuiNode> children = this.getChildrenOfCurrentNode();
if (children == null || children.isEmpty()) {
// Empty page: auto-navigate back
this.navigateBack();
return;
}
this.renderCurrentNodeChildren();
this.addNavigationButtons();
}
@Nullable
private Set<GuiNode> getChildrenOfCurrentNode() {
if (this.currentNode == null) {
return null;
}
if (this.currentNode instanceof GuiRootNode rootNode) {
return rootNode.getChildren();
}
return null;
}
private void renderActionTypes() {
List<ActionType> allTypes = List.of(ActionType.values());
this.renderPagedItems(allTypes, (actionType, slot) -> {
ItemStack item = actionType.toConfirmNode(null).getItemStack();
if (item != null && !item.isEmpty()) {
this.setItem(slot, item);
}
});
}
private void renderRootNodes() {
List<GuiRootNode> allNodes = new ArrayList<>(GUI_ROOT_NODE_MAP.values());
this.renderPagedItems(allNodes, (node, slot) -> {
ItemStack item = createNodeItemWithRunHint(node);
if (item != null && !item.isEmpty()) {
this.setItem(slot, item);
}
});
}
private void renderCurrentNodeChildren() {
Set<GuiNode> children = this.getChildrenOfCurrentNode();
if (children != null && !children.isEmpty()) {
List<GuiNode> childList = new ArrayList<>(children);
this.renderPagedItems(childList, (node, slot) -> {
ItemStack item = createNodeItemWithRunHint(node);
if (item != null && !item.isEmpty()) {
this.setItem(slot, item);
}
});
}
}
private void renderBotActions() {
int actionSize = this.bot.getActionSize();
if (actionSize > 0) {
List<Integer> actionIndices = new ArrayList<>();
for (int i = 0; i < actionSize; i++) {
actionIndices.add(i);
}
this.renderPagedItems(actionIndices, (index, slot) -> {
BotAction<?> action = this.bot.getAction(index);
ItemStack item = createActionItem(action, index);
if (!item.isEmpty()) {
this.setItem(slot, item);
}
});
} else {
// Show empty placeholder when no actions are active
this.setItem(CONTENT_SLOTS[0], emptyActionPlaceholder);
}
}
private static ItemStack createEmptyActionPlaceholder() {
ItemStack item = new ItemStack(Items.STRUCTURE_VOID);
item.set(DataComponents.CUSTOM_NAME, Component.literal("§cNo active actions"));
item.set(DataComponents.LORE, new ItemLore(List.of(
Component.literal("§cThis bot has no running actions"),
Component.literal("§cUse START to add new actions")
)));
return item;
}
@Nullable
public GuiNode getGuiNodeAtSlot(int slot) {
if (slot == BACK_BUTTON_SLOT && this.canNavigateBack()) {
return null; // back button is handled separately
}
// Check if slot is a border slot
for (int borderSlot : BORDER_SLOTS) {
if (borderSlot == slot) {
return null;
}
}
Set<GuiNode> nodes = this.getCurrentDisplayNodes();
if (nodes == null) {
return null;
}
// Find the content index for this slot
int contentIndex = -1;
for (int i = 0; i < CONTENT_SLOTS.length; i++) {
if (CONTENT_SLOTS[i] == slot) {
contentIndex = i;
break;
}
}
if (contentIndex == -1) {
return null;
}
// Apply pagination offset
int actualIndex = this.currentPage * CONTENT_SLOTS.length + contentIndex;
int index = 0;
for (GuiNode node : nodes) {
if (index == actualIndex) {
return node;
}
index++;
}
return null;
}
public boolean isBackButtonSlot(int slot) {
return slot == BACK_BUTTON_SLOT && this.canNavigateBack();
}
public boolean isHomeButtonSlot(int slot) {
return slot == HOME_BUTTON_SLOT && this.canNavigateHome();
}
private static ItemStack createBackButtonItem() {
ItemStack item = new ItemStack(Items.RED_WOOL);
item.set(DataComponents.CUSTOM_NAME, Component.literal("§cBack"));
item.set(DataComponents.LORE, new ItemLore(List.of(Component.literal("Return to previous page"))));
return item;
}
private static ItemStack createHomeButtonItem() {
ItemStack item = new ItemStack(Items.RED_BED);
item.set(DataComponents.CUSTOM_NAME, Component.literal("§aHome"));
item.set(DataComponents.LORE, new ItemLore(List.of(Component.literal("Return to main menu"))));
return item;
}
private ItemStack createNodeItemWithRunHint(GuiNode node) {
ItemStack itemStack = node.getItemStack();
// Check if this is a last-level node (no children)
boolean isLastLevel;
if (node instanceof GuiRootNode rootNode) {
isLastLevel = rootNode.getChildren().isEmpty();
} else {
// Non-RootNode is always considered last level
isLastLevel = true;
}
// If it's the last level and we have an action type selected, add run hint
if (isLastLevel && this.selectedActionType != null && !this.isSelectingActionType) {
// Get existing lore or create new one
ItemLore existingLore = itemStack.get(DataComponents.LORE);
List<Component> loreLines = new ArrayList<>();
if (existingLore != null) {
loreLines.addAll(existingLore.lines());
}
// Add golden run hint
loreLines.add(Component.literal("§6Click to execute"));
itemStack.set(DataComponents.LORE, new ItemLore(loreLines));
}
return itemStack;
}
/**
* Render items with pagination support.
*
* @param items the full list of items
* @param renderer callback to render each item at a specific slot
*/
private <T> void renderPagedItems(List<T> items, PagedItemRenderer<T> renderer) {
int pageSize = CONTENT_SLOTS.length;
int totalPages = Math.max(1, (items.size() + pageSize - 1) / pageSize);
// Clamp current page
if (this.currentPage >= totalPages) {
this.currentPage = totalPages - 1;
}
if (this.currentPage < 0) {
this.currentPage = 0;
}
int start = this.currentPage * pageSize;
int end = Math.min(start + pageSize, items.size());
for (int i = start; i < end; i++) {
int slotIndex = i - start;
renderer.render(items.get(i), CONTENT_SLOTS[slotIndex]);
}
}
@FunctionalInterface
private interface PagedItemRenderer<T> {
void render(T item, int slot);
}
/**
* Add navigation buttons including pagination controls.
*/
private void addNavigationButtons() {
if (this.canNavigateBack()) {
this.setItem(BACK_BUTTON_SLOT, createBackButtonItem());
}
this.setItem(COMMAND_BUILDER_SLOT, createCommandBuilderItem());
if (this.canNavigateHome()) {
this.setItem(HOME_BUTTON_SLOT, createHomeButtonItem());
}
// Pagination buttons
if (this.hasPrevPage()) {
this.setItem(PREV_PAGE_SLOT, createPrevPageItem());
}
if (this.hasNextPage()) {
this.setItem(NEXT_PAGE_SLOT, createNextPageItem());
}
}
private boolean hasPrevPage() {
return this.currentPage > 0;
}
private boolean hasNextPage() {
int totalItems = this.getCurrentTotalItemCount();
int totalPages = Math.max(1, (totalItems + CONTENT_SLOTS.length - 1) / CONTENT_SLOTS.length);
return this.currentPage < totalPages - 1;
}
private int getCurrentTotalItemCount() {
if (this.isSelectingActionType) {
return ActionType.values().length;
}
if (this.selectedActionType == ActionType.ACTION_STOP) {
return this.bot.getActionSize();
}
if (this.currentNode == null) {
return GUI_ROOT_NODE_MAP.size();
}
Set<GuiNode> children = this.getChildrenOfCurrentNode();
return children != null ? children.size() : 0;
}
public void prevPage() {
if (this.hasPrevPage()) {
this.currentPage--;
this.redisplayCurrentViewWithoutReset();
}
}
public void nextPage() {
if (this.hasNextPage()) {
this.currentPage++;
this.redisplayCurrentViewWithoutReset();
}
}
public boolean isPrevPageSlot(int slot) {
return slot == PREV_PAGE_SLOT && this.hasPrevPage();
}
public boolean isNextPageSlot(int slot) {
return slot == NEXT_PAGE_SLOT && this.hasNextPage();
}
/**
* Re-render the current view without resetting pagination state.
* Used for page navigation to preserve currentPage value.
*/
private void redisplayCurrentViewWithoutReset() {
this.clearContent();
this.fillBorder();
if (this.isSelectingActionType) {
this.renderActionTypes();
} else if (this.selectedActionType == ActionType.ACTION_STOP) {
this.renderBotActions();
} else if (this.currentNode != null) {
this.renderCurrentNodeChildren();
} else {
this.renderRootNodes();
}
this.addNavigationButtons();
}
private static ItemStack createPrevPageItem() {
ItemStack item = new ItemStack(Items.ARROW);
item.set(DataComponents.CUSTOM_NAME, Component.literal("§ePrevious Page"));
return item;
}
private static ItemStack createNextPageItem() {
ItemStack item = new ItemStack(Items.ARROW);
item.set(DataComponents.CUSTOM_NAME, Component.literal("§eNext Page"));
return item;
}
private ItemStack createCommandBuilderItem() {
ItemStack item = new ItemStack(Items.BOOK);
// Build the complete command preview
String commandPreview = buildCommandPreview();
// Check if current node is runnable (confirmable)
boolean canRun = this.currentNode != null && this.currentNode.isConfirmable();
List<Component> loreLines = new ArrayList<>();
loreLines.add(Component.literal("§eCommand:"));
loreLines.add(Component.literal("§f" + commandPreview));
// Add run hint if the node is confirmable
if (canRun) {
loreLines.add(Component.literal("§6Click to execute"));
}
item.set(DataComponents.CUSTOM_NAME, Component.literal("§6Command Builder"));
item.set(DataComponents.LORE, new ItemLore(loreLines));
return item;
}
private String buildCommandPreview() {
if (this.selectedActionType == null) {
return "Select an action type first";
}
// For STOP action type, show different preview
if (this.selectedActionType == ActionType.ACTION_STOP) {
int actionSize = this.bot.getActionSize();
if (actionSize == 0) {
return "No actions to stop";
}
return "Click an action to stop it (" + actionSize + " active)";
}
try {
String actionPrefix = this.selectedActionType.getCommandActionPrefix();
String actionSuffix = this.selectedActionType.getCommandActionSuffix();
if (!actionSuffix.isEmpty()) {
actionSuffix = actionSuffix + " ";
}
String extra = actionPrefix + " " + this.bot.getName() + " " + actionSuffix;
// If we have a current node and it's a GuiRootNode, build the command
if (this.currentNode instanceof GuiRootNode rootNode) {
String command = rootNode.buildCommand(extra);
// Apply parameter limit based on ActionType
if (this.selectedActionType.getMaxAllowedParameters() == 0) {
command = actionPrefix + " " + this.bot.getName();
}
return command;
} else if (!this.isSelectingActionType) {
// At root nodes level or selecting action type
return extra.trim() + " <command>";
} else {
return "Select a command node";
}
} catch (Exception e) {
return "Error building command";
}
}
@Nullable
private Set<GuiNode> getCurrentDisplayNodes() {
// If selecting action type, return null (handled separately)
if (this.isSelectingActionType) {
return null;
}
if (this.currentNode == null) {
return new LinkedHashSet<>(GUI_ROOT_NODE_MAP.values());
}
return this.getChildrenOfCurrentNode();
}
/**
* Called when user selects an ActionType (START/STOP)
*/
public void selectActionType(ActionType actionType) {
this.selectedActionType = actionType;
this.isSelectingActionType = false;
// If STOP action type is selected, show current bot actions instead of root nodes
if (actionType == ActionType.ACTION_STOP) {
this.showCurrentBotActions();
} else {
this.showRootNodes();
}
}
/**
* Show the current bot's scheduled actions for stopping
*/
public void showCurrentBotActions() {
this.clearContent();
this.fillBorder();
this.currentNode = null;
this.navigationStack.clear();
this.fromRootLevelStack.clear();
this.isSelectingActionType = false;
this.currentPage = 0;
this.renderBotActions();
this.addNavigationButtons();
}
/**
* Create an ItemStack representing a bot action for display in the GUI
*/
private ItemStack createActionItem(BotAction<?> action, int index) {
// Use the same item model as registered in GuiRootNode (start action display)
AbstractBotAction<?> handle = ((CraftBotAction<?, ?>) action).getHandle();
GuiRootNode guiData = handle.getGuiData();
ItemStack item = guiData != null ? guiData.getItemStack() : new ItemStack(Items.PAPER);
String actionName = action.getName();
String actionHash = action.getUUID().toString();
item.set(DataComponents.CUSTOM_NAME, Component.literal("§c" + actionName));
// Store action hash in CUSTOM_DATA for later retrieval
CompoundTag customTag = new CompoundTag();
customTag.putString("action_hash", actionHash);
item.set(DataComponents.CUSTOM_DATA, CustomData.of(customTag));
List<Component> loreLines = new ArrayList<>();
CompoundTag nbt = new CompoundTag();
((CraftBotAction<?, ?>) action).getHandle().save(nbt);
nbt.forEach((key, tag) -> loreLines.add(Component.literal("§7" + key + ": §f" + tag)));
loreLines.add(Component.literal("§7Index: §f" + index));
loreLines.add(Component.literal("§7Hash: §f" + actionHash.substring(0, 8)));
loreLines.add(Component.literal("§6Click to stop this action"));
item.set(DataComponents.LORE, new ItemLore(loreLines));
return item;
}
/**
* Get the action hash (UUID string) at a specific slot (for STOP action type)
* Returns null if not found or not in STOP mode
*/
@Nullable
public String getActionHashAtSlot(int slot) {
if (this.selectedActionType != ActionType.ACTION_STOP) {
return null;
}
// Read the action hash directly from the ItemStack's CUSTOM_DATA
ItemStack item = this.getItem(slot);
if (item.isEmpty()) {
return null;
}
CustomData customData = item.get(DataComponents.CUSTOM_DATA);
if (customData == null) {
return null;
}
CompoundTag tag = customData.copyTag();
if (tag.contains("action_hash")) {
return tag.getString("action_hash").get();
}
return null;
}
/**
* Get the ActionType at a specific slot, accounting for pagination offset.
* Returns null if the slot is not a valid content slot or the index is out of bounds.
*/
@Nullable
public ActionType getActionTypeAtSlot(int slot) {
if (!this.isSelectingActionType) {
return null;
}
int contentIndex = -1;
for (int i = 0; i < CONTENT_SLOTS.length; i++) {
if (CONTENT_SLOTS[i] == slot) {
contentIndex = i;
break;
}
}
if (contentIndex == -1) {
return null;
}
ActionType[] actionTypes = ActionType.values();
int actualIndex = this.currentPage * CONTENT_SLOTS.length + contentIndex;
if (actualIndex >= 0 && actualIndex < actionTypes.length) {
return actionTypes[actualIndex];
}
return null;
}
/**
* Get the currently selected ActionType
*/
@Nullable
public ActionType getSelectedActionType() {
return this.selectedActionType;
}
/**
* Check if we're in action type selection mode
*/
public boolean isSelectingActionType() {
return this.isSelectingActionType;
}
public boolean canNavigateBack() {
return !this.navigationStack.isEmpty() || (!this.isSelectingActionType && this.selectedActionType != null);
}
public boolean canNavigateHome() {
return !this.isSelectingActionType && (this.currentNode != null || this.selectedActionType != null);
}
/**
* Check if the command builder can be executed.
* Returns true if there is a current node and it is confirmable.
*/
public boolean canExecuteCommandBuilder() {
return this.currentNode != null && this.currentNode.isConfirmable();
}
@Nullable
public GuiNode getCurrentNode() {
return this.currentNode;
}
/**
* Get the current parameter count (number of selected command nodes).
* This equals the navigation stack size plus 1 if currentNode is not null.
*/
public int getCurrentParameterCount() {
return this.navigationStack.size() + (this.currentNode != null ? 1 : 0);
}
public CraftBot getBot() {
return this.bot;
}
public CraftPlayer getPlayer() {
return this.player;
}
@Override
public boolean stillValid(@NotNull Player player) {
return this.player.getHandle() == player && this.bot.isValid();
}
}
@@ -0,0 +1,279 @@
package fun.bm.lophine.bot;
import com.mojang.logging.LogUtils;
import fun.bm.lophine.bot.action.gui.ActionType;
import fun.bm.lophine.bot.action.gui.GuiNode;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerInput;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.entity.bot.CraftBot;
import java.rmi.UnexpectedException;
public class BotActionGuiMenu extends AbstractContainerMenu {
private final BotActionGuiContainer container;
private final CraftBot bot;
private final CraftPlayer player;
private CraftInventoryView view = null;
public BotActionGuiMenu(int containerId, Inventory inventory, BotActionGuiContainer container) {
super(MenuType.GENERIC_9x6, containerId);
this.container = container;
this.bot = container.getBot();
this.player = container.getPlayer();
for (int row = 0; row < 6; row++) {
for (int col = 0; col < 9; col++) {
this.addSlot(new Slot(container, col + row * 9, 8 + col * 18, 18 + row * 18) {
@Override
public boolean mayPickup(Player player) {
return false;
}
@Override
public boolean mayPlace(ItemStack stack) {
return false;
}
});
}
}
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 9; col++) {
this.addSlot(new Slot(inventory, col + row * 9 + 9, 8 + col * 18, 140 + row * 18));
}
}
for (int col = 0; col < 9; col++) {
this.addSlot(new Slot(inventory, col, 8 + col * 18, 198));
}
}
@Override
public org.bukkit.inventory.InventoryView getBukkitView() {
if (this.view == null) {
CraftInventory inventory = new CraftInventory(this.container);
this.view = new CraftInventoryView(
this.player,
inventory,
this
);
}
return this.view;
}
@Override
public boolean stillValid(@NotNull Player player) {
return this.container.stillValid(player);
}
@Override
public void clicked(int slotIndex, int buttonNum, ContainerInput containerInput, Player player) {
if (slotIndex >= 0 && slotIndex < 54) {
if (this.container.isBackButtonSlot(slotIndex)) {
this.container.navigateBack();
this.refreshSlots();
return;
}
if (this.container.isHomeButtonSlot(slotIndex)) {
this.container.navigateHome();
this.refreshSlots();
return;
}
// Handle pagination buttons
if (this.container.isPrevPageSlot(slotIndex)) {
this.container.prevPage();
this.refreshSlots();
return;
}
if (this.container.isNextPageSlot(slotIndex)) {
this.container.nextPage();
this.refreshSlots();
return;
}
// Handle command builder click
if (this.container.isCommandBuilderSlot(slotIndex) && this.container.canExecuteCommandBuilder()) {
this.executeCommandBuilder(player);
this.refreshSlots();
return;
}
// Handle ActionType selection (with pagination offset)
if (this.container.isSelectingActionType()) {
ActionType clickedType = this.container.getActionTypeAtSlot(slotIndex);
if (clickedType != null) {
this.container.selectActionType(clickedType);
this.refreshSlots();
}
return;
}
// Handle action stop click (when STOP action type is selected)
if (this.container.getSelectedActionType() == ActionType.ACTION_STOP) {
String actionHash = this.container.getActionHashAtSlot(slotIndex);
if (actionHash != null) {
this.stopActionByHash(actionHash, player);
this.refreshSlots();
}
return;
}
GuiNode node = this.container.getGuiNodeAtSlot(slotIndex);
if (node != null) {
this.handleNodeClick(node, player);
this.refreshSlots();
}
return;
}
super.clicked(slotIndex, buttonNum, containerInput, player);
}
private void handleNodeClick(GuiNode node, Player player) {
if (node instanceof GuiRootNode rootNode) {
// Get the selected action type
ActionType actionType = this.container.getSelectedActionType();
if (actionType == null) {
return;
}
int maxAllowedParameters = actionType.getMaxAllowedParameters();
// If the node has children, check parameter limit before navigating
if (!rootNode.getChildren().isEmpty()) {
// Calculate current parameter count (navigation stack size + 1 for current node if exists)
int currentParamCount = this.container.getCurrentParameterCount();
// If adding this node would exceed the limit, execute command instead of navigating
if (currentParamCount + 1 > maxAllowedParameters) {
this.executeCommand(rootNode, actionType, player);
// Close GUI after START action execution
if (actionType == ActionType.ACTION_START && player instanceof ServerPlayer serverPlayer) {
serverPlayer.closeContainer();
}
} else {
this.container.navigateToChild(rootNode);
}
} else {
// Execute command with t`he selected action type
this.executeCommand(rootNode, actionType, player);
// Close GUI after START action execution
if (actionType == ActionType.ACTION_START && player instanceof ServerPlayer serverPlayer) {
serverPlayer.closeContainer();
}
}
}
}
private void executeCommand(GuiRootNode node, ActionType actionType, Player player) {
try {
String actionPrefix = actionType.getCommandActionPrefix();
String actionSuffix = actionType.getCommandActionSuffix();
if (!actionSuffix.isEmpty()) {
actionSuffix = actionSuffix + " ";
}
String extra = actionPrefix + " " + bot.getName() + " " + actionSuffix;
String command = node.buildCommand(extra);
// Apply parameter limit based on ActionType
if (actionType.getMaxAllowedParameters() == 0) {
// For actions like STOP that don't allow parameters, trim to just "action botName"
command = actionPrefix + " " + bot.getName();
}
if (player instanceof ServerPlayer serverPlayer) {
MinecraftServer.getServer().getCommands().performPrefixedCommand(
serverPlayer.createCommandSourceStack(),
command
);
}
} catch (Exception e) {
LogUtils.getLogger().warn("Error executing command: ", e);
}
}
/**
* Execute the command from the command builder (book item).
* Uses the current node and selected action type.
*/
private void executeCommandBuilder(Player player) {
GuiNode currentNode = this.container.getCurrentNode();
ActionType actionType = this.container.getSelectedActionType();
if (currentNode instanceof GuiRootNode rootNode && actionType != null) {
this.executeCommand(rootNode, actionType, player);
// Close GUI after START action execution
if (actionType != ActionType.ACTION_STOP && player instanceof ServerPlayer serverPlayer) {
serverPlayer.closeContainer();
}
}
}
/**
* Stop a bot action by its hash (UUID string)
*/
private void stopActionByHash(String actionHash, Player player) {
try {
if (player instanceof ServerPlayer serverPlayer) {
String command = getStopActionCommand(actionHash);
MinecraftServer.getServer().getCommands().performPrefixedCommand(
serverPlayer.createCommandSourceStack(),
command
);
}
} catch (Exception e) {
LogUtils.getLogger().warn("Error stopping action with hash {}: ", actionHash, e);
}
// Always refresh to show updated action list after stop attempt
this.container.showCurrentBotActions();
}
private String getStopActionCommand(String actionHash) throws UnexpectedException {
boolean botCommand = FakeplayerConfig.enable;
boolean playerCommand = FakePlayerCompatConfig.commandPlayer;
String command;
if (botCommand) {
command = "bot ";
} else if (playerCommand) {
command = "player ";
} else {
throw new UnexpectedException("Unable to build String from commandNode.");
}
command = command + "action " + this.bot.getName() + " stop " + actionHash;
return command;
}
private void refreshSlots() {
for (int i = 0; i < 54; i++) {
Slot slot = this.slots.get(i);
ItemStack item = this.container.getItem(i);
slot.set(item);
}
}
@Override
public ItemStack quickMoveStack(Player player, int index) {
return ItemStack.EMPTY;
}
public BotActionGuiContainer getContainer() {
return this.container;
}
}
@@ -0,0 +1,115 @@
package fun.bm.lophine.bot.action.gui;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ItemLore;
import java.util.ArrayList;
import java.util.List;
public enum ActionType {
ACTION_START("Start", "Start a action", Items.LIME_DYE, "action", "start"),
ACTION_STOP("Stop", "Stop a action or see this bot scheduled tasks", Items.RED_DYE, "action", "stop", 0);
private final String displayName;
private final String description;
private final Item item;
private final String commandActionPrefix;
private final String commandActionSuffix;
private final int maxAllowedParameters;
ActionType(String displayName, String description, Item item, String commandActionPrefix) {
this(displayName, description, item, commandActionPrefix, "", Integer.MAX_VALUE);
}
ActionType(String displayName, String description, Item item, String commandActionPrefix, String commandActionSuffix) {
this(displayName, description, item, commandActionPrefix, commandActionSuffix, Integer.MAX_VALUE);
}
ActionType(String displayName, String description, Item item, String commandActionPrefix, String commandActionSuffix, int maxAllowedParameters) {
this.displayName = displayName;
this.description = description;
this.item = item;
this.commandActionPrefix = commandActionPrefix;
this.commandActionSuffix = commandActionSuffix;
this.maxAllowedParameters = maxAllowedParameters;
}
public String getDisplayName() {
return this.displayName;
}
public String getDescription() {
return this.description;
}
public Item getItem() {
return this.item;
}
public String getCommandActionPrefix() {
return this.commandActionPrefix;
}
public String getCommandActionSuffix() {
return commandActionSuffix;
}
public GuiNode toConfirmNode(GuiRootNode targetNode) {
return new ActionConfirmNode(this.displayName, this.description, this.item, targetNode, this.commandActionPrefix, this.maxAllowedParameters);
}
public int getMaxAllowedParameters() {
return maxAllowedParameters;
}
/**
* A special node used in the action type confirmation UI.
* It holds a reference to the target GuiRootNode and the selected action string.
*/
public static class ActionConfirmNode extends GuiNode {
private final GuiRootNode targetNode;
private final String action;
private final int maxAllowedParameters;
public ActionConfirmNode(String name, String description, Item item, GuiRootNode targetNode, String action, int maxAllowedParameters) {
super(name, description, item);
this.targetNode = targetNode;
this.action = action;
this.maxAllowedParameters = maxAllowedParameters;
}
public GuiRootNode getTargetNode() {
return this.targetNode;
}
public String getAction() {
return this.action;
}
public int getMaxAllowedParameters() {
return this.maxAllowedParameters;
}
@Override
public ItemStack getItemStack() {
ItemStack itemStack = super.getItemStack();
// Add parameter limit info to lore
List<Component> loreLines = new ArrayList<>();
if (this.description != null && !this.description.isEmpty()) {
loreLines.add(Component.literal(this.description));
}
if (!loreLines.isEmpty()) {
itemStack.set(DataComponents.LORE, new ItemLore(loreLines));
}
return itemStack;
}
}
}
@@ -0,0 +1,52 @@
package fun.bm.lophine.bot.action.gui;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ItemLore;
import java.util.List;
public class GuiNode {
protected final String name;
protected final String description;
protected final Item item;
protected final boolean confirmable;
private static final Item defaultItem = Items.PAPER;
public GuiNode(String name, String description, Item item, boolean confirmable) {
this.name = name;
this.description = description;
this.item = item;
this.confirmable = confirmable;
}
public GuiNode(String name, String description, Item item) {
this(name, description, item, true);
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
public boolean isConfirmable() {
return this.confirmable;
}
public ItemStack getItemStack() {
ItemStack itemStack = new ItemStack(this.item == null ? defaultItem : this.item).copy();
itemStack.set(DataComponents.CUSTOM_NAME, Component.literal(this.name));
if (this.description != null && !this.description.isEmpty()) {
ItemLore lore = new ItemLore(List.of(Component.literal(this.description)));
itemStack.set(DataComponents.LORE, lore);
}
return itemStack;
}
}
@@ -0,0 +1,78 @@
package fun.bm.lophine.bot.action.gui;
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
import net.minecraft.world.item.Item;
import java.rmi.UnexpectedException;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class GuiRootNode extends GuiNode {
protected final Set<GuiNode> children;
protected final String commandNode;
public GuiRootNode(String name, String description, Item item, String commandNode) {
this(name, description, item, commandNode, true);
}
public GuiRootNode(String name, String description, Item item, String commandNode, boolean confirmable) {
this(name, description, item, new LinkedHashSet<>(), commandNode, confirmable);
}
public GuiRootNode(String name, String description, Item item, Set<GuiNode> children, String commandNode) {
this(name, description, item, children, commandNode, true);
}
public GuiRootNode(String name, String description, Item item, Set<GuiNode> children, String commandNode, boolean confirmable) {
super(name, description, item, confirmable);
this.children = children;
this.commandNode = commandNode;
}
public final void child(GuiNode... node) {
this.children.addAll(List.of(node));
}
@SafeVarargs
public final void child(Supplier<? extends GuiNode>... node) {
this.children.addAll(Stream.of(node).map(Supplier::get).toList());
}
public Set<GuiNode> getChildren() {
return this.children;
}
public Set<GuiNode> getAllFurthestChildren() {
if (this.children.isEmpty()) {
Set<GuiNode> result = new LinkedHashSet<>();
result.add(this);
return result;
}
Set<GuiNode> furthestChildren = new LinkedHashSet<>();
for (GuiNode child : this.children) {
furthestChildren.addAll(((GuiRootNode) child).getAllFurthestChildren());
}
return furthestChildren;
}
public String getCommandNode() {
return this.commandNode;
}
public String buildCommand(String extra) throws UnexpectedException {
boolean botCommand = FakeplayerConfig.enable;
boolean playerCommand = FakePlayerCompatConfig.commandPlayer;
if (botCommand) {
return "bot " + extra + this.getCommandNode();
}
if (playerCommand) {
return "player " + extra + this.getCommandNode();
}
throw new UnexpectedException("Unable to build String from commandNode.");
}
}
@@ -0,0 +1,37 @@
package fun.bm.lophine.bot.action.gui;
import net.minecraft.world.item.Item;
import java.rmi.UnexpectedException;
import java.util.LinkedHashSet;
import java.util.Set;
public class GuiSubNode extends GuiRootNode {
protected final GuiNode parent;
public GuiSubNode(String name, String description, Item item, GuiNode parent, Set<GuiNode> children, String commandNode) {
this(name, description, item, parent, children, commandNode, true);
}
public GuiSubNode(String name, String description, Item item, GuiNode parent, Set<GuiNode> children, String commandNode, boolean confirmable) {
super(name, description, item, children, commandNode, confirmable);
this.parent = parent;
}
public GuiSubNode(String name, String description, Item item, GuiNode parent, String commandNode) {
this(name, description, item, parent, commandNode, true);
}
public GuiSubNode(String name, String description, Item item, GuiNode parent, String commandNode, boolean confirmable) {
this(name, description, item, parent, new LinkedHashSet<>(), commandNode, confirmable);
}
public GuiNode getParent() {
return this.parent;
}
@Override
public String buildCommand(String extra) throws UnexpectedException {
return ((GuiRootNode) parent).buildCommand(extra) + " " + getCommandNode();
}
}
@@ -4,6 +4,7 @@ import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
import fun.bm.lophine.carpet.config.modules.GeneralCompatConfig;
import fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig;
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
import fun.bm.lophine.config.modules.function.protocol.PcaSyncProtocolConfig;
import fun.bm.lophine.protocol.CarpetLoggerProtocol;
import org.leavesmc.leaves.protocol.CarpetServerProtocol;
@@ -24,75 +25,83 @@ public final class CarpetCompatSync {
}
private static void registerProtocolRules() {
CarpetServerProtocol.CarpetRules.clear();
CarpetServerProtocol.CarpetRules.beginBatch();
try {
CarpetServerProtocol.CarpetRules.clear();
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "language", GeneralCompatConfig.language));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "amsUpdateSuppressionCrashFix", GeneralCompatConfig.amsUpdateSuppressionCrashFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetUpdateSuppressionCrash", GeneralCompatConfig.yeetUpdateSuppressionCrash));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "dustTrapdoorReintroduced", GeneralCompatConfig.dustTrapdoorReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "shulkerBoxCCEReintroduced", GeneralCompatConfig.shulkerBoxCCEReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "instantBlockUpdaterReintroduced", GeneralCompatConfig.instantBlockUpdaterReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandTick", GeneralCompatConfig.commandTick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "creativeNoClip", GeneralCompatConfig.creativeNoClip));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedDragonRespawn", GeneralCompatConfig.optimizedDragonRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "antiSpamDisabled", GeneralCompatConfig.antiSpamDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "blockPlacementIgnoreEntity", GeneralCompatConfig.blockPlacementIgnoreEntity));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeOpenContainerForcibly", GeneralCompatConfig.creativeOpenContainerForcibly));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "creativeOneHitKill", GeneralCompatConfig.creativeOneHitKill));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "observerNoDetection", GeneralCompatConfig.observerNoDetection));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "bambooModelNoOffset", GeneralCompatConfig.bambooModelNoOffset));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeNoItemCooldown", GeneralCompatConfig.creativeNoItemCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "ctrlQCraftingFix", GeneralCompatConfig.ctrlQCraftingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "carpetAlwaysSetDefault", GeneralCompatConfig.carpetAlwaysSetDefault));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "placementRotationFix", GeneralCompatConfig.placementRotationFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntDoNotUpdate", GeneralCompatConfig.tntDoNotUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "totallyNoBlockUpdate", GeneralCompatConfig.totallyNoBlockUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tiscmNetworkProtocol", GeneralCompatConfig.tiscmNetworkProtocol));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "hopperNoItemCost", GeneralCompatConfig.hopperNoItemCost));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "explosionNoBlockDamage", GeneralCompatConfig.explosionNoBlockDamage));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedTNTHighPriority", GeneralCompatConfig.optimizedTNTHighPriority));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntPrimerMomentumRemoved", GeneralCompatConfig.tntPrimerMomentumRemoved));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntIgnoreRedstoneSignal", GeneralCompatConfig.tntIgnoreRedstoneSignal));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntDupingFix", GeneralCompatConfig.tntDupingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "interactionUpdates", GeneralCompatConfig.interactionUpdates));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "xpNoCooldown", GeneralCompatConfig.xpNoCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "powerfulExpMending", GeneralCompatConfig.powerfulExpMending));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "clientSettingsLostOnRespawnFix", GeneralCompatConfig.clientSettingsLostOnRespawnFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "sensibleEnderman", GeneralCompatConfig.sensibleEnderman));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "entityInstantDeathRemoval", GeneralCompatConfig.entityInstantDeathRemoval));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "farmlandTrampledDisabled", GeneralCompatConfig.farmlandTrampledDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "shulkerGolem", GeneralCompatConfig.shulkerGolem));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "preventEndSpikeRespawn", GeneralCompatConfig.preventEndSpikeRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetOutOfOrderChatKick", GeneralCompatConfig.yeetOutOfOrderChatKick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableBoneBlock", GeneralCompatConfig.betterCraftableBoneBlock));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableDispenser", GeneralCompatConfig.betterCraftableDispenser));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "viewDistance", GeneralCompatConfig.viewDistance));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickCommandPermission", GeneralCompatConfig.normalizedTickCommandPermission()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickFreezeCommandToggleable", GeneralCompatConfig.tickFreezeCommandToggleable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "syncServerMsptMetricsData", GeneralCompatConfig.syncServerMsptMetricsData));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "simpleInGameCalculator", GeneralCompatConfig.simpleInGameCalculator));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "microTiming", GeneralCompatConfig.microTiming));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "fastRedstoneDust", GeneralCompatConfig.fastRedstoneDust));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "lagFreeSpawning", GeneralCompatConfig.lagFreeSpawning));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedFastEntityMovement", GeneralCompatConfig.optimizedFastEntityMovement));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedHardHitBoxEntityCollision", GeneralCompatConfig.optimizedHardHitBoxEntityCollision));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntFuseDuration", GeneralCompatConfig.normalizedTntFuseDuration()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "defaultLoggers", CarpetLoggerProtocol.serializeConfiguredDefaults(sanitizeDefaultLoggers(GeneralCompatConfig.defaultLoggers))));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "language", GeneralCompatConfig.language));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "amsUpdateSuppressionCrashFix", GeneralCompatConfig.amsUpdateSuppressionCrashFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetUpdateSuppressionCrash", GeneralCompatConfig.yeetUpdateSuppressionCrash));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "dustTrapdoorReintroduced", GeneralCompatConfig.dustTrapdoorReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "shulkerBoxCCEReintroduced", GeneralCompatConfig.shulkerBoxCCEReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "instantBlockUpdaterReintroduced", GeneralCompatConfig.instantBlockUpdaterReintroduced));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandTick", GeneralCompatConfig.commandTick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "creativeNoClip", GeneralCompatConfig.creativeNoClip));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedDragonRespawn", GeneralCompatConfig.optimizedDragonRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "antiSpamDisabled", GeneralCompatConfig.antiSpamDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "blockPlacementIgnoreEntity", GeneralCompatConfig.blockPlacementIgnoreEntity));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeOpenContainerForcibly", GeneralCompatConfig.creativeOpenContainerForcibly));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "creativeOneHitKill", GeneralCompatConfig.creativeOneHitKill));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "observerNoDetection", GeneralCompatConfig.observerNoDetection));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "bambooModelNoOffset", GeneralCompatConfig.bambooModelNoOffset));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "creativeNoItemCooldown", GeneralCompatConfig.creativeNoItemCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "ctrlQCraftingFix", GeneralCompatConfig.ctrlQCraftingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "carpetAlwaysSetDefault", GeneralCompatConfig.carpetAlwaysSetDefault));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "placementRotationFix", GeneralCompatConfig.placementRotationFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntDoNotUpdate", GeneralCompatConfig.tntDoNotUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "totallyNoBlockUpdate", GeneralCompatConfig.totallyNoBlockUpdate));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tiscmNetworkProtocol", GeneralCompatConfig.tiscmNetworkProtocol));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "hopperNoItemCost", GeneralCompatConfig.hopperNoItemCost));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "explosionNoBlockDamage", GeneralCompatConfig.explosionNoBlockDamage));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedTNTHighPriority", GeneralCompatConfig.optimizedTNTHighPriority));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "tntPrimerMomentumRemoved", GeneralCompatConfig.tntPrimerMomentumRemoved));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntIgnoreRedstoneSignal", GeneralCompatConfig.tntIgnoreRedstoneSignal));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntDupingFix", GeneralCompatConfig.tntDupingFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "interactionUpdates", GeneralCompatConfig.interactionUpdates));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "xpNoCooldown", GeneralCompatConfig.xpNoCooldown));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "powerfulExpMending", GeneralCompatConfig.powerfulExpMending));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "clientSettingsLostOnRespawnFix", GeneralCompatConfig.clientSettingsLostOnRespawnFix));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "sensibleEnderman", GeneralCompatConfig.sensibleEnderman));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "entityInstantDeathRemoval", GeneralCompatConfig.entityInstantDeathRemoval));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "farmlandTrampledDisabled", GeneralCompatConfig.farmlandTrampledDisabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "shulkerGolem", GeneralCompatConfig.shulkerGolem));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "preventEndSpikeRespawn", GeneralCompatConfig.preventEndSpikeRespawn));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "yeetOutOfOrderChatKick", GeneralCompatConfig.yeetOutOfOrderChatKick));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableBoneBlock", GeneralCompatConfig.betterCraftableBoneBlock));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "betterCraftableDispenser", GeneralCompatConfig.betterCraftableDispenser));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "viewDistance", GeneralCompatConfig.viewDistance));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickCommandPermission", GeneralCompatConfig.normalizedTickCommandPermission()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tickFreezeCommandToggleable", GeneralCompatConfig.tickFreezeCommandToggleable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "syncServerMsptMetricsData", GeneralCompatConfig.syncServerMsptMetricsData));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetorgaddition", "simpleInGameCalculator", GeneralCompatConfig.simpleInGameCalculator));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "microTiming", GeneralCompatConfig.microTiming));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "fastRedstoneDust", GeneralCompatConfig.fastRedstoneDust));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "lagFreeSpawning", GeneralCompatConfig.lagFreeSpawning));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedFastEntityMovement", GeneralCompatConfig.optimizedFastEntityMovement));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "optimizedHardHitBoxEntityCollision", GeneralCompatConfig.optimizedHardHitBoxEntityCollision));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "tntFuseDuration", GeneralCompatConfig.normalizedTntFuseDuration()));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "defaultLoggers", CarpetLoggerProtocol.serializeConfiguredDefaults(sanitizeDefaultLoggers(GeneralCompatConfig.defaultLoggers))));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "commandBot", FakeplayerConfig.enable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandPlayer", FakePlayerCompatConfig.commandPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerResident", FakePlayerCompatConfig.fakePlayerResident));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "openFakePlayerInventory", FakePlayerCompatConfig.openFakePlayerInventory));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "fakePlayerTicksLikeRealPlayer", FakePlayerCompatConfig.fakePlayerTicksLikeRealPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerDefaultSurvivalMode", FakePlayerCompatConfig.fakePlayerDefaultSurvivalMode));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerInteractLikeClient", FakePlayerCompatConfig.fakePlayerInteractLikeClient));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplaceTool", FakePlayerCompatConfig.fakePlayerAutoReplaceTool));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplenishment", FakePlayerCompatConfig.fakePlayerAutoReplenishment));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerAutoReplenishmentFormShulkerBox", FakePlayerCompatConfig.fakePlayerAutoReplenishmentFormShulkerBox));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoFish", FakePlayerCompatConfig.fakePlayerAutoFish));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerReloadAction", FakePlayerCompatConfig.fakePlayerReloadAction));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "commandBot", FakeplayerConfig.enable));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "commandPlayer", FakePlayerCompatConfig.commandPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerResident", FakePlayerCompatConfig.fakePlayerResident));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "openFakePlayerInventory", FakePlayerCompatConfig.openFakePlayerInventory));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "fakePlayerTicksLikeRealPlayer", FakePlayerCompatConfig.fakePlayerTicksLikeRealPlayer));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerDefaultSurvivalMode", FakePlayerCompatConfig.fakePlayerDefaultSurvivalMode));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerInteractLikeClient", FakePlayerCompatConfig.fakePlayerInteractLikeClient));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplaceTool", FakePlayerCompatConfig.fakePlayerAutoReplaceTool));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoReplenishment", FakePlayerCompatConfig.fakePlayerAutoReplenishment));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpetamsaddition", "fakePlayerAutoReplenishmentFormShulkerBox", FakePlayerCompatConfig.fakePlayerAutoReplenishmentFormShulkerBox));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerAutoFish", FakePlayerCompatConfig.fakePlayerAutoFish));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("lophine", "fakePlayerReloadAction", FakePlayerCompatConfig.fakePlayerReloadAction));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "hopperCounters", WoolHopperCounterConfig.hopperCounters));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "hopperCountersUnlimitedSpeed", WoolHopperCounterConfig.hopperCountersUnlimitedSpeed));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpet", "hopperCounters", WoolHopperCounterConfig.hopperCounters));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("carpettisaddition", "hopperCountersUnlimitedSpeed", WoolHopperCounterConfig.hopperCountersUnlimitedSpeed));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("pca", "pcaSyncProtocol", PcaSyncProtocolConfig.enabled));
CarpetServerProtocol.CarpetRules.register(CarpetServerProtocol.CarpetRule.of("pca", "pcaSyncPlayerEntity", PcaSyncProtocolConfig.syncPlayerEntity));
} finally {
CarpetServerProtocol.CarpetRules.endBatch();
}
}
}
@@ -70,7 +70,7 @@ public class FakePlayerCompatConfig implements IConfigModule {
@Override
public void onLoaded(CommentedFileConfig configInstance, @Nullable Set<Exception> exs) {
if (commandPlayer) {
if (commandPlayer && command == null) {
command = new BotCommand("player");
command.register();
}
@@ -1,20 +1,67 @@
package fun.bm.lophine.config.modules.experiment;
import fun.bm.lophine.enums.GlobalEntitiesCounterType;
import me.earthme.luminol.config.ConfigManager;
import me.earthme.luminol.config.ConfigsInstance;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigClassInfo;
import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.config.flags.DoNotLoad;
import me.earthme.luminol.config.flags.HotReloadUnsupported;
import me.earthme.luminol.enums.EnumConfigCategory;
@ConfigClassInfo(name = "global_entities_counter", category = EnumConfigCategory.EXPERIMENT)
public class GlobalEntitiesCounter implements IConfigModule {
@HotReloadUnsupported
@ConfigInfo(name = "enabled", comments = """
Enable global entities counter.
@ConfigInfo(name = "version", comments = """
DISABLED
DEFAULT_SYNC: Enable global entities counter origin version with sync counter module.
DEFAULT_ASYNC: Enable global entities counter origin version with async counter module.
PRECISE: Enable precise mob cap calculation with incremental counting. Replaces the periodic full-scan with event-driven real-time updates.
You need to set per-player-mob-spawns to false on paper-world-defaults.yml or paper-world.yml""")
public static boolean enabled = false;
public static GlobalEntitiesCounterType type = GlobalEntitiesCounterType.DISABLED;
@HotReloadUnsupported
@ConfigInfo(name = "async", comments = "Enable Asynchronous(maybe cause bugs)")
public static boolean async = false;
@DoNotLoad
private static boolean enabled;
@DoNotLoad
private static boolean async;
@DoNotLoad
private static boolean defaultModule;
public static boolean isEnabled() {
return enabled;
}
public static boolean isAsync() {
return async;
}
public static boolean isDefaultModule() {
return defaultModule;
}
@Override
public void beforeFinalLoad() {
ConfigsInstance configsInstance = ConfigManager.getConfigs("lophine");
try {
Boolean enabled0 = configsInstance.getConfigOrigin("experiment.global_entities_counter.enabled");
Boolean async0 = configsInstance.getConfigOrigin("experiment.global_entities_counter.async");
if (enabled0 != null) {
if (enabled0) {
if (async0 != null && async0) {
type = GlobalEntitiesCounterType.DEFAULT_ASYNC;
} else {
type = GlobalEntitiesCounterType.DEFAULT_SYNC;
}
}
}
configsInstance.removeConfig("experiment.global_entities_counter.enabled");
configsInstance.removeConfig("experiment.global_entities_counter.async");
} catch (Exception ignored) {
}
enabled = type != GlobalEntitiesCounterType.DISABLED;
async = type == GlobalEntitiesCounterType.DEFAULT_ASYNC;
defaultModule = type == GlobalEntitiesCounterType.DEFAULT_SYNC || type == GlobalEntitiesCounterType.DEFAULT_ASYNC;
}
}
@@ -0,0 +1,13 @@
package fun.bm.lophine.config.modules.fixes;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigClassInfo;
import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.enums.EnumConfigCategory;
@ConfigClassInfo(category = EnumConfigCategory.FIXES, name = "vanilla-like-experience")
public class VanillaLikeExperienceConfig implements IConfigModule {
@ConfigInfo(name = "enabled", comments = """
Restore a more vanilla-like technical gameplay experience by bypassing some Paper safety and behavior changes.""")
public static boolean enabled = false;
}
@@ -40,6 +40,11 @@ public class FakeplayerConfig implements IConfigModule {
Regeneration amount for fakeplayers""")
public static double regenAmount = 0.0;
@ConfigInfo(name = "open-action-gui", comments = """
Allow opening fakeplayer action gui,
need sneak to open if you enabled inventory open gui""")
public static boolean canOpenActionGui = false;
@ConfigInfo(name = "use-action", comments = """
Allow fakeplayers to use actions""")
public static boolean canUseAction = true;
@@ -95,7 +100,7 @@ public class FakeplayerConfig implements IConfigModule {
@Override
public void onLoaded(CommentedFileConfig configInstance, @Nullable Set<Exception> exs) {
if (enable) {
if (enable && command == null) {
command = new BotCommand("bot");
command.register();
}
@@ -12,7 +12,7 @@ public class LanguageConfig implements IConfigModule {
@ConfigInfo(name = "lang", comments = """
Please use the key from https://minecraft.wiki/w/Language
Sample of format: en_us zh_cn zh_hk zh_tw
ATTENTION: If you want to edit language for carpet ststem,
ATTENTION: If you want to edit language for carpet system,
please edit it in carpet config file.""")
public static String lang = "en_us";
@@ -13,6 +13,9 @@ public class OldFeatureConfig implements IConfigModule {
@ConfigInfo(name = "old_zombie_reinforcement")
public static boolean oldZombieReinforcement = false;
@ConfigInfo(name = "old_leader_zombie_health")
public static boolean oldLeaderZombieHealth = false;
@ConfigInfo(name = "old_explosion_damage_calculator")
public static boolean oldExplosionDamageCalculator = false;
@@ -0,0 +1,43 @@
package fun.bm.lophine.config.modules.function.protocol;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import fun.bm.lophine.carpet.CarpetCompatSync;
import fun.bm.lophine.enums.PcaPlayerEntityType;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigClassInfo;
import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.config.flags.TransformedConfig;
import me.earthme.luminol.enums.EnumConfigCategory;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.protocol.PcaSyncProtocol;
import java.util.Set;
@ConfigClassInfo(category = EnumConfigCategory.FUNCTION, name = "pca", directory = {"protocol"})
public class PcaSyncProtocolConfig implements IConfigModule {
private static boolean lastEnabled = false;
@TransformedConfig(name = "pca-sync-protocol", directory = {"protocol"})
@ConfigInfo(name = "enabled", comments = """
Enable PCA sync protocol support""")
public static boolean enabled = false;
@TransformedConfig(name = "pca-sync-player-entity", directory = {"protocol"})
@ConfigInfo(name = "sync-player-entity", comments = """
Controls which player entities can be watched through the PCA sync protocol.
NOBODY: never sync player entities
BOT: only sync Lophine fake players
OPS: sync fake players and allow operators to sync real players
OPS_AND_SELF: sync fake players, operators, and a player's own entity
EVERYONE: allow all player entities""")
public static PcaPlayerEntityType syncPlayerEntity = PcaPlayerEntityType.OPS;
@Override
public void onLoaded(CommentedFileConfig configInstance, @Nullable Set<Exception> e) {
if (lastEnabled != enabled) {
PcaSyncProtocol.onConfigModify(enabled);
lastEnabled = enabled;
}
CarpetCompatSync.apply();
}
}
@@ -0,0 +1,8 @@
package fun.bm.lophine.enums;
public enum GlobalEntitiesCounterType {
DISABLED,
DEFAULT_SYNC,
DEFAULT_ASYNC,
PRECISE
}
@@ -0,0 +1,9 @@
package fun.bm.lophine.enums;
public enum PcaPlayerEntityType {
NOBODY,
BOT,
OPS,
OPS_AND_SELF,
EVERYONE
}
@@ -6,6 +6,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.mojang.logging.LogUtils;
import fun.bm.lophine.config.modules.experiment.GlobalEntitiesCounter;
import fun.bm.lophine.config.modules.fixes.VanillaLikeExperienceConfig;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
@@ -24,10 +25,10 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import static net.minecraft.world.level.NaturalSpawner.getRoughBiome;
import java.util.concurrent.atomic.AtomicInteger;
public class EntitiesCounterUtil {
// global entities counter
private static final Map<ServerLevel, Cache<Integer, ReferenceList<Entity>>> globalLoadedEntities = new ConcurrentHashMap<>();
private static final Map<ServerLevel, Object2IntOpenHashMap<MobCategory>> mobsMap = Collections.synchronizedMap(new WeakHashMap<>());
private static final Map<ServerLevel, Cache<Integer, PositionCountingAreaMap<ServerPlayer>>> mobsAreaMap = new ConcurrentHashMap<>();
@@ -35,6 +36,9 @@ public class EntitiesCounterUtil {
private static final Map<ServerLevel, CompletableFuture<Void>> tasks = new ConcurrentHashMap<>();
private static final Set<Integer> UniqueIds = ConcurrentHashMap.newKeySet();
// precise mob counter extra
private static final Map<ServerLevel, EnumMap<MobCategory, AtomicInteger>> globalMobCounts = new ConcurrentHashMap<>();
private static int lastUsedId = 0;
private static final int CLEANUP_INTERVAL = 200; // each 200 ids used
@@ -104,94 +108,193 @@ public class EntitiesCounterUtil {
}
public static void tick(ServerLevel level) {
Runnable task = () -> {
try {
Cache<Integer, ReferenceList<Entity>> data0 = globalLoadedEntities.get(level);
if (data0 == null) return;
if (GlobalEntitiesCounter.isDefaultModule()) {
Runnable task = () -> {
try {
Cache<Integer, ReferenceList<Entity>> data0 = globalLoadedEntities.get(level);
if (data0 == null) return;
Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
Collection<ReferenceList<Entity>> snapshot = data0.asMap().values();
Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
Collection<ReferenceList<Entity>> snapshot = data0.asMap().values();
for (ReferenceList<Entity> data : snapshot) {
if (data == null) continue;
for (Entity entity : GlobalEntitiesCounter.async ? data.copy() : data) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
MobCategory category = entity.getType().getCategory();
if (category != MobCategory.MISC) {
// Paper start - Only count natural spawns
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
for (ReferenceList<Entity> data : snapshot) {
if (data == null) continue;
for (Entity entity : GlobalEntitiesCounter.isAsync() ? data.copy() : data) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
MobCategory category = entity.getType().getCategory();
if (category != MobCategory.MISC) {
// Paper start - Only count natural spawns
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
}
// Paper end - Only count natural spawns
map.addTo(category, 1);
}
// Paper end - Only count natural spawns
map.addTo(category, 1);
}
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
}
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
}
mobsMap.put(level, map);
mobsMap.put(level, map);
Cache<Integer, PositionCountingAreaMap<ServerPlayer>> collection = mobsAreaMap.get(level);
if (collection != null) {
int count = 0;
for (PositionCountingAreaMap<ServerPlayer> areaMap : collection.asMap().values()) {
if (areaMap != null) {
count += areaMap.getTotalPositions();
Cache<Integer, PositionCountingAreaMap<ServerPlayer>> collection = mobsAreaMap.get(level);
if (collection != null) {
int count = 0;
for (PositionCountingAreaMap<ServerPlayer> areaMap : collection.asMap().values()) {
if (areaMap != null) {
count += areaMap.getTotalPositions();
}
}
spawnableChunkCount.put(level, count);
}
spawnableChunkCount.put(level, count);
} catch (Exception e) {
LogUtils.getClassLogger().error("Failed to run task", e);
}
} catch (Exception e) {
LogUtils.getClassLogger().error("Failed to run task", e);
};
if (GlobalEntitiesCounter.isAsync()) {
tasks.put(level, CompletableFuture.runAsync(task).exceptionally(ex -> {
LogUtils.getClassLogger().error("Failed to run task", ex);
return null;
}));
} else {
task.run();
}
};
if (GlobalEntitiesCounter.async) {
tasks.put(level, CompletableFuture.runAsync(task).exceptionally(ex -> {
LogUtils.getClassLogger().error("Failed to run task", ex);
return null;
}));
} else {
task.run();
Cache<Integer, PositionCountingAreaMap<ServerPlayer>> cache = mobsAreaMap.get(level);
if (cache == null) return;
int total = 0;
for (PositionCountingAreaMap<ServerPlayer> map : cache.asMap().values()) {
if (map != null) {
total += map.getTotalPositions();
}
}
spawnableChunkCount.put(level, total);
}
}
public static NaturalSpawner.SpawnState runRemainingTasks(
public static NaturalSpawner.SpawnState createSpawnState(
ServerLevel level, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs
) {
Object2IntOpenHashMap<MobCategory> map = getMobsMap(level);
if (map == null) return null; // skip if no data
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
PotentialCalculator potentialCalculator = new PotentialCalculator();
for (Entity entity : entities) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
// Paper start - Only count natural spawns
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
if (GlobalEntitiesCounter.isDefaultModule()) {
Object2IntOpenHashMap<MobCategory> map = getMobsMap(level);
if (map == null) return null; // skip if no data
// Lophine start - Copy from net/minecraft/world/level/NaturalSpawner
PotentialCalculator potentialCalculator = new PotentialCalculator();
for (Entity entity : entities) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
// Paper start - Only count natural spawns
if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
!(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL ||
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
}
// Paper end - Only count natural spawns
BlockPos blockPos = entity.blockPosition();
chunkGetter.query(ChunkPos.pack(blockPos), chunk -> {
MobSpawnSettings.MobSpawnCost mobSpawnCost = NaturalSpawner.getRoughBiome(blockPos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
if (mobSpawnCost != null) {
potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
}
if (calculator != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
calculator.addMob(chunk.getPos(), entity.getType().getCategory());
}
// Paper start - Optional per player mob spawns
if (countMobs) {
chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
}
// Paper end - Optional per player mob spawns
});
}
// Paper end - Only count natural spawns
BlockPos blockPos = entity.blockPosition();
chunkGetter.query(ChunkPos.pack(blockPos), chunk -> {
MobSpawnSettings.MobSpawnCost mobSpawnCost = getRoughBiome(blockPos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
if (mobSpawnCost != null) {
potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
}
return new NaturalSpawner.SpawnState(getTotalChunkCount(level), map, potentialCalculator, calculator);
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
} else {
int chunkCount = getSpawnableChunkCount(level);
if (chunkCount == 0) return null;
if (calculator != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
calculator.addMob(chunk.getPos(), entity.getType().getCategory());
}
Object2IntOpenHashMap<MobCategory> globalCounts = getGlobalCounts(level);
// Paper start - Optional per player mob spawns
if (countMobs) {
chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
}
// Paper end - Optional per player mob spawns
});
PotentialCalculator potentialCalculator = new PotentialCalculator();
for (Entity entity : entities) {
if (entity == null || entity.isRemoved() || !entity.isAlive()) continue;
if (!shouldCount(entity)) continue;
BlockPos pos = entity.blockPosition();
chunkGetter.query(ChunkPos.pack(pos), chunk -> {
MobSpawnSettings.MobSpawnCost mobSpawnCost = NaturalSpawner.getRoughBiome(pos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
if (mobSpawnCost != null) {
potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
}
if (calculator != null && entity instanceof Mob) {
calculator.addMob(chunk.getPos(), entity.getType().getCategory());
}
});
}
return new NaturalSpawner.SpawnState(chunkCount, globalCounts, potentialCalculator, calculator);
}
}
public static Object2IntOpenHashMap<MobCategory> getGlobalCounts(ServerLevel level) {
EnumMap<MobCategory, AtomicInteger> counts = globalMobCounts.get(level);
Object2IntOpenHashMap<MobCategory> result = new Object2IntOpenHashMap<>();
if (counts != null) {
for (Map.Entry<MobCategory, AtomicInteger> entry : counts.entrySet()) {
result.put(entry.getKey(), entry.getValue().get());
}
}
return result;
}
public static int getSpawnableChunkCount(ServerLevel level) {
Integer value = spawnableChunkCount.get(level);
return value != null ? value : 0;
}
public static void onWorldUnload(ServerLevel level) {
globalMobCounts.remove(level);
mobsAreaMap.remove(level);
spawnableChunkCount.remove(level);
}
public static void onEntityTrackingStart(ServerLevel level, Entity entity) {
if (!shouldCount(entity)) return;
MobCategory category = entity.getType().getCategory();
getOrCreateCounts(level).computeIfAbsent(category, k -> new AtomicInteger(0)).incrementAndGet();
}
public static boolean shouldCount(Entity entity) {
MobCategory category = entity.getType().getCategory();
if (category == MobCategory.MISC) return false;
if (entity instanceof Mob mob && (mob.isPersistenceRequired() || mob.requiresCustomPersistence())) {
return false;
}
if (VanillaLikeExperienceConfig.enabled || entity.level().paperConfig().entities.spawning.countAllMobsForSpawning) {
return true;
}
return entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL
|| entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN;
}
private static EnumMap<MobCategory, AtomicInteger> getOrCreateCounts(ServerLevel level) {
return globalMobCounts.computeIfAbsent(level, _ -> new EnumMap<>(MobCategory.class));
}
public static void onEntityTrackingEnd(ServerLevel level, Entity entity) {
if (!shouldCount(entity)) return;
MobCategory category = entity.getType().getCategory();
EnumMap<MobCategory, AtomicInteger> counts = getOrCreateCounts(level);
AtomicInteger counter = counts.get(category);
if (counter != null) {
counter.updateAndGet(v -> Math.max(0, v - 1));
}
return new NaturalSpawner.SpawnState(getTotalChunkCount(level), map, potentialCalculator, calculator);
// Lophine end - Copy from net/minecraft/world/level/NaturalSpawner
}
}
@@ -315,11 +315,13 @@ public class BotList {
bot.unRide();
for (ThrownEnderpearl thrownEnderpearl : bot.getEnderPearls()) {
if (!thrownEnderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) {
thrownEnderpearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT);
} else {
thrownEnderpearl.setOwner(null);
}
// Lophine start - restore vanilla ender pearl loading on Folia
thrownEnderpearl.getBukkitEntity().taskScheduler.scheduleOrExecute((Entity pearl) -> {
if (!pearl.isRemoved()) {
pearl.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER, EntityRemoveEvent.Cause.PLAYER_QUIT);
}
});
// Lophine end - restore vanilla ender pearl loading on Folia
}
bot.level().getCurrentWorldData().connections.remove(bot.connection.connection);
@@ -20,6 +20,8 @@ package org.leavesmc.leaves.bot;
import com.google.common.collect.ImmutableMap;
import com.mojang.authlib.GameProfile;
import fun.bm.lophine.LophineLogger;
import fun.bm.lophine.bot.BotActionGuiContainer;
import fun.bm.lophine.bot.BotActionGuiMenu;
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
import io.papermc.paper.adventure.PaperAdventure;
@@ -357,15 +359,28 @@ public class ServerBot extends ServerPlayer {
}
@Override
public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand, @NotNull net.minecraft.world.phys.Vec3 location) { // Leaves - Paper 26.1: Entity#interact now takes Vec3
if (FakePlayerCompatConfig.openFakePlayerInventory) {
if (player instanceof ServerPlayer player1 && player.getMainHandItem().isEmpty()) {
public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand, @NotNull net.minecraft.world.phys.Vec3 location) {
if (player instanceof ServerPlayer player1 && player.getMainHandItem().isEmpty()) {
boolean isSneaking = player.isShiftKeyDown();
boolean enabled1Only = FakePlayerCompatConfig.openFakePlayerInventory ^ FakeplayerConfig.canOpenActionGui;
boolean openInventory = enabled1Only ? FakePlayerCompatConfig.openFakePlayerInventory : FakePlayerCompatConfig.openFakePlayerInventory && !isSneaking;
boolean openActionGui = enabled1Only ? FakeplayerConfig.canOpenActionGui : FakeplayerConfig.canOpenActionGui && isSneaking;
if (openInventory) {
BotInventoryOpenEvent event = new BotInventoryOpenEvent(this.getBukkitEntity(), player1.getBukkitEntity());
getServer().server.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
player.openMenu(new SimpleMenuProvider((i, inventory, p) -> ChestMenu.sixRows(i, inventory, this.container), this.getDisplayName()));
return InteractionResult.SUCCESS;
}
} else if (openActionGui) {
BotActionGuiOpenEvent event = new BotActionGuiOpenEvent(this.getBukkitEntity(), player1.getBukkitEntity());
getServer().server.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
BotActionGuiContainer container = new BotActionGuiContainer(this.getBukkitEntity(), player1.getBukkitEntity());
player.openMenu(new SimpleMenuProvider((i, inventory, p) -> new BotActionGuiMenu(i, inventory, container), this.getDisplayName()));
return InteractionResult.SUCCESS;
}
}
}
return super.interact(player, hand, location);
@@ -17,6 +17,7 @@
package org.leavesmc.leaves.bot.agent;
import fun.bm.lophine.bot.BotActionGuiContainer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -59,6 +60,9 @@ public class Actions {
if (!actionsByName.containsKey(action.getName())) {
actionsByName.put(action.getName(), action);
actionsByClass.put(type, action);
if (action.getGuiData() != null) {
BotActionGuiContainer.registerGuiRootNode(action.getGuiData());
}
return true;
}
return false;
@@ -70,6 +74,8 @@ public class Actions {
public static boolean unregister(@NotNull String name) {
AbstractBotAction<?> action = actionsByName.remove(name);
BotActionGuiContainer.unregisterGuiRootNode(name);
if (action != null) {
actionsByClass.remove(action.getClass());
return true;
@@ -20,10 +20,12 @@ package org.leavesmc.leaves.bot.agent.actions;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import fun.bm.lophine.LophineLogger;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.core.UUIDUtil;
import net.minecraft.nbt.CompoundTag;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.ExtraData;
import org.leavesmc.leaves.command.CommandContext;
@@ -57,6 +59,8 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
private Consumer<E> onSuccess;
private Consumer<E> onStop;
protected GuiRootNode guiData;
public AbstractBotAction(String name, Supplier<E> creator) {
this.name = name;
this.uuid = UUID.randomUUID();
@@ -261,4 +265,8 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
public void setOnStop(Consumer<E> onStop) {
this.onStop = onStop;
}
public @Nullable GuiRootNode getGuiData() {
return this.guiData;
}
}
@@ -17,6 +17,8 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import fun.bm.lophine.bot.action.gui.GuiSubNode;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.agent.ExtraData;
@@ -29,13 +31,37 @@ import static org.leavesmc.leaves.command.ArgumentNode.ArgumentSuggestions.strin
public abstract class AbstractTimerBotAction<E extends AbstractTimerBotAction<E>> extends AbstractBotAction<E> {
public AbstractTimerBotAction(String name, Supplier<E> creator) {
public AbstractTimerBotAction(String name, Supplier<E> creator, GuiRootNode guiData) {
super(name, creator);
this.addArgument("delay", integer(0)).suggests(strings("0", "5", "10", "20")).setOptional(true);
this.addArgument("interval", integer(0)).suggests(strings("20", "0", "5", "10")).setOptional(true);
String[] delaySuggestions = {"0", "5", "10", "20"};
String[] intervalSuggestions = {"20", "0", "5", "10"};
this.addArgument("delay", integer(0)).suggests(strings(delaySuggestions)).setOptional(true);
this.addArgument("interval", integer(0)).suggests(strings(intervalSuggestions)).setOptional(true);
this.addArgument("do_number", integer(-1))
.suggests(((context, builder) -> builder.suggest("-1", Component.literal("do infinite times"))))
.setOptional(true);
if (guiData == null) return;
this.guiData = guiData;
GuiSubNode[] node1 = new GuiSubNode[delaySuggestions.length];
for (int i = 0; i < delaySuggestions.length; i++) {
node1[i] = new GuiSubNode(delaySuggestions[i], "Delay for a few ticks", null, guiData, delaySuggestions[i]);
guiData.child(node1[i]);
}
GuiSubNode[] node2 = new GuiSubNode[delaySuggestions.length * intervalSuggestions.length];
for (int i = 0; i < delaySuggestions.length; i++) {
for (int j = 0; j < intervalSuggestions.length; j++) {
int id = i * intervalSuggestions.length + j;
node2[id] = new GuiSubNode(intervalSuggestions[j], "Interval for a few ticks", null, node1[i], intervalSuggestions[j]);
node1[i].child(node2[id]);
}
}
for (GuiSubNode node : node2) {
GuiSubNode subNode = new GuiSubNode("-1", "Number of times to do", null, node, "-1");
node.child(subNode);
}
}
@Override
@@ -17,6 +17,9 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiNode;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import fun.bm.lophine.bot.action.gui.GuiSubNode;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionResult;
@@ -35,8 +38,8 @@ public abstract class AbstractUseBotAction<T extends AbstractUseBotAction<T>> ex
private int alreadyUsedTick = 0;
private int useItemRemainingTicks = 0;
public AbstractUseBotAction(String name, Supplier<T> supplier) {
super(name, supplier);
public AbstractUseBotAction(String name, Supplier<T> supplier, GuiRootNode guiData) {
super(name, supplier, guiData);
this.addArgument("use_timeout", integer(-1))
.suggests((context, builder) -> {
builder.suggest("-1", Component.literal("no use timeout"));
@@ -44,6 +47,17 @@ public abstract class AbstractUseBotAction<T extends AbstractUseBotAction<T>> ex
builder.suggest("10", Component.literal("minimum trident shoot time"));
})
.setOptional(true);
if (guiData == null) return;
for (GuiNode node : guiData.getAllFurthestChildren()) {
GuiSubNode node0 = (GuiSubNode) node;
node0.child(
new GuiSubNode("-1", "no use timeout", null, node0, "-1"),
new GuiSubNode("3", "minimum bow shoot time", null, node0, "3"),
new GuiSubNode("10", "minimum trident shoot time", null, node0, "10")
);
}
}
@Override
@@ -17,6 +17,8 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.item.Items;
import net.minecraft.world.phys.EntityHitResult;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
@@ -25,7 +27,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftAttackAction;
public class ServerAttackAction extends AbstractTimerBotAction<ServerAttackAction> {
public ServerAttackAction() {
super("attack", ServerAttackAction::new);
GuiRootNode guiData = new GuiRootNode("Attack", "Attack an entity", Items.DIAMOND_SWORD, "attack");
super("attack", ServerAttackAction::new, guiData);
}
@Override
@@ -17,10 +17,12 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
@@ -33,7 +35,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftBreakBlockAction;
public class ServerBreakBlockAction extends AbstractTimerBotAction<ServerBreakBlockAction> {
public ServerBreakBlockAction() {
super("break", ServerBreakBlockAction::new);
GuiRootNode guiRootNode = new GuiRootNode("Break", "Break a block", Items.DIAMOND_PICKAXE, "break");
super("break", ServerBreakBlockAction::new, guiRootNode);
}
private ItemStack lastItem = null;
@@ -17,6 +17,8 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftDropAction;
@@ -24,7 +26,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftDropAction;
public class ServerDropAction extends AbstractTimerBotAction<ServerDropAction> {
public ServerDropAction() {
super("drop", ServerDropAction::new);
GuiRootNode guiRootNode = new GuiRootNode("Drop", "Drop all items", Items.BARRIER, "drop");
super("drop", ServerDropAction::new, guiRootNode);
}
@Override
@@ -17,11 +17,13 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.projectile.FishingHook;
import net.minecraft.world.item.FishingRodItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftFishAction;
@@ -29,7 +31,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftFishAction;
public class ServerFishAction extends AbstractTimerBotAction<ServerFishAction> {
public ServerFishAction() {
super("fish", ServerFishAction::new);
GuiRootNode guiRootNode = new GuiRootNode("Fish", "Fish", Items.FISHING_ROD, "fish");
super("fish", ServerFishAction::new, guiRootNode);
}
private static final int CATCH_ENTITY_DELAY = 20;
@@ -17,6 +17,8 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftJumpAction;
@@ -24,7 +26,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftJumpAction;
public class ServerJumpAction extends AbstractTimerBotAction<ServerJumpAction> {
public ServerJumpAction() {
super("jump", ServerJumpAction::new);
GuiRootNode guiRootNode = new GuiRootNode("Jump", "Jump", Items.ELYTRA, "jump");
super("jump", ServerJumpAction::new, guiRootNode);
}
@Override
@@ -17,6 +17,8 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.item.Items;
import org.bukkit.Location;
import org.bukkit.craftbukkit.entity.CraftVehicle;
import org.bukkit.entity.Vehicle;
@@ -31,6 +33,8 @@ public class ServerMountAction extends AbstractBotAction<ServerMountAction> {
public ServerMountAction() {
super("mount", ServerMountAction::new);
this.guiData = new GuiRootNode("Mount", "Mount", Items.SADDLE, "mount");
}
@Override
@@ -17,6 +17,8 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.ExtraData;
@@ -32,6 +34,11 @@ public class ServerMoveAction extends AbstractStateBotAction<ServerMoveAction> {
public ServerMoveAction() {
super("move", ServerMoveAction::new);
this.addArgument("direction", EnumArgumentType.fromEnum(MoveDirection.class));
this.guiData = new GuiRootNode("Move", "Move", null, "move", false);
for (MoveDirection direction : MoveDirection.values()) {
this.guiData.child(new GuiRootNode(direction.name, direction.name, Items.LEATHER_BOOTS, "move " + direction.name));
}
}
@Override
@@ -17,6 +17,7 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftSneakAction;
@@ -26,6 +27,8 @@ public class ServerSneakAction extends AbstractStateBotAction<ServerSneakAction>
public ServerSneakAction() {
super("sneak", ServerSneakAction::new);
this.guiData = new GuiRootNode("Sneak", "Sneak", null, "sneak");
}
@Override
@@ -17,8 +17,10 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftSwapAction;
@@ -27,6 +29,8 @@ public class ServerSwapAction extends AbstractBotAction<ServerSwapAction> {
public ServerSwapAction() {
super("swap", ServerSwapAction::new);
this.guiData = new GuiRootNode("Swap", "Swap", Items.SHIELD, "swap");
}
@Override
@@ -17,6 +17,8 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.item.Items;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
@@ -26,6 +28,8 @@ public class ServerSwimAction extends AbstractStateBotAction<ServerSwimAction> {
public ServerSwimAction() {
super("swim", ServerSwimAction::new);
this.guiData = new GuiRootNode("Swim", "Swim", Items.WATER_BUCKET, "swim");
}
@Override
@@ -26,7 +26,7 @@ import org.leavesmc.leaves.entity.bot.actions.CraftUseItemAction;
public class ServerUseItemAction extends AbstractUseBotAction<ServerUseItemAction> {
public ServerUseItemAction() {
super("use", ServerUseItemAction::new);
super("use", ServerUseItemAction::new, null);
}
@Override
@@ -17,10 +17,12 @@
package org.leavesmc.leaves.bot.agent.actions;
import fun.bm.lophine.bot.action.gui.GuiRootNode;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
@@ -37,7 +39,8 @@ import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemToAction.useIte
public class ServerUseItemAutoAction extends AbstractUseBotAction<ServerUseItemAutoAction> {
public ServerUseItemAutoAction() {
super("use_auto", ServerUseItemAutoAction::new);
GuiRootNode guiRootNode = new GuiRootNode("Use", "Use Item", Items.BOW, "use_auto");
super("use_auto", ServerUseItemAutoAction::new, guiRootNode);
}
@Override
@@ -27,7 +27,7 @@ import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemAction.useItem;
public class ServerUseItemOffhandAction extends AbstractUseBotAction<ServerUseItemOffhandAction> {
public ServerUseItemOffhandAction() {
super("use_offhand", ServerUseItemOffhandAction::new);
super("use_offhand", ServerUseItemOffhandAction::new, null);
}
@Override
@@ -28,7 +28,7 @@ import org.leavesmc.leaves.entity.bot.actions.CraftUseItemOnAction;
public class ServerUseItemOnAction extends AbstractUseBotAction<ServerUseItemOnAction> {
public ServerUseItemOnAction() {
super("use_on", ServerUseItemOnAction::new);
super("use_on", ServerUseItemOnAction::new, null);
}
@Override
@@ -28,7 +28,7 @@ import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemOnAction.useIte
public class ServerUseItemOnOffhandAction extends AbstractUseBotAction<ServerUseItemOnOffhandAction> {
public ServerUseItemOnOffhandAction() {
super("use_on_offhand", ServerUseItemOnOffhandAction::new);
super("use_on_offhand", ServerUseItemOnOffhandAction::new, null);
}
@Override
@@ -32,7 +32,7 @@ import org.leavesmc.leaves.entity.bot.actions.CraftUseItemToAction;
public class ServerUseItemToAction extends AbstractUseBotAction<ServerUseItemToAction> {
public ServerUseItemToAction() {
super("use_to", ServerUseItemToAction::new);
super("use_to", ServerUseItemToAction::new, null);
}
@Override
@@ -28,7 +28,7 @@ import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemToAction.useIte
public class ServerUseItemToOffhandAction extends AbstractUseBotAction<ServerUseItemToOffhandAction> {
public ServerUseItemToOffhandAction() {
super("use_to_offhand", ServerUseItemToOffhandAction::new);
super("use_to_offhand", ServerUseItemToOffhandAction::new, null);
}
@Override

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