Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a9f3c2c291 | |||
| c619486da9 | |||
| 5cd355881a | |||
| 5a28a619b7 | |||
| 9b5f3e1bd9 | |||
| 132ee404d4 | |||
| 0e10a8e8b0 | |||
| 24e68fb203 | |||
| 141c226294 | |||
| 1049012aff | |||
| 302825cc7e | |||
| d806e4a423 | |||
| 952c4321d9 | |||
| dd7ef6701a | |||
| 43036f971c | |||
| 25ce58c40d | |||
| 106f1edb09 | |||
| eea830188f | |||
| f517cc0b8a | |||
| d90c8567d3 | |||
| 78b3a8a6e7 | |||
| 2f93769135 | |||
| 4e277ad91e | |||
| 1620687dba | |||
| 7b7eb911c9 | |||
| 0724ba3fa9 | |||
| e6d6562f4f | |||
| 580201740e | |||
| d54b248f27 | |||
| 11b0b05a93 | |||
| 7db058ef56 | |||
| 019adaf46f | |||
| 6f55ed7e8e | |||
| 12c58f69b3 | |||
| 0fd3b32108 | |||
| b8f43b47e6 | |||
| 5f718d45a1 | |||
| 1cbb19d9e4 | |||
| 4339b5e8a6 | |||
| bcbc0685b2 | |||
| c9bfe55ce4 | |||
| 04bedd5dfc | |||
| 4cc1be5faa | |||
| 9c00870696 | |||
| e988b087a6 | |||
| 4d60979f75 | |||
| c8b50d84a9 | |||
| 6744e2c6d5 | |||
| 0678cc6e46 | |||
| f4aea025c1 | |||
| 847fec5cb0 | |||
| 576d2322ee | |||
| 917b2cf3d9 | |||
| 6309c478be | |||
| 012ea4f5b5 | |||
| 377c81f26f | |||
| 91e00f34ff | |||
| ac51af2fbc | |||
| 6df2e43b80 | |||
| a62cc74f09 | |||
| f703bda607 | |||
| 8a7b605fa6 | |||
| 9f2f53001a | |||
| f98781b7cc | |||
| 3251e0d8e0 | |||
| 03dddb546d | |||
| 37c22202ab | |||
| 2e67f978ec | |||
| ed2f464914 | |||
| 1cd09226f6 | |||
| 8cd8f4fbad | |||
| e90c758a01 | |||
| e508462093 | |||
| b9c68a9b84 | |||
| 74d0b5ca5f | |||
| 4df4d07ae9 | |||
| cfc73efc9a | |||
| 0989bcaec7 | |||
| 3763d0b885 | |||
| cd3db4ae8c | |||
| 11e9760eb3 | |||
| 13c5bd7331 | |||
| bbcc103643 | |||
| a721c27e96 | |||
| 09011f05e6 | |||
| b8692e23d2 | |||
| 1bb1811027 | |||
| a4936582bb | |||
| fc760a047f | |||
| 5567b194d7 | |||
| f6f2781237 | |||
| f469ad848b | |||
| 924ab75f1d | |||
| 1b2f577e42 | |||
| 76c504e86f | |||
| 7ada14e6b6 | |||
| 24965b48c5 | |||
| 5dab6a557b | |||
| e27300d2c2 | |||
| cd665f0168 | |||
| aa07ef21ca | |||
| d50ad73a17 | |||
| 0d794003bc | |||
| 3856196543 | |||
| eff43b61ff | |||
| 06514362b8 | |||
| 5b94c79f39 | |||
| 24a315a368 | |||
| 3d54e47c5e | |||
| 6aadb1ca19 | |||
| 0a4a6baf70 | |||
| ee36fab64c | |||
| e85db692f3 | |||
| 9635e516dd | |||
| d7e1b3a6bb | |||
| 0fc9a1426d | |||
| 017e49da8a | |||
| 42d870e32b | |||
| 54ff033ef6 | |||
| 9761fde77d | |||
| e0d42cb1d3 | |||
| 559b2e089a | |||
| a07649d14d | |||
| 6aa709cf75 | |||
| 6a452799cc | |||
| e17a3f2033 | |||
| 74ac0bccf5 | |||
| f65b7f176b | |||
| 97a17dbf78 | |||
| c5194eeb8f | |||
| 58c5573421 | |||
| 1907a41329 | |||
| 21cce73216 | |||
| 163a9902cc | |||
| ba1216d4d3 | |||
| beb5cbeb52 |
+1
-1
@@ -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] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
|
||||
+17
-14
@@ -10,11 +10,11 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
force-release:
|
||||
description: "Force disable release if you enter 2, force release if you enter 1, default release if not released else skip release"
|
||||
description: "Force disable release if you enter false, force release if you enter true, default release if not released else skip release"
|
||||
required: false
|
||||
default: ""
|
||||
force-push:
|
||||
description: "Force disable push to repo if you enter 2, force push to repo if you enter 1, default push if not released else skip push repo"
|
||||
description: "Force disable push to repo if you enter false, force push to repo if you enter true, default push if not released else skip push repo"
|
||||
required: false
|
||||
default: ""
|
||||
comments:
|
||||
@@ -28,36 +28,38 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
environment: default
|
||||
env:
|
||||
BUILD_NUMBER: ${{ github.run_number }}
|
||||
steps:
|
||||
- name: Checkout Git Repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Set Up JDK
|
||||
uses: actions/setup-java@v5
|
||||
uses: actions/setup-java@v5.7.0
|
||||
with:
|
||||
distribution: zulu
|
||||
java-version: 21
|
||||
java-version: 25
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- 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
|
||||
|
||||
- name: Build Paperclip Jar
|
||||
run: ./gradlew --refresh-dependencies createMojmapPaperclipJar
|
||||
run: ./gradlew --refresh-dependencies createPaperclipJar
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ env.project_id_b }} CI Artifacts
|
||||
path: lophine-server/build/libs/*-paperclip-*-mojmap.jar
|
||||
path: lophine-server/build/libs/*-paperclip-*.jar
|
||||
|
||||
- name: Set Environment
|
||||
if: github.event_name != 'pull_request'
|
||||
@@ -81,11 +83,12 @@ jobs:
|
||||
done
|
||||
echo "tag=${{ env.tag }}-${counter}" >> $GITHUB_ENV
|
||||
echo "release_count= - ${counter}" >> $GITHUB_ENV
|
||||
release_exists=false
|
||||
fi
|
||||
echo "release_exists=${release_exists}" >> $GITHUB_ENV
|
||||
|
||||
- name: Check If Branch In Expectations
|
||||
if: github.event_name != 'pull_request'
|
||||
if: github.event_name != 'pull_request' && env.flag_release == 'true'
|
||||
run: |
|
||||
if [[ "$GITHUB_REF_NAME" == ver/* ]] || [[ "$GITHUB_REF_NAME" == exp/* ]] || [[ "$GITHUB_REF_NAME" == dev/* ]]; then
|
||||
echo "Branch is in expected prefixes"
|
||||
@@ -96,7 +99,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Publish To Repo
|
||||
if: ( github.event_name != 'pull_request' && !( env.unexpect == 'true' ) && env.flag_release == 'true' && env.release_exists != 'true' && !( inputs.force-release == '2' )) || inputs.force-push == '1'
|
||||
if: ( github.event_name != 'pull_request' && !( env.unexpect == 'true' ) && env.flag_push_repo == 'true' && !( inputs.force-push == 'false' )) || inputs.force-push == 'true'
|
||||
continue-on-error: true
|
||||
run: ./gradlew --refresh-dependencies generateDevelopmentBundle publish -PpublishDevBundle=true
|
||||
env:
|
||||
@@ -104,7 +107,7 @@ jobs:
|
||||
PRIVATE_MAVEN_REPO_USERNAME: ${{ secrets.PRIVATE_MAVEN_REPO_USERNAME }}
|
||||
|
||||
- name: Create Release - Pre Process
|
||||
if: ( github.event_name != 'pull_request' && !( env.unexpect == 'true' ) && env.flag_release == 'true' && env.release_exists != 'true' && !(inputs.force-release == '2')) || inputs.force-release == '1'
|
||||
if: ( github.event_name != 'pull_request' && !( env.unexpect == 'true' ) && env.flag_release == 'true' && env.release_exists != 'true' && !(inputs.force-release == 'false')) || inputs.force-release == 'true'
|
||||
run: |
|
||||
if [ "${{ inputs.comments }}" == "" ]; then
|
||||
echo "No comments provided"
|
||||
@@ -121,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 }} [](https://github.com/LuminolMC/${{ env.project_id }}/releases/download/${{ env.tag }}/${{ env.jar }})
|
||||
📦Version: `${{ env.mcversion }}` | Commit ${{ env.commit_id }} [](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 }}
|
||||
@@ -140,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 }} [](https://github.com/LuminolMC/${{ env.project_id }}/releases/download/${{ env.tag }}/${{ env.jar }})
|
||||
📦Version: `${{ env.mcversion }}` | Commit ${{ env.commit_id }} [](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,7 +16,7 @@ jobs:
|
||||
pull-requests: write
|
||||
checks: write
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit
|
||||
fetch-depth: 0 # a full history is required for pull request analysis
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ build
|
||||
|
||||
/lophine-server/build.gradle.kts
|
||||
/lophine-api/build.gradle.kts
|
||||
/lophine-server/src/minecraft
|
||||
/luminol-server/src/minecraft
|
||||
/paper-server
|
||||
/paper-api
|
||||
/paper-api-generator
|
||||
|
||||
+3
-3
@@ -3,11 +3,11 @@ Lophine inherits its licensing from the included upstream projects.
|
||||
Lophine从上游继承了许可证。
|
||||
|
||||
As such, Lophine is licensed under the
|
||||
[GNU General Public License version 3](licenses/GPL.md); as it inherits it from Luminol,
|
||||
who in turn inherits it from the original Folia, Paper, Spigot, Bukkit and CraftBukkit projects.
|
||||
[GNU General Public License version 3](licenses/GPL.md); as it inherits it from Folia,
|
||||
who in turn inherits it from the original Paper, Spigot, Bukkit and CraftBukkit projects.
|
||||
|
||||
因此,Lophine中应当遵守[GNU通用公共许可证-第3版](licenses/GPL.md);
|
||||
因为Lophine从上游Luminol继承了它,而Luminol又从其上游的Folia、Paper、Spigot、Bukkit和Craftbukkit项目中继承了它。
|
||||
因为Lophine从上游Folia继承了它,而Folia又从其上游的Paper、Spigot、Bukkit和Craftbukkit项目中继承了它。
|
||||
|
||||
Any author who is _not_ listed below should be presumed to have released their work
|
||||
under the original [GPL](licenses/GPL.md) license.
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
|
||||
# Lophine
|
||||
|
||||
*Lophine 是一个基于Luminol的分支,具有许多有用的优化和可配置的原版特性,目标是在Folia上实现更多生电的内容(请注意,完整生电请使用Fabric)*
|
||||
*Lophine 是一个基于Folia的分支,具有许多有用的优化和可配置的原版特性,目标是在Folia上实现更多生电的内容(请注意,完整生电请使用Fabric)*
|
||||
|
||||

|
||||
[](LICENSE.md)
|
||||
[](https://github.com/LuminolMC/Lophine/issues)
|
||||

|
||||
[](LICENSE.md)
|
||||
[](https://github.com/LophineLabs/Lophine/issues)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
[English](./README_EN.md) | **中文**
|
||||
</div>
|
||||
@@ -29,10 +29,15 @@
|
||||
- 🔬 **生电功能增强** - 在 Folia 上实现更多生电内容(完整生电请使用 Fabric)
|
||||
- 🛠️ **更多实用功能** - 持续添加有用的服务器功能
|
||||
|
||||
### 额外启动参数
|
||||
|
||||
- morninggloryclip.useMojangSource 强制服务端使用mojang源下载文件
|
||||
- morninggloryclip.enable.mixin 启用服务器插件的mixin支持
|
||||
|
||||
## 📥 下载
|
||||
|
||||
### 稳定版本
|
||||
所有发布版本都可以在 [Releases](https://github.com/LuminolMC/Lophine/releases) 页面找到。
|
||||
所有发布版本都可以在 [Releases](https://github.com/LophineLabs/Lophine/releases) 页面找到。
|
||||
|
||||
### 开发版本
|
||||
如果您想体验最新功能,可以通过以下步骤自行构建。
|
||||
@@ -41,11 +46,11 @@
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone https://github.com/LuminolMC/Lophine.git
|
||||
git clone https://github.com/LophineLabs/Lophine.git
|
||||
cd Lophine
|
||||
|
||||
# 应用补丁并构建 Paperclip JAR
|
||||
./gradlew applyAllPatches && ./gradlew createMojmapPaperclipJar
|
||||
./gradlew applyAllPatches && ./gradlew createPaperclipJar
|
||||
```
|
||||
|
||||
构建完成后,您可以在 `lophine-server/build/libs` 目录中找到生成的 JAR 文件。
|
||||
@@ -57,12 +62,16 @@ cd Lophine
|
||||
```kotlin
|
||||
repositories {
|
||||
maven {
|
||||
url = "https://repo.menthamc.org/repository/maven-public/"
|
||||
url = "https://repo.bacteriawa.com/repository/maven-public/"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("fun.bm.lophine:lophine-api:$VERSION")
|
||||
compileOnly("fun.bm.lophine:lophine-api:26.2.build.+")
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(25))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -71,16 +80,16 @@ dependencies {
|
||||
```xml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>menthamc</id>
|
||||
<url>https://repo.menthamc.org/repository/maven-public/</url>
|
||||
<id>repository</id>
|
||||
<url>https://repo.bacteriawa.com/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>fun.bm.lophine</groupId>
|
||||
<artifactId>luminol-api</artifactId>
|
||||
<version>$VERSION</version>
|
||||
<artifactId>lophine-api</artifactId>
|
||||
<version>[26.2.build,)</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
@@ -91,15 +100,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 +131,6 @@ dependencies {
|
||||
|
||||

|
||||
|
||||
## 🎉 特别感谢
|
||||
|
||||
### 项目赞助商
|
||||
|
||||
<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>
|
||||
+30
-51
@@ -3,17 +3,17 @@
|
||||
|
||||
# Lophine
|
||||
|
||||
*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)*
|
||||
*Lophine is a Folia 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)*
|
||||
|
||||

|
||||
[](LICENSE.md)
|
||||
[](https://github.com/LuminolMC/Lophine/issues)
|
||||

|
||||
[](LICENSE.md)
|
||||
[](https://github.com/LophineLabs/Lophine/issues)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
**English** | [中文](./README.md)
|
||||
</div>
|
||||
@@ -29,10 +29,15 @@
|
||||
- 🔬 **Redstone Enhancement** - More redstone functionality on Folia (use Fabric for complete redstone features)
|
||||
- 🛠️ **More Useful Functions** - Continuously adding useful server features
|
||||
|
||||
### Additional Launch Parameters
|
||||
|
||||
- morninggloryclip.useMojangSource - Use Mojang's source for Minecraft Server
|
||||
- morninggloryclip.enable.mixin - Enable mixin support for Leaves Plugin
|
||||
|
||||
## 📥 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,11 +46,11 @@ 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
|
||||
./gradlew applyAllPatches && ./gradlew createMojmapPaperclipJar
|
||||
./gradlew applyAllPatches && ./gradlew createPaperclipJar
|
||||
```
|
||||
|
||||
After building, you can find the generated JAR file in the `lophine-server/build/libs` directory.
|
||||
@@ -57,12 +62,16 @@ After building, you can find the generated JAR file in the `lophine-server/build
|
||||
```kotlin
|
||||
repositories {
|
||||
maven {
|
||||
url = "https://repo.menthamc.org/repository/maven-public/"
|
||||
url = "https://repo.bacteriawa.com/repository/maven-public/"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("fun.bm.lophine:lophine-api:$VERSION")
|
||||
compileOnly("fun.bm.lophine:lophine-api:26.2.build.+")
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(25))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -71,16 +80,16 @@ dependencies {
|
||||
```xml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>menthamc</id>
|
||||
<url>https://repo.menthamc.org/repository/maven-public/</url>
|
||||
<id>repository</id>
|
||||
<url>https://repo.bacteriawa.com/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>fun.bm.lophine</groupId>
|
||||
<artifactId>luminol-api</artifactId>
|
||||
<version>$VERSION</version>
|
||||
<artifactId>lophine-api</artifactId>
|
||||
<version>[26.2.build,)</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -92,15 +101,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 +132,6 @@ We welcome community contributions! For detailed contribution guidelines, please
|
||||
|
||||

|
||||
|
||||
## 🎉 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>
|
||||
+114
-20
@@ -1,23 +1,27 @@
|
||||
import groovy.json.JsonSlurper
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import org.gradle.api.tasks.testing.logging.TestLogEvent
|
||||
|
||||
plugins {
|
||||
java // TODO java launcher tasks
|
||||
id("moe.luminolmc.hyacinthusweight.patcher") version "+" // Automatically pulls the latest
|
||||
id("fun.bm.comfreyweight.patcher")
|
||||
}
|
||||
|
||||
paperweight {
|
||||
upstreams.register("luminol") {
|
||||
repo = github("LuminolMC", "Luminol")
|
||||
ref = providers.gradleProperty("luminolRef")
|
||||
filterPatches = false
|
||||
upstreams.register("folia") {
|
||||
repo = github("PaperMC", "Folia")
|
||||
ref = providers.gradleProperty("foliaRef")
|
||||
|
||||
println("Upstream commit ref: " + ref.get())
|
||||
|
||||
patchFile {
|
||||
path = "luminol-server/build.gradle.kts"
|
||||
path = "folia-server/build.gradle.kts"
|
||||
outputFile = file("lophine-server/build.gradle.kts")
|
||||
patchFile = file("lophine-server/build.gradle.kts.patch")
|
||||
}
|
||||
patchFile {
|
||||
path = "luminol-api/build.gradle.kts"
|
||||
path = "folia-api/build.gradle.kts"
|
||||
outputFile = file("lophine-api/build.gradle.kts")
|
||||
patchFile = file("lophine-api/build.gradle.kts.patch")
|
||||
}
|
||||
@@ -26,22 +30,17 @@ paperweight {
|
||||
patchesDir = file("lophine-api/paper-patches")
|
||||
outputDir = file("paper-api")
|
||||
}
|
||||
patchRepo("foliaApi") {
|
||||
patchDir("foliaApi") {
|
||||
upstreamPath = "folia-api"
|
||||
excludes = listOf("build.gradle.kts", "build.gradle.kts.patch", "paper-patches")
|
||||
patchesDir = file("lophine-api/folia-patches")
|
||||
outputDir = file("folia-api")
|
||||
}
|
||||
patchDir("luminolApi") {
|
||||
upstreamPath = "luminol-api"
|
||||
excludes = listOf("build.gradle.kts", "build.gradle.kts.patch", "paper-patches")
|
||||
patchesDir = file("lophine-api/luminol-patches")
|
||||
outputDir = file("luminol-api")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
|
||||
val menthaMavenPublicUrl = "https://repo.menthamc.org/repository/maven-public/";
|
||||
val bacteriawaMavenPublicUrl = "https://repo.bacteriawa.com/repository/maven-public/";
|
||||
|
||||
subprojects {
|
||||
apply(plugin = "java-library")
|
||||
@@ -49,14 +48,14 @@ subprojects {
|
||||
|
||||
extensions.configure<JavaPluginExtension> {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
languageVersion = JavaLanguageVersion.of(25)
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven(paperMavenPublicUrl)
|
||||
maven(menthaMavenPublicUrl)
|
||||
maven(bacteriawaMavenPublicUrl)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -69,7 +68,7 @@ subprojects {
|
||||
}
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release = 21
|
||||
options.release = 25
|
||||
options.isFork = true
|
||||
}
|
||||
tasks.withType<Javadoc>().configureEach {
|
||||
@@ -88,8 +87,8 @@ subprojects {
|
||||
|
||||
extensions.configure<PublishingExtension> {
|
||||
repositories {
|
||||
maven("https://repo.menthamc.org/repository/maven-snapshots/") {
|
||||
name = "MenthaMC"
|
||||
maven("https://repo.bacteriawa.com/repository/maven-releases/") {
|
||||
name = "Bacteriawa"
|
||||
credentials(PasswordCredentials::class) {
|
||||
username = System.getenv("PRIVATE_MAVEN_REPO_USERNAME")
|
||||
password = System.getenv("PRIVATE_MAVEN_REPO_PASSWORD")
|
||||
@@ -106,4 +105,99 @@ subprojects {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort all JSON language files under the lang directory by key in ASCII order
|
||||
val langDir = layout.projectDirectory.dir("lophine-server/src/main/resources/assets/lophine/lang")
|
||||
tasks.register("sortLangKeys") {
|
||||
group = "lophine"
|
||||
description = "Sort all JSON language files by key in ASCII (ordinal) order"
|
||||
notCompatibleWithConfigurationCache("Inline task action references build script class")
|
||||
inputs.dir(langDir).optional()
|
||||
outputs.dir(langDir)
|
||||
doLast {
|
||||
val dir = langDir.asFile
|
||||
if (!dir.isDirectory) {
|
||||
logger.warn("Lang directory not found: $dir")
|
||||
return@doLast
|
||||
}
|
||||
val jsonFiles = dir.listFiles { f -> f.extension == "json" }?.sortedBy { it.name } ?: emptyList()
|
||||
if (jsonFiles.isEmpty()) {
|
||||
logger.lifecycle("No .json files found in: $dir")
|
||||
return@doLast
|
||||
}
|
||||
val slurper = JsonSlurper()
|
||||
for (file in jsonFiles) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val data = slurper.parse(file) as Map<String, Any?>
|
||||
val sorted = data.toSortedMap()
|
||||
val pretty = formatJson(sorted)
|
||||
file.writeText(pretty + "\n", charset = Charsets.UTF_8)
|
||||
logger.lifecycle("Processed: ${file.name} (${sorted.size} keys)")
|
||||
}
|
||||
logger.lifecycle("Done.")
|
||||
}
|
||||
}
|
||||
|
||||
// --- Pure-Kotlin JSON serializer that preserves non-ASCII characters (e.g. CJK) ---
|
||||
fun formatJson(value: Any?, indent: Int = 2): String {
|
||||
val sb = StringBuilder()
|
||||
appendJson(sb, value, indent, 0)
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private fun appendJson(sb: StringBuilder, value: Any?, indent: Int, level: Int) {
|
||||
when (value) {
|
||||
null -> sb.append("null")
|
||||
is Boolean -> sb.append(value)
|
||||
is Number -> sb.append(value)
|
||||
is String -> sb.append('"').append(escapeJsonString(value)).append('"')
|
||||
is List<*> -> {
|
||||
if (value.isEmpty()) { sb.append("[]"); return }
|
||||
sb.append("[\n")
|
||||
value.forEachIndexed { i, v ->
|
||||
sb.append(" ".repeat(indent * (level + 1)))
|
||||
appendJson(sb, v, indent, level + 1)
|
||||
if (i < value.size - 1) sb.append(',')
|
||||
sb.append('\n')
|
||||
}
|
||||
sb.append(" ".repeat(indent * level)).append(']')
|
||||
}
|
||||
is Map<*, *> -> {
|
||||
if (value.isEmpty()) { sb.append("{}"); return }
|
||||
sb.append("{\n")
|
||||
val entries = value.entries.toList()
|
||||
entries.forEachIndexed { i, (k, v) ->
|
||||
sb.append(" ".repeat(indent * (level + 1)))
|
||||
sb.append('"').append(escapeJsonString(k.toString())).append('"')
|
||||
sb.append(": ")
|
||||
appendJson(sb, v, indent, level + 1)
|
||||
if (i < entries.size - 1) sb.append(',')
|
||||
sb.append('\n')
|
||||
}
|
||||
sb.append(" ".repeat(indent * level)).append('}')
|
||||
}
|
||||
else -> sb.append('"').append(escapeJsonString(value.toString())).append('"')
|
||||
}
|
||||
}
|
||||
|
||||
private fun escapeJsonString(s: String): String {
|
||||
val sb = StringBuilder(s.length)
|
||||
for (c in s) {
|
||||
when (c) {
|
||||
'"' -> sb.append("\\\"")
|
||||
'\\' -> sb.append("\\\\")
|
||||
'\b' -> sb.append("\\b")
|
||||
'\u000C' -> sb.append("\\f")
|
||||
'\n' -> sb.append("\\n")
|
||||
'\r' -> sb.append("\\r")
|
||||
'\t' -> sb.append("\\t")
|
||||
else -> if (c.code < 0x20) {
|
||||
sb.append("\\u").append(String.format("%04x", c.code))
|
||||
} else {
|
||||
sb.append(c) // preserve CJK and all other printable chars as-is
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
+13
-5
@@ -21,7 +21,7 @@
|
||||
在开始开发之前,您首先需要拥有以下软件作为开发环境:
|
||||
|
||||
- `git`
|
||||
- `JDK 21 或更高版本`
|
||||
- `JDK 25 或更高版本`
|
||||
|
||||
特别提醒:在操作前,您需要启用系统和Git的长路径支持,以下为部分平台的相关描述。
|
||||
|
||||
@@ -41,7 +41,7 @@ Lophine 使用和 Folia 一样的补丁系统,并为了针对不同部分的
|
||||
|
||||
1. 将你的仓库 clone 到本地;
|
||||
2. 在你的 IDE 或 终端 内执行 Gradle 的 `applyAllPatches` 任务,如果是在终端内,你可以执行 `./gradlew applyAllPatches`;
|
||||
3. 在执行操作后,仓库根目录下应该存在以下目录对: `lophine-api` 和 `lophine-server` , `luminol-api` 和 `luminol-server` , `folia-api` 和 `folia-server` , 以及 `paper-api` 和 `paper-server`(下文称作 `*-api` 和 `*-server` );
|
||||
3. 在执行操作后,仓库根目录下应该存在以下目录对: `lophine-api` 和 `lophine-server` , `folia-api` 和 `folia-server` , 以及 `paper-api` 和 `paper-server`(下文称作 `*-api` 和 `*-server` );
|
||||
4. 进入 仓库根目录下的 `*-api` 和 `*-server` 文件夹进行修改。
|
||||
|
||||
以下为对上述各个文件夹的简单描述,详细描述可以参考[这里](https://github.com/Toffikk/paperweight-examples/blob/18241979c88068d5b061d95ad69c98ecb201c246/README.md):
|
||||
@@ -49,14 +49,12 @@ Lophine 使用和 Folia 一样的补丁系统,并为了针对不同部分的
|
||||
1. API部分
|
||||
|
||||
- `lophine-api` :对新增API的修改
|
||||
- `luminol-api` :对luminol-API的修改应当在此文件夹下进行
|
||||
- `folia-api` :对folia-API的修改应当在此文件夹下进行
|
||||
- `paper-api` :对paper-API/spigot-API/bukkit-API的修改应该在此文件夹下进行
|
||||
|
||||
2. Server部分
|
||||
|
||||
- `lophine-server` :对Minecraft原版服务器的修改和新增文件应当在此文件夹下进行
|
||||
- `luminol-server` :对luminol-server的修改应当在此文件夹下进行
|
||||
- `folia-server` :对folia-Server的修改应当在此文件夹下进行
|
||||
- `paper-server` :对于paper对服务器逻辑的修改应当在此文件夹下进行
|
||||
|
||||
@@ -64,7 +62,7 @@ Lophine 使用和 Folia 一样的补丁系统,并为了针对不同部分的
|
||||
|
||||
- 在应用补丁前,基点将会指向未被更改的源码
|
||||
- 在基点后的每一个提交都是一个补丁
|
||||
- 只有在 Luminol 最后一个提交后的提交才会被视为 lophine 补丁
|
||||
- 只有在 Folia 最后一个提交后的提交才会被视为 lophine 补丁
|
||||
|
||||
## 增加补丁
|
||||
|
||||
@@ -90,3 +88,13 @@ Lophine 使用和 Folia 一样的补丁系统,并为了针对不同部分的
|
||||
4. 运行 Gradle 任务 `fixupPaperApiFilePatches` 来修改已被修改的在lophine新建文件的补丁(注意不要提交);
|
||||
5. 运行 Gradle 任务 `rebuildAllServerPatches` 来修改已被修改的补丁;
|
||||
6. 将修改后的补丁 PR 发回储存库。
|
||||
|
||||
## 为配置项提供本地化的注释支持
|
||||
|
||||
1. 在 `lophine-server/src/main/resources/assets/lophine/lang` 目录下创建或修改相应的语言文件,添加本地化的注释;
|
||||
- 文件的名字应当符合 `https://minecraft.wiki/w/Language` 页面下的格式,如 `en_us` `zh_cn` `zh_hk` `zh_tw`,文件以 `json` 为格式类型;
|
||||
2. 运行 Gradle 任务 `sortLangKeys` 来对你的语言文件内容进行重排序;
|
||||
3. 使用 `git commit -m <提交信息>` 进行提交;
|
||||
4. 将你修改的文件进行推送。
|
||||
|
||||
这样做以后,你就可以将你的修改进行 PR 提交。
|
||||
|
||||
+13
-5
@@ -23,7 +23,7 @@ See also [This issue](https://github.com/isaacs/github/issues/1681), and then yo
|
||||
Before coding, you need these pieces of software / tools as Dev Environment.
|
||||
|
||||
- `git`
|
||||
- `JDK 21 or higher`
|
||||
- `JDK 25 or higher`
|
||||
|
||||
PS: You need to enable long path support in your System and Git before start, some of the platform's resolution here.
|
||||
|
||||
@@ -44,7 +44,7 @@ If you have forked the main repository, then you should follow the steps below:
|
||||
|
||||
1. Clone your repository to local
|
||||
2. Run Gradle's `applyAllPatches` task in your IDE or terminal (You can run `./gradlew applyAllPatches` directly in terminal.)
|
||||
3. After performing the operation, the following directory pairs should exist in the root directory of the warehouse: `lophine-api` and `lophine-server` , `luminol-api` and `luminol-server` , `folia-api` and `folia-server` , `paper-api` and `paper-server` (Referred to `*-api` and `*-server` as below)
|
||||
3. After performing the operation, the following directory pairs should exist in the root directory of the warehouse: `lophine-api` and `lophine-server` , `folia-api` and `folia-server` , `paper-api` and `paper-server` (Referred to `*-api` and `*-server` as below)
|
||||
4. Enter `*-api` and `*-server` directory to carry out modifications.
|
||||
|
||||
The following is the simple description of the aforementioned folders, detailed description can be referred to [here](https://github.com/Toffikk/paperweight-examples/blob/18241979c88068d5b061d95ad69c98ecb201c246/README.md):
|
||||
@@ -52,14 +52,12 @@ The following is the simple description of the aforementioned folders, detailed
|
||||
1. API part
|
||||
|
||||
- `lophine-api` : Modifications to the new API
|
||||
- `luminol-api` : Modifications to Luminol API should be carried out in this folder
|
||||
- `folia-api` : Modifications to Folia API should be carried out in this folder
|
||||
- `paper-api` : Modifications to Paper API/Spigot API/Bukkit API should be carried out in this folder
|
||||
|
||||
2. Server part
|
||||
|
||||
- `lophine-server` : Changes and new files to the Minecraft vanilla server should be made in this folder
|
||||
- `luminol-server` : Changes to luminol-server should be made in this folder
|
||||
- `folia-server` : Changes to folia-server should be made in this folder
|
||||
- `paper-server` : Modifications to the server logic for paper should be made in this folder
|
||||
|
||||
@@ -67,7 +65,7 @@ BTW, `*-api` and `*-server` and are not normal git repositories.
|
||||
|
||||
- Before applying patches, the base will point to unmodified source code.
|
||||
- Every commit after the base is a patch.
|
||||
- Only commits after the last commit of Luminol will be considered as Lophine patches.
|
||||
- Only commits after the last commit of Folia will be considered as Lophine patches.
|
||||
|
||||
## Adding new patches
|
||||
|
||||
@@ -93,3 +91,13 @@ You can modify an existing patch by following the steps below:
|
||||
4. Run Gradle's task `fixupPaperApiFilePatches` to regenerate lophine-created files to patches (PS: do not commit again before you run this task)
|
||||
5. Run Gradle's task `rebuildAllServerPatches` to modify existing patches
|
||||
6. Push and PR again
|
||||
|
||||
## Providing localized comment support for configuration entries
|
||||
|
||||
1. Create or modify the corresponding language file under the `lophine-server/src/main/resources/assets/lophine/lang` directory to add localized comments;
|
||||
- The file name should follow the format listed on the `https://minecraft.wiki/w/Language` page, such as `en_us`, `zh_cn`, `zh_hk`, `zh_tw`. The file format is `json`;
|
||||
2. Run the Gradle task `sortLangKeys` to re-sort the keys in your language file;
|
||||
3. Commit your changes using `git commit -m <Commit Message>`;
|
||||
4. Push your modified files to your repository.
|
||||
|
||||
After pushing, you can open a PR to submit your changes.
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
### Carpet 原版
|
||||
|
||||
| 规则 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `language` | 已映射 | 转发到 `lophine.function.language.lang` |
|
||||
| `commandTick` | 已映射 | 转发到现有的 tick 指令补丁 |
|
||||
| `creativeNoClip` | 已映射 | 转发到 Lophine 的创造飞行穿墙实现 |
|
||||
| `ctrlQCraftingFix` | 结构等价 | 当前的合成与切石机菜单已经自带修复后的 Ctrl+Q 结果槽丢弃行为 |
|
||||
| `placementRotationFix` | 已移植 | 放置朝向判断可使用玩家身体朝向而不是头部旋转 |
|
||||
| `tntDoNotUpdate` | 已移植 | 新放置的 TNT 不会再因放置时更新而自动点燃 |
|
||||
| `explosionNoBlockDamage` | 已移植 | 爆炸仍会伤害实体,但不会破坏方块 |
|
||||
| `interactionUpdates` | 已移植 | 玩家交互和破坏方块时可以在不触发邻居更新与形状更新的情况下运行 |
|
||||
| `xpNoCooldown` | 已移植 | 经验球可以在同一 tick 内被连续吸收,不再有拾取冷却 |
|
||||
| `viewDistance` | 已移植 | 专用服务器启动视距会被兼容配置覆盖 |
|
||||
| `fastRedstoneDust` | 已移植 | 规则启用时,红石粉更新会统一走 Alternate Current 快速更新后端 |
|
||||
| `lagFreeSpawning` | 已移植 | 自然生成会使用轻量碰撞检查与预构造实体路径 |
|
||||
| `defaultLoggers` | 已移植 | 按 Carpet 默认订阅语义为玩家启用 HUD logger,当前支持 `tps`、`mobcaps`、`counter` |
|
||||
| `commandPlayer` | 已映射 | 当前由同一套 `/bot` 假人能力承接 |
|
||||
| `hopperCounters` | 已映射 | 转发到 Lophine 的羊毛漏斗计数器 |
|
||||
|
||||
### Carpet TIS Addition
|
||||
|
||||
| 规则 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `yeetUpdateSuppressionCrash` | 已映射 | 转发到同一套 Lophine 崩溃修复逻辑 |
|
||||
| `dustTrapdoorReintroduced` | 已映射 | 转发到 `lophine.experiment.redstone.redstone-ignore-upwards-update` |
|
||||
| `shulkerBoxCCEReintroduced` | 已映射 | 转发到 `lophine.experiment.redstone.cce-update-suppression` |
|
||||
| `instantBlockUpdaterReintroduced` | 已映射 | 转发到 `lophine.experiment.redstone.instant-block-updater` |
|
||||
| `optimizedDragonRespawn` | 已映射 | 转发到 Luminol 的末影龙重生优化 |
|
||||
| `antiSpamDisabled` | 已移植 | 在 `ServerGamePacketListenerImpl` 中关闭聊天和创造丢物防刷屏限制 |
|
||||
| `blockPlacementIgnoreEntity` | 已移植 | 创造模式放置方块时忽略实体碰撞检查 |
|
||||
| `creativeOpenContainerForcibly` | 已移植 | 创造玩家可以强制打开被阻挡的箱子、末影箱和潜影盒 |
|
||||
| `observerNoDetection` | 已移植 | 观察者的检测触发会在发出脉冲前被取消 |
|
||||
| `creativeNoItemCooldown` | 已移植 | 创造玩家不会应用物品冷却 |
|
||||
| `totallyNoBlockUpdate` | 已移植 | 邻居更新和形状更新会在 `NeighborUpdater` 中被统一短路 |
|
||||
| `tiscmNetworkProtocol` | 已移植 | 原生 `tiscm:network/v1` 握手与数据包协商已经通过专用 Leaves 协议接入 |
|
||||
| `optimizedTNTHighPriority` | 结构等价 | 当前 `ServerExplosion` 路径已经运行在优化过的服务端爆炸实现上 |
|
||||
| `tntIgnoreRedstoneSignal` | 已移植 | TNT 在自动点燃判断时忽略红石信号 |
|
||||
| `tntDupingFix` | 已移植 | 活塞复制 TNT 的路径现在由 `PistonBaseBlock` 中的兼容规则直接控制 |
|
||||
| `clientSettingsLostOnRespawnFix` | 已移植 | 玩家上一次的客户端设置会在 `ServerPlayer.restoreFrom` 中恢复 |
|
||||
| `entityInstantDeathRemoval` | 已移植 | 已死亡生物不会再保留原版的 20gt 延迟,而是立即移除 |
|
||||
| `farmlandTrampledDisabled` | 已移植 | 耕地不会再因实体踩踏而变回泥土 |
|
||||
| `yeetOutOfOrderChatKick` | 已移植 | 乱序的签名聊天不会再破坏安全聊天链 |
|
||||
| `tickCommandPermission` | 已移植 | `/tick` 的权限等级可通过兼容配置调整 |
|
||||
| `tickFreezeCommandToggleable` | 已移植 | 已冻结时再次执行 `/tick freeze` 会切换回运行状态 |
|
||||
| `syncServerMsptMetricsData` | 已移植 | 实时 MSPT 样本会通过原生 TISCM 协议通道广播 |
|
||||
| `microTiming` | 结构等价 | 当前 Folia 的区块级性能分析与计时钩子已经提供对应的服务端观测能力 |
|
||||
| `optimizedFastEntityMovement` | 结构等价 | Moonrise/Paper 的快速实体移动碰撞优化已经是基础运行时的一部分 |
|
||||
| `optimizedHardHitBoxEntityCollision` | 结构等价 | Moonrise/Paper 的硬碰撞箱实体碰撞优化已经是基础运行时的一部分 |
|
||||
| `tntFuseDuration` | 已移植 | 可配置的 TNT 引信时长已接入 NMS TNT 逻辑 |
|
||||
| `fakePlayerTicksLikeRealPlayer` | 已映射 | 转发到 Leaves 的假人网络阶段 tick 行为 |
|
||||
| `hopperCountersUnlimitedSpeed` | 已映射 | 转发到不限速计数器模式 |
|
||||
|
||||
### Carpet Org Addition
|
||||
|
||||
| 规则 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `hopperNoItemCost` | 已移植 | 漏斗上方放置羊毛时,可在传输后恢复被推出的物品堆,实现零消耗供给线 |
|
||||
| `simpleInGameCalculator` | 已移植 | 以 `=` 开头的聊天内容会作为简单计算表达式私聊回复 |
|
||||
|
||||
### Carpet AMS Addition
|
||||
|
||||
| 规则 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `amsUpdateSuppressionCrashFix` | 已映射 | 转发到 Lophine 现有的更新抑制崩溃修复 |
|
||||
| `creativeOneHitKill` | 已移植 | 创造玩家可通过 `Player.attack` 瞬间击杀附近符合条件的目标 |
|
||||
| `bambooModelNoOffset` | 已移植 | 竹子和竹笋始终返回零模型偏移 |
|
||||
| `carpetAlwaysSetDefault` | 结构等价 | 兼容配置默认值已经会在 `ConfigsInstance.preLoadConfig` 中被写入 |
|
||||
| `powerfulExpMending` | 已移植 | 经验拾取会修复玩家整个背包内所有受损的经验修补物品 |
|
||||
| `sensibleEnderman` | 已移植 | 末影人仅会在规则开启时拾取南瓜和西瓜 |
|
||||
| `shulkerGolem` | 已移植 | 潜影盒上方放置雕刻南瓜时可以召唤潜影贝 |
|
||||
| `preventEndSpikeRespawn` | 已移植 | 末影龙重生时会跳过黑曜石柱重建和柱顶水晶重建 |
|
||||
| `betterCraftableBoneBlock` | 已移植 | 向配方管理器注入 AMS 的替代骨块配方 |
|
||||
| `betterCraftableDispenser` | 已移植 | 向配方管理器注入 AMS 的替代发射器配方 |
|
||||
| `fakePlayerDefaultSurvivalMode` | 已移植 | 新创建的假人可以被强制设为生存模式,而不是沿用服务器默认游戏模式 |
|
||||
| `fakePlayerInteractLikeClient` | 已移植 | 假人与盔甲架交互时会先按真实客户端方式回退,再进入普通实体交互 |
|
||||
| `fakePlayerAutoReplenishmentFormShulkerBox` | 已移植 | 假人自动补货现在可以从背包里的潜影盒中抽取匹配物品 |
|
||||
|
||||
### Lophine 扩展承接
|
||||
|
||||
| 规则 | 状态 | 说明 |
|
||||
| --- | --- |----------------------------------|
|
||||
| `commandBot` | 已映射 | 启用 Lophine `/bot` |
|
||||
| `fakePlayerResident` | 已映射 | 转发到 Lophine 的假人常驻模式 |
|
||||
| `openFakePlayerInventory` | 已映射 | 转发到 Lophine 的假人背包打开功能 |
|
||||
| `fakePlayerAutoReplaceTool` | 已映射 | 为现有自动换工具逻辑增加了新开关 |
|
||||
| `fakePlayerAutoReplenishment` | 已映射 | 为现有自动补货逻辑增加了新开关 |
|
||||
| `fakePlayerReloadAction` | 已映射 | 为假人动作持久化增加了新开关 |
|
||||
| `fakePlayerAutoFish` | 已移植 | 手持鱼竿的假人会自动抛竿和收杆,除非显式执行 `fish` 动作 |
|
||||
+10
-6
@@ -1,11 +1,15 @@
|
||||
group=fun.bm.lophine
|
||||
version=1.21.11-R0.1-SNAPSHOT
|
||||
mcVersion=1.21.11
|
||||
apiVersion=1.21.11
|
||||
release=2
|
||||
# 0 for skip release, 1 for pre-release, 2 for release
|
||||
mcVersion=26.2
|
||||
apiVersion=26.2
|
||||
channel=STABLE
|
||||
clipVersion=1.0.1
|
||||
weightVersion=1.0.0
|
||||
# true for release, false for skip release, pre for pre-release
|
||||
release=true
|
||||
# true for push to repo, false for skip push repo, auto for detect by release value
|
||||
pushRepo=auto
|
||||
|
||||
luminolRef=aee26e2fb9a2477588fe245531c1a0e0deb014c6
|
||||
foliaRef=57f643f10e0a9d01024773232d38ae666067d593
|
||||
|
||||
org.gradle.configuration-cache=true
|
||||
org.gradle.caching=true
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,27 +1,52 @@
|
||||
--- a/luminol-api/build.gradle.kts
|
||||
+++ b/luminol-api/build.gradle.kts
|
||||
@@ -104,20 +_,24 @@
|
||||
--- a/folia-api/build.gradle.kts
|
||||
+++ b/folia-api/build.gradle.kts
|
||||
@@ -53,6 +_,7 @@
|
||||
api("org.apache.logging.log4j:log4j-api:$log4jVersion")
|
||||
api("org.slf4j:slf4j-api:$slf4jVersion")
|
||||
api("com.mojang:brigadier:1.3.10")
|
||||
+ api("io.sentry:sentry:8.0.0-rc.2") // Pufferfish
|
||||
|
||||
// Deprecate bungeecord-chat in favor of adventure
|
||||
api("net.md-5:bungeecord-chat:$bungeeCordChatVersion") {
|
||||
@@ -105,17 +_,21 @@
|
||||
java {
|
||||
srcDir(generatedDir)
|
||||
srcDir(file("../paper-api/src/main/java"))
|
||||
srcDir(file("../folia-api/src/main/java"))
|
||||
+ srcDir(file("../luminol-api/src/main/java"))
|
||||
+ srcDir(file("../folia-api/src/main/java"))
|
||||
}
|
||||
resources {
|
||||
srcDir(file("../paper-api/src/main/resources"))
|
||||
srcDir(file("../folia-api/src/main/resources"))
|
||||
+ srcDir(file("../luminol-api/src/main/resources"))
|
||||
+ srcDir(file("../folia-api/src/main/resources"))
|
||||
}
|
||||
}
|
||||
test {
|
||||
java {
|
||||
srcDir(file("../paper-api/src/test/java"))
|
||||
srcDir(file("../folia-api/src/test/java"))
|
||||
+ srcDir(file("../luminol-api/src/test/java"))
|
||||
+ srcDir(file("../folia-api/src/test/java"))
|
||||
}
|
||||
resources {
|
||||
srcDir(file("../paper-api/src/test/resources"))
|
||||
srcDir(file("../folia-api/src/test/resources"))
|
||||
+ srcDir(file("../luminol-api/src/test/resources"))
|
||||
+ srcDir(file("../folia-api/src/test/resources"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,3 +_,19 @@
|
||||
tasks.check {
|
||||
dependsOn(scanJarForBadCalls)
|
||||
}
|
||||
+
|
||||
+// Pufferfish Start
|
||||
+tasks.withType<JavaCompile> {
|
||||
+ val compilerArgs = options.compilerArgs
|
||||
+ compilerArgs.add("--add-modules=jdk.incubator.vector")
|
||||
+}
|
||||
+// Pufferfish End
|
||||
+
|
||||
+// Lophine start - Hide unnecessary warnings
|
||||
+tasks.withType<JavaCompile> {
|
||||
+ val compilerArgs = options.compilerArgs
|
||||
+ compilerArgs.add("-Xlint:-module")
|
||||
+ compilerArgs.add("-Xlint:-removal")
|
||||
+ compilerArgs.add("-Xlint:-dep-ann")
|
||||
+}
|
||||
+// Lophine end
|
||||
|
||||
@@ -5,14 +5,24 @@ Subject: [PATCH] Rebrand to Lophine
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java
|
||||
index db5e2f10278c20286779362cfdfadb2f42c724e0..c18c0cb45a193883aa12b5d1abe690e95d289f82 100644
|
||||
index 56a5877181e8d37518b178c95155e892c442e96d..ebe0290bf0235af2ba353ac1f74b29080daebba4 100644
|
||||
--- a/src/main/java/io/papermc/paper/ServerBuildInfo.java
|
||||
+++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java
|
||||
@@ -29,6 +29,7 @@ public interface ServerBuildInfo {
|
||||
@@ -19,6 +19,17 @@ public interface ServerBuildInfo {
|
||||
*/
|
||||
Key BRAND_LUMINOL_ID = Key.key("luminolmc", "luminol");
|
||||
// Luminol end
|
||||
+ Key BRAND_LOPHINE_ID = Key.key("luminolmc", "lophine"); // Lophine
|
||||
Key BRAND_PAPER_ID = Key.key("papermc", "paper");
|
||||
|
||||
+ // Lophine start
|
||||
+ /**
|
||||
+ * The brand id for folia
|
||||
+ */
|
||||
+ Key BRAND_FOLIA_ID = Key.key("papermc", "folia");
|
||||
+ /**
|
||||
+ * The brand id for Lophine.
|
||||
+ */
|
||||
+ Key BRAND_LOPHINE_ID = Key.key("lophinelabs", "lophine");
|
||||
+ // Lophine end
|
||||
+
|
||||
/**
|
||||
* Gets the {@code ServerBuildInfo}.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 14 Jun 2026 18:10:20 +0800
|
||||
Subject: [PATCH] Luminol Config System
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
|
||||
index 067d901c69a54c4b6ae5a00488f0dacc5fde7961..209d1968f4bff3b33785fd8bfbeea5ae231e581a 100644
|
||||
--- a/src/main/java/org/bukkit/Server.java
|
||||
+++ b/src/main/java/org/bukkit/Server.java
|
||||
@@ -2774,6 +2774,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
||||
*/
|
||||
void allowPausing(@NotNull org.bukkit.plugin.Plugin plugin, boolean value);
|
||||
// Paper end - API to check if the server is sleeping
|
||||
+
|
||||
+ // Luminol start - Luminol Config API
|
||||
+ me.earthme.luminol.api.config.LuminolConfigsInstance getLuminolConfigs(String name);
|
||||
+ me.earthme.luminol.api.config.LuminolConfigBuilder getLuminolConfigBuilder();
|
||||
+ // Luminol end - Luminol Config API
|
||||
+
|
||||
// Folia start - region TPS API
|
||||
/**
|
||||
* Gets the TPS from the region which owns the specified location, or {@code null} if no region owns
|
||||
@@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Sat, 8 Aug 2026 01:25:33 +0800
|
||||
Subject: [PATCH] KioCG Chunk API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/Chunk.java b/src/main/java/org/bukkit/Chunk.java
|
||||
index d873b78f6935a23ff8f6092b80968267b182cc0f..b4323370859dd4d9e86614484cdb9d2e35c45b40 100644
|
||||
--- a/src/main/java/org/bukkit/Chunk.java
|
||||
+++ b/src/main/java/org/bukkit/Chunk.java
|
||||
@@ -392,4 +392,6 @@ public interface Chunk extends PersistentDataHolder {
|
||||
*/
|
||||
UNLOADED;
|
||||
}
|
||||
+
|
||||
+ long getChunkHotAvg(); // KioCG
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
|
||||
index 65e83e171ab4c514662b9344e08f7065fa9efaa1..274af6397b5f7c0b6787e2669de80e54858950a2 100644
|
||||
--- a/src/main/java/org/bukkit/entity/Player.java
|
||||
+++ b/src/main/java/org/bukkit/entity/Player.java
|
||||
@@ -4050,4 +4050,6 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
|
||||
* clearing any fixed pose in the process.
|
||||
*/
|
||||
void unsetFixedPose();
|
||||
+
|
||||
+ long getNearbyChunkHot(); // KioCG
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <wangxyper@163.com>
|
||||
Date: Sun, 12 Jan 2025 12:22:53 +0800
|
||||
Subject: [PATCH] Disable timings warn msg and commands
|
||||
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java
|
||||
index 89017af09ce32e7a66014fc3aeb50155921252a5..b862779b48176dd7e67a2f1a3e7f24bc8c84e993 100644
|
||||
--- a/src/main/java/co/aikar/timings/Timings.java
|
||||
+++ b/src/main/java/co/aikar/timings/Timings.java
|
||||
@@ -147,7 +147,7 @@ public final class Timings {
|
||||
public static void setTimingsEnabled(boolean enabled) {
|
||||
enabled = false; // Folia - region threading - disable timings
|
||||
if (enabled && !warnedAboutDeprecationOnEnable) {
|
||||
- Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage()));
|
||||
+ // Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage())); // Luminol - Disable timings warn msg and commands
|
||||
warnedAboutDeprecationOnEnable = true;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java
|
||||
index ad1330d87223dfcf3c9da40aa5ece8c21141f0d6..22edf161ba1ca8c31140e25e8c4fe1503c44dba8 100644
|
||||
--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java
|
||||
+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java
|
||||
@@ -34,7 +34,7 @@ public class SimpleCommandMap implements CommandMap {
|
||||
final ReloadCommand reload = new ReloadCommand("reload");
|
||||
this.knownCommands.put("bukkit:reload", reload);
|
||||
this.knownCommands.put("bukkit:rl", reload);
|
||||
- register("bukkit", new co.aikar.timings.TimingsCommand("timings"));
|
||||
+ //register("bukkit", new co.aikar.timings.TimingsCommand("timings")); // Luminol - Disable timings warn msg and commands
|
||||
}
|
||||
|
||||
public void setFallbackCommands() {
|
||||
diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||
index 457e75bbecb70ac3da4c21382f97d68de5a00547..cf22ea227f6dcc13702fb5f6f94bba5b6e326b97 100644
|
||||
--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||
+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||
@@ -960,7 +960,7 @@ public final class SimplePluginManager implements PluginManager {
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public void useTimings(boolean use) {
|
||||
- co.aikar.timings.Timings.setTimingsEnabled(use); // Paper
|
||||
+ // co.aikar.timings.Timings.setTimingsEnabled(use); // Paper // Luminol - Disable timings warn msg and commands
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@@ -0,0 +1,23 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <wangxyper@163.com>
|
||||
Date: Thu, 23 Jan 2025 12:04:04 +0800
|
||||
Subject: [PATCH] Force disable reload command
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java
|
||||
index 22edf161ba1ca8c31140e25e8c4fe1503c44dba8..50384eb221ad96e766b91335ff57b082410885e9 100644
|
||||
--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java
|
||||
+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java
|
||||
@@ -31,9 +31,9 @@ public class SimpleCommandMap implements CommandMap {
|
||||
}
|
||||
|
||||
private void setDefaultCommands() {
|
||||
- final ReloadCommand reload = new ReloadCommand("reload");
|
||||
- this.knownCommands.put("bukkit:reload", reload);
|
||||
- this.knownCommands.put("bukkit:rl", reload);
|
||||
+ //final ReloadCommand reload = new ReloadCommand("reload"); // Luminol - Force disable reload command
|
||||
+ //this.knownCommands.put("bukkit:reload", reload); // Luminol - Force disable reload command
|
||||
+ //this.knownCommands.put("bukkit:rl", reload); // Luminol - Force disable reload command
|
||||
//register("bukkit", new co.aikar.timings.TimingsCommand("timings")); // Luminol - Disable timings warn msg and commands
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <wangxyper@163.com>
|
||||
Date: Sun, 12 Jan 2025 13:27:38 +0800
|
||||
Subject: [PATCH] Pufferfish: Sentry
|
||||
|
||||
As part of: Pufferfish
|
||||
Licensed under: GPL-3.0 (https://github.com/pufferfish-gg/Pufferfish/blob/04bc249f9eee6157338b6884113b6fa3192bf59b/PATCH-LICENSE)
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||
index cf22ea227f6dcc13702fb5f6f94bba5b6e326b97..71ef6055df30506bb0d6648a2300d1cab7b0d026 100644
|
||||
--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||
+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||
@@ -596,7 +596,9 @@ public final class SimplePluginManager implements PluginManager {
|
||||
|
||||
// Paper start
|
||||
private void handlePluginException(String msg, Throwable ex, Plugin plugin) {
|
||||
+ gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish
|
||||
server.getLogger().log(Level.SEVERE, msg, ex);
|
||||
+ gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish
|
||||
callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerPluginEnableDisableException(msg, ex, plugin)));
|
||||
}
|
||||
// Paper end
|
||||
@@ -666,9 +668,11 @@ public final class SimplePluginManager implements PluginManager {
|
||||
));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
+ gg.pufferfish.pufferfish.sentry.SentryContext.setEventContext(event, registration); // Pufferfish
|
||||
// Paper start - error reporting
|
||||
String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName();
|
||||
server.getLogger().log(Level.SEVERE, msg, ex);
|
||||
+ gg.pufferfish.pufferfish.sentry.SentryContext.removeEventContext(); // Pufferfish
|
||||
if (!(event instanceof com.destroystokyo.paper.event.server.ServerExceptionEvent)) { // We don't want to cause an endless event loop
|
||||
callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event)));
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
||||
index 9023a39c6481710478747482f0b16c21274afd15..0755065f86aba3ef5ecdf045620878eb045f4999 100644
|
||||
--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
||||
+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
|
||||
@@ -329,7 +329,13 @@ public final class JavaPluginLoader implements PluginLoader {
|
||||
try {
|
||||
jPlugin.setEnabled(true);
|
||||
} catch (Throwable ex) {
|
||||
+ gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish
|
||||
server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
|
||||
+ gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish
|
||||
+ // Paper start - Disable plugins that fail to load
|
||||
+ this.server.getPluginManager().disablePlugin(jPlugin);
|
||||
+ return;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
// Perhaps abort here, rather than continue going, but as it stands,
|
||||
@@ -354,7 +360,9 @@ public final class JavaPluginLoader implements PluginLoader {
|
||||
try {
|
||||
jPlugin.setEnabled(false);
|
||||
} catch (Throwable ex) {
|
||||
+ gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish
|
||||
server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
|
||||
+ gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish
|
||||
}
|
||||
|
||||
if (cloader instanceof PluginClassLoader) {
|
||||
@@ -0,0 +1,33 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <wangxyper@163.com>
|
||||
Date: Sun, 12 Jan 2025 14:00:28 +0800
|
||||
Subject: [PATCH] Pufferfish: SIMD Utilities
|
||||
|
||||
As part of: Pufferfish
|
||||
Licensed under: GPL-3.0 (https://github.com/pufferfish-gg/Pufferfish/blob/04bc249f9eee6157338b6884113b6fa3192bf59b/PATCH-LICENSE)
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java
|
||||
index 76ae2750ff7b04a281d4b794dc1f48dd832db2b6..fc9cd106b1ed2e92aced783e9cb0bc8867828df3 100644
|
||||
--- a/src/main/java/org/bukkit/map/MapPalette.java
|
||||
+++ b/src/main/java/org/bukkit/map/MapPalette.java
|
||||
@@ -35,7 +35,7 @@ public final class MapPalette {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
- static final Color[] colors = {
|
||||
+ public static final Color[] colors = { // Luminol - package-private -> public
|
||||
// Start generate - MapPalette#colors
|
||||
new Color(0x00000000, true),
|
||||
new Color(0x00000000, true),
|
||||
@@ -394,9 +394,11 @@ public final class MapPalette {
|
||||
temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth());
|
||||
|
||||
byte[] result = new byte[temp.getWidth() * temp.getHeight()];
|
||||
+ if ((mapColorCache != null && mapColorCache.isCached()) || !gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled) { // Luminol - Pufferfish - vectorized map color conversion
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
result[i] = matchColor(new Color(pixels[i], true));
|
||||
}
|
||||
+ } else gg.pufferfish.pufferfish.simd.VectorMapPalette.matchColorVectorized(pixels, result); // Luminol - Pufferfish - vectorized map color conversion
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <wangxyper@163.com>
|
||||
Date: Mon, 27 Jan 2025 13:01:59 +0800
|
||||
Subject: [PATCH] Tick regions api
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
|
||||
index bf2f7c4959f9f2cd43bbd4d4310e7eedf10cf892..bccb33456d84384bd90887822e16cbad65986106 100644
|
||||
--- a/src/main/java/org/bukkit/World.java
|
||||
+++ b/src/main/java/org/bukkit/World.java
|
||||
@@ -4719,4 +4719,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Luminol start - Tick regions api
|
||||
+ me.earthme.luminol.api.ThreadedRegionizer getThreadedRegionizer();
|
||||
+ // Luminol end - Tick regions api
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Wed, 22 Apr 2026 12:59:08 +0800
|
||||
Subject: [PATCH] Leaves: Leaves plugin
|
||||
|
||||
Co-authored by: MC_XiaoHei <xiaohei.xor7@outlook.com>
|
||||
As part of: Leaves (https://github.com/HyacinthHaru/Leaves/blob/90080d238e2fcfc14a9293150dc351a4f0f696e6/leaves-api/paper-patches/features/0009-Leaves-Plugin.patch)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
|
||||
index 325d797766de527268eb18bcf9db594ca3a0c519..e922a0eefb03db5e33f3306aaea558b6ed61b42a 100644
|
||||
--- a/src/main/java/org/bukkit/Bukkit.java
|
||||
+++ b/src/main/java/org/bukkit/Bukkit.java
|
||||
@@ -3045,4 +3045,10 @@ public final class Bukkit {
|
||||
public static void restart() {
|
||||
server.restart();
|
||||
}
|
||||
+
|
||||
+ // Leaves start - Feature API
|
||||
+ public static org.leavesmc.leaves.plugin.FeatureManager getFeatureManager() {
|
||||
+ return server.getFeatureManager();
|
||||
+ }
|
||||
+ // Leaves end - Feature API
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
|
||||
index 209d1968f4bff3b33785fd8bfbeea5ae231e581a..ac19fd1b6b8e48313c79d9fb26c3df50f67b64b8 100644
|
||||
--- a/src/main/java/org/bukkit/Server.java
|
||||
+++ b/src/main/java/org/bukkit/Server.java
|
||||
@@ -2780,6 +2780,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
||||
me.earthme.luminol.api.config.LuminolConfigBuilder getLuminolConfigBuilder();
|
||||
// Luminol end - Luminol Config API
|
||||
|
||||
+ // Leaves start - Feature API
|
||||
+ org.leavesmc.leaves.plugin.FeatureManager getFeatureManager();
|
||||
+ // Leaves End - Feature API
|
||||
+
|
||||
// Folia start - region TPS API
|
||||
/**
|
||||
* Gets the TPS from the region which owns the specified location, or {@code null} if no region owns
|
||||
@@ -0,0 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Thu, 12 Jun 2025 08:00:15 +0800
|
||||
Subject: [PATCH] Purpur: Lobotomize stuck villagers
|
||||
|
||||
Co-authored by: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
As part of: Purpur (https://github.com/PurpurMC/Purpur/blob/09f547de09fc5d886f18f6d99ff389289766ec9d/purpur-server/minecraft-patches/features/0001-Ridables.patch)
|
||||
Licensed under: MIT (https://github.com/PurpurMC/Purpur/blob/09f547de09fc5d886f18f6d99ff389289766ec9d/LICENSE)
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java
|
||||
index a2024b5dda030a7724c13b2446224903ae837339..71f34a40b136f7f08a4820056c00692b986f63bd 100644
|
||||
--- a/src/main/java/org/bukkit/entity/Villager.java
|
||||
+++ b/src/main/java/org/bukkit/entity/Villager.java
|
||||
@@ -405,4 +405,13 @@ public interface Villager extends AbstractVillager {
|
||||
* Demand is still updated even if all events are canceled.
|
||||
*/
|
||||
public void restock();
|
||||
+ // Purpur start
|
||||
+
|
||||
+ /**
|
||||
+ * Check if villager is currently lobotomized
|
||||
+ *
|
||||
+ * @return True if lobotomized
|
||||
+ */
|
||||
+ boolean isLobotomized();
|
||||
+ // Purpur end
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 5 Jun 2026 09:12:20 +0800
|
||||
Subject: [PATCH] World load/unload APIs
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
|
||||
index ac19fd1b6b8e48313c79d9fb26c3df50f67b64b8..c037307f926d64bac3b51a91aa61f63d0357770c 100644
|
||||
--- a/src/main/java/org/bukkit/Server.java
|
||||
+++ b/src/main/java/org/bukkit/Server.java
|
||||
@@ -775,6 +775,17 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
||||
* @throws IllegalStateException when {@link #isTickingWorlds() isTickingWorlds} is true
|
||||
*/
|
||||
public boolean unloadWorld(@NotNull World world, boolean save);
|
||||
+ // Luminol start - Async world unloading api
|
||||
+
|
||||
+ /**
|
||||
+ * Unloads the given world asynchronously
|
||||
+ *
|
||||
+ * @param world the world to unload
|
||||
+ * @param save whether to save the chunks before unloading
|
||||
+ * @param callback the callback to accept the result, true if successful, false otherwise
|
||||
+ */
|
||||
+ public void unloadWorld(World world, boolean save, java.util.concurrent.CompletableFuture<Boolean> callback);
|
||||
+ // Luminol end
|
||||
|
||||
/**
|
||||
* Gets the world that players respawn in.
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Mon, 11 May 2026 10:47:42 +0800
|
||||
Subject: [PATCH] Add cancel task by task id in FoliaGlobalRegionScheduler
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java
|
||||
index 57455aca80ecc458b96b44c086cea94ddcecae47..763d27d303b9a588526445c453e07f5886534e82 100644
|
||||
--- a/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java
|
||||
+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java
|
||||
@@ -55,4 +55,10 @@ public interface GlobalRegionScheduler {
|
||||
* @param plugin Specified plugin.
|
||||
*/
|
||||
void cancelTasks(@NotNull Plugin plugin);
|
||||
+
|
||||
+ /**
|
||||
+ * Attempts to cancel the specified task.
|
||||
+ * @param taskId The task id.
|
||||
+ */
|
||||
+ void cancelTask(final int taskId);
|
||||
}
|
||||
+6
-6
@@ -8,13 +8,13 @@ As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
|
||||
index b9d34c0b80a5d0c26f43e4959c3a8256a854585a..850f65d764030b09d469e33a69409204503d9ca1 100644
|
||||
index e922a0eefb03db5e33f3306aaea558b6ed61b42a..7120bbea89c1c240b09562c73833f21a9980886f 100644
|
||||
--- a/src/main/java/org/bukkit/Bukkit.java
|
||||
+++ b/src/main/java/org/bukkit/Bukkit.java
|
||||
@@ -3039,4 +3039,15 @@ public final class Bukkit {
|
||||
public static void restart() {
|
||||
server.restart();
|
||||
@@ -3051,4 +3051,15 @@ public final class Bukkit {
|
||||
return server.getFeatureManager();
|
||||
}
|
||||
// Leaves end - Feature API
|
||||
+
|
||||
+ // Leaves start - Bot API
|
||||
+ /**
|
||||
@@ -28,10 +28,10 @@ index b9d34c0b80a5d0c26f43e4959c3a8256a854585a..850f65d764030b09d469e33a69409204
|
||||
+ // Leaves end - Bot API
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
|
||||
index 1dc5d8c96786950fc98cada5bad981c0c716b154..cb8c4e09511f99558eb5af26c08c5cb1f936780d 100644
|
||||
index c037307f926d64bac3b51a91aa61f63d0357770c..6c91cabdcacf7a9bf6421fbb7d52aa17516100f8 100644
|
||||
--- a/src/main/java/org/bukkit/Server.java
|
||||
+++ b/src/main/java/org/bukkit/Server.java
|
||||
@@ -2791,4 +2791,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
||||
@@ -2825,4 +2825,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
||||
*/
|
||||
double @Nullable [] getRegionTPS(@NotNull World world, int chunkX, int chunkZ);
|
||||
// Folia end - region TPS API
|
||||
+4
-4
@@ -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/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
|
||||
index 850f65d764030b09d469e33a69409204503d9ca1..78b947352aa32ae0c59101459f420bf8e3497707 100644
|
||||
index 7120bbea89c1c240b09562c73833f21a9980886f..b114df0dde2e5bede7bb2956359fdd4ca25ac3da 100644
|
||||
--- a/src/main/java/org/bukkit/Bukkit.java
|
||||
+++ b/src/main/java/org/bukkit/Bukkit.java
|
||||
@@ -3050,4 +3050,10 @@ public final class Bukkit {
|
||||
@@ -3062,4 +3062,10 @@ public final class Bukkit {
|
||||
return server.getBotManager();
|
||||
}
|
||||
// Leaves end - Bot API
|
||||
@@ -23,10 +23,10 @@ index 850f65d764030b09d469e33a69409204503d9ca1..78b947352aa32ae0c59101459f420bf8
|
||||
+ // Leaves end - Photographer API
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
|
||||
index cb8c4e09511f99558eb5af26c08c5cb1f936780d..b770b6f990d46f5325554f5d73c6a2a6ed361158 100644
|
||||
index 6c91cabdcacf7a9bf6421fbb7d52aa17516100f8..e6295c4bb86286aa893b55b77ddbfb2f63fdd05c 100644
|
||||
--- a/src/main/java/org/bukkit/Server.java
|
||||
+++ b/src/main/java/org/bukkit/Server.java
|
||||
@@ -2800,4 +2800,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
||||
@@ -2834,4 +2834,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
||||
*/
|
||||
@NotNull org.leavesmc.leaves.entity.bot.BotManager getBotManager();
|
||||
// Leaves end - Bot API
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* This file is part of Pufferfish (https://github.com/pufferfish-gg/Pufferfish)
|
||||
*
|
||||
* Pufferfish is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Pufferfish is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Pufferfish. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package gg.pufferfish.pufferfish.sentry;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.logging.log4j.ThreadContext;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.player.PlayerEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class SentryContext {
|
||||
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
public static void setPluginContext(@Nullable Plugin plugin) {
|
||||
if (plugin != null) {
|
||||
ThreadContext.put("pufferfishsentry_pluginname", plugin.getName());
|
||||
ThreadContext.put("pufferfishsentry_pluginversion", plugin.getPluginMeta().getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
public static void removePluginContext() {
|
||||
ThreadContext.remove("pufferfishsentry_pluginname");
|
||||
ThreadContext.remove("pufferfishsentry_pluginversion");
|
||||
}
|
||||
|
||||
public static void setSenderContext(@Nullable CommandSender sender) {
|
||||
if (sender != null) {
|
||||
ThreadContext.put("pufferfishsentry_playername", sender.getName());
|
||||
if (sender instanceof Player player) {
|
||||
ThreadContext.put("pufferfishsentry_playerid", player.getUniqueId().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeSenderContext() {
|
||||
ThreadContext.remove("pufferfishsentry_playername");
|
||||
ThreadContext.remove("pufferfishsentry_playerid");
|
||||
}
|
||||
|
||||
public static void setEventContext(Event event, RegisteredListener registration) {
|
||||
setPluginContext(registration.getPlugin());
|
||||
|
||||
try {
|
||||
// Find the player that was involved with this event
|
||||
Player player = null;
|
||||
if (event instanceof PlayerEvent) {
|
||||
player = ((PlayerEvent) event).getPlayer();
|
||||
} else {
|
||||
Class<? extends Event> eventClass = event.getClass();
|
||||
|
||||
Field playerField = null;
|
||||
|
||||
for (Field field : eventClass.getDeclaredFields()) {
|
||||
if (field.getType().equals(Player.class)) {
|
||||
playerField = field;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (playerField != null) {
|
||||
playerField.setAccessible(true);
|
||||
player = (Player) playerField.get(event);
|
||||
}
|
||||
}
|
||||
|
||||
if (player != null) {
|
||||
setSenderContext(player);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
} // We can't really safely log exceptions.
|
||||
|
||||
ThreadContext.put("pufferfishsentry_eventdata", GSON.toJson(serializeFields(event)));
|
||||
}
|
||||
|
||||
public static void removeEventContext() {
|
||||
removePluginContext();
|
||||
removeSenderContext();
|
||||
ThreadContext.remove("pufferfishsentry_eventdata");
|
||||
}
|
||||
|
||||
private static Map<String, String> serializeFields(Object object) {
|
||||
Map<String, String> fields = new TreeMap<>();
|
||||
fields.put("_class", object.getClass().getName());
|
||||
for (Field declaredField : object.getClass().getDeclaredFields()) {
|
||||
try {
|
||||
if (Modifier.isStatic(declaredField.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String fieldName = declaredField.getName();
|
||||
if (fieldName.equals("handlers")) {
|
||||
continue;
|
||||
}
|
||||
declaredField.setAccessible(true);
|
||||
Object value = declaredField.get(object);
|
||||
if (value != null) {
|
||||
fields.put(fieldName, value.toString());
|
||||
} else {
|
||||
fields.put(fieldName, "<null>");
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
} // We can't really safely log exceptions.
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
public static class State {
|
||||
|
||||
private Plugin plugin;
|
||||
private Command command;
|
||||
private String commandLine;
|
||||
private Event event;
|
||||
private RegisteredListener registeredListener;
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public void setPlugin(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public Command getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setCommand(Command command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public String getCommandLine() {
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
public void setCommandLine(String commandLine) {
|
||||
this.commandLine = commandLine;
|
||||
}
|
||||
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
public void setEvent(Event event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public RegisteredListener getRegisteredListener() {
|
||||
return registeredListener;
|
||||
}
|
||||
|
||||
public void setRegisteredListener(RegisteredListener registeredListener) {
|
||||
this.registeredListener = registeredListener;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of Pufferfish (https://github.com/pufferfish-gg/Pufferfish)
|
||||
*
|
||||
* Pufferfish is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Pufferfish is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Pufferfish. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package gg.pufferfish.pufferfish.simd;
|
||||
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.IntVector;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Basically, java is annoying, and we have to push this out to its own class.
|
||||
*/
|
||||
@Deprecated
|
||||
public class SIMDChecker {
|
||||
|
||||
@Deprecated
|
||||
public static boolean canEnable(Logger logger) {
|
||||
try {
|
||||
SIMDDetection.testRun = true;
|
||||
|
||||
VectorSpecies<Integer> ISPEC = IntVector.SPECIES_PREFERRED;
|
||||
VectorSpecies<Float> FSPEC = FloatVector.SPECIES_PREFERRED;
|
||||
|
||||
logger.info("Max SIMD vector size on this system is {} bits (int)", ISPEC.vectorBitSize());
|
||||
logger.info("Max SIMD vector size on this system is " + FSPEC.vectorBitSize() + " bits (float)");
|
||||
|
||||
if (ISPEC.elementSize() < 2 || FSPEC.elementSize() < 2) {
|
||||
logger.warn("SIMD is not properly supported on this system!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (NoClassDefFoundError | Exception ignored) {
|
||||
} // Basically, we don't do anything. This lets us detect if it's not functional and disable it.
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of Pufferfish (https://github.com/pufferfish-gg/Pufferfish)
|
||||
*
|
||||
* Pufferfish is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Pufferfish is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Pufferfish. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package gg.pufferfish.pufferfish.simd;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@Deprecated
|
||||
public class SIMDDetection {
|
||||
|
||||
public static boolean isEnabled = false;
|
||||
public static boolean testRun = false;
|
||||
|
||||
@Deprecated
|
||||
public static boolean canEnable(Logger logger) {
|
||||
try {
|
||||
return SIMDChecker.canEnable(logger);
|
||||
} catch (NoClassDefFoundError | Exception ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static int getJavaVersion() {
|
||||
// https://stackoverflow.com/a/2591122
|
||||
String version = System.getProperty("java.version");
|
||||
if (version.startsWith("1.")) {
|
||||
version = version.substring(2, 3);
|
||||
} else {
|
||||
int dot = version.indexOf(".");
|
||||
if (dot != -1) {
|
||||
version = version.substring(0, dot);
|
||||
}
|
||||
}
|
||||
version = version.split("-")[0]; // Azul is stupid
|
||||
return Integer.parseInt(version);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of Pufferfish (https://github.com/pufferfish-gg/Pufferfish)
|
||||
*
|
||||
* Pufferfish is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Pufferfish is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Pufferfish. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package gg.pufferfish.pufferfish.simd;
|
||||
|
||||
import jdk.incubator.vector.FloatVector;
|
||||
import jdk.incubator.vector.IntVector;
|
||||
import jdk.incubator.vector.VectorMask;
|
||||
import jdk.incubator.vector.VectorSpecies;
|
||||
import org.bukkit.map.MapPalette;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@Deprecated
|
||||
public class VectorMapPalette {
|
||||
|
||||
private static final VectorSpecies<Integer> I_SPEC = IntVector.SPECIES_PREFERRED;
|
||||
private static final VectorSpecies<Float> F_SPEC = FloatVector.SPECIES_PREFERRED;
|
||||
|
||||
@Deprecated
|
||||
public static void matchColorVectorized(int[] in, byte[] out) {
|
||||
int speciesLength = I_SPEC.length();
|
||||
int i;
|
||||
for (i = 0; i < in.length - speciesLength; i += speciesLength) {
|
||||
float[] redsArr = new float[speciesLength];
|
||||
float[] bluesArr = new float[speciesLength];
|
||||
float[] greensArr = new float[speciesLength];
|
||||
int[] alphasArr = new int[speciesLength];
|
||||
|
||||
for (int j = 0; j < speciesLength; j++) {
|
||||
alphasArr[j] = (in[i + j] >> 24) & 0xFF;
|
||||
redsArr[j] = (in[i + j] >> 16) & 0xFF;
|
||||
greensArr[j] = (in[i + j] >> 8) & 0xFF;
|
||||
bluesArr[j] = (in[i + j] >> 0) & 0xFF;
|
||||
}
|
||||
|
||||
IntVector alphas = IntVector.fromArray(I_SPEC, alphasArr, 0);
|
||||
FloatVector reds = FloatVector.fromArray(F_SPEC, redsArr, 0);
|
||||
FloatVector greens = FloatVector.fromArray(F_SPEC, greensArr, 0);
|
||||
FloatVector blues = FloatVector.fromArray(F_SPEC, bluesArr, 0);
|
||||
IntVector resultIndex = IntVector.zero(I_SPEC);
|
||||
VectorMask<Integer> modificationMask = VectorMask.fromLong(I_SPEC, 0xffffffff);
|
||||
|
||||
modificationMask = modificationMask.and(alphas.lt(128).not());
|
||||
FloatVector bestDistances = FloatVector.broadcast(F_SPEC, Float.MAX_VALUE);
|
||||
|
||||
for (int c = 4; c < MapPalette.colors.length; c++) {
|
||||
// We're using 32-bit floats here because it's 2x faster and nobody will know the difference.
|
||||
// For correctness, the original algorithm uses 64-bit floats instead. Completely unnecessary.
|
||||
FloatVector compReds = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getRed());
|
||||
FloatVector compGreens = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getGreen());
|
||||
FloatVector compBlues = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getBlue());
|
||||
|
||||
FloatVector rMean = reds.add(compReds).div(2.0f);
|
||||
FloatVector rDiff = reds.sub(compReds);
|
||||
FloatVector gDiff = greens.sub(compGreens);
|
||||
FloatVector bDiff = blues.sub(compBlues);
|
||||
|
||||
FloatVector weightR = rMean.div(256.0f).add(2);
|
||||
FloatVector weightG = FloatVector.broadcast(F_SPEC, 4.0f);
|
||||
FloatVector weightB = FloatVector.broadcast(F_SPEC, 255.0f).sub(rMean).div(256.0f).add(2.0f);
|
||||
|
||||
FloatVector distance = weightR.mul(rDiff).mul(rDiff).add(weightG.mul(gDiff).mul(gDiff)).add(weightB.mul(bDiff).mul(bDiff));
|
||||
|
||||
// Now we compare to the best distance we've found.
|
||||
// This mask contains a "1" if better, and a "0" otherwise.
|
||||
VectorMask<Float> bestDistanceMask = distance.lt(bestDistances);
|
||||
bestDistances = bestDistances.blend(distance, bestDistanceMask); // Update the best distances
|
||||
|
||||
// Update the result array
|
||||
// We also AND with the modification mask because we don't want to interfere if the alpha value isn't large enough.
|
||||
resultIndex = resultIndex.blend(c, bestDistanceMask.cast(I_SPEC).and(modificationMask)); // Update the results
|
||||
}
|
||||
|
||||
for (int j = 0; j < speciesLength; j++) {
|
||||
int index = resultIndex.lane(j);
|
||||
out[i + j] = (byte) (index < 128 ? index : -129 + (index - 127));
|
||||
}
|
||||
}
|
||||
|
||||
// For the final ones, fall back to the regular method
|
||||
for (; i < in.length; i++) {
|
||||
out[i] = MapPalette.matchColor(new Color(in[i], true));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package me.earthme.luminol.api;
|
||||
|
||||
/**
|
||||
* A simple package of folia's tick region state.It linked to the RegionStats of the nms part so that</br>
|
||||
* You could call these methods to get the status of this tick region</br>
|
||||
*/
|
||||
public interface RegionStats {
|
||||
/**
|
||||
* Get the entity count in this tick region
|
||||
*
|
||||
* @return the entity count
|
||||
*/
|
||||
int getEntityCount();
|
||||
|
||||
/**
|
||||
* Get the player count in this tick region
|
||||
*
|
||||
* @return the player count
|
||||
*/
|
||||
int getPlayerCount();
|
||||
|
||||
/**
|
||||
* Get the chunk count in this tick region
|
||||
*
|
||||
* @return the chunk count
|
||||
*/
|
||||
int getChunkCount();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package me.earthme.luminol.api;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A mirror of folia's ThreadedRegion</br>
|
||||
* Including some handy methods to get the information of the tick region</br>
|
||||
* Note: You should call these methods inside this tick region's thread context
|
||||
*/
|
||||
public interface ThreadedRegion {
|
||||
/**
|
||||
* Get the center chunk pos of this tick region</br>
|
||||
* Note:</br>
|
||||
* 1.Global region will return a null value(But we don't finish the global region yet()</br>
|
||||
* 2.You should call these methods inside this tick region's thread context
|
||||
*
|
||||
* @return The center chunk pos
|
||||
*/
|
||||
@Nullable
|
||||
Location getCenterChunkPos();
|
||||
|
||||
/**
|
||||
* Get the dead section percent of this tick region
|
||||
* Note: </br>
|
||||
* 1.Dead percent is mean the percent of the unloaded chunk count of this tick region, which is also used for determine
|
||||
* that the tick region should or not check for splitting</br>
|
||||
* 2.You should call these methods inside this tick region's thread context
|
||||
*
|
||||
* @return The dead section percent
|
||||
*/
|
||||
double getDeadSectionPercent();
|
||||
|
||||
/**
|
||||
* Get the tick region data of this tick region</br>
|
||||
* Note:</br>
|
||||
* 1.You should call this method inside this tick region's thread context</br>
|
||||
* 2.You should call these methods inside this tick region's thread context
|
||||
*
|
||||
* @return The tick region data
|
||||
*/
|
||||
TickRegionData getTickRegionData();
|
||||
|
||||
/**
|
||||
* Get the world of this tick region</br>
|
||||
* Note: Global region will return a null value too
|
||||
*
|
||||
* @return The world of this tick region
|
||||
*/
|
||||
@Nullable
|
||||
World getWorld();
|
||||
|
||||
/**
|
||||
* Get the id of the tick region</br>
|
||||
*
|
||||
* @return The id of the tick region
|
||||
*/
|
||||
long getId();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package me.earthme.luminol.api;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A mirror of folia's ThreadedRegionizer
|
||||
*/
|
||||
public interface ThreadedRegionizer {
|
||||
/**
|
||||
* Get all the tick regions
|
||||
*
|
||||
* @return Temporary copied collection of all tick regions
|
||||
*/
|
||||
Collection<ThreadedRegion> getAllRegions();
|
||||
|
||||
/**
|
||||
* Get the tick region at the given chunk coordinates
|
||||
*
|
||||
* @param chunkX Chunk X
|
||||
* @param chunkZ Chunk Z
|
||||
* @return The tick region at the given chunk coordinates
|
||||
*/
|
||||
@Nullable
|
||||
ThreadedRegion getAtSynchronized(int chunkX, int chunkZ);
|
||||
|
||||
/**
|
||||
* Get the tick region at the given chunk coordinates
|
||||
*
|
||||
* @param chunkX Chunk X
|
||||
* @param chunkZ Chunk Z
|
||||
* @return The tick region at the given chunk coordinates
|
||||
*/
|
||||
@Nullable
|
||||
ThreadedRegion getAtUnSynchronized(int chunkX, int chunkZ);
|
||||
|
||||
/**
|
||||
* Get the tick region at the given location
|
||||
*
|
||||
* @param pos The location
|
||||
* @return The tick region at the given location
|
||||
*/
|
||||
@Nullable
|
||||
default ThreadedRegion getAtSynchronized(@NotNull Location pos) {
|
||||
return this.getAtSynchronized(pos.getBlockX() >> 4, pos.getBlockZ() >> 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tick region at the given location
|
||||
*
|
||||
* @param pos The location
|
||||
* @return The tick region at the given location
|
||||
*/
|
||||
@Nullable
|
||||
default ThreadedRegion getAtUnSynchronized(@NotNull Location pos) {
|
||||
return this.getAtUnSynchronized(pos.getBlockX() >> 4, pos.getBlockZ() >> 4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package me.earthme.luminol.api;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
/**
|
||||
* A mirror of folia's tick region data
|
||||
*/
|
||||
public interface TickRegionData {
|
||||
/**
|
||||
* Get the world it's currently holding
|
||||
*
|
||||
* @return the world
|
||||
*/
|
||||
World getWorld();
|
||||
|
||||
/**
|
||||
* Get the current tick count
|
||||
*
|
||||
* @return the current tick count
|
||||
*/
|
||||
long getCurrentTickCount();
|
||||
|
||||
/**
|
||||
* Get the region stats
|
||||
*
|
||||
* @return the region stats
|
||||
*/
|
||||
RegionStats getRegionStats();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package me.earthme.luminol.api.config;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public record ConfigDataPair(
|
||||
String key,
|
||||
Object value,
|
||||
@Nullable String comment,
|
||||
@Nullable String[] suggestions
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package me.earthme.luminol.api.config;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Builder interface for creating {@link LuminolConfigsInstance} instances.
|
||||
* <p>
|
||||
* Provides multiple overloaded factory methods to construct configuration instances
|
||||
* with varying levels of customization, including custom base directories,
|
||||
* file names, and command names.
|
||||
*/
|
||||
public interface LuminolConfigBuilder {
|
||||
/**
|
||||
* Creates a configuration instance using the default base directory and file name.
|
||||
*
|
||||
* @param loader the class loader used to load configuration resources
|
||||
* @param name the configuration name identifier
|
||||
* @param pack the package path where configuration classes are located
|
||||
* @return a new {@link LuminolConfigsInstance}
|
||||
*/
|
||||
LuminolConfigsInstance of(
|
||||
@NotNull ClassLoader loader,
|
||||
@NotNull String name,
|
||||
@NotNull String pack
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a configuration instance with a custom base directory.
|
||||
*
|
||||
* @param loader the class loader used to load configuration resources
|
||||
* @param base the base directory where the configuration file is stored
|
||||
* @param name the configuration name identifier
|
||||
* @param pack the package path where configuration classes are located
|
||||
* @return a new {@link LuminolConfigsInstance}
|
||||
*/
|
||||
LuminolConfigsInstance of(
|
||||
@NotNull ClassLoader loader,
|
||||
@NotNull File base,
|
||||
@NotNull String name,
|
||||
@NotNull String pack
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a configuration instance with a custom base directory and file name.
|
||||
*
|
||||
* @param loader the class loader used to load configuration resources
|
||||
* @param base the base directory where the configuration file is stored
|
||||
* @param name the configuration name identifier
|
||||
* @param file_name the configuration file name (without extension)
|
||||
* @param pack the package path where configuration classes are located
|
||||
* @return a new {@link LuminolConfigsInstance}
|
||||
*/
|
||||
LuminolConfigsInstance of(
|
||||
@NotNull ClassLoader loader,
|
||||
@NotNull File base,
|
||||
@NotNull String name,
|
||||
@NotNull String file_name,
|
||||
@NotNull String pack
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a configuration instance with full customization options.
|
||||
*
|
||||
* @param loader the class loader used to load configuration resources
|
||||
* @param base the base directory where the configuration file is stored
|
||||
* @param name the configuration name identifier
|
||||
* @param file_name the configuration file name (without extension)
|
||||
* @param command_name the command name associated with this configuration
|
||||
* @param pack the package path where configuration classes are located
|
||||
* @return a new {@link LuminolConfigsInstance}
|
||||
*/
|
||||
LuminolConfigsInstance of(
|
||||
@NotNull ClassLoader loader,
|
||||
@NotNull File base,
|
||||
@NotNull String name,
|
||||
@NotNull String file_name,
|
||||
@NotNull String command_name,
|
||||
@NotNull String pack
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package me.earthme.luminol.api.config;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Interface for managing configuration instances and operations.
|
||||
* Provides methods for loading, saving, modifying, and querying configuration values.
|
||||
*/
|
||||
public interface LuminolConfigsInstance {
|
||||
/**
|
||||
* Initialize the configuration subsystem for this instance.
|
||||
* Implementations should load configuration files, apply defaults and
|
||||
* prepare any internal caches or state needed for subsequent operations.
|
||||
* This method may perform I/O and therefore can throw an {@link IOException}
|
||||
* if initialization fails.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs while initializing
|
||||
*/
|
||||
void initialize() throws IOException;
|
||||
|
||||
/**
|
||||
* Reloads all configurations asynchronously
|
||||
*
|
||||
* @param keepComments whether to preserve existing comments in the config file
|
||||
* @return CompletableFuture that completes when reload is finished
|
||||
*/
|
||||
@NotNull CompletableFuture<Void> reloadAsync(boolean keepComments);
|
||||
|
||||
/**
|
||||
* Sets a configuration value by key
|
||||
*
|
||||
* @param key the configuration key (dot-separated path)
|
||||
* @param value the value to set
|
||||
* @return true if the key exists and value was set, false otherwise
|
||||
*/
|
||||
boolean setConfig(String key, Object value);
|
||||
|
||||
/**
|
||||
* Saves all pending configuration changes to disk
|
||||
*/
|
||||
void saveConfigs();
|
||||
|
||||
/**
|
||||
* Resets a configuration value to its default
|
||||
*
|
||||
* @param key the configuration key to reset
|
||||
*/
|
||||
void resetConfig(String key);
|
||||
|
||||
/**
|
||||
* Gets the default value of a configuration as string
|
||||
*
|
||||
* @param key the configuration key
|
||||
* @return the default value as string
|
||||
*/
|
||||
String getDefaultConfig(String key);
|
||||
|
||||
/**
|
||||
* Gets the current value of a configuration as string
|
||||
*
|
||||
* @param key the configuration key
|
||||
* @return the current value as string
|
||||
*/
|
||||
String getConfig(String key);
|
||||
|
||||
/**
|
||||
* Gets the original (untransformed) value of a configuration
|
||||
*
|
||||
* @param key the configuration key
|
||||
* @param <T> the expected type of the value
|
||||
* @return the original configuration value
|
||||
*/
|
||||
<T> T getConfigOrigin(String key);
|
||||
|
||||
/**
|
||||
* Gets available suggestions for a configuration key
|
||||
*
|
||||
* @param key the configuration key
|
||||
* @return array of suggestion strings, or null if no suggestions available
|
||||
*/
|
||||
String[] getConfigSuggestions(String key);
|
||||
|
||||
/**
|
||||
* Completes a partial configuration path by finding matching keys
|
||||
*
|
||||
* @param partialPath the partial path to complete
|
||||
* @return list of possible completions
|
||||
*/
|
||||
List<String> completeConfigPath(String partialPath);
|
||||
|
||||
/**
|
||||
* Completes a partial configuration path with specific depth
|
||||
*
|
||||
* @param partialPath the partial path to complete
|
||||
* @param dotIndex the maximum number of dots (depth) in the result
|
||||
* @return list of possible completions
|
||||
*/
|
||||
List<String> completeConfigPath(String partialPath, int dotIndex);
|
||||
|
||||
/**
|
||||
* Gets all configuration paths that start with the given prefix
|
||||
*
|
||||
* @param currentPath the prefix to search for
|
||||
* @return list of matching configuration paths
|
||||
*/
|
||||
List<String> getAllConfigPaths(String currentPath);
|
||||
|
||||
/**
|
||||
* Gets all configuration data pairs without prefix filter
|
||||
*
|
||||
* @return set of all configuration data
|
||||
*/
|
||||
Set<ConfigDataPair> getAllData();
|
||||
|
||||
/**
|
||||
* Gets configuration data pairs filtered by prefix
|
||||
*
|
||||
* @param prefix the prefix to filter by
|
||||
* @return set of matching configuration data
|
||||
*/
|
||||
Set<ConfigDataPair> getData(String prefix);
|
||||
|
||||
/**
|
||||
* Gets all configuration data pairs with full information (comments and suggestions)
|
||||
*
|
||||
* @return set of all configuration data with full details
|
||||
*/
|
||||
Set<ConfigDataPair> getAllDataFull();
|
||||
|
||||
/**
|
||||
* Gets configuration data pairs with full information filtered by prefix
|
||||
*
|
||||
* @param prefix the prefix to filter by
|
||||
* @return set of matching configuration data with full details
|
||||
*/
|
||||
Set<ConfigDataPair> getDataFull(String prefix);
|
||||
|
||||
/**
|
||||
* Gets configuration data pairs with optional comments and suggestions
|
||||
*
|
||||
* @param prefix the prefix to filter by
|
||||
* @param _comment whether to include comments
|
||||
* @param _withSuggestions whether to include suggestions
|
||||
* @return set of matching configuration data
|
||||
*/
|
||||
Set<ConfigDataPair> getData(String prefix, boolean _comment, boolean _withSuggestions);
|
||||
|
||||
/**
|
||||
* Gets configuration data pairs for specified keys
|
||||
*
|
||||
* @param list list of configuration keys
|
||||
* @return set of configuration data for the specified keys
|
||||
*/
|
||||
Set<ConfigDataPair> getData(List<String> list);
|
||||
|
||||
/**
|
||||
* Gets configuration data pairs with comments for specified keys
|
||||
*
|
||||
* @param list list of configuration keys
|
||||
* @return set of configuration data with comments
|
||||
*/
|
||||
Set<ConfigDataPair> getDataWithComment(List<String> list);
|
||||
|
||||
/**
|
||||
* Gets configuration data pairs with full information for specified keys
|
||||
*
|
||||
* @param list list of configuration keys
|
||||
* @return set of configuration data with full details
|
||||
*/
|
||||
Set<ConfigDataPair> getDataFull(List<String> list);
|
||||
|
||||
/**
|
||||
* Gets configuration data pairs for specified keys with optional features
|
||||
*
|
||||
* @param list list of configuration keys
|
||||
* @param _comment whether to include comments
|
||||
* @param _withSuggestions whether to include suggestions
|
||||
* @return set of configuration data
|
||||
*/
|
||||
Set<ConfigDataPair> getData(List<String> list, boolean _comment, boolean _withSuggestions);
|
||||
|
||||
/**
|
||||
* Remove a configuration entry by its key.
|
||||
* If the key does not exist this should be a no-op.
|
||||
*
|
||||
* @param key the configuration key to remove
|
||||
*/
|
||||
void removeConfig(String key);
|
||||
|
||||
/**
|
||||
* Remove multiple configuration entries by their keys.
|
||||
* Implementations should attempt to remove each key provided. If some
|
||||
* keys do not exist they may be ignored.
|
||||
*
|
||||
* @param keys an array of configuration keys to remove
|
||||
*/
|
||||
void removeConfig(String[] keys);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package me.earthme.luminol.api.entity;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A simple event fired when a teleportAsync was called
|
||||
*
|
||||
* @see org.bukkit.entity.Entity#teleportAsync(org.bukkit.Location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause)
|
||||
* @see org.bukkit.entity.Entity#teleportAsync(org.bukkit.Location)
|
||||
* (Also fired when teleportAsync called from nms)
|
||||
*/
|
||||
public class EntityTeleportAsyncEvent extends Event {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Entity entity;
|
||||
private final PlayerTeleportEvent.TeleportCause teleportCause;
|
||||
private final Location destination;
|
||||
|
||||
public EntityTeleportAsyncEvent(Entity entity, PlayerTeleportEvent.TeleportCause teleportCause, Location destination) {
|
||||
Validate.notNull(entity, "entity cannot be a null value!");
|
||||
Validate.notNull(teleportCause, "teleportCause cannot be a null value!");
|
||||
Validate.notNull(destination, "destination cannot be a null value!");
|
||||
|
||||
this.entity = entity;
|
||||
this.teleportCause = teleportCause;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity is about to be teleported
|
||||
*
|
||||
* @return that entity
|
||||
*/
|
||||
public @NotNull Entity getEntity() {
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cause of the teleport
|
||||
*
|
||||
* @return the cause
|
||||
*/
|
||||
public @NotNull PlayerTeleportEvent.TeleportCause getTeleportCause() {
|
||||
return this.teleportCause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination of the teleport
|
||||
*
|
||||
* @return the destination
|
||||
*/
|
||||
public @NotNull Location getDestination() {
|
||||
return this.destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package me.earthme.luminol.api.entity;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A simple event created for missing teleport events api of folia
|
||||
* This event is fired when the entity portal process has been done
|
||||
*/
|
||||
public class PostEntityPortalEvent extends Event {
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
|
||||
private final Entity teleportedEntity;
|
||||
|
||||
public PostEntityPortalEvent(Entity teleportedEntity) {
|
||||
Validate.notNull(teleportedEntity, "teleportedEntity cannot be null!");
|
||||
|
||||
this.teleportedEntity = teleportedEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity which was teleported
|
||||
*
|
||||
* @return the entity which was teleported
|
||||
*/
|
||||
public Entity getTeleportedEntity() {
|
||||
return this.teleportedEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package me.earthme.luminol.api.entity;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A simple event created for missing teleport events api of folia
|
||||
* This event will be fired when a portal teleportation is about to happen
|
||||
*/
|
||||
public class PreEntityPortalEvent extends Event implements Cancellable {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Entity entity;
|
||||
private final Location portalPos;
|
||||
private final World destination;
|
||||
|
||||
private boolean cancelled = false;
|
||||
|
||||
public PreEntityPortalEvent(Entity entity, Location portalPos, World destination) {
|
||||
Validate.notNull(entity, "entity cannot be null!");
|
||||
Validate.notNull(portalPos, "portalPos cannot be null!");
|
||||
Validate.notNull(destination, "destination cannot be null!");
|
||||
|
||||
this.entity = entity;
|
||||
this.portalPos = portalPos;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity that is about to teleport
|
||||
*
|
||||
* @return the entity
|
||||
*/
|
||||
public @NotNull Entity getEntity() {
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location of the portal
|
||||
*
|
||||
* @return the portal location
|
||||
*/
|
||||
public @NotNull Location getPortalPos() {
|
||||
return this.portalPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination world
|
||||
*
|
||||
* @return the destination world
|
||||
*/
|
||||
public @NotNull World getDestination() {
|
||||
return this.destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package me.earthme.luminol.api.entity.player;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A simple event fired when the respawn process of player is done
|
||||
*/
|
||||
public class PostPlayerRespawnEvent extends Event {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Player player;
|
||||
|
||||
public PostPlayerRespawnEvent(Player player) {
|
||||
Validate.notNull(player, "Player cannot be a null value!");
|
||||
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the respawned player
|
||||
*
|
||||
* @return the player
|
||||
*/
|
||||
public @NotNull Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package me.earthme.luminol.api.portal;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A event fired when an end platform is created.
|
||||
*/
|
||||
public class EndPlatformCreateEvent extends Event implements Cancellable {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private boolean cancelled = false;
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package me.earthme.luminol.api.portal;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A event fired when the portal process started locating the destination position
|
||||
* Notice: If you changed the destination to an another position in end teleportation.The end platform won't create under the entity and won't create
|
||||
* if the position is out of current tick region
|
||||
*/
|
||||
public class PortalLocateEvent extends Event {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Location original;
|
||||
private final Location destination;
|
||||
|
||||
public PortalLocateEvent(Location original, Location destination) {
|
||||
Validate.notNull(original, "original couldn't be null!");
|
||||
Validate.notNull(destination, "destination couldn't be null!");
|
||||
|
||||
this.original = original;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination position of this teleportation
|
||||
*
|
||||
* @return the destination position
|
||||
*/
|
||||
public Location getDestination() {
|
||||
return this.destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original portal position of this teleportation
|
||||
*
|
||||
* @return the original portal position
|
||||
*/
|
||||
public Location getOriginal() {
|
||||
return this.original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* This file is licensed under the MIT license.
|
||||
* Origin : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
*/
|
||||
|
||||
package org.leavesmc.leaves.plugin;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface FeatureManager {
|
||||
Set<String> getAvailableFeatures();
|
||||
|
||||
boolean isFeatureAvailable(String feature);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* This file is licensed under the MIT license.
|
||||
* Origin : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
*/
|
||||
|
||||
package org.leavesmc.leaves.plugin;
|
||||
|
||||
public class Features {
|
||||
public static final String MIXIN = "mixin";
|
||||
public static final String FAKEPLAYER = "fakeplayer";
|
||||
public static final String PHOTOGRAPHER = "photographer";
|
||||
public static final String RECORDER = "recorder";
|
||||
public static final String BYTEBUF = "bytebuf";
|
||||
public static final String UPDATE_SUPPRESSION_EVENT = "update_suppression_event";
|
||||
}
|
||||
@@ -1,81 +1,151 @@
|
||||
--- a/luminol-server/build.gradle.kts
|
||||
+++ b/luminol-server/build.gradle.kts
|
||||
@@ -48,7 +_,23 @@
|
||||
--- a/folia-server/build.gradle.kts
|
||||
+++ b/folia-server/build.gradle.kts
|
||||
@@ -7,15 +_,16 @@
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
idea
|
||||
- id("io.papermc.paperweight.core")
|
||||
+ id("fun.bm.comfreyweight.core")
|
||||
id("io.papermc.fill.gradle") version "1.0.12"
|
||||
}
|
||||
|
||||
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
|
||||
+val bacteriawaMavenPublicUrl = "https://repo.bacteriawa.com/repository/maven-public/"
|
||||
|
||||
dependencies {
|
||||
mache("io.papermc:mache:26.2+build.1")
|
||||
- paperclip("io.papermc:paperclip:3.0.4")
|
||||
+ morninggloryclip("fun.bm:morninggloryclip:${providers.gradleProperty("clipVersion").get()}")
|
||||
}
|
||||
|
||||
paperweight {
|
||||
@@ -23,7 +_,8 @@
|
||||
filterPatches = false
|
||||
gitFilePatches = false
|
||||
|
||||
- val fork = forks.register("folia") {
|
||||
+ val folia = forks.register("folia") {
|
||||
+ rootDirectory = upstreamsDirectory().map { it.dir("folia") }
|
||||
upstream.patchDir("paperServer") {
|
||||
upstreamPath = "paper-server"
|
||||
excludes = setOf("src/minecraft", "patches", "build.gradle.kts")
|
||||
@@ -32,7 +_,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
- activeFork = luminol
|
||||
- activeFork = fork
|
||||
+ val lophine = forks.register("lophine") {
|
||||
+ forks = luminol
|
||||
+ forks = folia
|
||||
+ upstream.patchRepo("paperServer") {
|
||||
+ upstreamRepo = luminol.patchedRepo("paperServer")
|
||||
+ upstreamRepo = folia.patchedRepo("paperServer")
|
||||
+ patchesDir = rootDirectory.dir("lophine-server/paper-patches")
|
||||
+ outputDir = rootDirectory.dir("paper-server")
|
||||
+ }
|
||||
+
|
||||
+ upstream.patchDir("luminolServer") {
|
||||
+ upstreamPath = "luminol-server"
|
||||
+ upstream.patchDir("foliaServer") {
|
||||
+ upstreamPath = "folia-server"
|
||||
+ excludes = setOf("src/minecraft", "paper-patches", "minecraft-patches", "build.gradle.kts", "build.gradle.kts.patch")
|
||||
+ patchesDir = rootDirectory.dir("lophine-server/luminol-patches")
|
||||
+ outputDir = rootDirectory.dir("luminol-server")
|
||||
+ patchesDir = rootDirectory.dir("lophine-server/folia-patches")
|
||||
+ outputDir = rootDirectory.dir("folia-server")
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ activeFork = lophine
|
||||
|
||||
|
||||
spigot {
|
||||
@@ -139,12 +_,16 @@
|
||||
updatingMinecraft {
|
||||
@@ -44,6 +_,7 @@
|
||||
libraryRepositories.addAll(
|
||||
"https://repo.maven.apache.org/maven2/",
|
||||
paperMavenPublicUrl,
|
||||
+ bacteriawaMavenPublicUrl
|
||||
)
|
||||
}
|
||||
|
||||
@@ -103,10 +_,14 @@
|
||||
main {
|
||||
java { srcDir("../paper-server/src/main/java"); srcDir("../paper-server/src/generated/java") }
|
||||
resources { srcDir("../paper-server/src/main/resources") }
|
||||
java { srcDir("../folia-server/src/main/java") }
|
||||
resources { srcDir("../folia-server/src/main/resources") }
|
||||
+ java { srcDir("../luminol-server/src/main/java") }
|
||||
+ resources { srcDir("../luminol-server/src/main/resources") }
|
||||
+ java { srcDir("../folia-server/src/main/java") }
|
||||
+ resources { srcDir("../folia-server/src/main/resources") }
|
||||
}
|
||||
test {
|
||||
java { srcDir("../paper-server/src/test/java") }
|
||||
resources { srcDir("../paper-server/src/test/resources") }
|
||||
java { srcDir("../folia-server/src/test/java") }
|
||||
resources { srcDir("../folia-server/src/test/resources") }
|
||||
+ java { srcDir("../luminol-server/src/main/java") }
|
||||
+ resources { srcDir("../luminol-server/src/main/resources") }
|
||||
+ java { srcDir("../folia-server/src/test/java") }
|
||||
+ resources { srcDir("../folia-server/src/test/resources") }
|
||||
}
|
||||
}
|
||||
val log4jPlugins = sourceSets.create("log4jPlugins") {
|
||||
@@ -172,7 +_,7 @@
|
||||
@@ -134,7 +_,21 @@
|
||||
}
|
||||
|
||||
dependencies {
|
||||
- implementation(project(":luminol-api")) // Luminol
|
||||
+ implementation(project(":lophine-api")) // Lophine
|
||||
// Luminol start - Dependenices insert
|
||||
implementation("net.objecthunter:exp4j:0.4.8")
|
||||
implementation("io.netty:netty-all:4.2.9.Final") // used for io_uring
|
||||
@@ -274,14 +_,14 @@
|
||||
- implementation(project(":folia-api"))
|
||||
+ implementation(project(":lophine-api")) // Lophine - api update
|
||||
+ // Lophine start - Dependenices insert
|
||||
+ implementation("net.objecthunter:exp4j:0.4.8")
|
||||
+ 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")
|
||||
+ implementation("net.openhft:affinity:3.23.3")
|
||||
+ // Leaves start - leaves plugin
|
||||
+ implementation("org.spongepowered:configurate-gson:4.2.0-SNAPSHOT") {
|
||||
+ exclude(group = "com.google.code.gson", module = "gson")
|
||||
+ exclude(group = "com.google.guava", module = "guava")
|
||||
+ }
|
||||
+ // Leaves end - leaves plugin
|
||||
+ // Lophine end
|
||||
implementation("ca.spottedleaf:leafpile:1.0.0")
|
||||
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
|
||||
implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21
|
||||
@@ -189,21 +_,21 @@
|
||||
val git = Git(rootProject.layout.projectDirectory.path)
|
||||
val mcVersion = rootProject.providers.gradleProperty("mcVersion").get()
|
||||
val build = System.getenv("BUILD_NUMBER") ?: null
|
||||
- val buildTime = providers.environmentVariable("BUILD_STARTED_AT").map(Instant::parse).orElse(Instant.EPOCH).get()
|
||||
+ val buildTime = Instant.now() // Always use current as build time
|
||||
val gitHash = git.exec(providers, "rev-parse", "--short=7", "HEAD").get().trim()
|
||||
val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
|
||||
val date = git.exec(providers, "show", "-s", "--format=%ci", gitHash).get().trim()
|
||||
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
|
||||
attributes(
|
||||
"Main-Class" to "org.bukkit.craftbukkit.Main",
|
||||
- "Implementation-Title" to "Luminol",
|
||||
+ "Implementation-Title" to "Lophine",
|
||||
- "Implementation-Title" to "Folia",
|
||||
+ "Implementation-Title" to "Lophine", // Lophine - Rebrand
|
||||
"Implementation-Version" to implementationVersion,
|
||||
"Implementation-Vendor" to date,
|
||||
- "Specification-Title" to "Luminol",
|
||||
+ "Specification-Title" to "Lophine",
|
||||
- "Specification-Title" to "Folia",
|
||||
+ "Specification-Title" to "Lophine", // Lophine - Rebrand
|
||||
"Specification-Version" to project.version,
|
||||
"Specification-Vendor" to "LuminolMC org",
|
||||
- "Brand-Id" to "luminolmc:luminol",
|
||||
- "Brand-Name" to "Luminol",
|
||||
+ "Brand-Id" to "luminolmc:lophine",
|
||||
+ "Brand-Name" to "Lophine",
|
||||
- "Specification-Vendor" to "Paper Team",
|
||||
- "Brand-Id" to "papermc:folia",
|
||||
- "Brand-Name" to "Folia",
|
||||
+ "Specification-Vendor" to "LophineLabs", // Lophine - Rebrand
|
||||
+ "Brand-Id" to "lophinelabs:lophine", // Lophine - Rebrand
|
||||
+ "Brand-Name" to "Lophine", // Lophine - Rebrand
|
||||
"Build-Number" to (build ?: ""),
|
||||
"Build-Time" to buildTime.toString(),
|
||||
"Git-Branch" to gitBranch,
|
||||
@@ -433,7 +_,7 @@
|
||||
@@ -214,6 +_,20 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
+// Pufferfish Start
|
||||
+tasks.withType<JavaCompile> {
|
||||
+ val compilerArgs = options.compilerArgs
|
||||
+ compilerArgs.add("--add-modules=jdk.incubator.vector")
|
||||
+}
|
||||
+// Pufferfish End
|
||||
+// Lophine start - Hide unnecessary warnings
|
||||
+tasks.withType<JavaCompile> {
|
||||
+ val compilerArgs = options.compilerArgs
|
||||
+ compilerArgs.add("-Xlint:-module")
|
||||
+ compilerArgs.add("-Xlint:-removal")
|
||||
+ compilerArgs.add("-Xlint:-dep-ann")
|
||||
+}
|
||||
+// Lophine end
|
||||
|
||||
fill {
|
||||
- project("luminol")
|
||||
+ project("lophine")
|
||||
versionFamily(paperweight.minecraftVersion.map { it.split(".", "-").takeWhile { part -> part.toIntOrNull() != null }.take(2).joinToString(".") })
|
||||
version(paperweight.minecraftVersion)
|
||||
|
||||
// Compile tests with -parameters for better junit parameterized test names
|
||||
tasks.compileTestJava {
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 8 Jun 2025 00:58:13 +0800
|
||||
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 0bebc2cc87fb9c1c526e4de4f3bc157552307a72..cb1657939b86c039fcfe6403d3f202c2c5879e88 100644
|
||||
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
|
||||
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
|
||||
@@ -23,6 +23,7 @@ public class ConfigManager {
|
||||
|
||||
public static void initConfigs() {
|
||||
configfiles.put("luminol", ConfigsInstance.of("luminol", "me.earthme.luminol.config.modules"));
|
||||
+ configfiles.put("lophine", ConfigsInstance.of("lophine", "fun.bm.lophine.config.modules")); // add lophine config to global config
|
||||
preLoad();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
|
||||
index e4022494b050b68d54bac3cde87bdfc9e908859c..a4188ef831825764c0756b826651e2e7a9f99c5b 100644
|
||||
--- a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
|
||||
+++ b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
|
||||
@@ -8,7 +8,7 @@ import me.earthme.luminol.enums.EnumConfigCategory;
|
||||
@ConfigClassInfo(category = EnumConfigCategory.MISC, name = "server_mod_name")
|
||||
public class ServerModNameConfig implements IConfigModule {
|
||||
@ConfigInfo(name = "name", comments = "Decides the server mod name shown in your F3 debug screen.")
|
||||
- public static String serverModName = "Luminol";
|
||||
+ public static String serverModName = "Lophine";
|
||||
|
||||
@ConfigInfo(name = "vanilla_spoof", comments = "Ignore any plugin's modification and server mod name set in this config block, only force sending brand name of vanilla")
|
||||
public static boolean fakeVanilla = false;
|
||||
@@ -1,40 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Tue, 26 Aug 2025 22:08:54 +0800
|
||||
Subject: [PATCH] Transformed Configs
|
||||
|
||||
|
||||
diff --git a/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java b/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
|
||||
index ad2ba680bedb2336de24146676e70a1f64fd9c5a..505f7fe2ac40451e56967c90df9c52fb35f80fdf 100644
|
||||
--- a/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
|
||||
+++ b/src/main/java/me/earthme/luminol/config/modules/experiment/CommandConfig.java
|
||||
@@ -13,6 +13,7 @@ public class CommandConfig implements IConfigModule {
|
||||
@ConfigInfo(name = "enable_data_command")
|
||||
@HotReloadUnsupported
|
||||
public static boolean data = false;
|
||||
+ @TransformedConfig(name = "command_block_enabled", directory = {"experiment", "command"}, originInstance = "lophine")
|
||||
@TransformedConfig(name = "enabled", directory = {"experiment", "force_enable_command_block_command_execution"})
|
||||
@ConfigInfo(name = "enable_command_block", comments = """
|
||||
Force to enable command blocks.
|
||||
@@ -20,6 +21,9 @@ public class CommandConfig implements IConfigModule {
|
||||
DO NOT ENABLE UNLESS YOU KNOW WHAT YOU ARE DOING!!!
|
||||
""")
|
||||
public static boolean commandBlock = false;
|
||||
+ @TransformedConfig(name = "enable-waypoint", directory = {"experiment", "waypoint bar"}, originInstance = "lophine")
|
||||
+ @TransformedConfig(name = "enable-waypoint", directory = {"experiment", "waypoint_bar"}, originInstance = "lophine")
|
||||
+ @TransformedConfig(name = "waypoint_command_enabled", directory = {"experiment", "command"}, originInstance = "lophine")
|
||||
@ConfigInfo(name = "enable_waypoints_and_waypoint_command", comments = """
|
||||
Enable waypoint and waypoint command.
|
||||
WARN: Still under testing
|
||||
diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/PaperPacketLimiterConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/PaperPacketLimiterConfig.java
|
||||
index aece37eb6406f8ada56428e68cf198c43f8ae309..d5f99fd672e33c16fc3c3e2031ce2e5a5001ab55 100644
|
||||
--- a/src/main/java/me/earthme/luminol/config/modules/misc/PaperPacketLimiterConfig.java
|
||||
+++ b/src/main/java/me/earthme/luminol/config/modules/misc/PaperPacketLimiterConfig.java
|
||||
@@ -11,6 +11,7 @@ import me.earthme.luminol.enums.EnumConfigCategory;
|
||||
"has negative impacts on security"
|
||||
)
|
||||
public class PaperPacketLimiterConfig implements IConfigModule {
|
||||
+ @TransformedConfig(name = "unlimit-packet", directory = {"misc", "network"}, originInstance = "lophine")
|
||||
@TransformedConfig(name = "force_disable", directory = {"optimizations", "force_disable_packet_limiter_of_paper"})
|
||||
@ConfigInfo(name = "force_disable")
|
||||
public static boolean forceDisable = false;
|
||||
@@ -1,76 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Wed, 13 Aug 2025 22:23:46 +0800
|
||||
Subject: [PATCH] Leaves: Item overstack util
|
||||
|
||||
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/d93e9766d3797d130f66179e70a1b374c546fef7/leaves-server/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java b/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java
|
||||
index 112dc08eb62c4c50fb4859f51a366cedf027ca00..b5f661fd20b382725ad117c56ce2c94ded32b1b7 100644
|
||||
--- a/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java
|
||||
+++ b/src/main/java/org/leavesmc/leaves/util/ItemOverstackUtils.java
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.leavesmc.leaves.util;
|
||||
|
||||
+import fun.bm.lophine.config.modules.function.ContainerExpansionConfig;
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.item.ItemEnchantments;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
@@ -135,9 +136,9 @@ public class ItemOverstackUtils {
|
||||
|
||||
private static class ShulkerBox implements ItemUtil {
|
||||
public static boolean shulkerBoxCheck(@NotNull ItemStack stack1, @NotNull ItemStack stack2) {
|
||||
- /*if (LeavesConfig.modify.shulkerBox.sameNbtStackable) {
|
||||
+ if (ContainerExpansionConfig.nbtShulkerStackable) {
|
||||
return Objects.equals(stack1.getComponents(), stack2.getComponents());
|
||||
- }*/ // Luminol
|
||||
+ }
|
||||
return shulkerBoxNoItem(stack1) && shulkerBoxNoItem(stack2) && Objects.equals(stack1.getComponents(), stack2.getComponents());
|
||||
}
|
||||
|
||||
@@ -147,16 +148,15 @@ public class ItemOverstackUtils {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
- // return LeavesConfig.modify.shulkerBox.stackableShulkerBoxes > 1; // Luminol
|
||||
- return false; // Luminol
|
||||
+ return ContainerExpansionConfig.shulkerCount > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryStackItems(ItemEntity self, ItemEntity other) {
|
||||
ItemStack selfStack = self.getItem();
|
||||
if (!isEnabled() ||
|
||||
- !(selfStack.getItem() instanceof net.minecraft.world.item.BlockItem blockItem) ||
|
||||
- !(blockItem.getBlock() instanceof net.minecraft.world.level.block.ShulkerBoxBlock)
|
||||
+ !(selfStack.getItem() instanceof BlockItem blockItem) ||
|
||||
+ !(blockItem.getBlock() instanceof ShulkerBoxBlock)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -164,8 +164,8 @@ public class ItemOverstackUtils {
|
||||
ItemStack otherStack = other.getItem();
|
||||
if (selfStack.getItem() == otherStack.getItem()
|
||||
&& shulkerBoxCheck(selfStack, otherStack)
|
||||
- && selfStack.getCount() != /*org.leavesmc.leaves.LeavesConfig.modify.shulkerBox.stackableShulkerBoxes*/ 1) { // Luminol
|
||||
- int amount = Math.min(otherStack.getCount(), /*org.leavesmc.leaves.LeavesConfig.modify.shulkerBox.stackableShulkerBoxes*/1 - selfStack.getCount()); // Luminol
|
||||
+ && selfStack.getCount() != ContainerExpansionConfig.shulkerCount) {
|
||||
+ int amount = Math.min(otherStack.getCount(), ContainerExpansionConfig.shulkerCount - selfStack.getCount());
|
||||
|
||||
selfStack.grow(amount);
|
||||
self.setItem(selfStack);
|
||||
@@ -187,9 +187,8 @@ public class ItemOverstackUtils {
|
||||
@Override
|
||||
public int getMaxServerStackCount(ItemStack stack) {
|
||||
if (isEnabled() && stack.getItem() instanceof BlockItem bi &&
|
||||
- bi.getBlock() instanceof ShulkerBoxBlock && (/*LeavesConfig.modify.shulkerBox.sameNbtStackable ||*/ shulkerBoxNoItem(stack))) { // Luminol
|
||||
- // return LeavesConfig.modify.shulkerBox.stackableShulkerBoxes; // Luminol
|
||||
- return 1; // Luminol
|
||||
+ bi.getBlock() instanceof ShulkerBoxBlock && (ContainerExpansionConfig.nbtShulkerStackable || shulkerBoxNoItem(stack))) {
|
||||
+ return ContainerExpansionConfig.shulkerCount;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Wed, 18 Feb 2026 00:15:08 +0800
|
||||
Subject: [PATCH] Leaves: Fakeplayer
|
||||
|
||||
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java b/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
|
||||
index 948730740e151352b4a12a90862f1e16925e52b0..0e6c9edbceef525bf102ad8f1fc0cb08e789d0e6 100644
|
||||
--- a/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
|
||||
+++ b/src/main/java/me/earthme/luminol/utils/FoliaServerWaypointManager.java
|
||||
@@ -39,6 +39,12 @@ public class FoliaServerWaypointManager implements WaypointManager<@NotNull Wayp
|
||||
return;
|
||||
}
|
||||
|
||||
+ // Leaves start - fakeplayer
|
||||
+ if (waypoint instanceof org.leavesmc.leaves.bot.ServerBot bot && !bot.getConfigValue(org.leavesmc.leaves.bot.agent.Configs.ENABLE_LOCATOR_BAR)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaves end - fakeplayer
|
||||
+
|
||||
this.waypoints.add(waypoint);
|
||||
|
||||
for (ServerPlayer toCreateFor : this.trackingPlayers) {
|
||||
@@ -92,6 +98,12 @@ public class FoliaServerWaypointManager implements WaypointManager<@NotNull Wayp
|
||||
public void addPlayer(ServerPlayer player) {
|
||||
this.trackingPlayers.add(player);
|
||||
|
||||
+ // Leaves start - fakeplayer
|
||||
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaves end - fakeplayer
|
||||
+
|
||||
for (WaypointTransmitter waypointTransmitter : this.waypoints) {
|
||||
this.createConnection(player, waypointTransmitter);
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Mon, 16 Mar 2026 15:51:40 +0800
|
||||
Subject: [PATCH] Diff in auto-update patch
|
||||
|
||||
|
||||
diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/AutoUpdateConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/AutoUpdateConfig.java
|
||||
index ce01352b637547c1cf8308d56d4b3f9c48fcca70..d57c04d839401e8ba88e56d92be2798bb312949f 100644
|
||||
--- a/src/main/java/me/earthme/luminol/config/modules/misc/AutoUpdateConfig.java
|
||||
+++ b/src/main/java/me/earthme/luminol/config/modules/misc/AutoUpdateConfig.java
|
||||
@@ -16,13 +16,13 @@ import java.util.Set;
|
||||
category = EnumConfigCategory.MISC,
|
||||
name = "auto_update",
|
||||
comments = """
|
||||
- Checks GitHub Releases for newer Luminol jars on a schedule.
|
||||
- Downloads are staged under auto_update/luminol and written to auto_update/core.path,
|
||||
+ Checks GitHub Releases for newer version's jars on a schedule.
|
||||
+ Downloads are staged under auto_update/lophine and written to auto_update/core.path,
|
||||
which Hyacinthusclip can consume on the next restart.
|
||||
- If target_jar_path is set, Luminol will also try to replace that launcher jar directly."""
|
||||
+ If target_jar_path is set, server will also try to replace that launcher jar directly."""
|
||||
)
|
||||
public class AutoUpdateConfig implements IConfigModule {
|
||||
- @ConfigInfo(name = "enabled", comments = "Whether Luminol should check for updates automatically.")
|
||||
+ @ConfigInfo(name = "enabled", comments = "Whether the server should check for updates automatically.")
|
||||
public static boolean enabled = false;
|
||||
|
||||
@ConfigInfo(name = "check_times", comments = "List of daily check times in HH:mm, based on the server's local time zone.")
|
||||
@@ -33,7 +33,7 @@ public class AutoUpdateConfig implements IConfigModule {
|
||||
|
||||
@ConfigInfo(name = "target_jar_path", comments = """
|
||||
Optional launcher jar path to replace after a successful download.
|
||||
- Leave this blank to keep the downloaded jar staged in auto_update/luminol
|
||||
+ Leave this blank to keep the downloaded jar staged in auto_update/lophine
|
||||
and let Hyacinthusclip switch to it through auto_update/core.path on restart.""")
|
||||
public static String targetJarPath = "";
|
||||
|
||||
@@ -42,7 +42,7 @@ public class AutoUpdateConfig implements IConfigModule {
|
||||
|
||||
@Override
|
||||
public void onLoaded(CommentedFileConfig configInstance, @Nullable Set<Exception> exs) {
|
||||
- if (enabled) {
|
||||
+ if (enabled || fun.bm.lophine.config.modules.misc.AutoUpdateConfig.enabled) {
|
||||
if (instance == null) {
|
||||
instance = new AutoUpdateHelper();
|
||||
}
|
||||
diff --git a/src/main/java/me/earthme/luminol/utils/AutoUpdateHelper.java b/src/main/java/me/earthme/luminol/utils/AutoUpdateHelper.java
|
||||
index 94a25cd681c9352d6931edafd9ec67fd7ba8a777..d0d0cf5e5ff8d4b8efa4d9778c27267b41cf8cf8 100644
|
||||
--- a/src/main/java/me/earthme/luminol/utils/AutoUpdateHelper.java
|
||||
+++ b/src/main/java/me/earthme/luminol/utils/AutoUpdateHelper.java
|
||||
@@ -35,10 +35,10 @@ public final class AutoUpdateHelper {
|
||||
private final Logger LOGGER = LogUtils.getClassLogger();
|
||||
private final Gson GSON = new Gson();
|
||||
|
||||
- private final String GITHUB_API_BASE = "https://api.github.com/repos/LuminolMC/Luminol";
|
||||
+ private final String GITHUB_API_BASE = "https://api.github.com/repos/lophineMC/lophine";
|
||||
private final Path AUTO_UPDATE_DIR = Path.of("auto_update");
|
||||
private final Path CORE_PATH_FILE = AUTO_UPDATE_DIR.resolve("core.path");
|
||||
- private final Path LUMINOL_UPDATE_DIR = AUTO_UPDATE_DIR.resolve("luminol");
|
||||
+ private final Path LUMINOL_UPDATE_DIR = AUTO_UPDATE_DIR.resolve("lophine");
|
||||
private final Path LATEST_PATH_FILE = LUMINOL_UPDATE_DIR.resolve("latest.path");
|
||||
private final long DAILY_TASK_PERIOD_MILLIS = TimeUnit.DAYS.toMillis(1);
|
||||
|
||||
@@ -51,13 +51,13 @@ public final class AutoUpdateHelper {
|
||||
ensureWorkingDirectories();
|
||||
|
||||
scheduler = Executors.newSingleThreadScheduledExecutor(task -> {
|
||||
- final Thread thread = new Thread(task, "Luminol Auto Update Scheduler");
|
||||
+ final Thread thread = new Thread(task, "Lophine Auto Update Scheduler");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
|
||||
if (AutoUpdateConfig.checkTimes.isEmpty()) {
|
||||
- LOGGER.warn("Luminol auto-update is enabled, but misc.auto_update.check_times is empty.");
|
||||
+ LOGGER.warn("Lophine auto-update is enabled, but misc.auto_update.check_times is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -95,14 +95,14 @@ public final class AutoUpdateHelper {
|
||||
|
||||
private void checkForUpdatesSafely() {
|
||||
if (!UPDATE_RUNNING.compareAndSet(false, true)) {
|
||||
- LOGGER.info("A Luminol auto-update check is already running, skipping this schedule.");
|
||||
+ LOGGER.info("A Lophine auto-update check is already running, skipping this schedule.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
checkForUpdates();
|
||||
} catch (Exception e) {
|
||||
- LOGGER.warn("Luminol auto-update failed.", e);
|
||||
+ LOGGER.warn("Lophine auto-update failed.", e);
|
||||
} finally {
|
||||
UPDATE_RUNNING.set(false);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ public final class AutoUpdateHelper {
|
||||
|
||||
final ReleaseAssetInfo latestRelease = getLatestCompatibleRelease(mcVersion, gitBranch);
|
||||
if (latestRelease == null) {
|
||||
- LOGGER.warn("No compatible Luminol release was found for Minecraft {}{}.",
|
||||
+ LOGGER.warn("No compatible Lophine release was found for Minecraft {}{}.",
|
||||
mcVersion,
|
||||
gitBranch == null ? "" : " on branch " + gitBranch
|
||||
);
|
||||
@@ -132,7 +132,7 @@ public final class AutoUpdateHelper {
|
||||
|
||||
final UpdateStatus updateStatus = compareReleaseWithCurrentBuild(latestRelease.releaseCommitHash(), currentGitHash);
|
||||
if (updateStatus == UpdateStatus.UP_TO_DATE) {
|
||||
- LOGGER.info("You are already running the latest compatible Luminol release: {}", latestRelease.tagName());
|
||||
+ LOGGER.info("You are already running the latest compatible Lophine release: {}", latestRelease.tagName());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ public final class AutoUpdateHelper {
|
||||
return;
|
||||
}
|
||||
|
||||
- LOGGER.info("Found a newer Luminol release: {}", latestRelease.tagName());
|
||||
+ LOGGER.info("Found a newer Lophine release: {}", latestRelease.tagName());
|
||||
|
||||
final Path stagedJar = downloadAndStageRelease(latestRelease);
|
||||
final Path finalJarPath = tryApplyTargetJar(stagedJar);
|
||||
@@ -163,7 +163,7 @@ public final class AutoUpdateHelper {
|
||||
|
||||
if (finalJarPath.equals(stagedJar)) {
|
||||
LOGGER.info(
|
||||
- "Downloaded the latest Luminol jar to {} and refreshed auto_update/core.path for Hyacinthusclip. Please restart your server.",
|
||||
+ "Downloaded the latest Lophine jar to {} and refreshed auto_update/core.path for Hyacinthusclip. Please restart your server.",
|
||||
finalJarPath.toAbsolutePath()
|
||||
);
|
||||
} else {
|
||||
@@ -179,7 +179,7 @@ public final class AutoUpdateHelper {
|
||||
try {
|
||||
Files.createDirectories(LUMINOL_UPDATE_DIR);
|
||||
} catch (IOException e) {
|
||||
- throw new RuntimeException("Failed to create Luminol auto update directory", e);
|
||||
+ throw new RuntimeException("Failed to create Lophine auto update directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ public final class AutoUpdateHelper {
|
||||
private @NotNull HttpURLConnection openConnection(String url) throws IOException, URISyntaxException {
|
||||
final HttpURLConnection connection = (HttpURLConnection) new URI(url).toURL().openConnection();
|
||||
connection.setRequestProperty("Accept", "application/vnd.github+json");
|
||||
- connection.setRequestProperty("User-Agent", "Luminol Auto Update");
|
||||
+ connection.setRequestProperty("User-Agent", "Lophine Auto Update");
|
||||
connection.setConnectTimeout(10000);
|
||||
connection.setReadTimeout(10000);
|
||||
return connection;
|
||||
@@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 14 Jun 2026 18:10:20 +0800
|
||||
Subject: [PATCH] Luminol Config System
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
|
||||
index 693ce1c23c7be6406eda22da57aa4a1b86a08f5f..4385488983a7544eb6d9193d913dc55294f4620d 100644
|
||||
--- a/net/minecraft/server/Main.java
|
||||
+++ b/net/minecraft/server/Main.java
|
||||
@@ -110,6 +110,7 @@ public class Main {
|
||||
JvmProfiler.INSTANCE.start(Environment.SERVER);
|
||||
}
|
||||
|
||||
+ me.earthme.luminol.config.ConfigManager.initConfigs(); // Luminol - Luminol config
|
||||
io.papermc.paper.plugin.PluginInitializerManager.load(options); // Paper
|
||||
Bootstrap.bootStrap();
|
||||
Bootstrap.validate();
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index be15a671e0b39b455cd5983f4b90f8f3022a2ebc..56d26866cb8f413684e62558e5609b273efb8552 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1168,6 +1168,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
ca.spottedleaf.moonrise.common.util.MoonriseCommon.haltExecutors();
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ // Luminol start - Config Systems
|
||||
+ me.earthme.luminol.config.ConfigManager.saveConfigs(false);
|
||||
+ // Luminol end
|
||||
// Paper start - Improved watchdog support - move final shutdown items here
|
||||
Util.shutdownExecutors();
|
||||
this.onServerExit();
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index cd5551c0221ad2a7b5c7d452d8d91ffc9711c3ee..1ad4704523a3d90414ac514488207b1b5def9afd 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -238,6 +238,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
|
||||
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
|
||||
// Paper end - initialize global and world-defaults configuration
|
||||
+ me.earthme.luminol.config.ConfigManager.loadConfigFiles(); // Luminol - load config file
|
||||
this.server.spark.enableEarlyIfRequested(); // Paper - spark
|
||||
// Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save
|
||||
if (this.convertOldUsers()) {
|
||||
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 17:56:30 +0800
|
||||
Subject: [PATCH] Correct player respawn place
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 16f49ae6736c475207f31392307e280ec06edbc3..a2e40bc7a15ba0663314a288f4a9b3ec3a39dc4d 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -511,8 +511,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
double amountX = selectMaxX - selectMinX;
|
||||
double amountZ = selectMaxZ - selectMinZ;
|
||||
|
||||
- int selectX = amountX < 1.0 ? Mth.floor(worldBorder.getCenterX()) : (int)Mth.floor((amountX + 1.0) * random.nextDouble() + selectMinX);
|
||||
- int selectZ = amountZ < 1.0 ? Mth.floor(worldBorder.getCenterZ()) : (int)Mth.floor((amountZ + 1.0) * random.nextDouble() + selectMinZ);
|
||||
+ // Luminol start - Correct player respawn place
|
||||
+ int selectX = amountX < 0.0 ? Mth.floor(worldBorder.getCenterX()) : (int)Mth.floor(amountX * random.nextDouble() + selectMinX);
|
||||
+ int selectZ = amountZ < 0.0 ? Mth.floor(worldBorder.getCenterZ()) : (int)Mth.floor(amountZ * random.nextDouble() + selectMinZ);
|
||||
+ // Luminol end - Correct player respawn place
|
||||
|
||||
return new BlockPos(selectX, 0, selectZ);
|
||||
}
|
||||
@@ -523,10 +525,20 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
}
|
||||
|
||||
private static BlockPos findSpawnAround(ServerLevel world, BlockPos selected) {
|
||||
+ // Luminol start - Correct player respawn place
|
||||
+ BlockPos inChunk = PlayerSpawnFinder.getLevelRespawnPos(world, selected.getX(), selected.getZ());
|
||||
+ if (inChunk != null) {
|
||||
+ AABB checkVolume = PlayerSpawnFinder.PLAYER_DIMENSIONS.makeBoundingBox((double)inChunk.getX() + 0.5, (double)inChunk.getY(), (double)inChunk.getZ() + 0.5);
|
||||
+
|
||||
+ if (world.noCollision(null, checkVolume, true)) {
|
||||
+ return inChunk;
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end - Correct player respawn place
|
||||
// try hard to find, so that we don't attempt another chunk load
|
||||
for (int dz = -SPAWN_RADIUS_SELECTION_SEARCH; dz <= SPAWN_RADIUS_SELECTION_SEARCH; ++dz) {
|
||||
for (int dx = -SPAWN_RADIUS_SELECTION_SEARCH; dx <= SPAWN_RADIUS_SELECTION_SEARCH; ++dx) {
|
||||
- BlockPos inChunk = PlayerSpawnFinder.getLevelRespawnPos(world, selected.getX() + dx, selected.getZ() + dz);
|
||||
+ inChunk = PlayerSpawnFinder.getLevelRespawnPos(world, selected.getX() + dx, selected.getZ() + dz); // Luminol - Correct player respawn place
|
||||
if (inChunk == null) {
|
||||
continue;
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 17 Apr 2026 23:01:59 +0800
|
||||
Subject: [PATCH] Correct volatile reference get in RegionizedTaskQueue
|
||||
|
||||
|
||||
diff --git a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
|
||||
index d1a045d47dcd12f246d95ecdfc202da357897cbf..b264dbd13a392cde3f24ff75c0034985fda68ccc 100644
|
||||
--- a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
|
||||
+++ b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java
|
||||
@@ -533,7 +533,7 @@ public final class RegionizedTaskQueue {
|
||||
}
|
||||
|
||||
private ReferenceCountData getReferenceCounterVolatile() {
|
||||
- return (ReferenceCountData)REFERENCE_COUNTER_HANDLE.get(this);
|
||||
+ return (ReferenceCountData)REFERENCE_COUNTER_HANDLE.getVolatile(this); // Luminol - Correct volatile reference get in RegionizedTaskQueue
|
||||
}
|
||||
|
||||
private ReferenceCountData compareAndExchangeReferenceCounter(final ReferenceCountData expect, final ReferenceCountData update) {
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Tue, 30 Jun 2026 22:34:00 +0800
|
||||
Subject: [PATCH] Correct thread unsafe random sources
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java
|
||||
index 01b3cda3da79abd30860eb33491ac00f9e958767..dd35e72757b1be1a73e67b272c138bb4e3b6336a 100644
|
||||
--- a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java
|
||||
+++ b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java
|
||||
@@ -30,7 +30,7 @@ public class WanderingTraderSpawner implements CustomSpawner {
|
||||
private static final int SPAWN_CHANCE_INCREASE = 25;
|
||||
private static final int SPAWN_ONE_IN_X_CHANCE = 10;
|
||||
private static final int NUMBER_OF_SPAWN_ATTEMPTS = 10;
|
||||
- private final RandomSource random = RandomSource.create();
|
||||
+ private final RandomSource random = io.papermc.paper.threadedregions.util.ThreadLocalRandomSource.INSTANCE; // Luminol - Correct thread unsafe random sources
|
||||
private final SavedDataStorage savedDataStorage;
|
||||
// Folia - moved to global data
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java b/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
|
||||
index 22b9f70f76ff8f592359e958fa439e9806a29fcc..818598ed4e498bf3f177faac03336097b41915ee 100644
|
||||
--- a/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
|
||||
@@ -28,7 +28,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable
|
||||
public float rot;
|
||||
public float oRot;
|
||||
public float tRot;
|
||||
- private static final RandomSource RANDOM = RandomSource.create();
|
||||
+ private static final RandomSource RANDOM = io.papermc.paper.threadedregions.util.ThreadLocalRandomSource.INSTANCE; // Luminol - Correct thread unsafe random sources
|
||||
private @Nullable Component name;
|
||||
|
||||
public EnchantingTableBlockEntity(final BlockPos worldPosition, final BlockState blockState) {
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Thu, 2 Jul 2026 22:31:15 +0800
|
||||
Subject: [PATCH] Correct portal logic of some projectile entities
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/projectile/ShulkerBullet.java b/net/minecraft/world/entity/projectile/ShulkerBullet.java
|
||||
index d5506bfc84912ec50cd5391225b9b5291435d3aa..6339a770526324bdc1bcc0c0e3bacc0a10f359ab 100644
|
||||
--- a/net/minecraft/world/entity/projectile/ShulkerBullet.java
|
||||
+++ b/net/minecraft/world/entity/projectile/ShulkerBullet.java
|
||||
@@ -229,7 +229,7 @@ public class ShulkerBullet extends Projectile {
|
||||
this.setPos(this.position().add(movement));
|
||||
this.applyEffectsFromBlocks();
|
||||
if (this.portalProcess != null && this.portalProcess.isInsidePortalThisTick()) {
|
||||
- this.handlePortal();
|
||||
+ if (this.handlePortal()) return; // Luminol - Correct portal logic of some projectile entities (Should not be ticking anymore after portal logics)
|
||||
}
|
||||
|
||||
if (hitResult != null && this.isAlive() && hitResult.getType() != HitResult.Type.MISS) {
|
||||
diff --git a/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java b/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java
|
||||
index 88c2f0f927bd8376522eb9aed184abd6f09230f6..d66a4826400eca835645e1115c4fefc61715f336 100644
|
||||
--- a/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java
|
||||
+++ b/net/minecraft/world/entity/projectile/arrow/AbstractArrow.java
|
||||
@@ -276,7 +276,7 @@ public abstract class AbstractArrow extends Projectile {
|
||||
.clipIncludingBorder(
|
||||
new ClipContext(originalPosition, originalPosition.add(movement), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)
|
||||
);
|
||||
- this.stepMoveAndHit(blockHitResult);
|
||||
+ if (this.stepMoveAndHit(blockHitResult)) return; // Luminol - Correct portal logic of some projectile entities (Should not be ticking anymore after portal logics)
|
||||
} else {
|
||||
this.setPos(originalPosition.add(movement));
|
||||
this.applyEffectsFromBlocks();
|
||||
@@ -299,7 +299,7 @@ public abstract class AbstractArrow extends Projectile {
|
||||
return 0.99F;
|
||||
}
|
||||
|
||||
- private void stepMoveAndHit(final BlockHitResult blockHitResult) {
|
||||
+ private boolean stepMoveAndHit(final BlockHitResult blockHitResult) { // Luminol - Correct portal logic of some projectile entities
|
||||
while (this.isAlive()) {
|
||||
Vec3 initialPosition = this.position();
|
||||
ArrayList<EntityHitResult> entitiesHit = new ArrayList<>(this.findHitEntities(initialPosition, blockHitResult.getLocation()));
|
||||
@@ -309,7 +309,7 @@ public abstract class AbstractArrow extends Projectile {
|
||||
this.setPos(nextLocation);
|
||||
this.applyEffectsFromBlocks(initialPosition, nextLocation);
|
||||
if (this.portalProcess != null && this.portalProcess.isInsidePortalThisTick()) {
|
||||
- this.handlePortal();
|
||||
+ if (this.handlePortal()) return true; // Luminol - Correct portal logic of some projectile entities (Should not be ticking anymore after portal logics)
|
||||
}
|
||||
|
||||
if (entitiesHit.isEmpty()) {
|
||||
@@ -327,6 +327,7 @@ public abstract class AbstractArrow extends Projectile {
|
||||
break;
|
||||
}
|
||||
}
|
||||
+ return false; // Luminol - Correct portal logic of some projectile entities
|
||||
}
|
||||
|
||||
private ProjectileDeflection hitTargetsOrDeflectSelf(final Collection<EntityHitResult> entityHitResults) {
|
||||
+391
@@ -0,0 +1,391 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 18:54:50 +0800
|
||||
Subject: [PATCH] Anonymous Object: Configurable region format framework
|
||||
|
||||
As requested by the original author, this patch will be anonymous and hide the original commit address.
|
||||
This patch is used with permission from the original author.
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
|
||||
index a814512fcfb85312474ae2c2c21443843bf57831..9d69a022872e06b320bee46329cd8889f74fbbaa 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
|
||||
@@ -8,9 +8,9 @@ public interface ChunkSystemRegionFileStorage {
|
||||
|
||||
public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ);
|
||||
|
||||
- public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ);
|
||||
+ public io.anonymous.anonymous.data.RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // Anonymous - Configurable region file format
|
||||
|
||||
- public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException;
|
||||
+ public io.anonymous.anonymous.data.RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // Anonymous - Configurable region file format
|
||||
|
||||
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(
|
||||
final int chunkX, final int chunkZ, final CompoundTag compound
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
|
||||
index 3bb9b58ee97464687e348e23b99159226415c267..4c3ad63f17bb4a04f982b36ad3f53d3c0f58bdb5 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
|
||||
@@ -1273,7 +1273,7 @@ public final class MoonriseRegionFileIO {
|
||||
this.regionDataController.finishWrite(this.chunkX, this.chunkZ, writeData);
|
||||
// Paper start - flush regionfiles on save
|
||||
if (this.world.paperConfig().chunks.flushRegionsOnSave) {
|
||||
- final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ);
|
||||
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // Anonymous - Configurable region file format
|
||||
if (regionFile != null) {
|
||||
regionFile.flush();
|
||||
} // else: evicted from cache, which should have called flush
|
||||
@@ -1489,7 +1489,7 @@ public final class MoonriseRegionFileIO {
|
||||
|
||||
public static interface IORunnable {
|
||||
|
||||
- public void run(final RegionFile regionFile) throws IOException;
|
||||
+ public void run(final io.anonymous.anonymous.data.RegionFile regionFile) throws IOException; // Anonymous - Configurable region file format
|
||||
|
||||
}
|
||||
}
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
|
||||
index 51c126735ace8fdde89ad97b5cab62f244212db0..ea2f45964fb8c617f90938597c230b50d83744aa 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
|
||||
@@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer {
|
||||
|
||||
public void moonrise$setWriteOnClose(final boolean value);
|
||||
|
||||
- public void moonrise$write(final RegionFile regionFile) throws IOException;
|
||||
+ public void moonrise$write(final io.anonymous.anonymous.data.RegionFile regionFile) throws IOException; // Anonymous - Configurable region file format
|
||||
}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 56d26866cb8f413684e62558e5609b273efb8552..dd63f14cf6b857202146348b2242673af1883cb7 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -986,10 +986,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (flush) {
|
||||
for (ServerLevel level : this.getAllLevels()) {
|
||||
String storageName = level.getChunkSource().chunkMap.getStorageName();
|
||||
- LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", LEGACY_WORLD_NAMES_FOR_REALMS_LOG.getOrDefault(storageName, storageName));
|
||||
+ LOGGER.info("ThreadedChunkStorage ({}): All chunks are saved", LEGACY_WORLD_NAMES_FOR_REALMS_LOG.getOrDefault(storageName, storageName)); // Anonymous - Configurable region format
|
||||
}
|
||||
|
||||
- LOGGER.info("ThreadedAnvilChunkStorage: All dimensions are saved");
|
||||
+ LOGGER.info("ThreadedChunkStorage: All dimensions are saved"); // Anonymous - configurable region format
|
||||
}
|
||||
|
||||
return result;
|
||||
diff --git a/net/minecraft/util/worldupdate/FileToUpgrade.java b/net/minecraft/util/worldupdate/FileToUpgrade.java
|
||||
index a7f2cfa9277c898038f6b9e0a3401db51012b64c..7b96f3ec2738875a3ed7aa34347c0f174b6579c5 100644
|
||||
--- a/net/minecraft/util/worldupdate/FileToUpgrade.java
|
||||
+++ b/net/minecraft/util/worldupdate/FileToUpgrade.java
|
||||
@@ -4,5 +4,5 @@ import java.util.List;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFile;
|
||||
|
||||
-public record FileToUpgrade(RegionFile file, List<ChunkPos> chunksToUpgrade) {
|
||||
+public record FileToUpgrade(io.anonymous.anonymous.data.RegionFile file, List<ChunkPos> chunksToUpgrade) { // Anonymous - Configurable region file format
|
||||
}
|
||||
diff --git a/net/minecraft/util/worldupdate/RegionStorageUpgrader.java b/net/minecraft/util/worldupdate/RegionStorageUpgrader.java
|
||||
index b228cd6c54e8c8998923ab332882d99092769c67..2dd3d0afd8f58e5e68a361dd38c95da06b4d133b 100644
|
||||
--- a/net/minecraft/util/worldupdate/RegionStorageUpgrader.java
|
||||
+++ b/net/minecraft/util/worldupdate/RegionStorageUpgrader.java
|
||||
@@ -36,7 +36,7 @@ import org.slf4j.Logger;
|
||||
public class RegionStorageUpgrader {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final String NEW_DIRECTORY_PREFIX = "new_";
|
||||
- private static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
|
||||
+ private static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\." + me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat.getArgument() + "$"); // Anonymous - Configurable region file format
|
||||
private final DataFixer dataFixer;
|
||||
private final UpgradeProgress upgradeProgress;
|
||||
private final String type;
|
||||
@@ -176,7 +176,8 @@ public class RegionStorageUpgrader {
|
||||
int zOffset = Integer.parseInt(regex.group(2)) << 5;
|
||||
List<ChunkPos> chunkPositions = Lists.newArrayList();
|
||||
|
||||
- try (RegionFile regionSource = new RegionFile(info, regionFile.toPath(), regionFolder, true)) {
|
||||
+ var regionFileInfo = new io.anonymous.anonymous.utils.RegionCreatorInfo(info, regionFile.toPath(), regionFolder, true); // Anonymous - Configurable region file format
|
||||
+ try (io.anonymous.anonymous.data.RegionFile regionSource = me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat.getCreator().newFile(regionFileInfo)) { // Anonymous - Configurable region file format
|
||||
for (int x = 0; x < 32; x++) {
|
||||
for (int z = 0; z < 32; z++) {
|
||||
ChunkPos pos = new ChunkPos(x + xOffset, z + zOffset);
|
||||
@@ -253,7 +254,7 @@ public class RegionStorageUpgrader {
|
||||
return storage.upgradeChunkTag(chunkTag, this.defaultVersion, this.dataFixContextTag, targetVersion);
|
||||
}
|
||||
|
||||
- private void onFileFinished(final RegionFile regionFile) {
|
||||
+ private void onFileFinished(final io.anonymous.anonymous.data.RegionFile regionFile) { // Anonymous - Configurable region file format
|
||||
if (this.recreateRegionFiles) {
|
||||
if (this.previousWriteFuture != null) {
|
||||
this.previousWriteFuture.join();
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 3de7fd2b084c38e72d7a6bc416880a881f514ad3..821924f85a507589a039832be8657e1dc3c0ce0c 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -22,7 +22,7 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
-public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system
|
||||
+public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile , io.anonymous.anonymous.data.RegionFile{ // Paper - rewrite chunk system // Anonymous - Configurable region file format
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
|
||||
private static final int SECTOR_BYTES = 4096;
|
||||
@@ -130,7 +130,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
return this.recalculateCount.get();
|
||||
}
|
||||
|
||||
- boolean recalculateHeader() throws IOException {
|
||||
+ public boolean recalculateHeader() throws IOException { // Anonymous - Configurable region file format
|
||||
if (!this.canRecalcHeader) {
|
||||
return false;
|
||||
}
|
||||
@@ -789,7 +789,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
}
|
||||
|
||||
- protected synchronized void write(final ChunkPos pos, final ByteBuffer data) throws IOException {
|
||||
+ public synchronized void write(final ChunkPos pos, final ByteBuffer data) throws IOException { // Anonymous - Configurable region file format
|
||||
int offsetIndex = getOffsetIndex(pos);
|
||||
int offset = this.offsets.get(offsetIndex);
|
||||
int sectorNumber = getSectorNumber(offset);
|
||||
@@ -907,7 +907,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
|
||||
@Override
|
||||
- public final void moonrise$write(final RegionFile regionFile) throws IOException {
|
||||
+ public final void moonrise$write(final io.anonymous.anonymous.data.RegionFile regionFile) throws IOException { // Anonymous - Configurable region file format
|
||||
regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count));
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
@@ -973,11 +973,11 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
return (x & 31) + (z & 31) * 32;
|
||||
}
|
||||
|
||||
- synchronized boolean isOversized(int x, int z) {
|
||||
+ public synchronized boolean isOversized(int x, int z) { // Anonymous - Configurable region file format
|
||||
return this.oversized[getChunkIndex(x, z)] == 1;
|
||||
}
|
||||
|
||||
- synchronized void setOversized(int x, int z, boolean oversized) throws IOException {
|
||||
+ public synchronized void setOversized(int x, int z, boolean oversized) throws IOException { // Anonymous - Configurable region file format
|
||||
final int offset = getChunkIndex(x, z);
|
||||
boolean previous = this.oversized[offset] == 1;
|
||||
this.oversized[offset] = (byte) (oversized ? 1 : 0);
|
||||
@@ -1016,7 +1016,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
return this.path.getParent().resolve(this.path.getFileName().toString().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt");
|
||||
}
|
||||
|
||||
- synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException {
|
||||
+ public synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException { // Anonymous - Configurable region file format
|
||||
Path file = getOversizedFile(x, z);
|
||||
try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new java.util.zip.InflaterInputStream(Files.newInputStream(file))))) {
|
||||
return net.minecraft.nbt.NbtIo.read((java.io.DataInput) out);
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 63b40c420030d935bb81a219fb33defe0946e21f..e0e19f091f6b85d7788259cfcc53cc3db848b68e 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -19,7 +19,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper
|
||||
public static final String ANVIL_EXTENSION = ".mca";
|
||||
private static final int MAX_CACHE_SIZE = 256;
|
||||
- private final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
+ private final Long2ObjectLinkedOpenHashMap<io.anonymous.anonymous.data.RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); // Anonymous - Configurable region file format
|
||||
private final RegionStorageInfo info;
|
||||
private final Path folder;
|
||||
private final boolean sync;
|
||||
@@ -30,7 +30,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@Nullable
|
||||
public static ChunkPos getRegionFileCoordinates(Path file) {
|
||||
String fileName = file.getFileName().toString();
|
||||
- if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) {
|
||||
+ if (!fileName.startsWith("r.") || !fileName.endsWith(getExtensionName())) { // Anonymous - Configurable region file format
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -55,8 +55,32 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
private static final int MAX_NON_EXISTING_CACHE = 1024 * 4;
|
||||
private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet();
|
||||
private static String getRegionFileName(final int chunkX, final int chunkZ) {
|
||||
- return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".mca";
|
||||
+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + getExtensionName(); // Anonymous - Configurable region file format
|
||||
}
|
||||
+ // Anonymous start - Configurable region file format
|
||||
+ public static io.anonymous.anonymous.data.RegionFile createNew(RegionStorageInfo info, Path filePath, Path folder, boolean sync) throws IOException{
|
||||
+ final io.anonymous.anonymous.enums.EnumRegionFormat regionFormat = me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat;
|
||||
+ final String fullFileName = filePath.getFileName().toString();
|
||||
+ final String[] fullNameSplit = fullFileName.split("\\.");
|
||||
+ final String extensionName = fullNameSplit[fullNameSplit.length - 1];
|
||||
+
|
||||
+ if (!regionFormat.getArgument().equalsIgnoreCase(extensionName)) {
|
||||
+ // raise a delayed crash
|
||||
+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> {
|
||||
+ throw new RuntimeException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument());
|
||||
+ });
|
||||
+
|
||||
+
|
||||
+ throw new IOException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument());
|
||||
+ }
|
||||
+
|
||||
+ return regionFormat.getCreator().newFile(new io.anonymous.anonymous.utils.RegionCreatorInfo(info, filePath, folder, sync));
|
||||
+ }
|
||||
+
|
||||
+ public static String getExtensionName() {
|
||||
+ return "." + me.earthme.luminol.config.modules.function.RegionFormatConfig.regionFormat.getArgument();
|
||||
+ }
|
||||
+ // Anonymous end
|
||||
|
||||
private boolean doesRegionFilePossiblyExist(final long position) {
|
||||
synchronized (this.nonExistingRegionFiles) {
|
||||
@@ -90,15 +114,15 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
|
||||
@Override
|
||||
- public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) {
|
||||
+ public synchronized final io.anonymous.anonymous.data.RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // Anonymous - Configurable region file format
|
||||
return this.regionCache.getAndMoveToFirst(ChunkPos.pack(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
- public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException {
|
||||
+ public synchronized final io.anonymous.anonymous.data.RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // Anonymous - Configurable region file format
|
||||
final long key = ChunkPos.pack(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT);
|
||||
|
||||
- RegionFile ret = this.regionCache.getAndMoveToFirst(key);
|
||||
+ io.anonymous.anonymous.data.RegionFile ret = this.regionCache.getAndMoveToFirst(key); // Anonymous - Configurable region file format
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
@@ -124,7 +148,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
FileUtil.createDirectoriesSafe(this.folder);
|
||||
|
||||
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
|
||||
+ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // Anonymous - Configurable region file format
|
||||
|
||||
this.regionCache.putAndMoveToFirst(key, ret);
|
||||
|
||||
@@ -143,7 +167,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
|
||||
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
||||
- final RegionFile regionFile = this.getRegionFile(pos);
|
||||
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.getRegionFile(pos); // Anonymous - Configurable region file format
|
||||
|
||||
// note: not required to keep regionfile loaded after this call, as the write param takes a regionfile as input
|
||||
// (and, the regionfile parameter is unused for writing until the write call)
|
||||
@@ -177,7 +201,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
) throws IOException {
|
||||
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
||||
if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) {
|
||||
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
|
||||
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // Anonymous - Configurable region file format
|
||||
if (regionFile != null) {
|
||||
regionFile.clear(pos);
|
||||
} // else: didn't exist
|
||||
@@ -192,7 +216,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.ReadData moonrise$readData(
|
||||
final int chunkX, final int chunkZ
|
||||
) throws IOException {
|
||||
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
|
||||
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // Anonymous - Configurable region file format
|
||||
|
||||
final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ));
|
||||
|
||||
@@ -237,7 +261,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
||||
final ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(ret);
|
||||
- final RegionFile regionFile = this.getRegionFile(pos);
|
||||
+ final io.anonymous.anonymous.data.RegionFile regionFile = this.getRegionFile(pos); // Anonymous - Configurable region file format
|
||||
|
||||
if (regionFile.getRecalculateCount() != readData.recalculateCount()) {
|
||||
return null;
|
||||
@@ -261,7 +285,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
// Paper start - rewrite chunk system
|
||||
- public RegionFile getRegionFile(ChunkPos pos) throws IOException {
|
||||
+ public io.anonymous.anonymous.data.RegionFile getRegionFile(ChunkPos pos) throws IOException { // Anonymous - Configurable region file format
|
||||
return this.getRegionFile(pos, false);
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
@@ -273,7 +297,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
this.isChunkData = info.dfuType()[0] == net.minecraft.util.datafix.DataFixTypes.CHUNK; // Paper - recalculate region file headers
|
||||
}
|
||||
|
||||
- @org.jetbrains.annotations.Contract("_, false -> !null") private @Nullable RegionFile getRegionFile(final ChunkPos pos, boolean existingOnly) throws IOException { // CraftBukkit
|
||||
+ @org.jetbrains.annotations.Contract("_, false -> !null") private io.anonymous.anonymous.data.RegionFile getRegionFile(final ChunkPos pos, boolean existingOnly) throws IOException { // CraftBukkit // Anonymous - Configurable region file format
|
||||
// Paper start - rewrite chunk system
|
||||
if (existingOnly) {
|
||||
return this.moonrise$getRegionFileIfExists(pos.x(), pos.z());
|
||||
@@ -281,7 +305,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
synchronized (this) {
|
||||
final long key = ChunkPos.pack(pos.x() >> REGION_SHIFT, pos.z() >> REGION_SHIFT);
|
||||
|
||||
- RegionFile ret = this.regionCache.getAndMoveToFirst(key);
|
||||
+ io.anonymous.anonymous.data.RegionFile ret = this.regionCache.getAndMoveToFirst(key); // Anonymous - Configurable region file format
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
@@ -298,7 +322,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
FileUtil.createDirectoriesSafe(this.folder);
|
||||
|
||||
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
|
||||
+ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // Anonymous - Configurable region file format
|
||||
|
||||
this.regionCache.putAndMoveToFirst(key, ret);
|
||||
|
||||
@@ -312,7 +336,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
LOGGER.error("{} ({} - {},{}) Go clean it up to remove this message. /minecraft:tp {} 128 {} - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed.", msg, file.toString().replaceAll(".+[\\\\/]", ""), x, z, x << 4, z << 4);
|
||||
}
|
||||
|
||||
- private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException {
|
||||
+ private static CompoundTag readOversizedChunk(io.anonymous.anonymous.data.RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // Anonymous - Configurable region file format
|
||||
synchronized (regionfile) {
|
||||
try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
|
||||
CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x(), chunkCoordinate.z());
|
||||
@@ -346,7 +370,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
public @Nullable CompoundTag read(final ChunkPos pos) throws IOException {
|
||||
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
|
||||
- RegionFile region = this.getRegionFile(pos, true);
|
||||
+ io.anonymous.anonymous.data.RegionFile region = this.getRegionFile(pos, true); // Anonymous - Configurable region file format
|
||||
if (region == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -383,7 +407,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
public void scanChunk(final ChunkPos pos, final StreamTagVisitor scanner) throws IOException {
|
||||
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
|
||||
- RegionFile region = this.getRegionFile(pos, true);
|
||||
+ io.anonymous.anonymous.data.RegionFile region = this.getRegionFile(pos, true); // Anonymous - Configurable region file format
|
||||
if (region == null) {
|
||||
return;
|
||||
}
|
||||
@@ -398,7 +422,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
public void write(final ChunkPos pos, final @Nullable CompoundTag value) throws IOException {
|
||||
if (!SharedConstants.DEBUG_DONT_SAVE_WORLD) {
|
||||
- RegionFile region = this.getRegionFile(pos, value == null); // CraftBukkit // Paper - rewrite chunk system
|
||||
+ io.anonymous.anonymous.data.RegionFile region = this.getRegionFile(pos, value == null); // CraftBukkit // Paper - rewrite chunk system // Anonymous - Configurable region file format
|
||||
// Paper start - rewrite chunk system
|
||||
if (region == null) {
|
||||
// if the RegionFile doesn't exist, no point in deleting from it
|
||||
@@ -430,7 +454,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
// Paper start - rewrite chunk system
|
||||
synchronized (this) {
|
||||
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
|
||||
- for (final RegionFile regionFile : this.regionCache.values()) {
|
||||
+ for (final io.anonymous.anonymous.data.RegionFile regionFile : this.regionCache.values()) { // Anonymous - Configurable region file format
|
||||
try {
|
||||
regionFile.close();
|
||||
} catch (final IOException ex) {
|
||||
@@ -446,7 +470,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
// Paper start - rewrite chunk system
|
||||
synchronized (this) {
|
||||
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
|
||||
- for (final RegionFile regionFile : this.regionCache.values()) {
|
||||
+ for (final io.anonymous.anonymous.data.RegionFile regionFile : this.regionCache.values()) { // Anonymous - Configurable region file format
|
||||
try {
|
||||
regionFile.flush();
|
||||
} catch (final IOException ex) {
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 17 Apr 2026 23:00:48 +0800
|
||||
Subject: [PATCH] Do not enable any debug subscriptions
|
||||
|
||||
Really this would really crash the server by accident when the operators used F3 + J or toggled the debug synchronizer
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index a2e40bc7a15ba0663314a288f4a9b3ec3a39dc4d..216c9263999f05c36fb4c5598b41ff70e5759f5e 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -3483,7 +3483,8 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
}
|
||||
|
||||
public Set<DebugSubscription<?>> debugSubscriptions() {
|
||||
- return !this.server.debugSubscribers().hasRequiredPermissions(this) ? Set.of() : this.requestedDebugSubscriptions;
|
||||
+ // return !this.server.debugSubscribers().hasRequiredPermissions(this) ? Set.of() : this.requestedDebugSubscriptions; // Luminol - Do not enable any debug subscriptions
|
||||
+ return Set.of(); // Luminol - Do not enable any debug subscriptions
|
||||
}
|
||||
|
||||
public record RespawnConfig(LevelData.RespawnData respawnData, boolean forced) {
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 17 Apr 2026 23:25:45 +0800
|
||||
Subject: [PATCH] Do not load too far poi chunk in poi compete scan
|
||||
|
||||
Beeeeeeeeeeeeeeee
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java b/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java
|
||||
index 53131c1b8d5562f9a1b45dfab4fdbdd37b655139..0e9c19a820aefa802d6df134b21f5128a5e8d656 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java
|
||||
@@ -24,8 +24,18 @@ public class PoiCompetitorScan {
|
||||
return true;
|
||||
}
|
||||
// Folia end - region threading
|
||||
- level.getPoiManager()
|
||||
- .getType(pos.pos())
|
||||
+ // Luminol start - POI fixes
|
||||
+ var blockPosOfJobSite = pos.pos();
|
||||
+ var sectionPosOfJobSite = net.minecraft.core.SectionPos.asLong(blockPosOfJobSite);
|
||||
+ var poiManager = level.getPoiManager();
|
||||
+ // we don't care if we should clear the memory of JOB_SITE
|
||||
+ // as it will be automatically removed in SetWalkTargetFromBlockMemory
|
||||
+ // so simply break down if it's not loaded
|
||||
+ var poiChunk = me.earthme.luminol.config.modules.fixes.POIRangeFixes.doNotCompetePOIIfUnloaded ? poiManager.get(sectionPosOfJobSite) : poiManager.getOrLoad(sectionPosOfJobSite);
|
||||
+ poiChunk.flatMap(poiSection -> poiSection.getType(blockPosOfJobSite))
|
||||
+ // Luminol end - POI fixes
|
||||
+ /*level.getPoiManager() // Luminol - POI fixes
|
||||
+ .getType(pos.pos())*/ // Luminol - POI fixes
|
||||
.ifPresent(
|
||||
// Paper start - Improve performance of PoiCompetitorScan by unrolling stream
|
||||
// The previous logic used Stream#reduce to simulate a form of single-iteration bubble sort
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Wed, 2 Jul 2025 23:36:25 +0800
|
||||
Subject: [PATCH] Fix datapack command save function
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 504f21c5f1e3101e7164b97059aecce630d18cee..d5b680fc6e13ec26d0db2448009e4cbe59933e22 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -2437,6 +2437,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
return this.reloadResources(selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN);
|
||||
}
|
||||
|
||||
+ // Lophine start - region thread skip reload // TODO - add reload support
|
||||
+ public void saveDatapacks(Collection<String> selectedIds) {
|
||||
+ this.packRepository.setSelected(selectedIds, false); // Paper - add pendingReload flag to determine required pack loading - false as this is *after* a reload (see above)
|
||||
+ WorldDataConfiguration worldDataConfiguration = new WorldDataConfiguration(
|
||||
+ getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()
|
||||
+ );
|
||||
+ this.worldData.setDataConfiguration(worldDataConfiguration);
|
||||
+ }
|
||||
+ // Lophine end - region thread skip reload // TODO - add reload support
|
||||
+
|
||||
public CompletableFuture<Void> reloadResources(Collection<String> selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause) {
|
||||
// Paper end - Add ServerResourcesReloadedEvent
|
||||
CompletableFuture<Void> completableFuture = CompletableFuture.<ImmutableList>supplyAsync(
|
||||
diff --git a/net/minecraft/server/commands/DataPackCommand.java b/net/minecraft/server/commands/DataPackCommand.java
|
||||
index bb36fa4559cdfe82079af1c39516239119ff06f4..8c530eef0e416d8b96f190ada358d77d34dbc8ac 100644
|
||||
--- a/net/minecraft/server/commands/DataPackCommand.java
|
||||
+++ b/net/minecraft/server/commands/DataPackCommand.java
|
||||
@@ -98,7 +98,7 @@ public class DataPackCommand {
|
||||
dispatcher.register(
|
||||
Commands.literal("datapack")
|
||||
.requires(Commands.hasPermission(Commands.LEVEL_GAMEMASTERS))
|
||||
- /*.then( // Luminol - Add back read-only datapack command
|
||||
+ .then(
|
||||
Commands.literal("enable")
|
||||
.then(
|
||||
Commands.argument("name", StringArgumentType.string())
|
||||
@@ -160,11 +160,11 @@ public class DataPackCommand {
|
||||
.suggests(SELECTED_PACKS)
|
||||
.executes(commandContext -> disablePack(commandContext.getSource(), getPack(commandContext, "name", false)))
|
||||
)
|
||||
- )*/ // Luminol - Add back read-only datapack command
|
||||
+ )
|
||||
.then(
|
||||
Commands.literal("list")
|
||||
.executes(commandContext -> listPacks(commandContext.getSource()))
|
||||
- // .then(Commands.literal("available").executes(commandContext -> listAvailablePacks(commandContext.getSource()))) // Luminol - Add back read-only datapack command
|
||||
+ .then(Commands.literal("available").executes(commandContext -> listAvailablePacks(commandContext.getSource())))
|
||||
.then(Commands.literal("enabled").executes(commandContext -> listEnabledPacks(commandContext.getSource())))
|
||||
)
|
||||
.then(
|
||||
@@ -252,7 +252,7 @@ public class DataPackCommand {
|
||||
}
|
||||
|
||||
private static int listPacks(CommandSourceStack source) {
|
||||
- return listEnabledPacks(source) ;// + listAvailablePacks(source); // Luminol - Add back read-only datapack command
|
||||
+ return listEnabledPacks(source) + listAvailablePacks(source);
|
||||
}
|
||||
|
||||
private static int listAvailablePacks(CommandSourceStack source) {
|
||||
@@ -280,7 +280,7 @@ public class DataPackCommand {
|
||||
|
||||
private static int listEnabledPacks(CommandSourceStack source) {
|
||||
PackRepository packRepository = source.getServer().getPackRepository();
|
||||
- // packRepository.reload(); // Luminol - Add back read-only datapack command
|
||||
+ packRepository.reload();
|
||||
Collection<? extends Pack> selectedPacks = packRepository.getSelectedPacks();
|
||||
if (selectedPacks.isEmpty()) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.datapack.list.enabled.none"), false);
|
||||
diff --git a/net/minecraft/server/commands/ReloadCommand.java b/net/minecraft/server/commands/ReloadCommand.java
|
||||
index fcca0babb4e7929cc168fc8b9ad47619e6feb1a5..bac5f4e023f8b73eebea0f31fd253e04c8809918 100644
|
||||
--- a/net/minecraft/server/commands/ReloadCommand.java
|
||||
+++ b/net/minecraft/server/commands/ReloadCommand.java
|
||||
@@ -16,11 +16,17 @@ public class ReloadCommand {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public static void reloadPacks(Collection<String> selectedIds, CommandSourceStack source) {
|
||||
+ // Lophine start - region thread skip reload // TODO - add reload support
|
||||
+ source.getServer().saveDatapacks(selectedIds);
|
||||
+ source.getSender().sendMessage("You need to restart server to load datapacks update.");
|
||||
+ if (false) {
|
||||
source.getServer().reloadResources(selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.COMMAND).exceptionally(throwable -> { // Paper - Add ServerResourcesReloadedEvent
|
||||
LOGGER.warn("Failed to execute reload", throwable);
|
||||
source.sendFailure(Component.translatable("commands.reload.failure"));
|
||||
return null;
|
||||
});
|
||||
+ }
|
||||
+ // Lophine end - region thread skip reload // TODO - add reload support
|
||||
}
|
||||
|
||||
private static Collection<String> discoverNewPacks(PackRepository packRepository, WorldData worldData, Collection<String> selectedIds) {
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 19:02:01 +0800
|
||||
Subject: [PATCH] Fixes around entity brain and memories
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||
index 3b1c3e84ab24b6e3a0e4d129b3617b393b6d6651..9c8e8de53cbbd87ac7cb8483bd3c1af3fcf66b6e 100644
|
||||
--- a/net/minecraft/world/entity/Mob.java
|
||||
+++ b/net/minecraft/world/entity/Mob.java
|
||||
@@ -299,6 +299,11 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs
|
||||
if (Objects.equals(currentTarget, target)) {
|
||||
return false;
|
||||
}
|
||||
+ // Luminol start - Fix off-region targeting
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(target)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Luminol end
|
||||
LivingEntity originalTarget = target;
|
||||
target = asValidTarget(target);
|
||||
if (reason != null) {
|
||||
diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java
|
||||
index e097bc1268b4050e3948413c52dea69950858458..27894e2935e2afee8190708def4be3b00f922f64 100644
|
||||
--- a/net/minecraft/world/entity/ai/Brain.java
|
||||
+++ b/net/minecraft/world/entity/ai/Brain.java
|
||||
@@ -383,7 +383,7 @@ public class Brain<E extends LivingEntity> {
|
||||
}
|
||||
|
||||
public void tick(final ServerLevel level, final E body) {
|
||||
- this.forgetOutdatedMemories();
|
||||
+ this.forgetOutdatedMemories(body); // Luminol - Add config to force clean entity memory that don't belong to current tick region
|
||||
this.tickSensors(level, body);
|
||||
this.startEachNonRunningBehavior(level, body);
|
||||
this.tickEachRunningBehavior(level, body);
|
||||
@@ -395,8 +395,8 @@ public class Brain<E extends LivingEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
- private void forgetOutdatedMemories() {
|
||||
- this.memories.values().forEach(MemorySlot::tick);
|
||||
+ private void forgetOutdatedMemories(E body) { // Luminol - Add config to force clean entity memory that don't belong to current tick region
|
||||
+ this.memories.values().forEach(slot -> slot.tick(body)); // Luminol - Add config to force clean entity memory that don't belong to current tick region
|
||||
}
|
||||
|
||||
public void stopAll(final ServerLevel level, final E body) {
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java b/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
|
||||
index f744ecd20dc70786311a7162b52aa4ceca0717db..aa60fbfbe7283f1ed9cf5343d59d1222380857dd 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
|
||||
@@ -81,6 +81,11 @@ public class BehaviorUtils {
|
||||
public static void setWalkAndLookTargetMemories(
|
||||
final LivingEntity walker, final PositionTracker target, final float speedModifier, final int closeEnoughDistance
|
||||
) {
|
||||
+ // Luminol - Do not set walk target if target position is out of current tick region
|
||||
+ if (!target.checkThread(walker.level())) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Luminol end
|
||||
WalkTarget walkTarget = new WalkTarget(target, speedModifier, closeEnoughDistance);
|
||||
walker.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, target);
|
||||
walker.getBrain().setMemory(MemoryModuleType.WALK_TARGET, walkTarget);
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/BlockPosTracker.java b/net/minecraft/world/entity/ai/behavior/BlockPosTracker.java
|
||||
index 68251875edfa47ac34c64f99510998ad4bbb14b4..d83b353395bad7c6c41dfaa24018fd207904d995 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/BlockPosTracker.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/BlockPosTracker.java
|
||||
@@ -37,4 +37,11 @@ public class BlockPosTracker implements PositionTracker {
|
||||
public String toString() {
|
||||
return "BlockPosTracker{blockPos=" + this.blockPos + ", centerPosition=" + this.centerPosition + "}";
|
||||
}
|
||||
+
|
||||
+ // Luminol start - Fix a series issue around entity memory typed GlobalPos and WalkTarget
|
||||
+ @Override
|
||||
+ public boolean checkThread(net.minecraft.world.level.Level currOwnedByLevel) {
|
||||
+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(currOwnedByLevel, this.blockPos);
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/EntityTracker.java b/net/minecraft/world/entity/ai/behavior/EntityTracker.java
|
||||
index 3ac52b025ac3e1a3f9135b8e593a385a847afe0f..29c13f18cff52e9950e8932c75cb12fb02f952cb 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/EntityTracker.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/EntityTracker.java
|
||||
@@ -55,4 +55,11 @@ public class EntityTracker implements PositionTracker {
|
||||
public String toString() {
|
||||
return "EntityTracker for " + this.entity;
|
||||
}
|
||||
+
|
||||
+ // Luminol start - Fix a series issue around entity memory typed GlobalPos and WalkTarget
|
||||
+ @Override
|
||||
+ public boolean checkThread(net.minecraft.world.level.Level currOwnedByLevel) {
|
||||
+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.entity);
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/PositionTracker.java b/net/minecraft/world/entity/ai/behavior/PositionTracker.java
|
||||
index ce6cf5ecfb190428e3ef9b7dd39c98e3d27a7b9d..3334da2236fbe90cbdc3e67884f9c6ed80ac0f56 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/PositionTracker.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/PositionTracker.java
|
||||
@@ -10,4 +10,7 @@ public interface PositionTracker {
|
||||
BlockPos currentBlockPosition();
|
||||
|
||||
boolean isVisibleBy(final LivingEntity body);
|
||||
+
|
||||
+
|
||||
+ boolean checkThread(net.minecraft.world.level.Level currOwnedByLevel); // Luminol - Fix a series issue around entity memory typed GlobalPos and WalkTarget
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/SleepInBed.java b/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
index 16017d819c28b077f732e2ef571eac179d24e323..7a598aa1a0963fda3302946a30d0330c341da74f 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
@@ -57,6 +57,11 @@ public class SleepInBed extends Behavior<LivingEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Luminol Start - Prevent off-tick-region chunk operations
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, target.pos())) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Luminol End
|
||||
BlockState blockState = level.getBlockStateIfLoaded(target.pos()); // Paper - Prevent sync chunk loads when villagers try to find beds
|
||||
if (blockState == null) return false; // Paper - Prevent sync chunk loads when villagers try to find beds
|
||||
return target.pos().closerToCenterThan(body.position(), 2.0) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED);
|
||||
diff --git a/net/minecraft/world/entity/ai/memory/MemorySlot.java b/net/minecraft/world/entity/ai/memory/MemorySlot.java
|
||||
index 88a89b4c72cc99dc89d3f3cc928b2dfda4125759..3b51a44ab700740047c9e725547ceec65c0c80b1 100644
|
||||
--- a/net/minecraft/world/entity/ai/memory/MemorySlot.java
|
||||
+++ b/net/minecraft/world/entity/ai/memory/MemorySlot.java
|
||||
@@ -13,7 +13,7 @@ public class MemorySlot<T> {
|
||||
this.timeToLive = timeToLive;
|
||||
}
|
||||
|
||||
- public void tick() {
|
||||
+ public void tick(net.minecraft.world.entity.Entity owner) { // Luminol - Add config to force clean entity memory that don't belong to current tick region
|
||||
if (this.hasValue() && this.canExpire()) {
|
||||
if (this.hasExpired()) {
|
||||
this.clear();
|
||||
@@ -21,6 +21,41 @@ public class MemorySlot<T> {
|
||||
this.timeToLive--;
|
||||
}
|
||||
}
|
||||
+ // Luminol start - Add config to force clean entity memory that don't belong to current tick region
|
||||
+ final net.minecraft.world.level.Level ownerLevel = owner.level();
|
||||
+
|
||||
+ // type: entity
|
||||
+ if (me.earthme.luminol.config.modules.fixes.ForceCleanupEntityBrainMemoryConfig.enabledForEntity && this.value instanceof net.minecraft.world.entity.Entity entity) {
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) {
|
||||
+ this.clear();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // type: block_pos
|
||||
+ if (me.earthme.luminol.config.modules.fixes.ForceCleanupEntityBrainMemoryConfig.enabledForBlockPos && this.value instanceof net.minecraft.core.BlockPos blockPos) {
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(ownerLevel, blockPos)) {
|
||||
+ this.clear();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ //type: position_tracker and walk_target
|
||||
+ if (me.earthme.luminol.config.modules.fixes.ForceCleanupEntityBrainMemoryConfig.enabledForPositionTracker) {
|
||||
+ net.minecraft.world.entity.ai.behavior.PositionTracker tracker = null;
|
||||
+
|
||||
+ if (value instanceof net.minecraft.world.entity.ai.behavior.PositionTracker positionTracker) {
|
||||
+ tracker = positionTracker;
|
||||
+ }
|
||||
+
|
||||
+ if (value instanceof net.minecraft.world.entity.ai.memory.WalkTarget walkTarget) {
|
||||
+ tracker = walkTarget.getTarget();
|
||||
+ }
|
||||
+
|
||||
+ if (tracker != null && !tracker.checkThread(owner.level())) {
|
||||
+ this.clear();
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
|
||||
public static <T> MemorySlot<T> create() {
|
||||
diff --git a/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
index e44814cfb6afb594456b8215bd13a92e93de2c85..c18e2071c699d9c5f4d46b7a58191df4f4d8ab5d 100644
|
||||
--- a/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
+++ b/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
@@ -60,6 +60,17 @@ public class FlyingPathNavigation extends PathNavigation {
|
||||
|
||||
if (!this.isDone()) {
|
||||
Vec3 target = this.path.getNextEntityPos(this.mob);
|
||||
+ // Luminol - Recompute path when path finding out of current tick region
|
||||
+ if (me.earthme.luminol.config.modules.fixes.PathfindingFixesConfig.breakDownPathfindingWhenOutOfRegion) {
|
||||
+ // we assume that:
|
||||
+ // 1. The code above doesn't touch the 'main thread context' with the position from 'this.path'
|
||||
+ // 2. The pathfinder could correctly recompute or discard the incorrect target position and this situation is happening rarely
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.mob.level(), target)) {
|
||||
+ this.hasDelayedRecomputation = true;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end
|
||||
this.mob.getMoveControl().setWantedPosition(target.x, target.y, target.z, this.speedModifier);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
index 2ea1ec39a37899ae1510d0036aa670e758077537..4c727e4f224f6a31a4cd9d024bdcfaf0fa1bc0e5 100644
|
||||
--- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
+++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
@@ -188,6 +188,18 @@ public abstract class PathNavigation {
|
||||
}
|
||||
}
|
||||
// Paper end - EntityPathfindEvent
|
||||
+ // Luminol start - Do not path find for targets out of current region
|
||||
+ if (me.earthme.luminol.config.modules.fixes.PathfindingFixesConfig.doNotPathfindToNotOwnedTargets) {
|
||||
+ // filter the targets not owned by current region
|
||||
+ targets = new java.util.HashSet<>(targets); // well no idea about how to determine if this should be copied to a modifiable one
|
||||
+ targets.removeIf(pos -> !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.mob.level(), pos));
|
||||
+
|
||||
+ // return if no available (observe the logic in the first if block)
|
||||
+ if (targets.isEmpty()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end
|
||||
ProfilerFiller profiler = Profiler.get();
|
||||
profiler.push("pathfind");
|
||||
BlockPos fromPos = above ? this.mob.blockPosition().above() : this.mob.blockPosition();
|
||||
@@ -286,6 +298,17 @@ public abstract class PathNavigation {
|
||||
|
||||
if (!this.isDone()) {
|
||||
Vec3 target = this.path.getNextEntityPos(this.mob);
|
||||
+ // Luminol - Recompute path when path finding out of current tick region
|
||||
+ if (me.earthme.luminol.config.modules.fixes.PathfindingFixesConfig.breakDownPathfindingWhenOutOfRegion) {
|
||||
+ // we assume that:
|
||||
+ // 1. The code above doesn't touch the 'main thread context' with the position from 'this.path'
|
||||
+ // 2. The pathfinder could correctly recompute or discard the incorrect target position and this situation is happening rarely
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.mob.level(), target)) {
|
||||
+ this.hasDelayedRecomputation = true;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end
|
||||
this.mob.getMoveControl().setWantedPosition(target.x, this.getGroundY(target), target.z, this.speedModifier);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/animal/allay/AllayAi.java b/net/minecraft/world/entity/animal/allay/AllayAi.java
|
||||
index c3667e7997551e0f5ce63bc6ee890082d1431400..2e2458535a8ec542d6371ceba2fff1260773c7f5 100644
|
||||
--- a/net/minecraft/world/entity/animal/allay/AllayAi.java
|
||||
+++ b/net/minecraft/world/entity/animal/allay/AllayAi.java
|
||||
@@ -112,6 +112,17 @@ public class AllayAi {
|
||||
Optional<GlobalPos> likedNoteblockPos = brain.getMemory(MemoryModuleType.LIKED_NOTEBLOCK_POSITION);
|
||||
if (likedNoteblockPos.isPresent()) {
|
||||
GlobalPos position = likedNoteblockPos.get();
|
||||
+ // Luminol start - Do not like item if they were out of current tickregion
|
||||
+ final Level targetLevel = allay.level().getServer().getLevel(position.dimension());
|
||||
+ final BlockPos targetPos = position.pos();
|
||||
+
|
||||
+ // thread checks
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(targetLevel, targetPos)) {
|
||||
+ brain.eraseMemory(MemoryModuleType.LIKED_NOTEBLOCK_POSITION); // The memory value is not being belong to current tick region anymore
|
||||
+ return Optional.empty();
|
||||
+ }
|
||||
+ // Luminol end
|
||||
+
|
||||
if (shouldDepositItemsAtLikedNoteblock(allay, brain, position)) {
|
||||
return Optional.of(new BlockPosTracker(position.pos().above()));
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
|
||||
index d5394ae7ce56555ad21aeafb2d78c291c62e2988..a2873d8bbfa3e04678bc31637222b3a10cd6fedd 100644
|
||||
--- a/net/minecraft/world/entity/animal/sniffer/Sniffer.java
|
||||
+++ b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
|
||||
@@ -279,8 +279,18 @@ public class Sniffer extends Animal {
|
||||
|
||||
private boolean canDig(final BlockPos position) {
|
||||
return this.level().getBlockState(position).is(BlockTags.SNIFFER_DIGGABLE_BLOCK)
|
||||
- && this.getExploredPositions().noneMatch(explored -> GlobalPos.of(this.level().dimension(), position).equals(explored))
|
||||
- && Optional.ofNullable(this.getNavigation().createPath(position, 1)).map(Path::canReach).orElse(false);
|
||||
+ && this.getExploredPositions().noneMatch(explored -> { // Luminol start - Do not pathfind out of tickregion
|
||||
+ // thread checks
|
||||
+ final Level targetLevel = net.minecraft.server.MinecraftServer.getServer().getLevel(explored.dimension());
|
||||
+ final BlockPos targetPos = explored.pos();
|
||||
+
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(targetLevel, targetPos)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return GlobalPos.of(this.level().dimension(), position).equals(explored); // Original logic
|
||||
+ }) // Luminol end
|
||||
+ && Optional.ofNullable(this.getNavigation().createPath(position, 1)).map(Path::canReach).orElse(false); // Luminol - Do not pathfind out of tickregion - diff on change
|
||||
}
|
||||
|
||||
private void dropSeed() {
|
||||
@@ -0,0 +1,38 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 17 Apr 2026 23:16:45 +0800
|
||||
Subject: [PATCH] Fix off region leashing
|
||||
|
||||
PS: My friend reported me this bug and I still need to check the details of how the bug was caused
|
||||
|
||||
XD
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Leashable.java b/net/minecraft/world/entity/Leashable.java
|
||||
index 98034a4c96bf2972316078d3b3a49140921aab50..284ba0c3742d5d5ab0b344a84a9c8e2c2a98a74a 100644
|
||||
--- a/net/minecraft/world/entity/Leashable.java
|
||||
+++ b/net/minecraft/world/entity/Leashable.java
|
||||
@@ -95,10 +95,24 @@ public interface Leashable {
|
||||
if (leashUuid.isPresent()) {
|
||||
Entity leasher = serverLevel.getEntity(leashUuid.get());
|
||||
if (leasher != null) {
|
||||
+ // Luminol start - Fix off region leashing
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(leasher)) {
|
||||
+ entity.spawnAtLocation(serverLevel, Items.LEAD);
|
||||
+ entity.setLeashData(null);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Luminol end
|
||||
setLeashedTo(entity, leasher, true);
|
||||
return;
|
||||
}
|
||||
} else if (pos.isPresent()) {
|
||||
+ // Luminol start - Fix off region leashing
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(serverLevel, pos.get())) {
|
||||
+ entity.spawnAtLocation(serverLevel, Items.LEAD);
|
||||
+ entity.setLeashData(null);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Luminol end
|
||||
setLeashedTo(entity, LeashFenceKnotEntity.getOrCreateKnot(serverLevel, pos.get()), true);
|
||||
return;
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 17 Apr 2026 23:21:30 +0800
|
||||
Subject: [PATCH] Fix unpatched task returning of
|
||||
ServerConfigurationPacketListenerImpl#disconnectAsync
|
||||
|
||||
Inspired by https://github.com/CraftCanvasMC/Canvas/blob/ver/1.21.8/canvas-server/minecraft-patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch
|
||||
but Canvas loses its main thread checks so fixed that btw
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
index 77c4670868a95dc7b13461dfa67af34b0a3c329a..111789b4aca281dd1899dfbcc4e7e0ca36d74b51 100644
|
||||
--- a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -299,13 +299,14 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
// Paper start
|
||||
@Override
|
||||
public void disconnectAsync(final net.minecraft.network.DisconnectionDetails disconnectionInfo) {
|
||||
- if (this.cserver.isPrimaryThread()) {
|
||||
+ if (io.papermc.paper.threadedregions.RegionizedServer.isGlobalTickThread()) { // Luminol - Fix unpatched task returning of ServerConfigurationPacketListenerImpl#disconnectAsync
|
||||
this.disconnect(disconnectionInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
this.connection.setReadOnly();
|
||||
- this.server.scheduleOnMain(() -> {
|
||||
+ // this.server.scheduleOnMain(() -> { // Luminol - Fix unpatched task returning of ServerConfigurationPacketListenerImpl#disconnectAsync
|
||||
+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Luminol - Fix unpatched task returning of ServerConfigurationPacketListenerImpl#disconnectAsync
|
||||
this.disconnect(disconnectionInfo); // Currently you cannot cancel disconnect during the config stage
|
||||
});
|
||||
}
|
||||
@@ -1,472 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sat, 26 Jul 2025 01:11:54 +0800
|
||||
Subject: [PATCH] Leaves: Item overstack util
|
||||
|
||||
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/46cccfc39cafbca1681620d03947bc3ad558327f/leaves-server/minecraft-patches/features/0034-Item-overstack-util.patch)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/commands/arguments/item/ItemInput.java b/net/minecraft/commands/arguments/item/ItemInput.java
|
||||
index 8e08cb90dc94171a8da7126fe18c46eaa49a58f2..a7804a0d099c79c81eb45eb20402a001d8734529 100644
|
||||
--- a/net/minecraft/commands/arguments/item/ItemInput.java
|
||||
+++ b/net/minecraft/commands/arguments/item/ItemInput.java
|
||||
@@ -39,11 +39,13 @@ public class ItemInput {
|
||||
public ItemStack createItemStack(int count, boolean allowOversizedStacks) throws CommandSyntaxException {
|
||||
ItemStack itemStack = new ItemStack(this.item, count);
|
||||
itemStack.applyComponents(this.components);
|
||||
- if (allowOversizedStacks && count > itemStack.getMaxStackSize()) {
|
||||
- throw ERROR_STACK_TOO_BIG.create(this.getItemName(), itemStack.getMaxStackSize());
|
||||
+ // Leaves start - item over-stack util
|
||||
+ if (allowOversizedStacks && count > org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack)) {
|
||||
+ throw ERROR_STACK_TOO_BIG.create(this.getItemName(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack));
|
||||
} else {
|
||||
return itemStack;
|
||||
}
|
||||
+ // Leaves end - item over-stack util
|
||||
}
|
||||
|
||||
public String serialize(HolderLookup.Provider levelRegistry) {
|
||||
diff --git a/net/minecraft/server/commands/GiveCommand.java b/net/minecraft/server/commands/GiveCommand.java
|
||||
index 1281eadb2d0c5b4ce5e3afd51d8205f9a4ef011c..b1446dfb4689174ee9f55cec6080622ec34de250 100644
|
||||
--- a/net/minecraft/server/commands/GiveCommand.java
|
||||
+++ b/net/minecraft/server/commands/GiveCommand.java
|
||||
@@ -54,7 +54,7 @@ public class GiveCommand {
|
||||
|
||||
private static int giveItem(CommandSourceStack source, ItemInput item, Collection<ServerPlayer> targets, int count) throws CommandSyntaxException {
|
||||
ItemStack itemStack = item.createItemStack(1, false);
|
||||
- int maxStackSize = itemStack.getMaxStackSize();
|
||||
+ int maxStackSize = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
|
||||
int i = maxStackSize * 100;
|
||||
if (count > i) {
|
||||
source.sendFailure(Component.translatable("commands.give.failed.toomanyitems", i, itemStack.getDisplayName()));
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 3acd8d2226d4a7ba8fcecc1cc715b01cc9ce63d1..cc82414e813fe0a97bfd405096d06ad279098479 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3170,7 +3170,7 @@ public class ServerGamePacketListenerImpl
|
||||
} else if (slot.mayPlace(cursor)) {
|
||||
if (ItemStack.isSameItemSameComponents(clickedItem, cursor)) {
|
||||
int toPlace = packet.buttonNum() == 0 ? cursor.getCount() : 1;
|
||||
- toPlace = Math.min(toPlace, clickedItem.getMaxStackSize() - clickedItem.getCount());
|
||||
+ toPlace = Math.min(toPlace, org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(clickedItem) - clickedItem.getCount()); // Leaves - item over-stack util
|
||||
toPlace = Math.min(toPlace, slot.container.getMaxStackSize() - clickedItem.getCount());
|
||||
if (toPlace == 1) {
|
||||
action = InventoryAction.PLACE_ONE;
|
||||
@@ -3206,7 +3206,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
} else if (ItemStack.isSameItemSameComponents(cursor, clickedItem)) {
|
||||
if (clickedItem.getCount() >= 0) {
|
||||
- if (clickedItem.getCount() + cursor.getCount() <= cursor.getMaxStackSize()) {
|
||||
+ if (clickedItem.getCount() + cursor.getCount() <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(cursor)) { // Leaves - item over-stack util
|
||||
// As of 1.5, this is result slots only
|
||||
action = InventoryAction.PICKUP_ALL;
|
||||
}
|
||||
@@ -3423,6 +3423,7 @@ public class ServerGamePacketListenerImpl
|
||||
this.player.containerMenu.broadcastFullState();
|
||||
} else {
|
||||
this.player.containerMenu.broadcastChanges();
|
||||
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.broadcastCarriedItem(); // Leaves - item over-stack util - force send carried item
|
||||
}
|
||||
if (packet.buttonNum() == Inventory.SLOT_OFFHAND && this.player.containerMenu != this.player.inventoryMenu) this.player.containerSynchronizer.sendOffHandSlotChange(); // Paper - update offhand data when the player is clicking in an inventory not their own as the sychronizer does not include offhand slots
|
||||
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
|
||||
@@ -3534,7 +3535,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45;
|
||||
- boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize();
|
||||
+ boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
|
||||
if (flag || (flag1 && !ItemStack.matches(this.player.inventoryMenu.getSlot(packet.slotNum()).getItem(), packet.itemStack()))) { // Insist on valid slot
|
||||
// CraftBukkit start - Call click event
|
||||
org.bukkit.inventory.InventoryView inventory = this.player.inventoryMenu.getBukkitView();
|
||||
@@ -3576,6 +3577,7 @@ public class ServerGamePacketListenerImpl
|
||||
this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemStack);
|
||||
this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemStack);
|
||||
this.player.inventoryMenu.broadcastChanges();
|
||||
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.sendSingleSlot(packet.slotNum(), itemStack); // Leaves - item over-stack util - force send carried item
|
||||
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
|
||||
} else if (flag && flag2) {
|
||||
if (this.dropSpamThrottler.isUnderThreshold()) {
|
||||
diff --git a/net/minecraft/world/Container.java b/net/minecraft/world/Container.java
|
||||
index b63cecafd841b97a694f6d2610141dcdb8f30574..392678778dc2a036c1e3db4b6bb2800e452d3cd0 100644
|
||||
--- a/net/minecraft/world/Container.java
|
||||
+++ b/net/minecraft/world/Container.java
|
||||
@@ -37,6 +37,12 @@ public interface Container extends Clearable, SlotProvider, Iterable<ItemStack>,
|
||||
return Math.min(this.getMaxStackSize(), stack.getMaxStackSize());
|
||||
}
|
||||
|
||||
+ // Leaves start - item over-stack util
|
||||
+ default int getMaxStackLeaves(ItemStack stack) {
|
||||
+ return Math.min(this.getMaxStackSize(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack));
|
||||
+ }
|
||||
+ // Leaves end - item over-stack util
|
||||
+
|
||||
void setChanged();
|
||||
|
||||
boolean stillValid(Player player);
|
||||
diff --git a/net/minecraft/world/SimpleContainer.java b/net/minecraft/world/SimpleContainer.java
|
||||
index 0233c2b5e40c33330870e598431897a2ff98c2a3..3cf1819a9c82da2d2e0c43187e204353e3643369 100644
|
||||
--- a/net/minecraft/world/SimpleContainer.java
|
||||
+++ b/net/minecraft/world/SimpleContainer.java
|
||||
@@ -210,7 +210,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
|
||||
@Override
|
||||
public void setItem(int index, ItemStack stack) {
|
||||
this.items.set(index, stack);
|
||||
- stack.limitSize(this.getMaxStackSize(stack));
|
||||
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
|
||||
this.setChanged();
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
|
||||
}
|
||||
|
||||
private void moveItemsBetweenStacks(ItemStack stack, ItemStack other) {
|
||||
- int maxStackSize = this.getMaxStackSize(other);
|
||||
+ int maxStackSize = this.getMaxStackLeaves(other); // Leaves - item over-stack util
|
||||
int min = Math.min(stack.getCount(), maxStackSize - other.getCount());
|
||||
if (min > 0) {
|
||||
other.grow(min);
|
||||
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 16c42a5e35c6ee1df640e5831818099fab6338f1..f3f067c62dc024a747d059608ae7a2e8740dbff2 100644
|
||||
--- a/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -271,10 +271,15 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
|
||||
|
||||
private boolean isMergable() {
|
||||
ItemStack item = this.getItem();
|
||||
- return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < item.getMaxStackSize(); // Paper - Alternative item-despawn-rate
|
||||
+ return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(item); // Paper - Alternative item-despawn-rate // Leaves - item over-stack util
|
||||
}
|
||||
|
||||
private void tryToMerge(ItemEntity itemEntity) {
|
||||
+ // Leaves start - item over-stack util
|
||||
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.tryStackItems(this, itemEntity)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaves end - item over-stack util
|
||||
ItemStack item = this.getItem();
|
||||
ItemStack item1 = itemEntity.getItem();
|
||||
if (Objects.equals(this.target, itemEntity.target) && areMergable(item, item1)) {
|
||||
diff --git a/net/minecraft/world/entity/player/Inventory.java b/net/minecraft/world/entity/player/Inventory.java
|
||||
index 41e59f3739945ca7f6ab710c993b5c0f15fcd529..b849b04f227b43d036f4f6b3ae7accfafc389d9f 100644
|
||||
--- a/net/minecraft/world/entity/player/Inventory.java
|
||||
+++ b/net/minecraft/world/entity/player/Inventory.java
|
||||
@@ -166,10 +166,12 @@ public class Inventory implements Container, Nameable {
|
||||
}
|
||||
|
||||
private boolean hasRemainingSpaceForItem(ItemStack destination, ItemStack origin) {
|
||||
+ // Leaves start - item over-stack util
|
||||
return !destination.isEmpty()
|
||||
- && destination.isStackable()
|
||||
- && destination.getCount() < this.getMaxStackSize(destination)
|
||||
+ && org.leavesmc.leaves.util.ItemOverstackUtils.isStackable(destination)
|
||||
+ && destination.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(destination)
|
||||
&& ItemStack.isSameItemSameComponents(destination, origin); // Paper - check if itemstack is stackable first
|
||||
+ // Leaves end - item over-stack util
|
||||
}
|
||||
|
||||
// CraftBukkit start - Watch method above! :D
|
||||
@@ -182,7 +184,7 @@ public class Inventory implements Container, Nameable {
|
||||
}
|
||||
|
||||
if (this.hasRemainingSpaceForItem(itemInSlot, itemStack)) {
|
||||
- remains -= (itemInSlot.getMaxStackSize() < this.getMaxStackSize() ? itemInSlot.getMaxStackSize() : this.getMaxStackSize()) - itemInSlot.getCount();
|
||||
+ remains -= (org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInSlot) < this.getMaxStackSize() ? org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInSlot) : this.getMaxStackSize()) - itemInSlot.getCount(); // Leaves - item over-stack util
|
||||
}
|
||||
if (remains <= 0) {
|
||||
return itemStack.getCount();
|
||||
@@ -191,7 +193,7 @@ public class Inventory implements Container, Nameable {
|
||||
|
||||
ItemStack itemInOffhand = this.equipment.get(EquipmentSlot.OFFHAND);
|
||||
if (this.hasRemainingSpaceForItem(itemInOffhand, itemStack)) {
|
||||
- remains -= (itemInOffhand.getMaxStackSize() < this.getMaxStackSize() ? itemInOffhand.getMaxStackSize() : this.getMaxStackSize()) - itemInOffhand.getCount();
|
||||
+ remains -= (org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInOffhand) < this.getMaxStackSize() ? org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInOffhand) : this.getMaxStackSize()) - itemInOffhand.getCount(); // Leaves - item over-stack util
|
||||
}
|
||||
if (remains <= 0) {
|
||||
return itemStack.getCount();
|
||||
@@ -315,7 +317,7 @@ public class Inventory implements Container, Nameable {
|
||||
this.setItem(slot, item);
|
||||
}
|
||||
|
||||
- int i = this.getMaxStackSize(item) - item.getCount();
|
||||
+ int i = this.getMaxStackLeaves(item) - item.getCount(); // Leaves - item over-stack util
|
||||
int min = Math.min(count, i);
|
||||
if (min == 0) {
|
||||
return count;
|
||||
@@ -421,7 +423,7 @@ public class Inventory implements Container, Nameable {
|
||||
break;
|
||||
}
|
||||
|
||||
- int i = stack.getMaxStackSize() - this.getItem(slotWithRemainingSpace).getCount();
|
||||
+ int i = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack) - this.getItem(slotWithRemainingSpace).getCount(); // Leaves - item over-stack util
|
||||
if (this.add(slotWithRemainingSpace, stack.split(i)) && sendPacket && this.player instanceof ServerPlayer serverPlayer) {
|
||||
serverPlayer.connection.send(this.createInventoryUpdatePacket(slotWithRemainingSpace));
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/player/StackedItemContents.java b/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
index 00dbc0d125b2c8c208ffa46f9084c6317efaba90..1f57b3c60fd0cbfdd65e06f8994525ade6dc6bd9 100644
|
||||
--- a/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
+++ b/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
@@ -36,7 +36,7 @@ public class StackedItemContents {
|
||||
}
|
||||
|
||||
public void accountStack(ItemStack stack) {
|
||||
- this.accountStack(stack, stack.getMaxStackSize());
|
||||
+ this.accountStack(stack, org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack)); // Leaves - item over-stack util
|
||||
}
|
||||
|
||||
public void accountStack(ItemStack stack, int maxStackSize) {
|
||||
diff --git a/net/minecraft/world/entity/vehicle/ContainerEntity.java b/net/minecraft/world/entity/vehicle/ContainerEntity.java
|
||||
index 44276ba9c7aab306cfd12833a834ebe61cf64e7c..0a19a7782f3fa27c41e02393e887ba7cc727012b 100644
|
||||
--- a/net/minecraft/world/entity/vehicle/ContainerEntity.java
|
||||
+++ b/net/minecraft/world/entity/vehicle/ContainerEntity.java
|
||||
@@ -162,7 +162,7 @@ public interface ContainerEntity extends Container, MenuProvider {
|
||||
default void setChestVehicleItem(int slot, ItemStack stack) {
|
||||
this.unpackChestVehicleLootTable(null);
|
||||
this.getItemStacks().set(slot, stack);
|
||||
- stack.limitSize(this.getMaxStackSize(stack));
|
||||
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
|
||||
}
|
||||
|
||||
default @Nullable SlotAccess getChestVehicleSlot(final int slot) {
|
||||
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
index 3b1c6a2397950ceb167890961b635cc69aaf8950..e7ea8849e8fa942709f505145e8076f064476206 100644
|
||||
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
@@ -292,6 +292,13 @@ public abstract class AbstractContainerMenu {
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
+ // Leaves start - item over-stack util
|
||||
+ public void sendSingleSlot(int slotIndex, ItemStack item) {
|
||||
+ if (this.synchronizer != null) {
|
||||
+ this.synchronizer.sendSlotChange(this, slotIndex, item);
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaves end - item over-stack util
|
||||
private void updateDataSlotListeners(int slotIndex, int value) {
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.dataChanged(this, slotIndex, value);
|
||||
@@ -448,7 +455,7 @@ public abstract class AbstractContainerMenu {
|
||||
&& (this.quickcraftType == 2 || carried1.getCount() >= this.quickcraftSlots.size())
|
||||
&& this.canDragTo(slot1)) {
|
||||
int i2 = slot1.hasItem() ? slot1.getItem().getCount() : 0;
|
||||
- int min = Math.min(itemStack.getMaxStackSize(), slot1.getMaxStackSize(itemStack));
|
||||
+ int min = Math.min(org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack), slot1.getMaxStackSize(itemStack)); // Leaves - item over-stack util
|
||||
int min1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemStack) + i2, min);
|
||||
count -= min1 - i2;
|
||||
// slot1.setByPlayer(itemStack.copyWithCount(min1));
|
||||
@@ -556,7 +563,7 @@ public abstract class AbstractContainerMenu {
|
||||
slot.setByPlayer(carried2);
|
||||
}
|
||||
} else if (ItemStack.isSameItemSameComponents(carried, carried2)) {
|
||||
- Optional<ItemStack> optional1 = slot.tryRemove(carried.getCount(), carried2.getMaxStackSize() - carried2.getCount(), player);
|
||||
+ Optional<ItemStack> optional1 = slot.tryRemove(carried.getCount(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(carried2) - carried2.getCount(), player); // Leaves - item over-stack util
|
||||
optional1.ifPresent(itemStack2 -> {
|
||||
carried2.grow(itemStack2.getCount());
|
||||
slot.onTake(player, itemStack2);
|
||||
@@ -618,7 +625,7 @@ public abstract class AbstractContainerMenu {
|
||||
Slot slot2 = this.slots.get(slotIndex);
|
||||
if (slot2.hasItem()) {
|
||||
ItemStack itemStack = slot2.getItem();
|
||||
- this.setCarried(itemStack.copyWithCount(itemStack.getMaxStackSize()));
|
||||
+ this.setCarried(itemStack.copyWithCount(org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack))); // Leaves - item over-stack util
|
||||
}
|
||||
} else if (clickType == ClickType.THROW && this.getCarried().isEmpty() && slotIndex >= 0) {
|
||||
Slot slot2 = this.slots.get(slotIndex);
|
||||
@@ -653,15 +660,15 @@ public abstract class AbstractContainerMenu {
|
||||
int maxStackSize = button == 0 ? 1 : -1;
|
||||
|
||||
for (int i3 = 0; i3 < 2; i3++) {
|
||||
- for (int i4 = count; i4 >= 0 && i4 < this.slots.size() && itemStack.getCount() < itemStack.getMaxStackSize(); i4 += maxStackSize) {
|
||||
+ for (int i4 = count; i4 >= 0 && i4 < this.slots.size() && itemStack.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); i4 += maxStackSize) { // Leaves - item over-stack util
|
||||
Slot slot3 = this.slots.get(i4);
|
||||
if (slot3.hasItem()
|
||||
&& canItemQuickReplace(slot3, itemStack, true)
|
||||
&& slot3.mayPickup(player)
|
||||
&& this.canTakeItemForPickAll(itemStack, slot3)) {
|
||||
ItemStack item1 = slot3.getItem();
|
||||
- if (i3 != 0 || item1.getCount() != item1.getMaxStackSize()) {
|
||||
- ItemStack itemStack1 = slot3.safeTake(item1.getCount(), itemStack.getMaxStackSize() - itemStack.getCount(), player);
|
||||
+ if (i3 != 0 || item1.getCount() != org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(item1)) { // Leaves - item over-stack util
|
||||
+ ItemStack itemStack1 = slot3.safeTake(item1.getCount(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack) - itemStack.getCount(), player); // Leaves - item over-stack util
|
||||
itemStack.grow(itemStack1.getCount());
|
||||
}
|
||||
}
|
||||
@@ -763,7 +770,7 @@ public abstract class AbstractContainerMenu {
|
||||
i = endIndex - 1;
|
||||
}
|
||||
|
||||
- if (stack.isStackable()) {
|
||||
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.isStackable(stack)) { // Leaves - item over-stack util
|
||||
while (!stack.isEmpty() && (reverseDirection ? i >= startIndex : i < endIndex)) {
|
||||
Slot slot = this.slots.get(i);
|
||||
ItemStack item = slot.getItem();
|
||||
@@ -864,7 +871,7 @@ public abstract class AbstractContainerMenu {
|
||||
public static boolean canItemQuickReplace(@Nullable Slot slot, ItemStack stack, boolean stackSizeMatters) {
|
||||
boolean flag = slot == null || !slot.hasItem();
|
||||
return !flag && ItemStack.isSameItemSameComponents(stack, slot.getItem())
|
||||
- ? slot.getItem().getCount() + (stackSizeMatters ? 0 : stack.getCount()) <= stack.getMaxStackSize()
|
||||
+ ? slot.getItem().getCount() + (stackSizeMatters ? 0 : stack.getCount()) <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack) // Leaves - item over-stack util
|
||||
: flag;
|
||||
}
|
||||
|
||||
@@ -872,7 +879,7 @@ public abstract class AbstractContainerMenu {
|
||||
return switch (type) {
|
||||
case 0 -> Mth.floor((float)stack.getCount() / slots.size());
|
||||
case 1 -> 1;
|
||||
- case 2 -> stack.getMaxStackSize();
|
||||
+ case 2 -> org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack); // Leaves - item over-stack util
|
||||
default -> stack.getCount();
|
||||
};
|
||||
}
|
||||
@@ -895,7 +902,7 @@ public abstract class AbstractContainerMenu {
|
||||
for (int i = 0; i < container.getContainerSize(); i++) {
|
||||
ItemStack item = container.getItem(i);
|
||||
if (!item.isEmpty()) {
|
||||
- f += (float)item.getCount() / container.getMaxStackSize(item);
|
||||
+ f += Math.clamp((float) item.getCount() / container.getMaxStackSize(item), 0f, 1f); // Leaves - item over-stack util
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/inventory/MerchantContainer.java b/net/minecraft/world/inventory/MerchantContainer.java
|
||||
index a4203c416c7a83557055099a9ea8f43ac2b18b21..46c8026876e851ec4a31fd34c9b64623469ffb8d 100644
|
||||
--- a/net/minecraft/world/inventory/MerchantContainer.java
|
||||
+++ b/net/minecraft/world/inventory/MerchantContainer.java
|
||||
@@ -108,7 +108,7 @@ public class MerchantContainer implements Container {
|
||||
@Override
|
||||
public void setItem(int index, ItemStack stack) {
|
||||
this.itemStacks.set(index, stack);
|
||||
- stack.limitSize(this.getMaxStackSize(stack));
|
||||
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
|
||||
if (this.isPaymentSlot(index)) {
|
||||
this.updateSellItem();
|
||||
}
|
||||
diff --git a/net/minecraft/world/inventory/Slot.java b/net/minecraft/world/inventory/Slot.java
|
||||
index 2b7e245ebf3bb471a1d817c4b5d56a64790cbab7..00083df87439ff0fa56e09853931b60579520d0e 100644
|
||||
--- a/net/minecraft/world/inventory/Slot.java
|
||||
+++ b/net/minecraft/world/inventory/Slot.java
|
||||
@@ -75,7 +75,7 @@ public class Slot {
|
||||
}
|
||||
|
||||
public int getMaxStackSize(ItemStack stack) {
|
||||
- return Math.min(this.getMaxStackSize(), stack.getMaxStackSize());
|
||||
+ return Math.min(this.getMaxStackSize(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack)); // Leaves - item over-stack util
|
||||
}
|
||||
|
||||
public @Nullable Identifier getNoItemIcon() {
|
||||
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
||||
index ed2971b54afbebe37a7ff61798778a4249b79856..73a97f4f62fe7d27b441cab58c6c86ffce011060 100644
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/net/minecraft/world/item/ItemStack.java
|
||||
@@ -174,7 +174,7 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
|
||||
private int popTime;
|
||||
@Deprecated
|
||||
private @Nullable Item item;
|
||||
- PatchedDataComponentMap components;
|
||||
+ public PatchedDataComponentMap components; // Leaves - item over-stack util
|
||||
private @Nullable Entity entityRepresentation;
|
||||
|
||||
public static DataResult<ItemStack> validateStrict(ItemStack stack) {
|
||||
@@ -200,7 +200,8 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
|
||||
} else {
|
||||
Holder<Item> holder = Item.STREAM_CODEC.decode(buffer);
|
||||
DataComponentPatch dataComponentPatch = codec.decode(buffer);
|
||||
- return new ItemStack(holder, varInt, dataComponentPatch);
|
||||
+ ItemStack itemStack = new ItemStack(holder, varInt, dataComponentPatch);
|
||||
+ return org.leavesmc.leaves.util.ItemOverstackUtils.decodeMaxStackSize(itemStack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,13 +210,15 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
|
||||
if (value.isEmpty() || value.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem()
|
||||
buffer.writeVarInt(0);
|
||||
} else {
|
||||
- buffer.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), value, value.getCount())); // Paper - potentially sanitize count
|
||||
- Item.STREAM_CODEC.encode(buffer, value.getItemHolder());
|
||||
+ // Leaves start - item over-stack util
|
||||
+ final ItemStack itemStack = org.leavesmc.leaves.util.ItemOverstackUtils.encodeMaxStackSize(value.copy());
|
||||
+ buffer.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), itemStack, itemStack.getCount())); // Paper - potentially sanitize count
|
||||
+ Item.STREAM_CODEC.encode(buffer, itemStack.getItemHolder());
|
||||
// Paper start - adventure; conditionally render translatable components
|
||||
boolean prev = net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.get();
|
||||
- try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.itemStack(value))) { // pass the itemstack as context to the obfuscation session
|
||||
+ try (final io.papermc.paper.util.SafeAutoClosable ignored = io.papermc.paper.util.sanitizer.ItemObfuscationSession.withContext(c -> c.itemStack(itemStack))) { // pass the itemstack as context to the obfuscation session
|
||||
net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(true);
|
||||
- codec.encode(buffer, value.components.asPatch());
|
||||
+ codec.encode(buffer, itemStack.components.asPatch());
|
||||
} finally {
|
||||
net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(prev);
|
||||
}
|
||||
@@ -309,7 +312,7 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
|
||||
|
||||
for (ItemStack itemStack : itemContainerContents.nonEmptyItems()) {
|
||||
int count = itemStack.getCount();
|
||||
- int maxStackSize = itemStack.getMaxStackSize();
|
||||
+ int maxStackSize = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
|
||||
if (count > maxStackSize) {
|
||||
return DataResult.error(() -> "Item stack with count of " + count + " was larger than maximum: " + maxStackSize);
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java
|
||||
index c5fe15844d405a27cdae18c903dd481c25b437de..3faa541c4a4623e915269d6241e1a3a3c6e374ff 100644
|
||||
--- a/net/minecraft/world/level/block/CrafterBlock.java
|
||||
+++ b/net/minecraft/world/level/block/CrafterBlock.java
|
||||
@@ -191,7 +191,7 @@ public class CrafterBlock extends BaseEntityBlock {
|
||||
Direction direction = state.getValue(ORIENTATION).front();
|
||||
Container containerAt = HopperBlockEntity.getContainerAt(level, pos.relative(direction));
|
||||
ItemStack itemStack = stack.copy();
|
||||
- if (containerAt != null && (containerAt instanceof CrafterBlockEntity || stack.getCount() > containerAt.getMaxStackSize(stack))) {
|
||||
+ if (containerAt != null && (containerAt instanceof CrafterBlockEntity || stack.getCount() > containerAt.getMaxStackLeaves(stack))) { // Leaves - item over-stack util
|
||||
// CraftBukkit start - InventoryMoveItemEvent
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
index 9346f2deca8eeca29fa2fced416247fd1609249e..07236e86638faa3231917af507cdd37ac49b1270 100644
|
||||
--- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
@@ -412,7 +412,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
ItemStack itemStack = this.items.get(index);
|
||||
boolean flag = !stack.isEmpty() && ItemStack.isSameItemSameComponents(itemStack, stack);
|
||||
this.items.set(index, stack);
|
||||
- stack.limitSize(this.getMaxStackSize(stack));
|
||||
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
|
||||
if (index == 0 && !flag && this.level instanceof ServerLevel serverLevel) {
|
||||
this.cookingTotalTime = getTotalCookTime(serverLevel, this, this.recipeType, this.cookSpeedMultiplier); // Paper - cook speed multiplier API
|
||||
this.cookingTimer = 0;
|
||||
diff --git a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
index 8f80c469c309bf61328c4f98037495f47a38c3c1..b4127d4b4386b98205275a9a0ef8067ccf287e67 100644
|
||||
--- a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
@@ -134,7 +134,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
|
||||
@Override
|
||||
public void setItem(int slot, ItemStack stack) {
|
||||
this.getItems().set(slot, stack);
|
||||
- stack.limitSize(this.getMaxStackSize(stack));
|
||||
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
|
||||
this.setChanged();
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
index f851e0f7d727cb9dca70c578777d871af424388c..6a51bace3151646afae9de820d9c8977a0221df4 100644
|
||||
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
@@ -145,7 +145,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
public void setItem(int index, ItemStack stack) {
|
||||
this.unpackLootTable(null);
|
||||
this.getItems().set(index, stack);
|
||||
- stack.limitSize(this.getMaxStackSize(stack));
|
||||
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -741,9 +741,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
if (item.isEmpty()) {
|
||||
// Spigot start - SPIGOT-6693, SimpleContainer#setItem
|
||||
ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size
|
||||
- if (!stack.isEmpty() && stack.getCount() > destination.getMaxStackSize()) {
|
||||
+ if (!stack.isEmpty() && (stack.getCount() > destination.getMaxStackSize() || stack.getCount() > stack.getMaxStackSize())) { // Leaves - item over-stack util
|
||||
leftover = stack; // Paper - Make hoppers respect inventory max stack size
|
||||
- stack = stack.split(destination.getMaxStackSize());
|
||||
+ stack = stack.split(Math.min(destination.getMaxStackSize(), stack.getMaxStackSize())); // Leaves - item over-stack util
|
||||
}
|
||||
// Spigot end
|
||||
//IGNORE_TILE_UPDATES.set(Boolean.TRUE); // Paper - Perf: Optimize Hoppers // Folia - region threading // Luminol - vanilla hopper
|
||||
@@ -0,0 +1,64 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 17 Apr 2026 23:24:07 +0800
|
||||
Subject: [PATCH] Fix riding statistics desync
|
||||
|
||||
Referred to: https://github.com/CraftCanvasMC/Canvas/commit/057175b0c10d5a4d1d9059fd9d077750c32633b2
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 216c9263999f05c36fb4c5598b41ff70e5759f5e..6c2196726a0669bddda456a089aeec0d9d9bdfa3 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -2516,7 +2516,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
}
|
||||
}
|
||||
|
||||
- private void checkRidingStatistics(final double dx, final double dy, final double dz) {
|
||||
+ public void checkRidingStatistics(final double dx, final double dy, final double dz) { // Luminol - Fix riding statics desync (make public)
|
||||
if (this.isPassenger() && !didNotMove(dx, dy, dz)) {
|
||||
int distance = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F);
|
||||
Entity vehicle = this.getVehicle();
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 18b9e630442fd31a14e131bb9043be46e10881e3..b475a8fe259848749ee05ff6cf10e46f52f955d3 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -4194,7 +4194,13 @@ public abstract class Entity
|
||||
}
|
||||
}
|
||||
|
||||
+ // Luminol start - Fix riding statics desync
|
||||
public void adjustRiders(boolean teleport) {
|
||||
+ this.adjustRiders(teleport, false);
|
||||
+ }
|
||||
+
|
||||
+ public void adjustRiders(boolean teleport, boolean syncStatics) {
|
||||
+ // Luminol end - Fix riding statics desync
|
||||
java.util.ArrayDeque<EntityTreeNode> queue = new java.util.ArrayDeque<>();
|
||||
queue.add(this);
|
||||
|
||||
@@ -4207,14 +4213,24 @@ public abstract class Entity
|
||||
|
||||
for (EntityTreeNode passenger : passengers) {
|
||||
queue.add(passenger);
|
||||
+ // Luminol start - Fix riding statics desync
|
||||
+ final double oldX = passenger.root.getX();
|
||||
+ final double oldY = passenger.root.getY();
|
||||
+ final double oldZ = passenger.root.getZ();
|
||||
+ // Luminol end - Fix riding statics desync
|
||||
curr.root.positionRider(passenger.root, teleport ? Entity::snapTo : Entity::setPos);
|
||||
+ // Luminol start - Fix riding statics desync
|
||||
+ if (syncStatics && passenger.root instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
|
||||
+ serverPlayer.checkRidingStatistics(serverPlayer.getX() - oldX, serverPlayer.getY() - oldY, serverPlayer.getZ() - oldZ);
|
||||
+ }
|
||||
+ // Luminol end - Fix riding statics desync
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void repositionAllPassengers(boolean teleport) {
|
||||
- this.makePassengerTree().adjustRiders(teleport);
|
||||
+ this.makePassengerTree().adjustRiders(teleport, true); // Luminol - Fix riding statics desync
|
||||
}
|
||||
|
||||
protected EntityTreeNode makePassengerTree() {
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Sat, 18 Apr 2026 10:45:19 +0800
|
||||
Subject: [PATCH] Fix misbehaved ender pearls when player switched dimension
|
||||
|
||||
A fix of https://github.com/PaperMC/Folia/issues/421
|
||||
|
||||
Almost the same bug as:
|
||||
https://github.com/PaperMC/Folia/pull/418 and https://github.com/PaperMC/Folia/issues/393
|
||||
|
||||
diff --git a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
|
||||
index d0dba5cc351903fb762e231a95f302479794185f..fb00f70505a6c548cd1311d7ea55c6a501e814e3 100644
|
||||
--- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
|
||||
+++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
|
||||
@@ -264,7 +264,8 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
|
||||
int previousChunkZ = SectionPos.blockToSectionCoord(this.position().z());
|
||||
Entity owner = this.owner != null ? findOwnerIncludingDeadPlayer(serverLevel, this.owner.getUUID()) : null;
|
||||
if (owner instanceof ServerPlayer serverPlayer
|
||||
- && !owner.isAlive()
|
||||
+ // && !owner.isAlive() // Luminol - Fix misbehaved ender pearls when player switched dimension
|
||||
+ && (owner.getBukkitEntity().taskScheduler.isRetired() || serverPlayer.getHealth() <= 0.0D) // Luminol - Fix misbehaved ender pearls when player switched dimension
|
||||
&& !serverPlayer.wonGame
|
||||
&& serverPlayer.level().getGameRules().get(GameRules.ENDER_PEARLS_VANISH_ON_DEATH)) {
|
||||
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
@@ -1,216 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Fri, 11 Apr 2025 16:53:57 +0800
|
||||
Subject: [PATCH] Leaves: Old raid behavior
|
||||
|
||||
Co-authored by: huanli233 <392352840@qq.com>
|
||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/79d9ef74c2684eb49060f07e1ab31c827326c9a5/leaves-server/minecraft-patches/features/0106-Old-raid-behavior.patch)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/world/effect/BadOmenMobEffect.java b/net/minecraft/world/effect/BadOmenMobEffect.java
|
||||
index 80f17f33f670018240c854df589cf90cdeab6e70..c9af615ff9120c07787f436dbb6024e54e3a498b 100644
|
||||
--- a/net/minecraft/world/effect/BadOmenMobEffect.java
|
||||
+++ b/net/minecraft/world/effect/BadOmenMobEffect.java
|
||||
@@ -22,6 +22,11 @@ class BadOmenMobEffect extends MobEffect {
|
||||
&& !serverPlayer.isSpectator()
|
||||
&& level.getDifficulty() != Difficulty.PEACEFUL
|
||||
&& level.isVillage(serverPlayer.blockPosition())) {
|
||||
+ // Leaves start - Revert raid changes
|
||||
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
|
||||
+ return level.getRaids().createOrExtendRaid(serverPlayer, serverPlayer.blockPosition()) == null;
|
||||
+ }
|
||||
+ // Leaves end - Revert raid changes
|
||||
Raid raidAt = level.getRaidAt(serverPlayer.blockPosition());
|
||||
if (raidAt == null || raidAt.getRaidOmenLevel() < raidAt.getMaxRaidOmenLevel()) {
|
||||
serverPlayer.addEffect(new MobEffectInstance(MobEffects.RAID_OMEN, 600, amplifier));
|
||||
diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java
|
||||
index dcdd6f230ff153a7b58d13b963d32376b1905b72..be9c78f2cf121e8ae55c1b18685877637a25ec80 100644
|
||||
--- a/net/minecraft/world/entity/raid/Raid.java
|
||||
+++ b/net/minecraft/world/entity/raid/Raid.java
|
||||
@@ -264,7 +264,7 @@ public class Raid {
|
||||
}
|
||||
|
||||
public boolean absorbRaidOmen(ServerPlayer player) {
|
||||
- MobEffectInstance effect = player.getEffect(MobEffects.RAID_OMEN);
|
||||
+ MobEffectInstance effect = player.getEffect(fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior ? MobEffects.BAD_OMEN : MobEffects.RAID_OMEN); // Leaves - old Raid Behavior
|
||||
if (effect == null) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -341,7 +341,13 @@ public class Raid {
|
||||
}
|
||||
|
||||
if (flag1) {
|
||||
- this.waveSpawnPos = this.getValidSpawnPos(level);
|
||||
+ // Leaves Start - old FindSpawnPosition
|
||||
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
|
||||
+ this.waveSpawnPos = this.preCalcRavagerSpawnLocation(level, this.raidCooldownTicks < 100 ? 1 : 0);
|
||||
+ } else {
|
||||
+ this.waveSpawnPos = this.getValidSpawnPos(level);
|
||||
+ }
|
||||
+ // Leaves End - old FindSpawnPosition
|
||||
}
|
||||
|
||||
if (this.raidCooldownTicks == 300 || this.raidCooldownTicks % 20 == 0) {
|
||||
@@ -396,7 +402,14 @@ public class Raid {
|
||||
int i = 0;
|
||||
|
||||
while (this.shouldSpawnGroup()) {
|
||||
- BlockPos blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
|
||||
+ // Leaves Start - old FindSpawnPosition
|
||||
+ BlockPos blockPos;
|
||||
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior) {
|
||||
+ blockPos = this.getRavagerSpawnLocation(level, i, 20);
|
||||
+ } else {
|
||||
+ blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
|
||||
+ }
|
||||
+ // Leaves End - old FindSpawnPosition
|
||||
if (blockPos != null) {
|
||||
this.started = true;
|
||||
this.spawnGroup(level, blockPos);
|
||||
@@ -408,7 +421,7 @@ public class Raid {
|
||||
i++;
|
||||
}
|
||||
|
||||
- if (i > 5) {
|
||||
+ if (i > (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior ? 3 : 5)) { // Leaves - old FindSpawnPosition
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(level, this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE); // CraftBukkit
|
||||
this.stop();
|
||||
break;
|
||||
@@ -702,7 +715,7 @@ public class Raid {
|
||||
int i2 = this.center.getX() + Mth.floor(Mth.cos(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
|
||||
int i3 = this.center.getZ() + Mth.floor(Mth.sin(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
|
||||
int height = level.getHeight(Heightmap.Types.WORLD_SURFACE, i2, i3);
|
||||
- if (Mth.abs(height - this.center.getY()) <= 96) {
|
||||
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior || Mth.abs(height - this.center.getY()) <= 96) { // Leaves - skippable
|
||||
mutableBlockPos.set(i2, height, i3);
|
||||
if (!level.isVillage(mutableBlockPos) || i <= 7) {
|
||||
int i4 = 10;
|
||||
@@ -721,6 +734,36 @@ public class Raid {
|
||||
return null;
|
||||
}
|
||||
|
||||
+ // Leaves Start - old FindSpawnPosition
|
||||
+ @Nullable
|
||||
+ private BlockPos findRandomSpawnPos(ServerLevel level, int n, int n2) {
|
||||
+ int n3 = 2 - n;
|
||||
+ BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
+ SpawnPlacementType spawnPlacementType = SpawnPlacements.getPlacementType(EntityType.RAVAGER);
|
||||
+ for (int i = 0; i < n2; ++i) {
|
||||
+ float f = level.random.nextFloat() * ((float)Math.PI * 2);
|
||||
+ int n4 = this.center.getX() + Mth.floor(Mth.cos(f) * 32.0f * (float)n3) + level.random.nextInt(5);
|
||||
+ int n5 = this.center.getZ() + Mth.floor(Mth.sin(f) * 32.0f * (float)n3) + level.random.nextInt(5);
|
||||
+ int n6 = level.getHeight(Heightmap.Types.WORLD_SURFACE, n4, n5);
|
||||
+ mutableBlockPos.set(n4, n6, n5);
|
||||
+ if (level.isVillage(mutableBlockPos) && n < 2) continue;
|
||||
+ if (!level.hasChunksAt(mutableBlockPos.getX() - 10, mutableBlockPos.getZ() - 10, mutableBlockPos.getX() + 10, mutableBlockPos.getZ() + 10) || !level.isPositionEntityTicking(mutableBlockPos) || !spawnPlacementType.isSpawnPositionOk(level, mutableBlockPos, EntityType.RAVAGER) && (!level.getBlockState((BlockPos)mutableBlockPos.below()).is(Blocks.SNOW) || !level.getBlockState(mutableBlockPos).isAir())) continue;
|
||||
+ return mutableBlockPos;
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private Optional<BlockPos> getValidSpawnPos(ServerLevel level, int n) {
|
||||
+ for (int i = 0; i < 3; ++i) {
|
||||
+ BlockPos blockPos = this.findRandomSpawnPos(level, n, 1);
|
||||
+ if (blockPos == null) continue;
|
||||
+ return Optional.of(blockPos);
|
||||
+ }
|
||||
+ return Optional.empty();
|
||||
+ }
|
||||
+ // Leaves End - old FindSpawnPosition
|
||||
+
|
||||
+
|
||||
private boolean addWaveMob(ServerLevel level, int wave, Raider raider) {
|
||||
// Folia start - make raids thread-safe
|
||||
if (!this.ownsRaid(level)) {
|
||||
@@ -883,4 +926,43 @@ public class Raid {
|
||||
this.spawnsPerWaveBeforeBonus = spawnsPerWaveBeforeBonus;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Leaves start - old FindSpawnPosition
|
||||
+ private BlockPos getRavagerSpawnLocation(ServerLevel serverWorld, int proximity, int tries) {
|
||||
+ int i = proximity == 0 ? 2 : 2 - proximity;
|
||||
+ BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
+ SpawnPlacementType spawnLocation = SpawnPlacements.getPlacementType(EntityType.RAVAGER);
|
||||
+
|
||||
+ for (int j = 0; j < tries; j++) {
|
||||
+ float f = serverWorld.random.nextFloat() * (float) (Math.PI * 2);
|
||||
+ int k = this.center.getX() + Mth.floor(Mth.cos(f) * 32.0F * (float) i + serverWorld.random.nextInt(5));
|
||||
+ int l = this.center.getZ() + Mth.floor(Mth.sin(f) * 32.0F * (float) i + serverWorld.random.nextInt(5));
|
||||
+ int m = serverWorld.getHeight(Heightmap.Types.WORLD_SURFACE, k, l);
|
||||
+ mutable.set(k, m, l);
|
||||
+
|
||||
+ if (serverWorld.isVillage(mutable) && proximity < 2) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (serverWorld.hasChunksAt(mutable.getX() - 10, mutable.getZ() - 10, mutable.getX() + 10, mutable.getZ() + 10)
|
||||
+ && serverWorld.isPositionEntityTicking(mutable)
|
||||
+ && (spawnLocation.isSpawnPositionOk(serverWorld, mutable, EntityType.RAVAGER)
|
||||
+ || serverWorld.getBlockState(mutable.below()).is(Blocks.SNOW)
|
||||
+ && serverWorld.getBlockState(mutable).isAir())
|
||||
+ ) {
|
||||
+ return mutable;
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private Optional<BlockPos> preCalcRavagerSpawnLocation(ServerLevel serverWorld, int proximity) {
|
||||
+ for (int i = 0; i < 3; i++) {
|
||||
+ BlockPos blockPos = this.getRavagerSpawnLocation(serverWorld, proximity, 1);
|
||||
+ if (blockPos != null) {
|
||||
+ return Optional.of(blockPos);
|
||||
+ }
|
||||
+ }
|
||||
+ return Optional.empty();
|
||||
+ }
|
||||
+ // Leaves end - old FindSpawnPosition
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
|
||||
index 5e8245e6dd8a07ece83dd1bc20e351a92044e7a0..2b7894a4104d4cb237746a3e66d4368b6f8f3c1e 100644
|
||||
--- a/net/minecraft/world/entity/raid/Raider.java
|
||||
+++ b/net/minecraft/world/entity/raid/Raider.java
|
||||
@@ -127,6 +127,43 @@ public abstract class Raider extends PatrollingMonster {
|
||||
|
||||
currentRaid.removeFromRaid(serverLevel, this, false);
|
||||
}
|
||||
+
|
||||
+ // Leaves start - Revert raid changes
|
||||
+ if (this.level() instanceof ServerLevel) {
|
||||
+ if (fun.bm.lophine.config.modules.function.OldFeatureConfig.oldRaidBehavior && !this.hasRaid()) {
|
||||
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
|
||||
+ net.minecraft.world.entity.player.Player entityhuman = null;
|
||||
+ if (entity instanceof net.minecraft.world.entity.player.Player player) {
|
||||
+ entityhuman = player;
|
||||
+ } else if (entity instanceof net.minecraft.world.entity.animal.wolf.Wolf wolf) {
|
||||
+ LivingEntity entityliving = wolf.getOwner();
|
||||
+ if (wolf.isTame() && entityliving instanceof net.minecraft.world.entity.player.Player player) {
|
||||
+ entityhuman = player;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (entityhuman != null && !itemstack.isEmpty() && this.isCaptain()) {
|
||||
+ net.minecraft.world.effect.MobEffectInstance mobeffect = entityhuman.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN);
|
||||
+ int i = 1;
|
||||
+
|
||||
+ if (mobeffect != null) {
|
||||
+ i += mobeffect.getAmplifier();
|
||||
+ entityhuman.removeEffectNoUpdate(net.minecraft.world.effect.MobEffects.BAD_OMEN);
|
||||
+ } else {
|
||||
+ --i;
|
||||
+ }
|
||||
+
|
||||
+ i = net.minecraft.util.Mth.clamp(i, 0, 4);
|
||||
+ net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, 120000, i, false, false, true);
|
||||
+
|
||||
+ if (serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.RAIDS)) {
|
||||
+ entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit
|
||||
+ }
|
||||
+ this.setPatrolLeader(false);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaves end - Revert raid changes
|
||||
}
|
||||
|
||||
super.die(damageSource);
|
||||
@@ -0,0 +1,21 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Thu, 2 Apr 2026 12:26:24 +0800
|
||||
Subject: [PATCH] Fix long commands support
|
||||
|
||||
Some long commands can be run through the dialog command, but paper has prohibited it.
|
||||
Revert to vanilla to fix it.
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/game/ServerboundChatCommandPacket.java b/net/minecraft/network/protocol/game/ServerboundChatCommandPacket.java
|
||||
index 491af2413a4e793a121fec368259ff8211ed031e..042cb4792b0084f143608f05dd08da133a31e435 100644
|
||||
--- a/net/minecraft/network/protocol/game/ServerboundChatCommandPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ServerboundChatCommandPacket.java
|
||||
@@ -12,7 +12,7 @@ public record ServerboundChatCommandPacket(String command) implements Packet<Ser
|
||||
);
|
||||
|
||||
private ServerboundChatCommandPacket(final FriendlyByteBuf input) {
|
||||
- this(input.readUtf(MAX_CHAT_PACKET_INPUT_SIZE)); // Paper - limit chat command inputs
|
||||
+ this(me.earthme.luminol.config.modules.fixes.LongCommandSupportConfig.enabled ? input.readUtf() : input.readUtf(MAX_CHAT_PACKET_INPUT_SIZE)); // Paper - limit chat command inputs // Luminol - add support for long command inputs
|
||||
}
|
||||
|
||||
private void write(final FriendlyByteBuf output) {
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Mon, 20 Apr 2026 01:02:43 +0800
|
||||
Subject: [PATCH] Fix creative player item pick
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 223793bea54a483fefc66caa7e07b29ab351c339..303b9befb30d7156a9a71900ac1a6ea8f7e8d876 100644
|
||||
--- a/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -420,7 +420,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
Item item = itemStack.getItem();
|
||||
int orgCount = itemStack.getCount();
|
||||
// CraftBukkit start - fire PlayerPickupItemEvent
|
||||
- int canHold = player.getInventory().canHold(itemStack);
|
||||
+ int canHold = player.hasInfiniteMaterials() ? orgCount : player.getInventory().canHold(itemStack); // Luminol - Fix creative item picking
|
||||
int remaining = orgCount - canHold;
|
||||
boolean flyAtPlayer = false; // Paper
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Mon, 20 Apr 2026 01:10:30 +0800
|
||||
Subject: [PATCH] Fix entity portal-teleport speed
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 35ab432bbd59aba80a6eaca1769e6aa82c8a7e46..6950fa2462353f30ee02e1d0091cfcf289f63939 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1492,7 +1492,27 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
||||
foliaProfiler.startTimer(timerId);
|
||||
try {
|
||||
// Folia end - profiler
|
||||
+ // Luminol start - Entity portal-teleport speed fix
|
||||
if (isActive) { // Paper - EAR 2
|
||||
+ if (!(entity instanceof Player) && entity.teleportTickType == 2) { // Luminol - after portal compensate tick
|
||||
+ entity.tick();
|
||||
+ entity.tick();
|
||||
+ entity.teleportTickType = 0;
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (entity.handlePortal()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ } else if (!(entity instanceof Player) && entity.teleportTickType == 1) { // Luminol - portal teleport only
|
||||
+ entity.teleportTickType++;
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (entity.handlePortal()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ } else {
|
||||
entity.tick();
|
||||
// Folia start - region threading
|
||||
if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) {
|
||||
@@ -1503,6 +1523,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
||||
// portalled
|
||||
return;
|
||||
}
|
||||
+ }
|
||||
+ // Luminol end - Entity portal-teleport speed fix
|
||||
// Folia end - region threading
|
||||
} else {entity.inactiveTick();} // Paper - EAR 2
|
||||
profiler.pop();
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index b475a8fe259848749ee05ff6cf10e46f52f955d3..5e7cf38d241591715fec9ec008d3ac87bbaef662 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -387,6 +387,7 @@ public abstract class Entity
|
||||
public long activatedTick = Integer.MIN_VALUE;
|
||||
public boolean isTemporarilyActive;
|
||||
public long activatedImmunityTick = Integer.MIN_VALUE;
|
||||
+ public int teleportTickType = 0;// Luminol - Entity portal-teleport speed fix
|
||||
|
||||
public void inactiveTick() {
|
||||
}
|
||||
@@ -3591,6 +3592,7 @@ public abstract class Entity
|
||||
} else {
|
||||
if (this.portalProcess == null || !this.portalProcess.isSamePortal(portal)) {
|
||||
this.portalProcess = new PortalProcessor(portal, pos.immutable());
|
||||
+ this.teleportTickType = 1; // Luminol - Entity portal-teleport speed fix
|
||||
} else if (!this.portalProcess.isInsidePortalThisTick()) {
|
||||
this.portalProcess.updateEntryPosition(pos.immutable());
|
||||
this.portalProcess.setAsInsidePortalThisTick(true);
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Fri, 15 Aug 2025 02:29:30 +0800
|
||||
Subject: [PATCH] Compatibility fix for Raid Revert and Cross Region Damage
|
||||
Trace
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 5bae274f5ee869e540e4330e03af671b6b18313d..3fe9afe55b4d61db8030479d3d74b8656679cb10 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1240,6 +1240,29 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
}
|
||||
}
|
||||
|
||||
+ // Lophine Start - raid revert adapt Cross Region Damage trace
|
||||
+ public boolean addEffect(MobEffectInstance effectInstance, EntityPotionEffectEvent.Cause cause, boolean fireEvent, boolean async) {
|
||||
+ if (!async || ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this)) {
|
||||
+ return addEffect(effectInstance, this, cause, fireEvent);
|
||||
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
|
||||
+ postToAddEffect(effectInstance, this, cause, fireEvent);
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private void postToAddEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) {
|
||||
+ if (entity != null)
|
||||
+ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> {
|
||||
+ try {
|
||||
+ addEffect(effectInstance, nmsEntity, cause, fireEvent);
|
||||
+ } catch (Throwable ex) {
|
||||
+ LOGGER.error(ex.getMessage(), ex);
|
||||
+ }
|
||||
+ }, null, 1L );
|
||||
+ }
|
||||
+ // Lophine End - raid revert adapt Cross Region Damage trace
|
||||
+
|
||||
public boolean canBeAffected(MobEffectInstance effectInstance) {
|
||||
if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) {
|
||||
return !effectInstance.is(MobEffects.INFESTED);
|
||||
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
|
||||
index 2b7894a4104d4cb237746a3e66d4368b6f8f3c1e..03e3290367790add702a5856aaff3be465ea548c 100644
|
||||
--- a/net/minecraft/world/entity/raid/Raider.java
|
||||
+++ b/net/minecraft/world/entity/raid/Raider.java
|
||||
@@ -157,7 +157,7 @@ public abstract class Raider extends PatrollingMonster {
|
||||
net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, 120000, i, false, false, true);
|
||||
|
||||
if (serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.RAIDS)) {
|
||||
- entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit
|
||||
+ entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true, fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled); // Lophine - raid revert adapt Cross Region Damage trace
|
||||
}
|
||||
this.setPatrolLeader(false);
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Wed, 24 Jun 2026 22:52:13 +0800
|
||||
Subject: [PATCH] Fix player auto saving ignores interval
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 6c2196726a0669bddda456a089aeec0d9d9bdfa3..0802483484015fd92dec211aae9fd33e45621f74 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -208,7 +208,7 @@ import org.slf4j.Logger;
|
||||
|
||||
public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
- public static final long LAST_SAVE_ABSENT = Long.MIN_VALUE; public long lastSave = LAST_SAVE_ABSENT; // Paper // Folia - threaded regions - changed to nanoTime
|
||||
+ public static final long LAST_SAVE_ABSENT = Long.MIN_VALUE; public long lastSave = System.nanoTime(); // Paper // Folia - threaded regions - changed to nanoTime // Luminol - Fix player auto saving ignores interval
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
private static final int FLY_STAT_RECORDING_SPEED = 25;
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Tue, 21 Apr 2026 01:15:09 +0800
|
||||
Subject: [PATCH] Force disable builtin spark plugin
|
||||
|
||||
The spark passed down from paper has some memory leaking issue, so we fully removed it from the code to prevent that memory leaking issue.
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index dd63f14cf6b857202146348b2242673af1883cb7..88ccf32b3c1b3506fb76be5ae520168b6b167aa3 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -672,8 +672,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
// Paper end - Configurable player collision; Handle collideRule team for player collision toggle
|
||||
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
|
||||
- this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
|
||||
- this.server.spark.enableAfterPlugins(this.server); // Paper - spark
|
||||
+ if (false) this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark // Luminol - Force disable builtin spark
|
||||
+ if (false) this.server.spark.enableAfterPlugins(this.server); // Paper - spark // Luminol - Force disable builtin spark
|
||||
io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setValid(); // Paper - reset invalid state for event fire below
|
||||
io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, org.bukkit.plugin.Plugin.class, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); // Paper - call commands event for regular plugins
|
||||
this.server.getCommandMap().registerServerAliases(); // Paper - relocate initial CommandMap#registerServerAliases() call
|
||||
@@ -1087,7 +1087,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
||||
- this.server.spark.disable(); // Paper - spark
|
||||
+ if (false) this.server.spark.disable(); // Paper - spark // Luminol - Force disable builtin spark
|
||||
this.server.disablePlugins();
|
||||
this.server.waitForAsyncTasksShutdown(); // Paper - Wait for Async Tasks during shutdown
|
||||
}
|
||||
@@ -1351,7 +1351,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.statusIcon = this.loadStatusIcon().orElse(null);
|
||||
this.status = this.buildServerStatus();
|
||||
|
||||
- this.server.spark.enableBeforePlugins(); // Paper - spark
|
||||
+ if (false) this.server.spark.enableBeforePlugins(); // Paper - spark // Luminol - Force disable builtin spark
|
||||
// Folia start - region threading
|
||||
if (true) {
|
||||
io.papermc.paper.threadedregions.RegionizedServer.getInstance().init(); // Folia - region threading - only after loading worlds
|
||||
@@ -1665,7 +1665,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
if (this.emptyTicks >= emptyTickThreshold) {
|
||||
- this.server.spark.tickStart(); // Paper - spark
|
||||
+ if (false) this.server.spark.tickStart(); // Paper - spark // Luminol - Force disable builtin spark
|
||||
if (this.emptyTicks == emptyTickThreshold) {
|
||||
LOGGER.info("Server empty for {} seconds, pausing", this.pauseWhenEmptySeconds());
|
||||
this.autoSave();
|
||||
@@ -1684,7 +1684,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// Paper end - avoid issues with certain tasks not processing during sleep
|
||||
//this.server.spark.executeMainThreadTasks(); // Paper - spark // Folia - region threading
|
||||
this.tickConnection();
|
||||
- this.server.spark.tickEnd(((double)(System.nanoTime() - this.currentTickStart) / 1000000D)); // Paper - spark
|
||||
+ if (false) this.server.spark.tickEnd(((double)(System.nanoTime() - this.currentTickStart) / 1000000D)); // Paper - spark // Luminol - Force disable builtin spark
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1697,7 +1697,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
};
|
||||
// Folia end - region threading
|
||||
|
||||
- this.server.spark.tickStart(); // Paper - spark
|
||||
+ if (false) this.server.spark.tickStart(); // Paper - spark // Luminol - Force disable builtin spark
|
||||
new com.destroystokyo.paper.event.server.ServerTickStartEvent((int)region.getCurrentTick()).callEvent(); // Paper - Server Tick Events // Folia - region threading
|
||||
// Folia start - region threading
|
||||
if (region != null) {
|
||||
@@ -1784,7 +1784,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
long remaining = scheduledEnd - endTime; // Folia - region ticking
|
||||
new com.destroystokyo.paper.event.server.ServerTickEndEvent((int)io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(), ((double)(endTime - startTime) / 1000000D), remaining).callEvent(); // Folia - region ticking
|
||||
// Paper end - Server Tick Events
|
||||
- this.server.spark.tickEnd(((double)(endTime - startTime) / 1000000D)); // Paper - spark // Folia - region threading
|
||||
+ if (false) this.server.spark.tickEnd(((double)(endTime - startTime) / 1000000D)); // Paper - spark // Folia - region threading // Luminol - Force disable builtin spark
|
||||
// Folia - region threading
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 1ad4704523a3d90414ac514488207b1b5def9afd..1145d5839e621a02b7972c2ff1142f51db2237de 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -239,7 +239,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
|
||||
// Paper end - initialize global and world-defaults configuration
|
||||
me.earthme.luminol.config.ConfigManager.loadConfigFiles(); // Luminol - load config file
|
||||
- this.server.spark.enableEarlyIfRequested(); // Paper - spark
|
||||
+ if (false) this.server.spark.enableEarlyIfRequested(); // Paper - spark // Luminol - Force disable builtin spark
|
||||
// Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save
|
||||
if (this.convertOldUsers()) {
|
||||
this.services().nameToIdCache().save(false); // Paper
|
||||
@@ -249,7 +249,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread
|
||||
consoleThread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized
|
||||
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
|
||||
- this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
|
||||
+ if (false) this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark // Luminol - Force disable builtin spark
|
||||
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
|
||||
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 19:10:30 +0800
|
||||
Subject: [PATCH] Prevent tamable animals check can teleport in an unloaded
|
||||
chunk
|
||||
|
||||
Based on the implementation of Canvas(https://github.com/CraftCanvasMC/Canvas/commit/af2aacb12cbccfd328dda4961167786f5d9dad53)
|
||||
|
||||
We need to check canTeleport for TamableAnimal but this logic could do the check in another tick region itself, so we need to prevent that. But it needs to push off this check to schedule to the correct tickregion, which needs costly rewriting of this logic, so we could simply allow the read when the owner's position is loaded
|
||||
|
||||
diff --git a/net/minecraft/world/entity/TamableAnimal.java b/net/minecraft/world/entity/TamableAnimal.java
|
||||
index 95ba821a895c7ea8fffcbf1df2e7b3c174463d9e..b0a01673224522552672b7c8c9aa219108e8010f 100644
|
||||
--- a/net/minecraft/world/entity/TamableAnimal.java
|
||||
+++ b/net/minecraft/world/entity/TamableAnimal.java
|
||||
@@ -318,7 +318,8 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity {
|
||||
return false;
|
||||
}
|
||||
|
||||
- BlockState blockStateBelow = this.level().getBlockState(pos.below());
|
||||
+ BlockState blockStateBelow = this.level().getBlockStateIfLoaded(pos.below()); // Luminol - Prevent tamable animals check can teleport in an unloaded chunk
|
||||
+ if (blockStateBelow == null) return false; // Luminol - Prevent tamable animals check can teleport in an unloaded chunk
|
||||
if (!this.canFlyToOwner() && blockStateBelow.getBlock() instanceof LeavesBlock) {
|
||||
return false;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Mon, 19 May 2025 00:42:17 +0800
|
||||
Subject: [PATCH] Old zombie reinforcement
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/monster/zombie/Zombie.java b/net/minecraft/world/entity/monster/zombie/Zombie.java
|
||||
index 7a9394d4555464312418964f1a7a5d2581496774..3fcd32cc77458ce196ce0e468c1a99f456a57604 100644
|
||||
--- a/net/minecraft/world/entity/monster/zombie/Zombie.java
|
||||
+++ b/net/minecraft/world/entity/monster/zombie/Zombie.java
|
||||
@@ -314,7 +314,7 @@ public class Zombie extends Monster {
|
||||
int floor = Mth.floor(this.getX());
|
||||
int floor1 = Mth.floor(this.getY());
|
||||
int floor2 = Mth.floor(this.getZ());
|
||||
- EntityType<? extends Zombie> type = this.getType();
|
||||
+ EntityType<? extends Zombie> type = fun.bm.lophine.config.modules.function.OldFeatureConfig.oldZombieReinforcement ? EntityType.ZOMBIE : this.getType(); // Lophine - old zombie reinforcement
|
||||
Zombie zombie = type.create(level, EntitySpawnReason.REINFORCEMENT);
|
||||
if (zombie == null) {
|
||||
return true;
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 1 May 2026 21:52:07 +0800
|
||||
Subject: [PATCH] Prevent teleprotAsync calls in move events
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index c86b1fd5e200c478d178be32791b6e8c960d47e2..9be6d486082d344fb91fd74207eee83ca2f8e869 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -730,7 +730,9 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
Location oldTo = to.clone();
|
||||
PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
|
||||
+ this.player.blockTeleportAsync = true; // Luminol - Prevent teleprotAsync calls during move events
|
||||
this.cserver.getPluginManager().callEvent(event);
|
||||
+ this.player.blockTeleportAsync = false; // Luminol - Prevent teleprotAsync calls during move events
|
||||
|
||||
// If the event is cancelled we move the player back to their old location.
|
||||
if (event.isCancelled()) {
|
||||
@@ -1741,7 +1743,9 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
Location oldTo = to.clone();
|
||||
PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
|
||||
+ this.player.blockTeleportAsync = true; // Luminol - Prevent teleprotAsync calls during move events
|
||||
this.cserver.getPluginManager().callEvent(event);
|
||||
+ this.player.blockTeleportAsync = false; // Luminol - Prevent teleprotAsync calls during move events
|
||||
|
||||
// If the event is cancelled we move the player back to their old location.
|
||||
if (event.isCancelled()) {
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 5e7cf38d241591715fec9ec008d3ac87bbaef662..51dacbe395c85aba9b81831e511a413b303ca675 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -4472,12 +4472,25 @@ public abstract class Entity
|
||||
teleportTarget.cause(), teleportFlags, teleportComplete
|
||||
);
|
||||
}
|
||||
+ // Luminol start - Prevent teleprotAsync calls in move events
|
||||
+ public boolean blockTeleportAsync = false;
|
||||
+ // Luminol end
|
||||
|
||||
public final boolean teleportAsync(ServerLevel destination, Vec3 pos, Float yaw, Float pitch, Vec3 velocity,
|
||||
org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, long teleportFlags,
|
||||
java.util.function.Consumer<Entity> teleportComplete) {
|
||||
ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot teleport entity async");
|
||||
|
||||
+ // Luminol start - Prevent teleprotAsync calls in move events
|
||||
+ if (this.blockTeleportAsync && me.earthme.luminol.config.modules.fixes.PreventIncorrectTeleportAsyncConfig.enabled) {
|
||||
+ if (me.earthme.luminol.config.modules.fixes.PreventIncorrectTeleportAsyncConfig.throwWhenCaught) {
|
||||
+ throw new IllegalStateException("Call teleportAsync during move events!");
|
||||
+ }
|
||||
+
|
||||
+ LOGGER.error("Calling teleportAsync during move events!", new Throwable());
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Luminol end
|
||||
if (!ServerLevel.isInSpawnableBounds(new BlockPos(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getBlockX(pos), ca.spottedleaf.moonrise.common.util.CoordinateUtils.getBlockY(pos), ca.spottedleaf.moonrise.common.util.CoordinateUtils.getBlockZ(pos)))) {
|
||||
return false;
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java b/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
||||
index 3fcd534cee1f605a710ffc43eff4b5106c7dd40c..9b887b40236a212de513e3ceece1abfec5372ae2 100644
|
||||
--- a/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
||||
+++ b/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
||||
@@ -282,7 +282,9 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
||||
|
||||
if (this.lastLocation != null && !this.lastLocation.equals(to)) {
|
||||
org.bukkit.event.vehicle.VehicleMoveEvent event = new org.bukkit.event.vehicle.VehicleMoveEvent(vehicle, this.lastLocation, to);
|
||||
+ this.blockTeleportAsync = true; // Luminol - Prevent teleprotAsync calls during move events
|
||||
event.callEvent();
|
||||
+ this.blockTeleportAsync = false; // Luminol - Prevent teleprotAsync calls during move events
|
||||
}
|
||||
this.lastLocation = vehicle.getLocation();
|
||||
// CraftBukkit end
|
||||
diff --git a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java
|
||||
index 5ad77636d0681d1f0341cff4482ba6ad52f3583b..0ae8b5222c5f2f608af352cbaa866c493dd065aa 100644
|
||||
--- a/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java
|
||||
+++ b/net/minecraft/world/entity/vehicle/minecart/AbstractMinecart.java
|
||||
@@ -318,7 +318,9 @@ public abstract class AbstractMinecart extends VehicleEntity {
|
||||
new org.bukkit.event.vehicle.VehicleUpdateEvent(vehicle).callEvent();
|
||||
|
||||
if (!from.equals(to)) {
|
||||
+ this.blockTeleportAsync = true; // Luminol - Prevent teleprotAsync calls during move events
|
||||
new org.bukkit.event.vehicle.VehicleMoveEvent(vehicle, from, to).callEvent();
|
||||
+ this.blockTeleportAsync = false; // Luminol - Prevent teleprotAsync calls during move events
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.updateFluidInteraction();
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 19:19:31 +0800
|
||||
Subject: [PATCH] Sync dragon part when teleportation or firstly created
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
|
||||
index aa53138b3670a8337b639472a6ab5ce46702ff76..ed27b73e787782f328906b2a061feeca25d42a24 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
|
||||
@@ -93,6 +93,7 @@ public final class ServerEntityLookup extends EntityLookup {
|
||||
if (entity instanceof ThrownEnderpearl enderpearl) {
|
||||
this.addEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()), enderpearl.getId()); // Folia - region threading
|
||||
}
|
||||
+ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon dragon) dragon.syncDragonPartsAfterTeleportTransform(); // Luminol - Sync dragon part when teleportation or firstly created
|
||||
entity.registerScheduler(); // Paper - optimise Folia entity scheduler
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 51dacbe395c85aba9b81831e511a413b303ca675..e2e1b101de8afbec7d853593c527e35111c94319 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -4456,6 +4456,7 @@ public abstract class Entity
|
||||
Entity copy = this.getType().create(destination, EntitySpawnReason.DIMENSION_TRAVEL);
|
||||
copy.restoreFrom(this);
|
||||
copy.transform(pos, yaw, pitch, velocity);
|
||||
+ if (copy instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon dragon) dragon.syncDragonPartsAfterTeleportTransform(); // Luminol - Sync dragon part when teleportation or firstly created
|
||||
// vanilla code used to call remove _after_ copying, and some stuff is required to be after copy - so add hook here
|
||||
// for example, clearing of inventory after switching dimensions
|
||||
this.postRemoveAfterChangingDimensions();
|
||||
diff --git a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
index ab921ab4b4cc860abd77744f2bd201013e136e51..fd85816ec78c99f45c740ebf8052ff41f4859ed6 100644
|
||||
--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
+++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
@@ -1011,4 +1011,12 @@ public class EnderDragon extends Mob implements Enemy {
|
||||
return 500;
|
||||
}
|
||||
// Paper end - init expToDrop for already dying spawned dragon
|
||||
+
|
||||
+ // Luminol start - Sync dragon part when teleportation or firstly created
|
||||
+ public void syncDragonPartsAfterTeleportTransform() {
|
||||
+ for (EnderDragonPart part : this.subEntities) {
|
||||
+ this.tickPart(part, 0.0, 0.0, 0.0); // offset -> 0.0
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
@@ -1,773 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Sat, 30 Aug 2025 17:16:32 +0800
|
||||
Subject: [PATCH] Leaves: Fakeplayer
|
||||
|
||||
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java b/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java
|
||||
index 368a9d33f93c2e85abe4cf10df5a85c09fb03dd6..2b78040daeb3b09c08494cbc1d4a9d36080895f9 100644
|
||||
--- a/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java
|
||||
+++ b/net/minecraft/advancements/criterion/SimpleCriterionTrigger.java
|
||||
@@ -39,6 +39,7 @@ public abstract class SimpleCriterionTrigger<T extends SimpleCriterionTrigger.Si
|
||||
}
|
||||
|
||||
protected void trigger(ServerPlayer player, Predicate<T> testTrigger) {
|
||||
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) return; // Leaves - bot skip
|
||||
PlayerAdvancements advancements = player.getAdvancements();
|
||||
Set<CriterionTrigger.Listener<T>> set = (Set) advancements.criterionData.get(this); // Paper - fix PlayerAdvancements leak
|
||||
if (set != null && !set.isEmpty()) {
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index 9f444988d40208a1bfa9f147ef80489f81115e93..ab2fa0b86564622501238305714fff014e2b2a56 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -74,7 +74,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public boolean preparing = true;
|
||||
// Spigot end
|
||||
private volatile @Nullable PacketListener disconnectListener;
|
||||
- private volatile @Nullable PacketListener packetListener;
|
||||
+ public volatile @Nullable PacketListener packetListener; // Leaves - private -> protected // Lophine protected -> public
|
||||
private @Nullable DisconnectionDetails disconnectionDetails;
|
||||
private boolean encrypted;
|
||||
private final java.util.concurrent.atomic.AtomicBoolean disconnectionHandled = new java.util.concurrent.atomic.AtomicBoolean(false); // Folia - region threading - may be called concurrently during configuration stage
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index d5b680fc6e13ec26d0db2448009e4cbe59933e22..385c71d70ed9e5a3ae25fbecaefd6773c467d31d 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -425,6 +425,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
// Folia end - regionised ticking
|
||||
|
||||
+ private org.leavesmc.leaves.bot.BotList botList; // Leaves - fakeplayer
|
||||
+
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
AtomicReference<S> atomicReference = new AtomicReference<>();
|
||||
@@ -1050,6 +1052,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// Folia end - region threading
|
||||
|
||||
public void stopServer() {
|
||||
+ // Leaves end - save or remove bot
|
||||
+ if (!this.getBotList().forceShutdown && !this.getBotList().removeAll()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaves end - save or remove bot
|
||||
// Folia start - region threading
|
||||
// halt scheduler
|
||||
// don't wait, we may be on a scheduler thread
|
||||
@@ -1668,7 +1675,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
int i = this.pauseWhenEmptySeconds() * 20;
|
||||
this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping
|
||||
if (false && i > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy
|
||||
- if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping
|
||||
+ if (this.playerList.getPlayerCount() == 0 && this.botList.bots.isEmpty() && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping // Leaves - fakeplayer
|
||||
this.emptyTicks++;
|
||||
} else {
|
||||
this.emptyTicks = 0;
|
||||
@@ -1801,6 +1808,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.isSaving = true;
|
||||
if (playerSaveInterval > 0) {
|
||||
this.playerList.saveAll(playerSaveInterval);
|
||||
+ org.leavesmc.leaves.bot.BotList.INSTANCE.saveAllResumeBots(playerSaveInterval); // Leaves - resident fakeplayer
|
||||
}
|
||||
for (final ServerLevel level : (region == null ? this.getAllLevels() : Arrays.asList(region.world))) { // Folia - region threading
|
||||
if (level.paperConfig().chunks.autoSaveInterval.value() > 0) {
|
||||
@@ -2027,6 +2035,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
public void tickConnection() {
|
||||
this.getConnection().tick();
|
||||
+ this.botList.networkTick(); // Leaves - fakeplayer
|
||||
}
|
||||
|
||||
private void synchronizeTime(ServerLevel level) {
|
||||
@@ -3161,6 +3170,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
return this.debugSubscribers;
|
||||
}
|
||||
|
||||
+ // Leaves start - fakeplayer
|
||||
+ protected void setBotList(org.leavesmc.leaves.bot.BotList botList) {
|
||||
+ this.botList = botList;
|
||||
+ }
|
||||
+
|
||||
+ public org.leavesmc.leaves.bot.BotList getBotList() {
|
||||
+ return botList;
|
||||
+ }
|
||||
+ // Leaves end - fakeplayer
|
||||
+
|
||||
public record ReloadableResources(CloseableResourceManager resourceManager, ReloadableServerResources managers) implements AutoCloseable {
|
||||
@Override
|
||||
public void close() {
|
||||
diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java
|
||||
index c9e6cd428e4c74b14a992de9ffe85a5a707c4e6b..5bf7eb5b906cefa57a1dfcf828ff7872dbceac4f 100644
|
||||
--- a/net/minecraft/server/PlayerAdvancements.java
|
||||
+++ b/net/minecraft/server/PlayerAdvancements.java
|
||||
@@ -166,6 +166,11 @@ public class PlayerAdvancements {
|
||||
}
|
||||
|
||||
public boolean award(AdvancementHolder advancement, String criterionKey) {
|
||||
+ // Leaves start - bot can't get advancement
|
||||
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Leaves end - bot can't get advancement
|
||||
boolean flag = false;
|
||||
AdvancementProgress orStartProgress = this.getOrStartProgress(advancement);
|
||||
boolean isDone = orStartProgress.isDone();
|
||||
diff --git a/net/minecraft/server/commands/BanIpCommands.java b/net/minecraft/server/commands/BanIpCommands.java
|
||||
index d92492bca62fb02fe7a9e4e220cb8651c4d1e16d..7d0752f9a6a90cf389a9cb5829ab02606266f204 100644
|
||||
--- a/net/minecraft/server/commands/BanIpCommands.java
|
||||
+++ b/net/minecraft/server/commands/BanIpCommands.java
|
||||
@@ -44,6 +44,12 @@ public class BanIpCommands {
|
||||
return banIp(source, username, reason);
|
||||
} else {
|
||||
ServerPlayer playerByName = source.getServer().getPlayerList().getPlayerByName(username);
|
||||
+ // Leaves start - disable ban
|
||||
+ if (playerByName instanceof org.leavesmc.leaves.bot.ServerBot) {
|
||||
+ source.sendFailure(Component.literal("Permission denied"));
|
||||
+ return 0;
|
||||
+ }
|
||||
+ // Leaves end - disable ban
|
||||
if (playerByName != null) {
|
||||
return banIp(source, playerByName.getIpAddress(), reason);
|
||||
} else {
|
||||
diff --git a/net/minecraft/server/commands/BanPlayerCommands.java b/net/minecraft/server/commands/BanPlayerCommands.java
|
||||
index 978ef2e996a78e907f959bfe99d47de832427011..9644e68ba2c295fcda2d4a3034277520ade91bca 100644
|
||||
--- a/net/minecraft/server/commands/BanPlayerCommands.java
|
||||
+++ b/net/minecraft/server/commands/BanPlayerCommands.java
|
||||
@@ -45,7 +45,15 @@ public class BanPlayerCommands {
|
||||
UserBanList bans = source.getServer().getPlayerList().getBans();
|
||||
int i = 0;
|
||||
|
||||
+ boolean hasBot = false; // Leaves - disable kick
|
||||
for (NameAndId nameAndId : players) {
|
||||
+ // Leaves start - disable ban
|
||||
+ if (nameAndId.isBot()) {
|
||||
+ source.sendFailure(Component.literal("Permission denied"));
|
||||
+ hasBot = true;
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Leaves end - disable ban
|
||||
if (!bans.isBanned(nameAndId)) {
|
||||
UserBanListEntry userBanListEntry = new UserBanListEntry(
|
||||
nameAndId, null, source.getTextName(), null, reason == null ? null : reason.getString()
|
||||
@@ -63,7 +71,13 @@ public class BanPlayerCommands {
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
- throw ERROR_ALREADY_BANNED.create();
|
||||
+ // Leaves start - disable kick
|
||||
+ if (hasBot) {
|
||||
+ return i;
|
||||
+ } else {
|
||||
+ throw ERROR_ALREADY_BANNED.create();
|
||||
+ }
|
||||
+ // Leaves end - disable kick
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
diff --git a/net/minecraft/server/commands/KickCommand.java b/net/minecraft/server/commands/KickCommand.java
|
||||
index 5f78d629bab84acb2fa43a9fcc1cec52b4e91ae3..1c6059bd23afdd555d2dc8c533a5b027957c7b3a 100644
|
||||
--- a/net/minecraft/server/commands/KickCommand.java
|
||||
+++ b/net/minecraft/server/commands/KickCommand.java
|
||||
@@ -46,9 +46,17 @@ public class KickCommand {
|
||||
if (!source.getServer().isPublished()) {
|
||||
throw ERROR_SINGLEPLAYER.create();
|
||||
} else {
|
||||
+ boolean hasBot = false; // Leaves - disable kick
|
||||
int i = 0;
|
||||
|
||||
for (ServerPlayer serverPlayer : players) {
|
||||
+ // Leaves start - disable kick
|
||||
+ if (serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot) {
|
||||
+ source.sendFailure(Component.literal("Permission denied"));
|
||||
+ hasBot = true;
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Leaves end - disable kick
|
||||
if (!source.getServer().isSingleplayerOwner(serverPlayer.nameAndId())) {
|
||||
serverPlayer.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause
|
||||
source.sendSuccess(() -> Component.translatable("commands.kick.success", serverPlayer.getDisplayName(), reason), true);
|
||||
@@ -57,7 +65,13 @@ public class KickCommand {
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
- throw ERROR_KICKING_OWNER.create();
|
||||
+ // Leaves start - disable kick
|
||||
+ if (hasBot) {
|
||||
+ return i;
|
||||
+ } else {
|
||||
+ throw ERROR_KICKING_OWNER.create();
|
||||
+ }
|
||||
+ // Leaves end - disable kick
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
diff --git a/net/minecraft/server/commands/OpCommand.java b/net/minecraft/server/commands/OpCommand.java
|
||||
index 07332a86e6e0441bafacb020f27ec36a277f1486..590891d70a71ab30ceae3a3cf1923745e7c20b26 100644
|
||||
--- a/net/minecraft/server/commands/OpCommand.java
|
||||
+++ b/net/minecraft/server/commands/OpCommand.java
|
||||
@@ -43,6 +43,7 @@ public class OpCommand {
|
||||
int i = 0;
|
||||
|
||||
for (NameAndId nameAndId : players) {
|
||||
+ if (nameAndId.isBot()) continue; // Leaves - disable op
|
||||
if (!playerList.isOp(nameAndId)) {
|
||||
playerList.op(nameAndId);
|
||||
i++;
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 5fbcb5eac1d5449247da77b6120edbe2f2dd1d58..69cc67b7618d38e65ccb1f4c58013ef116886ad2 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -252,6 +252,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
|
||||
// Spigot start
|
||||
+ this.setBotList(new org.leavesmc.leaves.bot.BotList(this)); // Leaves - fakeplayer
|
||||
this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage));
|
||||
org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings"));
|
||||
org.spigotmc.SpigotConfig.registerCommands();
|
||||
@@ -263,6 +264,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
// Paper end - initialize global and world-defaults configuration
|
||||
me.earthme.luminol.config.ConfigManager.loadConfigFiles(); // Luminol - load config file
|
||||
fun.bm.lophine.utils.ServerI18nUtil.init(); // Lophine - I18n support
|
||||
+ this.getBotList().loadResumeBotInfo(); // Leaves - load resident bot info
|
||||
if (false) this.server.spark.enableEarlyIfRequested(); // Paper - spark // Luminol - Force disable builtin spark
|
||||
// Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save
|
||||
if (this.convertOldUsers()) {
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index fdccb06c918d387e46c29ede7337159db8c5d9ca..4cd5c5659ac098c3b7ff95efb94b1987e2dd40d0 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1386,6 +1386,13 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
||||
}
|
||||
} else {
|
||||
this.removePlayer(player);
|
||||
+ // Leaves start - render bot
|
||||
+ if (entity instanceof org.leavesmc.leaves.bot.ServerBot bot) {
|
||||
+ if (bot.needSendFakeData(player)) {
|
||||
+ bot.sendFakeData(player.connection, false);
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaves end - render bot
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index eb5722848d1c77044807510cd6a46a46c5763509..88efbe2bcb5621432b67366116150a3dab52e510 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -220,6 +220,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
public final boolean tickTime; // Folia - region threading
|
||||
private final RandomSequences randomSequences;
|
||||
final LevelDebugSynchronizers debugSynchronizers = new LevelDebugSynchronizers(this);
|
||||
+ final List<ServerPlayer> realPlayers; // Leaves - skip
|
||||
|
||||
// CraftBukkit start
|
||||
public final LevelStorageSource.LevelStorageAccess levelStorageAccess;
|
||||
@@ -669,6 +670,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// Paper end - rewrite chunk system
|
||||
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
||||
this.updateTickData(); // Folia - region threading - make sure it is initialised before ticked
|
||||
+ this.realPlayers = Lists.newArrayList(); // Leaves - skip
|
||||
}
|
||||
|
||||
// Folia start - region threading
|
||||
@@ -2518,6 +2520,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
return this.players;
|
||||
}
|
||||
|
||||
+ // Leaves start - fakeplayer skip
|
||||
+ public List<ServerPlayer> realPlayers() {
|
||||
+ return this.realPlayers;
|
||||
+ }
|
||||
+ // Leaves end - fakeplayer skip
|
||||
+
|
||||
@Override
|
||||
public void updatePOIOnBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) {
|
||||
Optional<Holder<PoiType>> optional = PoiTypes.forState(oldState);
|
||||
@@ -2991,6 +2999,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
ServerLevel.this.players.add(serverPlayer);
|
||||
+ // Leaves start - skip
|
||||
+ if (!(serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot)) {
|
||||
+ ServerLevel.this.realPlayers.add(serverPlayer);
|
||||
+ }
|
||||
+ // Leaves end - skip
|
||||
if (serverPlayer.isReceivingWaypoints()) {
|
||||
ServerLevel.this.getWaypointManager().addPlayer(serverPlayer);
|
||||
}
|
||||
@@ -3072,6 +3085,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
ServerLevel.this.getChunkSource().removeEntity(entity);
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
ServerLevel.this.players.remove(serverPlayer);
|
||||
+ // Leaves start - skip
|
||||
+ if (!(serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot)) {
|
||||
+ ServerLevel.this.realPlayers.remove(serverPlayer);
|
||||
+ }
|
||||
+ // Leaves end - skip
|
||||
ServerLevel.this.getWaypointManager().removePlayer(serverPlayer);
|
||||
ServerLevel.this.updateSleepingPlayerList();
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 6df8f98afa7810815b8d7c86b3dac57cd5915682..7c2d53ca863c2e50c6871938efc426ddefff9b5c 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -227,7 +227,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
private static final boolean DEFAULT_SPAWN_EXTRA_PARTICLES_ON_FALL = false;
|
||||
public ServerGamePacketListenerImpl connection;
|
||||
private final MinecraftServer server;
|
||||
- public final ServerPlayerGameMode gameMode;
|
||||
+ public ServerPlayerGameMode gameMode; // Leaves - not final
|
||||
private final PlayerAdvancements advancements;
|
||||
private final ServerStatsCounter stats;
|
||||
private float lastRecordedHealthAndAbsorption = Float.MIN_VALUE;
|
||||
@@ -248,7 +248,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
private @Nullable Entity camera;
|
||||
public boolean isChangingDimension;
|
||||
public boolean seenCredits = false;
|
||||
- private final ServerRecipeBook recipeBook;
|
||||
+ protected ServerRecipeBook recipeBook; // Leaves - not final and private -> protected
|
||||
private @Nullable Vec3 levitationStartPos;
|
||||
private int levitationStartTime;
|
||||
private boolean disconnected;
|
||||
@@ -1495,7 +1495,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
}
|
||||
// Luminol End - Cross Region Damage trace
|
||||
|
||||
- private void tellNeutralMobsThatIDied() {
|
||||
+ protected void tellNeutralMobsThatIDied() { // Leaves private -> protected
|
||||
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
|
||||
this.level()
|
||||
.getEntitiesOfClass(Mob.class, aabb, EntitySelector.NO_SPECTATORS)
|
||||
@@ -2132,6 +2132,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
this.lastSentHealth = -1.0F;
|
||||
this.lastSentFood = -1;
|
||||
this.teleportSpectators(teleportTransition, serverLevel);
|
||||
+ // Leaves start - bot support
|
||||
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
|
||||
+ this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(this, true)); // Leaves - render bot
|
||||
+ }
|
||||
+ // Leaves end - bot support
|
||||
// CraftBukkit start
|
||||
org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), serverLevel.getWorld());
|
||||
this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
|
||||
diff --git a/net/minecraft/server/players/CachedUserNameToIdResolver.java b/net/minecraft/server/players/CachedUserNameToIdResolver.java
|
||||
index 345bdb0ff82b8cd8c63e5ff1f2dabb68a1e54b77..c9a7c1c37155e0d339b880179a5988c9a6cb3797 100644
|
||||
--- a/net/minecraft/server/players/CachedUserNameToIdResolver.java
|
||||
+++ b/net/minecraft/server/players/CachedUserNameToIdResolver.java
|
||||
@@ -122,6 +122,12 @@ public class CachedUserNameToIdResolver implements UserNameToIdResolver {
|
||||
|
||||
@Override
|
||||
public Optional<NameAndId> get(String name) {
|
||||
+ // Leaves start - fix bot
|
||||
+ org.leavesmc.leaves.bot.ServerBot bot = org.leavesmc.leaves.bot.BotList.INSTANCE.getBotByName(name);
|
||||
+ if (bot != null) {
|
||||
+ return Optional.of(bot.nameAndId());
|
||||
+ }
|
||||
+ // Leaves end - fix bot
|
||||
String string = name.toLowerCase(Locale.ROOT);
|
||||
boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
||||
CachedUserNameToIdResolver.GameProfileInfo gameProfileInfo = this.profilesByName.get(string);
|
||||
diff --git a/net/minecraft/server/players/NameAndId.java b/net/minecraft/server/players/NameAndId.java
|
||||
index 05b4a75f6597e8613c91344d100bb7f005d169a7..9a5006362c12e972d031c48be4d30362d88d1c00 100644
|
||||
--- a/net/minecraft/server/players/NameAndId.java
|
||||
+++ b/net/minecraft/server/players/NameAndId.java
|
||||
@@ -8,18 +8,22 @@ import java.util.UUID;
|
||||
import net.minecraft.core.UUIDUtil;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
-public record NameAndId(UUID id, String name) {
|
||||
+public record NameAndId(UUID id, String name, boolean isBot) { // Leaves - fakeplayer
|
||||
public static final Codec<NameAndId> CODEC = RecordCodecBuilder.create(
|
||||
instance -> instance.group(UUIDUtil.STRING_CODEC.fieldOf("id").forGetter(NameAndId::id), Codec.STRING.fieldOf("name").forGetter(NameAndId::name))
|
||||
.apply(instance, NameAndId::new)
|
||||
);
|
||||
|
||||
public NameAndId(GameProfile profile) {
|
||||
- this(profile.id(), profile.name());
|
||||
+ this(profile.id(), profile.name(), com.google.common.collect.Iterables.getFirst(profile.properties().get("is_bot"), "false").equals("true")); // Leaves - fakeplayer
|
||||
}
|
||||
|
||||
public NameAndId(com.mojang.authlib.yggdrasil.response.NameAndId nameAndId) {
|
||||
- this(nameAndId.id(), nameAndId.name());
|
||||
+ this(nameAndId.id(), nameAndId.name(), false); // Leaves - fakeplayer
|
||||
+ }
|
||||
+
|
||||
+ public NameAndId(UUID uuid, String name) {
|
||||
+ this(uuid, name, false); // Leaves - fakeplayer
|
||||
}
|
||||
|
||||
public static @Nullable NameAndId fromJson(JsonObject json) {
|
||||
@@ -33,7 +37,7 @@ public record NameAndId(UUID id, String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
- return new NameAndId(uuid, json.get("name").getAsString());
|
||||
+ return new NameAndId(uuid, json.get("name").getAsString(), false); // Leaves - fakeplayer
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -46,7 +50,7 @@ public record NameAndId(UUID id, String name) {
|
||||
|
||||
public static NameAndId createOffline(String name) {
|
||||
UUID uuid = UUIDUtil.createOfflinePlayerUUID(name);
|
||||
- return new NameAndId(uuid, name);
|
||||
+ return new NameAndId(uuid, name, false); // Leaves - fakeplayer
|
||||
}
|
||||
|
||||
// Paper start - utility method for common conversion back to the game profile
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..3a5319739f0687fc6f09b2ac8ee31716593fe0de 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -317,6 +317,19 @@ public abstract class PlayerList {
|
||||
|
||||
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player);
|
||||
|
||||
+ // Leaves start - bot support
|
||||
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
|
||||
+ org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
|
||||
+ if (bot != null) {
|
||||
+ this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
|
||||
+ }
|
||||
+ this.server.getBotList().bots.forEach(bot1 -> {
|
||||
+ bot1.sendPlayerInfo(player);
|
||||
+ bot1.sendFakeDataIfNeed(player, true);
|
||||
+ }); // Leaves - render bot
|
||||
+ }
|
||||
+ // Leaves end - bot support
|
||||
+
|
||||
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
|
||||
|
||||
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
|
||||
@@ -791,6 +804,12 @@ public abstract class PlayerList {
|
||||
).callEvent();
|
||||
// Paper end
|
||||
|
||||
+ // Leaves start - bot support
|
||||
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
|
||||
+ this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(serverPlayer, true)); // Leaves - render bot
|
||||
+ }
|
||||
+ // Leaves end - bot support
|
||||
+
|
||||
return serverPlayer;
|
||||
}
|
||||
|
||||
@@ -892,11 +911,16 @@ public abstract class PlayerList {
|
||||
|
||||
public String[] getPlayerNamesArray() {
|
||||
List<ServerPlayer> players = new java.util.ArrayList<>(this.players); // Folia - region threading
|
||||
- String[] strings = new String[this.players.size()];
|
||||
+ String[] strings = new String[this.players.size() + this.server.getBotList().bots.size()]; // Leaves - fakeplayer support
|
||||
|
||||
for (int i = 0; i < players.size(); i++) { // Folia - region threading
|
||||
strings[i] = players.get(i).getGameProfile().name(); // Folia - region threading
|
||||
}
|
||||
+ // Leaves start - fakeplayer support
|
||||
+ for (int i = this.players.size(); i < strings.length; ++i) {
|
||||
+ strings[i] = this.server.getBotList().bots.get(i - this.players.size()).getGameProfile().name();
|
||||
+ }
|
||||
+ // Leaves end - fakeplayer support
|
||||
|
||||
return strings;
|
||||
}
|
||||
@@ -1016,7 +1040,14 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public @Nullable ServerPlayer getPlayerByName(String username) {
|
||||
- return this.playersByName.get(username.toLowerCase(java.util.Locale.ROOT)); // Spigot
|
||||
+ // Leaves start - fakeplayer support
|
||||
+ username = username.toLowerCase(java.util.Locale.ROOT);
|
||||
+ ServerPlayer player = this.playersByName.get(username);
|
||||
+ if (player == null) {
|
||||
+ player = this.server.getBotList().getBotByName(username);
|
||||
+ }
|
||||
+ return player; // Spigot
|
||||
+ // Leaves end - fakeplayer support
|
||||
}
|
||||
|
||||
public void broadcast(@Nullable Player except, double x, double y, double z, double radius, ResourceKey<Level> dimension, Packet<?> packet) {
|
||||
@@ -1353,7 +1384,13 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public @Nullable ServerPlayer getPlayer(UUID playerUUID) {
|
||||
- return this.playersByUUID.get(playerUUID);
|
||||
+ // Leaves start - fakeplayer support
|
||||
+ ServerPlayer player = this.playersByUUID.get(playerUUID);
|
||||
+ if (player == null) {
|
||||
+ player = this.server.getBotList().getBot(playerUUID);
|
||||
+ }
|
||||
+ return player;
|
||||
+ // Leaves start - fakeplayer support
|
||||
}
|
||||
|
||||
public @Nullable ServerPlayer getPlayer(String name) {
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 22e68cabb4554c3e21e6f4ef316186f60ec77511..5ac53fcdca5fa6aae0452840e78d67653ceececb 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1235,7 +1235,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
|
||||
|
||||
BlockPos onPosLegacy = this.getOnPosLegacy();
|
||||
BlockState blockState = this.level().getBlockState(onPosLegacy);
|
||||
- if (this.isLocalInstanceAuthoritative()) {
|
||||
+ if (this.isLocalInstanceAuthoritative() || this instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - ServerBot needs check fall damage
|
||||
this.checkFallDamage(vec3.y, this.onGround(), blockState, onPosLegacy);
|
||||
}
|
||||
|
||||
@@ -1570,7 +1570,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
|
||||
}
|
||||
|
||||
// Paper start - optimise collisions
|
||||
- private Vec3 collide(Vec3 movement) {
|
||||
+ public Vec3 collide(Vec3 movement) { // Leaves - private -> public
|
||||
final boolean xZero = movement.x == 0.0;
|
||||
final boolean yZero = movement.y == 0.0;
|
||||
final boolean zZero = movement.z == 0.0;
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 3fe9afe55b4d61db8030479d3d74b8656679cb10..c0ebd700caa950948c58846eaf164afc14f87f09 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3319,7 +3319,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
private void travelRidden(Player player, Vec3 travelVector) {
|
||||
Vec3 riddenInput = this.getRiddenInput(player, travelVector);
|
||||
this.tickRidden(player, riddenInput);
|
||||
- if (this.canSimulateMovement()) {
|
||||
+ if (this.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - Fakeplayer
|
||||
this.setSpeed(this.getRiddenSpeed(player));
|
||||
this.travel(riddenInput);
|
||||
} else {
|
||||
@@ -4228,7 +4228,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
// Paper start - lag compensate eating
|
||||
// we add 1 to the expected time to avoid lag compensating when we should not
|
||||
final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L));
|
||||
- if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide() && !usingItem.useOnRelease()) {
|
||||
+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !(this instanceof org.leavesmc.leaves.bot.ServerBot) && !this.level().isClientSide() && !usingItem.useOnRelease()) {
|
||||
this.useItemRemaining = 0;
|
||||
// Paper end - lag compensate eating
|
||||
this.completeUsingItem();
|
||||
@@ -4413,6 +4413,23 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
this.stopUsingItem();
|
||||
}
|
||||
|
||||
+ // Leaves start - Fakeplayer
|
||||
+ public boolean releaseUsingItemWithResult() {
|
||||
+ ItemStack itemInHand = this.getItemInHand(this.getUsedItemHand());
|
||||
+ boolean result = false;
|
||||
+ if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInHand, this.useItem)) {
|
||||
+ this.useItem = itemInHand;
|
||||
+ result = this.useItem.releaseUsingWithResult(this.level(), this, this.getUseItemRemainingTicks());
|
||||
+ if (this.useItem.useOnRelease()) {
|
||||
+ this.updatingUsingItem();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.stopUsingItem();
|
||||
+ return result;
|
||||
+ }
|
||||
+ // Leaves end - Fakeplayer
|
||||
+
|
||||
public void stopUsingItem() {
|
||||
if (!this.level().isClientSide()) {
|
||||
boolean isUsingItem = this.isUsingItem();
|
||||
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
|
||||
index 83612969b6058f444fc17e360cdcc4a8846f79aa..29ca31b05ec5636243b13fee8b3399d5e21808b4 100644
|
||||
--- a/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/net/minecraft/world/entity/player/Player.java
|
||||
@@ -168,7 +168,7 @@ public abstract class Player extends Avatar implements ContainerUser {
|
||||
private int lastLevelUpTime;
|
||||
public GameProfile gameProfile;
|
||||
private boolean reducedDebugInfo;
|
||||
- private ItemStack lastItemInMainHand = ItemStack.EMPTY;
|
||||
+ protected ItemStack lastItemInMainHand = ItemStack.EMPTY;
|
||||
private final ItemCooldowns cooldowns = this.createItemCooldowns();
|
||||
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
|
||||
public @Nullable FishingHook fishing;
|
||||
@@ -349,6 +349,12 @@ public abstract class Player extends Avatar implements ContainerUser {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaves start - fakeplayer
|
||||
+ protected void livingEntityTick() {
|
||||
+ super.tick();
|
||||
+ }
|
||||
+ // Leaves end - fakeplayer
|
||||
+
|
||||
@Override
|
||||
protected float getMaxHeadRotationRelativeToBody() {
|
||||
return this.isBlocking() ? 15.0F : super.getMaxHeadRotationRelativeToBody();
|
||||
@@ -574,7 +580,7 @@ public abstract class Player extends Avatar implements ContainerUser {
|
||||
public void removeEntitiesOnShoulder() {
|
||||
}
|
||||
|
||||
- private void touch(Entity entity) {
|
||||
+ public void touch(Entity entity) { // Leaves - private -> public
|
||||
entity.playerTouch(this);
|
||||
}
|
||||
|
||||
@@ -1251,7 +1257,7 @@ public abstract class Player extends Avatar implements ContainerUser {
|
||||
// Paper end - Configurable sprint interruption on attack
|
||||
}
|
||||
|
||||
- if (target instanceof ServerPlayer && target.hurtMarked) {
|
||||
+ if ((target instanceof ServerPlayer && !(target instanceof org.leavesmc.leaves.bot.ServerBot)) && target.hurtMarked) { // Leaves - bot knockback
|
||||
// CraftBukkit start - Add Velocity Event
|
||||
boolean cancelled = false;
|
||||
org.bukkit.entity.Player player = (org.bukkit.entity.Player) target.getBukkitEntity();
|
||||
diff --git a/net/minecraft/world/entity/projectile/FishingHook.java b/net/minecraft/world/entity/projectile/FishingHook.java
|
||||
index 71f6acc07d222fe512bf8d9fbaad35cb36bcf2d6..a9f5d503fbe50e54f2f44be2ca6d414430f4481e 100644
|
||||
--- a/net/minecraft/world/entity/projectile/FishingHook.java
|
||||
+++ b/net/minecraft/world/entity/projectile/FishingHook.java
|
||||
@@ -58,7 +58,7 @@ public class FishingHook extends Projectile {
|
||||
public static final EntityDataAccessor<Integer> DATA_HOOKED_ENTITY = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.INT);
|
||||
private static final EntityDataAccessor<Boolean> DATA_BITING = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.BOOLEAN);
|
||||
private int life;
|
||||
- private int nibble;
|
||||
+ public int nibble; // Leaves - private -> public
|
||||
public int timeUntilLured;
|
||||
public int timeUntilHooked;
|
||||
public float fishAngle;
|
||||
diff --git a/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java b/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
||||
index fc1b3501114108d0166256c514a225337955e461..56bc87fefc82c77077bfed50accbde778c0059ea 100644
|
||||
--- a/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
||||
+++ b/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
||||
@@ -270,6 +270,11 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
||||
}
|
||||
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+ } else if (this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves start - Fakeplayer
|
||||
+ this.floatBoat();
|
||||
+ this.controlBoat();
|
||||
+ this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+ // Leaves end - Fakeplayer
|
||||
} else {
|
||||
this.setDeltaMovement(Vec3.ZERO);
|
||||
}
|
||||
@@ -380,6 +385,13 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaves start - Fakeplayer
|
||||
+ @Override
|
||||
+ public boolean canSimulateMovement() {
|
||||
+ return super.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot;
|
||||
+ }
|
||||
+ // Leaves end - Fakeplayer
|
||||
+
|
||||
protected @Nullable SoundEvent getPaddleSound() {
|
||||
return switch (this.getStatus()) {
|
||||
case IN_WATER, UNDER_WATER, UNDER_FLOWING_WATER -> SoundEvents.BOAT_PADDLE_WATER;
|
||||
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
index e7ea8849e8fa942709f505145e8076f064476206..4935234fba5977246aa303bf8162404813b5491e 100644
|
||||
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
@@ -404,6 +404,7 @@ public abstract class AbstractContainerMenu {
|
||||
|
||||
private void doClick(int slotIndex, int button, ClickType clickType, Player player) {
|
||||
Inventory inventory = player.getInventory();
|
||||
+ if (!doClickCheck(slotIndex, button, clickType, player)) return; // Leaves - doClick check
|
||||
if (clickType == ClickType.QUICK_CRAFT) {
|
||||
int i = this.quickcraftStatus;
|
||||
this.quickcraftStatus = getQuickcraftHeader(button);
|
||||
@@ -678,6 +679,22 @@ public abstract class AbstractContainerMenu {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaves start - doClick check
|
||||
+ private boolean doClickCheck(int slotIndex, int button, ClickType actionType, Player player) {
|
||||
+ if (slotIndex < 0) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ Slot slot = getSlot(slotIndex);
|
||||
+ ItemStack itemStack = slot.getItem();
|
||||
+ net.minecraft.world.item.component.CustomData customData = itemStack.get(net.minecraft.core.component.DataComponents.CUSTOM_DATA);
|
||||
+ if (customData != null && customData.contains("Leaves.Gui.Placeholder")) {
|
||||
+ return !customData.copyTag().getBoolean("Leaves.Gui.Placeholder").orElse(false);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Leaves end - doClick check
|
||||
+
|
||||
private boolean tryItemClickBehaviourOverride(Player player, ClickAction action, Slot slot, ItemStack clickedItem, ItemStack carriedItem) {
|
||||
FeatureFlagSet featureFlagSet = player.level().enabledFeatures();
|
||||
return carriedItem.isItemEnabled(featureFlagSet) && carriedItem.overrideStackedOnOther(slot, action, player)
|
||||
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
||||
index 73a97f4f62fe7d27b441cab58c6c86ffce011060..ea6285b7f53f391c84519aa7ae39164cf5740b81 100644
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/net/minecraft/world/item/ItemStack.java
|
||||
@@ -456,7 +456,7 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
|
||||
placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(serverLevel, player, hand, blocks.getFirst(), clickedPos);
|
||||
}
|
||||
|
||||
- if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
|
||||
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild()) && (!(player instanceof org.leavesmc.leaves.bot.ServerBot))) { // Leaves - Fakeplayer skip this check
|
||||
interactionResult = InteractionResult.FAIL; // cancel placement
|
||||
// PAIL: Remove this when MC-99075 fixed
|
||||
player.containerMenu.forceHeldSlot(hand);
|
||||
@@ -987,6 +987,20 @@ public final class ItemStack implements DataComponentHolder, ChangePublisher<net
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaves start - Fakeplayer
|
||||
+ public boolean releaseUsingWithResult(Level level, LivingEntity livingEntity, int timeLeft) {
|
||||
+ ItemStack itemStack = this.copy();
|
||||
+ if (this.getItem().releaseUsing(this, level, livingEntity, timeLeft)) {
|
||||
+ ItemStack itemStack1 = this.applyAfterUseComponentSideEffects(livingEntity, itemStack);
|
||||
+ if (itemStack1 != this) {
|
||||
+ livingEntity.setItemInHand(livingEntity.getUsedItemHand(), itemStack1);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Leaves end - Fakeplayer
|
||||
+
|
||||
public boolean useOnRelease() {
|
||||
return this.getItem().useOnRelease(this);
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
index 557ea70254a8d6dd87c656098c5632bdcbe3df8f..1d60054146f970ec24054d2c76a27e2d8620ec67 100644
|
||||
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
@@ -145,7 +145,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
||||
break;
|
||||
}
|
||||
|
||||
- if (!(entity instanceof ServerPlayer)) {
|
||||
+ if (!(entity instanceof ServerPlayer) || (entity instanceof org.leavesmc.leaves.bot.ServerBot)) { // Leaves - bot slime block
|
||||
Vec3 deltaMovement = entity.getDeltaMovement();
|
||||
double d1 = deltaMovement.x;
|
||||
double d2 = deltaMovement.y;
|
||||
diff --git a/net/minecraft/world/level/levelgen/PhantomSpawner.java b/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
index e9c40ecb2309d386a2214593181f2d4f289eb28b..17dff8aed5015bfd22d021e2fcf536265d179139 100644
|
||||
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
||||
@@ -49,6 +49,11 @@ public class PhantomSpawner implements CustomSpawner {
|
||||
ServerStatsCounter stats = serverPlayer.getStats();
|
||||
int i = Mth.clamp(stats.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
|
||||
int i1 = 24000;
|
||||
+ // Leaves start - fakeplayer spawn
|
||||
+ if (serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot bot && bot.getConfigValue(org.leavesmc.leaves.bot.agent.Configs.SPAWN_PHANTOM)) {
|
||||
+ i1 = Math.max(bot.notSleepTicks, 1);
|
||||
+ }
|
||||
+ // Leaves end - fakeplayer spawn
|
||||
if (randomSource.nextInt(i) >= 72000) {
|
||||
BlockPos blockPos1 = blockPos.above(20 + randomSource.nextInt(15))
|
||||
.east(-10 + randomSource.nextInt(21))
|
||||
diff --git a/net/minecraft/world/level/storage/LevelResource.java b/net/minecraft/world/level/storage/LevelResource.java
|
||||
index bef794c3f58c41d910aa0bcc63fbdeea7225fddf..a601da588e6973cc5b87d3e3eeba49b53f6d9a6d 100644
|
||||
--- a/net/minecraft/world/level/storage/LevelResource.java
|
||||
+++ b/net/minecraft/world/level/storage/LevelResource.java
|
||||
@@ -15,7 +15,7 @@ public class LevelResource {
|
||||
public static final LevelResource ROOT = new LevelResource(".");
|
||||
private final String id;
|
||||
|
||||
- private LevelResource(String id) {
|
||||
+ public LevelResource(String id) { // Leaves - private -> public
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 19:32:34 +0800
|
||||
Subject: [PATCH] Teleport async if entity was moving to another region at once
|
||||
|
||||
On folia, entity usually cannot move out of the tickregion, but sometimes it actually does(like some end pearl gun that can shoot an end pearl to the block faraway than 10000 blocks even more). To fix this, we added a temporary fix which teleport these entities to the destination instead running its move logics so that we could ensure anything is under control.But one thing need to consider is that teleportAsync is actually calling halfway of the entity tick and there is still something running when teleportAsync called, which is actually modified the entity in another thread, so there is still need an improvement
|
||||
|
||||
Reference from : https://github.com/KaiijuMC/Kaiiju/blob/ver/1.20.1/patches/server/0040-Teleport-async-if-we-cannot-move-entity-off-main.patch
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index e2e1b101de8afbec7d853593c527e35111c94319..33c9692a59c58c44a77b1077553e2bda88cb8305 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1163,6 +1163,19 @@ public abstract class Entity
|
||||
this.moveStartZ = this.getZ();
|
||||
this.moveVector = delta;
|
||||
}
|
||||
+ //Luminol start - Fix high position moving
|
||||
+ // Filter the threads as it may be called by the chunk system worker thread
|
||||
+ if (me.earthme.luminol.config.modules.fixes.FoliaEntityMovingFixConfig.enabled && ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()){
|
||||
+ var finalPosition = delta.add(this.position);
|
||||
+ // not NaN (Prevent incorrect checks under NaN minecarts)
|
||||
+ if (!Double.isNaN(finalPosition.x) && !Double.isNaN(finalPosition.y) && !Double.isNaN(finalPosition.z)) {
|
||||
+ // kill tick passively if it's moving out of region and we'll catch this exception
|
||||
+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level,finalPosition)) {
|
||||
+ throw new me.earthme.luminol.utils.EntityMoveOutOfRegionException(this, delta, moverType);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ //Luminol end
|
||||
try {
|
||||
// Paper end - detailed watchdog information
|
||||
if (this.noPhysics) {
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index a0eb1f608a99301e0197ab1d1a6fbbb0a0be4ce0..dc28223684091cd0d8dbf7ff01626b20e4f1b662 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -1571,6 +1571,25 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
public <T extends Entity> void guardEntityTick(final Consumer<T> tick, final T entity) {
|
||||
try {
|
||||
tick.accept(entity);
|
||||
+ } catch (me.earthme.luminol.utils.EntityMoveOutOfRegionException moveOutOfRegionException) { // Luminol - Teleport async if entity was moving to another region at once
|
||||
+ // Luminol start - Teleport async if entity was moving to another region at once
|
||||
+ final Entity ent = moveOutOfRegionException.getEntity();
|
||||
+ var currPosition = ent.position();
|
||||
+ var toPosition = moveOutOfRegionException.getMovement().add(currPosition);
|
||||
+
|
||||
+ if (me.earthme.luminol.config.modules.fixes.FoliaEntityMovingFixConfig.warnOnDetected) {
|
||||
+ MinecraftServer.LOGGER.warn("Entity {} with entityId {} has tried moving to another region!",ent, ent.getId());
|
||||
+ }
|
||||
+
|
||||
+ ent.getBukkitEntity().taskScheduler.schedule(entityFresh -> entityFresh.teleportAsync(
|
||||
+ (ServerLevel) entityFresh.level(),
|
||||
+ toPosition,
|
||||
+ entityFresh.getYRot(), entityFresh.getXRot(),
|
||||
+ entityFresh.getDeltaMovement(), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN,
|
||||
+ Entity.TELEPORT_FLAG_LOAD_CHUNK | Entity.TELEPORT_FLAG_TELEPORT_PASSENGERS,
|
||||
+ null
|
||||
+ ), null, 1L);
|
||||
+ // Luminol end
|
||||
} catch (Throwable t) {
|
||||
// Paper start - Prevent block entity and entity crashes
|
||||
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", io.papermc.paper.util.MCUtil.getLevelName(entity.level()), entity.getX(), entity.getY(), entity.getZ());
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
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] 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 13d7965fd4f99f0848b080349df41f8b1c31a19b..5b83f2edd6afe94c28bf491afab737e92fb89dc0 100644
|
||||
--- a/net/minecraft/server/commands/TeleportCommand.java
|
||||
+++ b/net/minecraft/server/commands/TeleportCommand.java
|
||||
@@ -248,8 +248,8 @@ public class TeleportCommand {
|
||||
// Folia start - region threading
|
||||
if (true) {
|
||||
Vec3 posFinal = new Vec3(x, y, z);
|
||||
- Float yawFinal = Float.valueOf(newYRot);
|
||||
- Float pitchFinal = Float.valueOf(newXRot);
|
||||
+ 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 fb00f70505a6c548cd1311d7ea55c6a501e814e3..4df9a3356cfdee52761db47694e59779976840db 100644
|
||||
--- a/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
|
||||
+++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/ThrownEnderpearl.java
|
||||
@@ -99,7 +99,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,
|
||||
@@ -1,20 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Fri, 3 Oct 2025 19:43:36 +0800
|
||||
Subject: [PATCH] Modify merge ItemEntity logic
|
||||
|
||||
Add followTickSequenceMerge to modify merge items, due to Paper's modification of the merge radius, when the merge radius is large and stacks containing many items get stuck in an unexpected position, individual items may never reach their destination. This configuration option is added to fix this behavior.
|
||||
|
||||
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index f3f067c62dc024a747d059608ae7a2e8740dbff2..1b8a963726ee2b2244d429f1e7e3a08034bfbd70 100644
|
||||
--- a/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -283,7 +283,7 @@ public class ItemEntity extends Entity implements TraceableEntity, ChangePublish
|
||||
ItemStack item = this.getItem();
|
||||
ItemStack item1 = itemEntity.getItem();
|
||||
if (Objects.equals(this.target, itemEntity.target) && areMergable(item, item1)) {
|
||||
- if (item1.getCount() < item.getCount()) {
|
||||
+ if (fun.bm.lophine.config.modules.misc.ItemEntityConfig.followTickSequenceMerge || item1.getCount() < item.getCount()) { // Lophine - add follow Tick Sequence Merge, see Paper#13073
|
||||
merge(this, item, itemEntity, item1);
|
||||
} else {
|
||||
merge(itemEntity, item1, this, item);
|
||||
@@ -0,0 +1,288 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 19:47:24 +0800
|
||||
Subject: [PATCH] Improved Server Health Report
|
||||
|
||||
|
||||
diff --git a/io/papermc/paper/threadedregions/commands/CommandServerHealth.java b/io/papermc/paper/threadedregions/commands/CommandServerHealth.java
|
||||
index aa860cfe9de616f185163fe74e0f4f49bd13a805..05d4f73340412f737224cb1443ecf1e33586ed38 100644
|
||||
--- a/io/papermc/paper/threadedregions/commands/CommandServerHealth.java
|
||||
+++ b/io/papermc/paper/threadedregions/commands/CommandServerHealth.java
|
||||
@@ -29,6 +29,14 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
+// Luminol start - Improved Server Health Report
|
||||
+import java.util.concurrent.TimeUnit;
|
||||
+import java.lang.management.ManagementFactory;
|
||||
+import java.lang.management.MemoryMXBean;
|
||||
+import java.lang.management.MemoryUsage;
|
||||
+import java.lang.management.RuntimeMXBean;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+// Luminol end
|
||||
|
||||
public final class CommandServerHealth extends Command {
|
||||
|
||||
@@ -45,7 +53,7 @@ public final class CommandServerHealth extends Command {
|
||||
private static final TextColor HEADER = TextColor.color(79, 164, 240);
|
||||
private static final TextColor PRIMARY = TextColor.color(48, 145, 237);
|
||||
private static final TextColor SECONDARY = TextColor.color(104, 177, 240);
|
||||
- private static final TextColor INFORMATION = TextColor.color(145, 198, 243);
|
||||
+ private static final TextColor INFORMATION = TextColor.color(180, 220, 255); // Luminol start - Improved Server Health Report
|
||||
private static final TextColor LIST = TextColor.color(33, 97, 188);
|
||||
|
||||
public CommandServerHealth() {
|
||||
@@ -60,9 +68,11 @@ public final class CommandServerHealth extends Command {
|
||||
return Component.text()
|
||||
.append(Component.text(prefix, PRIMARY, TextDecoration.BOLD))
|
||||
.append(Component.text(ONE_DECIMAL_PLACES.get().format(util * 100.0), CommandUtil.getUtilisationColourRegion(util)))
|
||||
- .append(Component.text("% util at ", PRIMARY))
|
||||
+ .append(Component.text("% util", PRIMARY))
|
||||
+ .append(Component.text(" | ", SECONDARY))
|
||||
.append(Component.text(TWO_DECIMAL_PLACES.get().format(mspt), CommandUtil.getColourForMSPT(mspt)))
|
||||
- .append(Component.text(" MSPT at ", PRIMARY))
|
||||
+ .append(Component.text(" mspt", PRIMARY))
|
||||
+ .append(Component.text(" | ", SECONDARY))
|
||||
.append(Component.text(TWO_DECIMAL_PLACES.get().format(tps), CommandUtil.getColourForTPS(tps)))
|
||||
.append(Component.text(" TPS" + (newline ? "\n" : ""), PRIMARY))
|
||||
.build();
|
||||
@@ -81,7 +91,7 @@ public final class CommandServerHealth extends Command {
|
||||
|
||||
private static boolean executeRegion(final CommandSender sender, final String commandLabel, final String[] args) {
|
||||
final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region =
|
||||
- TickRegionScheduler.getCurrentRegion();
|
||||
+ TickRegionScheduler.getCurrentRegion();
|
||||
if (region == null) {
|
||||
sender.sendMessage(Component.text("You are not in a region currently", NamedTextColor.RED));
|
||||
return true;
|
||||
@@ -105,8 +115,7 @@ public final class CommandServerHealth extends Command {
|
||||
final double tps1m = report1m.tpsData().segmentAll().average();
|
||||
final double mspt1m = report1m.timePerTickData().segmentAll().average() / 1.0E6;
|
||||
|
||||
- final int yLoc = 80;
|
||||
- final String location = "[w:'" + world.getWorld().getName() + "'," + centerBlockX + "," + yLoc + "," + centerBlockZ + "]";
|
||||
+ final String location = world.getWorld().getName() + " (" + centerBlockX + ", " + centerBlockZ + ")";
|
||||
|
||||
final Component line = Component.text()
|
||||
.append(Component.text("Region around block ", PRIMARY))
|
||||
@@ -144,7 +153,7 @@ public final class CommandServerHealth extends Command {
|
||||
}
|
||||
|
||||
final List<ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData>> regions =
|
||||
- new ArrayList<>();
|
||||
+ new ArrayList<>();
|
||||
|
||||
for (final World bukkitWorld : Bukkit.getWorlds()) {
|
||||
final ServerLevel world = ((CraftWorld)bukkitWorld).getHandle();
|
||||
@@ -163,6 +172,18 @@ public final class CommandServerHealth extends Command {
|
||||
final long currTime = System.nanoTime();
|
||||
final TickData.TickReportData globalTickReport = RegionizedServer.getGlobalTickData().getTickReport15s(currTime);
|
||||
|
||||
+ final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
|
||||
+ final MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
|
||||
+ final long usedMemory = heapUsage.getUsed() / (1024 * 1024);
|
||||
+ final long maxMemory = heapUsage.getMax() / (1024 * 1024);
|
||||
+
|
||||
+ final double memPercent = (double) usedMemory / maxMemory * 100.0;
|
||||
+ final TextColor memColor = memPercent < 60 ? CommandUtil.getUtilisationColourRegion(0.0) : (memPercent < 85 ? NamedTextColor.YELLOW : NamedTextColor.RED);
|
||||
+
|
||||
+ final RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
|
||||
+ final long uptime = runtimeBean.getUptime();
|
||||
+ final String uptimeStr = formatUptime(uptime);
|
||||
+
|
||||
for (final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region : regions) {
|
||||
final TickData.TickReportData report = region.getData().getRegionSchedulingHandle().getTickReport15s(currTime);
|
||||
tpsByRegion.add(report == null ? 20.0 : report.tpsData().segmentAll().average());
|
||||
@@ -174,31 +195,27 @@ public final class CommandServerHealth extends Command {
|
||||
final double loadRate = ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkFullTask.loadRate(currTime);
|
||||
|
||||
totalUtil += globalTickReport.utilisation();
|
||||
+ final TextColor utilisationColor = CommandUtil.getUtilisationColourRegion(totalUtil / (double)maxThreadCount);
|
||||
|
||||
tpsByRegion.sort(null);
|
||||
if (!tpsByRegion.isEmpty()) {
|
||||
minTps = tpsByRegion.getDouble(0);
|
||||
maxTps = tpsByRegion.getDouble(tpsByRegion.size() - 1);
|
||||
-
|
||||
final int middle = tpsByRegion.size() >> 1;
|
||||
if ((tpsByRegion.size() & 1) == 0) {
|
||||
- // even, average the two middle points
|
||||
medianTps = (tpsByRegion.getDouble(middle - 1) + tpsByRegion.getDouble(middle)) / 2.0;
|
||||
} else {
|
||||
- // odd, can just grab middle
|
||||
medianTps = tpsByRegion.getDouble(middle);
|
||||
}
|
||||
} else {
|
||||
- // no regions = green
|
||||
minTps = medianTps = maxTps = 20.0;
|
||||
}
|
||||
|
||||
final List<ObjectObjectImmutablePair<ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData>, TickData.TickReportData>>
|
||||
- regionsBelowThreshold = new ArrayList<>();
|
||||
+ regionsBelowThreshold = new ArrayList<>();
|
||||
|
||||
for (int i = 0, len = regions.size(); i < len; ++i) {
|
||||
final TickData.TickReportData report = reportsByRegion.get(i);
|
||||
-
|
||||
regionsBelowThreshold.add(new ObjectObjectImmutablePair<>(regions.get(i), report));
|
||||
}
|
||||
|
||||
@@ -207,11 +224,18 @@ public final class CommandServerHealth extends Command {
|
||||
final TickData.TickReportData report2 = p2.right();
|
||||
final double util1 = report1 == null ? 0.0 : report1.utilisation();
|
||||
final double util2 = report2 == null ? 0.0 : report2.utilisation();
|
||||
-
|
||||
- // we want the largest first
|
||||
return Double.compare(util2, util1);
|
||||
});
|
||||
|
||||
+ long totalChunks = 0;
|
||||
+ long totalEntities = 0;
|
||||
+
|
||||
+ for (final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region : regions) {
|
||||
+ final TickRegions.RegionStats stats = region.getData().getRegionStats();
|
||||
+ totalChunks += stats.getChunkCount();
|
||||
+ totalEntities += stats.getEntityCount();
|
||||
+ }
|
||||
+
|
||||
final TextComponent.Builder lowestRegionsBuilder = Component.text();
|
||||
|
||||
if (sender instanceof Player) {
|
||||
@@ -219,23 +243,18 @@ public final class CommandServerHealth extends Command {
|
||||
}
|
||||
for (int i = 0, len = Math.min(lowestRegionsCount, regionsBelowThreshold.size()); i < len; ++i) {
|
||||
final ObjectObjectImmutablePair<ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData>, TickData.TickReportData>
|
||||
- pair = regionsBelowThreshold.get(i);
|
||||
+ pair = regionsBelowThreshold.get(i);
|
||||
|
||||
final TickData.TickReportData report = pair.right();
|
||||
final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region =
|
||||
- pair.left();
|
||||
+ pair.left();
|
||||
|
||||
- if (report == null) {
|
||||
- // skip regions with no data
|
||||
- continue;
|
||||
- }
|
||||
+ if (report == null) continue;
|
||||
|
||||
final ServerLevel world = region.regioniser.world;
|
||||
final ChunkPos chunkCenter = region.getCenterChunk();
|
||||
- if (chunkCenter == null) {
|
||||
- // region does not exist anymore
|
||||
- continue;
|
||||
- }
|
||||
+ if (chunkCenter == null) continue;
|
||||
+
|
||||
final int centerBlockX = ((chunkCenter.x() << 4) | 7);
|
||||
final int centerBlockZ = ((chunkCenter.z() << 4) | 7);
|
||||
final double util = report.utilisation();
|
||||
@@ -243,18 +262,21 @@ public final class CommandServerHealth extends Command {
|
||||
final double mspt = report.timePerTickData().segmentAll().average() / 1.0E6;
|
||||
|
||||
final int yLoc = 80;
|
||||
- final String location = "[w:'" + world.getWorld().getName() + "'," + centerBlockX + "," + yLoc + "," + centerBlockZ + "]";
|
||||
+ final String location = world.getWorld().getName() + " (" + centerBlockX + ", " + centerBlockZ + ")";
|
||||
+
|
||||
final Component line = Component.text()
|
||||
.append(Component.text(" - ", LIST, TextDecoration.BOLD))
|
||||
- .append(Component.text("Region around block ", PRIMARY))
|
||||
+ .append(Component.text("Region at ", PRIMARY))
|
||||
.append(Component.text(location, INFORMATION))
|
||||
.append(Component.text(":\n", PRIMARY))
|
||||
|
||||
.append(Component.text(" ", PRIMARY))
|
||||
.append(Component.text(ONE_DECIMAL_PLACES.get().format(util * 100.0), CommandUtil.getUtilisationColourRegion(util)))
|
||||
- .append(Component.text("% util at ", PRIMARY))
|
||||
+ .append(Component.text("% util", PRIMARY))
|
||||
+ .append(Component.text(" | ", SECONDARY))
|
||||
.append(Component.text(TWO_DECIMAL_PLACES.get().format(mspt), CommandUtil.getColourForMSPT(mspt)))
|
||||
- .append(Component.text(" MSPT at ", PRIMARY))
|
||||
+ .append(Component.text(" mspt", PRIMARY))
|
||||
+ .append(Component.text(" | ", SECONDARY))
|
||||
.append(Component.text(TWO_DECIMAL_PLACES.get().format(tps), CommandUtil.getColourForTPS(tps)))
|
||||
.append(Component.text(" TPS\n", PRIMARY))
|
||||
|
||||
@@ -270,29 +292,53 @@ public final class CommandServerHealth extends Command {
|
||||
|
||||
sender.sendMessage(
|
||||
Component.text()
|
||||
- .append(Component.text("Server Health Report\n", HEADER, TextDecoration.BOLD))
|
||||
+ .append(Component.text("Server Health Report", HEADER, TextDecoration.BOLD))
|
||||
+ .append(Component.text(" (Uptime: ", SECONDARY))
|
||||
+ .append(Component.text(uptimeStr, utilisationColor))
|
||||
+ .append(Component.text(")\n", SECONDARY))
|
||||
|
||||
.append(Component.text(" - ", LIST, TextDecoration.BOLD))
|
||||
.append(Component.text("Online Players: ", PRIMARY))
|
||||
- .append(Component.text(Bukkit.getOnlinePlayers().size() + "\n", INFORMATION))
|
||||
+ .append(Component.text(Bukkit.getOnlinePlayers().size(), INFORMATION))
|
||||
+ .append(Component.newline())
|
||||
|
||||
.append(Component.text(" - ", LIST, TextDecoration.BOLD))
|
||||
.append(Component.text("Total regions: ", PRIMARY))
|
||||
- .append(Component.text(regions.size() + "\n", INFORMATION))
|
||||
+ .append(Component.text(regions.size(), INFORMATION))
|
||||
+ .append(Component.text(", ", PRIMARY))
|
||||
+ .append(Component.text("Total Chunks: ", PRIMARY))
|
||||
+ .append(Component.text(NO_DECIMAL_PLACES.get().format(totalChunks), INFORMATION))
|
||||
+ .append(Component.text(", ", PRIMARY))
|
||||
+ .append(Component.text("Total Entities: ", PRIMARY))
|
||||
+ .append(Component.text(NO_DECIMAL_PLACES.get().format(totalEntities) + "\n", INFORMATION))
|
||||
|
||||
.append(Component.text(" - ", LIST, TextDecoration.BOLD))
|
||||
.append(Component.text("Utilisation: ", PRIMARY))
|
||||
- .append(Component.text(ONE_DECIMAL_PLACES.get().format(totalUtil * 100.0), CommandUtil.getUtilisationColourRegion(totalUtil / (double)maxThreadCount)))
|
||||
- .append(Component.text("% / ", PRIMARY))
|
||||
+ .append(Component.text(ONE_DECIMAL_PLACES.get().format(totalUtil * 100.0), utilisationColor))
|
||||
+ .append(Component.text("%", PRIMARY))
|
||||
+ .append(Component.text(" / ", SECONDARY))
|
||||
.append(Component.text(ONE_DECIMAL_PLACES.get().format(maxThreadCount * 100.0), INFORMATION))
|
||||
.append(Component.text("%\n", PRIMARY))
|
||||
|
||||
.append(Component.text(" - ", LIST, TextDecoration.BOLD))
|
||||
.append(Component.text("Load rate: ", PRIMARY))
|
||||
- .append(Component.text(TWO_DECIMAL_PLACES.get().format(loadRate) + ", ", INFORMATION))
|
||||
+ .append(Component.text(TWO_DECIMAL_PLACES.get().format(loadRate), INFORMATION))
|
||||
+ .append(Component.text(", ", PRIMARY))
|
||||
.append(Component.text("Gen rate: ", PRIMARY))
|
||||
.append(Component.text(TWO_DECIMAL_PLACES.get().format(genRate) + "\n", INFORMATION))
|
||||
|
||||
+ .append(Component.text(" - ", LIST, TextDecoration.BOLD))
|
||||
+ .append(Component.text("Memory: ", PRIMARY))
|
||||
+ .append(Component.text(NO_DECIMAL_PLACES.get().format(usedMemory), memColor))
|
||||
+ .append(Component.text(" MB", memColor))
|
||||
+ .append(Component.text(" / ", SECONDARY))
|
||||
+ .append(Component.text(NO_DECIMAL_PLACES.get().format(maxMemory), INFORMATION))
|
||||
+ .append(Component.text(" MB", INFORMATION))
|
||||
+ .append(Component.text(" (", SECONDARY))
|
||||
+ .append(Component.text(ONE_DECIMAL_PLACES.get().format(memPercent) + "%", memColor))
|
||||
+ .append(Component.text(")", SECONDARY))
|
||||
+ .append(Component.newline())
|
||||
+
|
||||
.append(Component.text(" - ", LIST, TextDecoration.BOLD))
|
||||
.append(Component.text("Lowest Region TPS: ", PRIMARY))
|
||||
.append(Component.text(TWO_DECIMAL_PLACES.get().format(minTps) + "\n", CommandUtil.getColourForTPS(minTps)))
|
||||
@@ -361,4 +407,21 @@ public final class CommandServerHealth extends Command {
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
+
|
||||
+ // Luminol start - Improved Server Health Report
|
||||
+ private static @NotNull String formatUptime(long uptimeMillis) {
|
||||
+ long days = TimeUnit.MILLISECONDS.toDays(uptimeMillis);
|
||||
+ long hours = TimeUnit.MILLISECONDS.toHours(uptimeMillis) % 24;
|
||||
+ long minutes = TimeUnit.MILLISECONDS.toMinutes(uptimeMillis) % 60;
|
||||
+ long seconds = TimeUnit.MILLISECONDS.toSeconds(uptimeMillis) % 60;
|
||||
+
|
||||
+ StringBuilder sb = new StringBuilder();
|
||||
+ if (days > 0) sb.append(days).append("d ");
|
||||
+ if (hours > 0) sb.append(hours).append("h ");
|
||||
+ if (minutes > 0) sb.append(minutes).append("m ");
|
||||
+ sb.append(seconds).append("s");
|
||||
+
|
||||
+ return sb.toString();
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
\ No newline at end of file
|
||||
@@ -0,0 +1,522 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 1 May 2026 18:37:50 +0800
|
||||
Subject: [PATCH] World load/unload APIs
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
好吧这里这一坨需要说明的太多了而且我也不是很会翻译所以就用中文注释了)
|
||||
|
||||
这一整个实现使用了一种安全点的思路,相对于folia pr里和canvas的让每个region自己卸载, 我更偏向于将调度器拆分到每个level中然后实现类似于单个level停服的逻辑,这样会更加符合直觉而且实现要更加快速而且易于排查问题
|
||||
|
||||
由于世界卸载可能发生在玩家登录或者传送的过程中,所以我使用了引用计数器来避免这个竟态条件的发生
|
||||
|
||||
diff --git a/io/papermc/paper/threadedregions/RegionShutdownThread.java b/io/papermc/paper/threadedregions/RegionShutdownThread.java
|
||||
index f2208bcd5ccf3bd5a428e8ea3bf3ff26b3c9483b..d5c4e9b82f2ebc135b6747d19678b1a15e808ec8 100644
|
||||
--- a/io/papermc/paper/threadedregions/RegionShutdownThread.java
|
||||
+++ b/io/papermc/paper/threadedregions/RegionShutdownThread.java
|
||||
@@ -14,11 +14,11 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
-public final class RegionShutdownThread extends ca.spottedleaf.moonrise.common.util.TickThread {
|
||||
+public class RegionShutdownThread extends ca.spottedleaf.moonrise.common.util.TickThread { // Luminol - Level schedulers - Make public
|
||||
|
||||
- private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
+ public static final Logger LOGGER = LogUtils.getClassLogger(); // Luminol - Level schedulers - Make public
|
||||
|
||||
- ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> shuttingDown;
|
||||
+ public ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> shuttingDown; // Luminol - Level schedulers - Make public
|
||||
|
||||
public RegionShutdownThread(final String name) {
|
||||
super(name);
|
||||
@@ -52,7 +52,7 @@ public final class RegionShutdownThread extends ca.spottedleaf.moonrise.common.u
|
||||
// the data required to do that is regionised, and we can only access it when we OWN the region, and we do not.
|
||||
// Thus, the only operation that the shutdown thread will perform
|
||||
|
||||
- private void saveLevelData(final ServerLevel world) {
|
||||
+ public void saveLevelData(final ServerLevel world) { // Luminol - Level hot unload apis - Make public
|
||||
try {
|
||||
world.saveLevelData(true);
|
||||
} catch (final Throwable thr) {
|
||||
@@ -60,7 +60,7 @@ public final class RegionShutdownThread extends ca.spottedleaf.moonrise.common.u
|
||||
}
|
||||
}
|
||||
|
||||
- private void finishTeleportations(final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region,
|
||||
+ public void finishTeleportations(final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region, // Luminol - Level hot unload apis - Make public
|
||||
final ServerLevel world) {
|
||||
try {
|
||||
this.shuttingDown = region;
|
||||
@@ -94,7 +94,7 @@ public final class RegionShutdownThread extends ca.spottedleaf.moonrise.common.u
|
||||
}
|
||||
}
|
||||
|
||||
- private void saveRegionChunks(final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region,
|
||||
+ public void saveRegionChunks(final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region, // Luminol - Level hot unload apis - Make public
|
||||
final boolean last) {
|
||||
ChunkPos center = null;
|
||||
try {
|
||||
@@ -109,7 +109,7 @@ public final class RegionShutdownThread extends ca.spottedleaf.moonrise.common.u
|
||||
}
|
||||
}
|
||||
|
||||
- private void haltChunkSystem(final ServerLevel world) {
|
||||
+ public void haltChunkSystem(final ServerLevel world) { // Luminol - Level hot unload apis - Make public
|
||||
try {
|
||||
world.moonrise$getChunkTaskScheduler().chunkHolderManager.close(false, true, true, false, false);
|
||||
} catch (final Throwable thr) {
|
||||
@@ -117,7 +117,7 @@ public final class RegionShutdownThread extends ca.spottedleaf.moonrise.common.u
|
||||
}
|
||||
}
|
||||
|
||||
- private void closePlayerInventories(final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region) {
|
||||
+ public void closePlayerInventories(final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region) { // Luminol - Level hot unload apis - Make public
|
||||
ChunkPos center = null;
|
||||
try {
|
||||
this.shuttingDown = region;
|
||||
@@ -150,7 +150,7 @@ public final class RegionShutdownThread extends ca.spottedleaf.moonrise.common.u
|
||||
}
|
||||
|
||||
@Override
|
||||
- public final void run() {
|
||||
+ public void run() { // Luminol - Level hot unload apis - Make public
|
||||
// await scheduler termination
|
||||
LOGGER.info("Awaiting scheduler termination for 60s...");
|
||||
if (TickRegions.getScheduler().halt(true, TimeUnit.SECONDS.toNanos(60L))) {
|
||||
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
|
||||
index aa575f3b76ef70ffb9f0410e7e5cfe7af384bfbd..ff90abb47203c03636d3175f2b3efcf43517b3b0 100644
|
||||
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
|
||||
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
|
||||
@@ -63,6 +63,12 @@ public final class RegionizedServer {
|
||||
this.worlds.add(world);
|
||||
}
|
||||
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ public void removeWorld(final ServerLevel world) {
|
||||
+ this.worlds.remove(world);
|
||||
+ }
|
||||
+ // Luminol end
|
||||
+
|
||||
public void init() {
|
||||
// call init event _before_ scheduling anything
|
||||
new RegionizedServerInitEvent().callEvent();
|
||||
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
index 5a72fa0d72bfdb927293abe921c57f6ae964a6ec..f8344f640f119e3865f2718d1abd0ede9bdb8aa8 100644
|
||||
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
@@ -49,7 +49,7 @@ public final class TickRegionScheduler {
|
||||
}
|
||||
// Folia end - watchdog
|
||||
|
||||
- private final Scheduler scheduler;
|
||||
+ public final Scheduler scheduler; // Luminol - Level schedulers - Make public
|
||||
|
||||
public static enum SchedulerType {
|
||||
EDF,
|
||||
@@ -220,7 +220,15 @@ public final class TickRegionScheduler {
|
||||
*/
|
||||
public void scheduleRegion(final RegionScheduleHandle region) {
|
||||
region.scheduler = this;
|
||||
+ // this.scheduler.schedule(region); // Luminol - Level schedulers
|
||||
+ // Luminol start - Level schedulers
|
||||
+ if(region.region != null) {
|
||||
+ region.region.world.levelScheduler.schedule(region);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
this.scheduler.schedule(region);
|
||||
+ // Luminol end
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,13 +241,77 @@ public final class TickRegionScheduler {
|
||||
region.markNonSchedulable();
|
||||
}
|
||||
|
||||
+ // Luminol start - Level schedulers
|
||||
+ private void handleParentSchedulerDead() {
|
||||
+ for (ServerLevel level : MinecraftServer.getServer().getAllLevels()) {
|
||||
+ level.levelScheduler.onParentHalted();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public boolean haltAndWaitLevelSchedulerHalt(final boolean sync, final long maxWaitNS) {
|
||||
+ final long deadline = System.nanoTime() + maxWaitNS;
|
||||
+
|
||||
+ boolean hasUnhaltedLevelScheduler = false;
|
||||
+ for (net.minecraft.server.level.ServerLevel serverLevel : MinecraftServer.getServer().getAllLevels()) {
|
||||
+ serverLevel.levelScheduler.halt(); // ensure it's halted so that we could skip running any other new tasks
|
||||
+
|
||||
+ // block any new reading reference acquiring going into this lock
|
||||
+ serverLevel.levelUnloadStateLock.blockReadingReferencing();
|
||||
+
|
||||
+ // sync not required, directly go next
|
||||
+ if (!sync) {
|
||||
+ hasUnhaltedLevelScheduler |= !serverLevel.levelScheduler.isFullyExited();
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final boolean writeLockHeld = serverLevel.levelUnloadStateLock.acquireWrite(deadline);
|
||||
+ // we got the write lock, abort the others unloading logics
|
||||
+ if (writeLockHeld) {
|
||||
+ serverLevel.levelUnloadStateLock.acquireUnreachable();
|
||||
+
|
||||
+ // since there is no unloading tasks, so the callback would be always empty, just directly go next,
|
||||
+ // and we'll handle the final saving in global shutdown logics
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ // cannot get write lock, might be marked as unreachable
|
||||
+ final boolean isUnreachable = serverLevel.levelUnloadStateLock.isUnreachable();
|
||||
+ // already fully terminated (we mark it as unreachable after all separate unload saving logics), check the scheduler state
|
||||
+ if (isUnreachable) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ // try linearly block wait for halt
|
||||
+ long failures = 0L;
|
||||
+ while (!serverLevel.levelScheduler.isFullyExited()) {
|
||||
+ // check deadline
|
||||
+ if (deadline - System.nanoTime() <= 0) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ failures = ca.spottedleaf.concurrentutil.util.ConcurrentUtil.linearLongBackoffDeadline(failures, 100, 1000L, deadline);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return !hasUnhaltedLevelScheduler;
|
||||
+ }
|
||||
+ // Luminol end - Level schedulers
|
||||
+
|
||||
public boolean halt(final boolean sync, final long maxWaitNS) {
|
||||
- this.scheduler.halt();
|
||||
+ final boolean allLevelSchedulersExited = this.haltAndWaitLevelSchedulerHalt(sync, maxWaitNS); // Luminol - Level schedulers
|
||||
+ if (allLevelSchedulersExited) this.scheduler.halt(); // Luminol - Level schedulers
|
||||
if (!sync) {
|
||||
return this.scheduler.getAliveThreads().length == 0;
|
||||
}
|
||||
|
||||
- return this.scheduler.join(maxWaitNS == 0L ? 0L : Math.max(1L, TimeUnit.NANOSECONDS.toMillis(maxWaitNS)));
|
||||
+ // return this.scheduler.join(maxWaitNS == 0L ? 0L : Math.max(1L, TimeUnit.NANOSECONDS.toMillis(maxWaitNS))); // Luminol - Level schedulers
|
||||
+ // Luminol start - Level schedulers
|
||||
+ final boolean waitResult = allLevelSchedulersExited && this.scheduler.join(maxWaitNS == 0L ? 0L : Math.max(1L, TimeUnit.NANOSECONDS.toMillis(maxWaitNS)));
|
||||
+
|
||||
+ this.handleParentSchedulerDead();
|
||||
+
|
||||
+ return waitResult;
|
||||
+ // Luminol - end
|
||||
}
|
||||
|
||||
void dumpAliveThreadTraces(final String reason) {
|
||||
@@ -251,7 +323,15 @@ public final class TickRegionScheduler {
|
||||
}
|
||||
|
||||
public void setHasTasks(final RegionScheduleHandle region) {
|
||||
+ //this.scheduler.notifyTasks(region); // Luminol - Level schedulers
|
||||
+ // Luminol start - Level schedulers
|
||||
+ if (region.region != null) {
|
||||
+ region.region.world.levelScheduler.notifyTasks(region);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
this.scheduler.notifyTasks(region);
|
||||
+ // Luminol end
|
||||
}
|
||||
|
||||
private void uncaughtException(final Thread thread, final Throwable thr) {
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 88ccf32b3c1b3506fb76be5ae520168b6b167aa3..8bc18bf35537d5bbf2dacef34886b9a95d44a340 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -236,7 +236,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
private String localIp;
|
||||
private int port = -1;
|
||||
private final LayeredRegistryAccess<RegistryLayer> registries;
|
||||
- private Map<ResourceKey<Level>, ServerLevel> levels = Maps.newLinkedHashMap();
|
||||
+ private volatile Map<ResourceKey<Level>, ServerLevel> levels = Maps.newLinkedHashMap(); // Luminol - World hot load/unload apis
|
||||
private PlayerList playerList;
|
||||
private volatile boolean running = true;
|
||||
private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart
|
||||
@@ -2047,14 +2047,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
- public void addLevel(ServerLevel level) {
|
||||
+ public synchronized void addLevel(ServerLevel level) { // Luminol - World hot load/unload apis
|
||||
Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
|
||||
Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
|
||||
newLevels.put(level.dimension(), level);
|
||||
this.levels = Collections.unmodifiableMap(newLevels);
|
||||
}
|
||||
|
||||
- public void removeLevel(ServerLevel level) {
|
||||
+ public synchronized void removeLevel(ServerLevel level) { // Luminol - World hot load/unload apis
|
||||
Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
|
||||
Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
|
||||
newLevels.remove(level.dimension());
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 6950fa2462353f30ee02e1d0091cfcf289f63939..def5d4ce012dba5f819680d671235173467bfe7a 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -221,6 +221,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
||||
private final StructureCheck structureCheck;
|
||||
public final boolean tickTime; // Folia - region threading
|
||||
private final LevelDebugSynchronizers debugSynchronizers = new LevelDebugSynchronizers(this);
|
||||
+ // Luminol start - Level schedulers
|
||||
+ private static final java.util.concurrent.atomic.AtomicInteger UNLOADER_ID_GEN = new java.util.concurrent.atomic.AtomicInteger(0);
|
||||
+ public final me.earthme.luminol.utils.thread.LevelAwareRegionScheduler levelScheduler = new me.earthme.luminol.utils.thread.LevelAwareRegionScheduler(io.papermc.paper.threadedregions.TickRegions.getScheduler().scheduler);
|
||||
+ public final me.earthme.luminol.utils.thread.SimpleReferenceRWLock levelUnloadStateLock = new me.earthme.luminol.utils.thread.SimpleReferenceRWLock();
|
||||
+ public final me.earthme.luminol.utils.thread.LevelSubRegionShutdownThread levelUnloader = new me.earthme.luminol.utils.thread.LevelSubRegionShutdownThread("Level Unload Thread - " + UNLOADER_ID_GEN.getAndIncrement(), this);
|
||||
+ // Luminol end
|
||||
|
||||
// CraftBukkit start
|
||||
private final ResourceKey<LevelStem> typeKey;
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0802483484015fd92dec211aae9fd33e45621f74..4c9915087798f6548bb22574051c7b0b5aed7732 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1694,7 +1694,30 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
|
||||
ServerLevel origin = this.level();
|
||||
ServerPlayer.RespawnConfig respawnConfig = this.getRespawnConfig();
|
||||
- ServerLevel respawnWorld = this.server.getLevel(ServerPlayer.RespawnConfig.getDimensionOrDefault(respawnConfig));
|
||||
+ ServerLevel respawnWorldLookup = this.server.getLevel(ServerPlayer.RespawnConfig.getDimensionOrDefault(respawnConfig)); // Luminol - Level hot unload apis
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ var toLockRelease = (ServerLevel)null;
|
||||
+ if (respawnWorldLookup != null) {
|
||||
+ if (respawnWorldLookup.levelUnloadStateLock.acquireRead()) {
|
||||
+ toLockRelease = respawnWorldLookup;
|
||||
+ } else {
|
||||
+ respawnWorldLookup = null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final ServerLevel respawnWorld = respawnWorldLookup;
|
||||
+ final ServerLevel finalToLockRelease = toLockRelease;
|
||||
+
|
||||
+ var finalRespawnCompleteCallback = (java.util.function.Consumer<ServerPlayer>) player -> {
|
||||
+ if (finalToLockRelease != null) {
|
||||
+ finalToLockRelease.levelUnloadStateLock.releaseRead();
|
||||
+ }
|
||||
+
|
||||
+ if (respawnComplete != null) {
|
||||
+ respawnComplete.accept(player);
|
||||
+ }
|
||||
+ };
|
||||
+ // Luminol end
|
||||
|
||||
// modified based off PlayerList#respawn
|
||||
|
||||
@@ -1745,8 +1768,8 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
// now the respawn logic is complete
|
||||
|
||||
// last, call the function callback
|
||||
- if (respawnComplete != null) {
|
||||
- respawnComplete.accept(ServerPlayer.this);
|
||||
+ if (finalRespawnCompleteCallback != null) { // Luminol - Level hot unload apis
|
||||
+ finalRespawnCompleteCallback.accept(ServerPlayer.this); // Luminol - Level hot unload apis
|
||||
}
|
||||
}
|
||||
);
|
||||
diff --git a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
index 111789b4aca281dd1899dfbcc4e7e0ca36d74b51..2d3b0243f061aeaa979ddfc89c0361ecc29edcde 100644
|
||||
--- a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -219,8 +219,23 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
|
||||
this.switchToMain = serverPlayer;
|
||||
// now the connection responsibility is transferred to the region
|
||||
- final net.minecraft.server.level.ServerLevel world = this.prepareSpawnTask.getSpawnWorld();
|
||||
+ net.minecraft.server.level.ServerLevel worldLookup = this.prepareSpawnTask.getSpawnWorld(); // Luminol - Level hot unload apis - world -> worldLookup, make mutable
|
||||
final net.minecraft.world.level.ChunkPos chunkPos = net.minecraft.world.level.ChunkPos.containing(net.minecraft.core.BlockPos.containing(this.prepareSpawnTask.getSpawnPosition()));
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ if (!worldLookup.levelUnloadStateLock.acquireRead()) {
|
||||
+ LOGGER.warn("Failed to acquire read reference for level {} for player placement, sending back to overworld!", worldLookup.dimension());
|
||||
+
|
||||
+ worldLookup = net.minecraft.server.MinecraftServer.getServer().overworld();
|
||||
+ if (!worldLookup.levelUnloadStateLock.acquireRead()) {
|
||||
+ throw new java.lang.IllegalStateException("Reference read for overworld should be always acquirable!");
|
||||
+ }
|
||||
+
|
||||
+ serverPlayer.setServerLevel(worldLookup);
|
||||
+ }
|
||||
+ var world = worldLookup;
|
||||
+ // note: the following logics would always be successfully executed, otherwise the server go crashed
|
||||
+ // so do not care the exception handling of the callbacks following
|
||||
+ // Luminol end
|
||||
world.moonrise$getChunkTaskScheduler().scheduleTickingState(
|
||||
chunkPos.x(), chunkPos.z(), net.minecraft.server.level.FullChunkStatus.ENTITY_TICKING, true,
|
||||
ca.spottedleaf.concurrentutil.util.Priority.HIGHER,
|
||||
@@ -232,9 +247,15 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
);
|
||||
io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue(
|
||||
world, chunkPos.x(), chunkPos.z(), () -> {
|
||||
+ try { // Luminol - Level hot unload apis
|
||||
net.minecraft.server.network.ServerConfigurationPacketListenerImpl.this.prepareSpawnTask.spawnPlayer(
|
||||
this.connection, commonListenerCookie, serverPlayer
|
||||
);
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ } finally {
|
||||
+ world.levelUnloadStateLock.releaseRead();
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
);
|
||||
}
|
||||
diff --git a/net/minecraft/server/network/config/PrepareSpawnTask.java b/net/minecraft/server/network/config/PrepareSpawnTask.java
|
||||
index 9fad06eda81b4c2c1889a9cfa7a6948e7ee01862..854f8954ccfd8c34c9f9c91fd1805260f9b429b5 100644
|
||||
--- a/net/minecraft/server/network/config/PrepareSpawnTask.java
|
||||
+++ b/net/minecraft/server/network/config/PrepareSpawnTask.java
|
||||
@@ -104,6 +104,16 @@ public class PrepareSpawnTask implements ConfigurationTask {
|
||||
spawnLevel = spawnDataLevel;
|
||||
}
|
||||
}
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ if (!spawnLevel.levelUnloadStateLock.acquireRead()) {
|
||||
+ spawnLevel = spawnDataLevel;
|
||||
+
|
||||
+ // the apis don't allow devs to unload overworld, so just simply do a check withoud fail-processing logics on it
|
||||
+ if (!spawnLevel.levelUnloadStateLock.acquireRead()) {
|
||||
+ throw new java.lang.IllegalStateException("Default level should be acquirable!");
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end
|
||||
// Folia start - region threading
|
||||
CompletableFuture<Vec3> spawnPosition = new java.util.concurrent.CompletableFuture<>();
|
||||
if (loadedPosition.position().isPresent()) {
|
||||
@@ -123,6 +133,10 @@ public class PrepareSpawnTask implements ConfigurationTask {
|
||||
}
|
||||
// Folia end - region threading
|
||||
// Paper end - move logic in Entity to here, to use bukkit supplied world UUID & reset to main world spawn if no valid world is found
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ final ServerLevel finalSpawnLevel = spawnLevel;
|
||||
+ spawnPosition.whenComplete((_, _) -> finalSpawnLevel.levelUnloadStateLock.releaseRead());
|
||||
+ // Luminol end
|
||||
Vec2 spawnAngle = loadedPosition.rotation().orElse(new Vec2(respawnData.yaw(), respawnData.pitch()));
|
||||
this.state = new PrepareSpawnTask.Preparing(spawnLevel, spawnPosition, spawnAngle);
|
||||
}
|
||||
@@ -272,9 +286,20 @@ public class PrepareSpawnTask implements ConfigurationTask {
|
||||
this.spawnPosition = CompletableFuture.completedFuture(spawnPosition);
|
||||
this.spawnAngle = new Vec2(location.getYaw(), location.getPitch());
|
||||
}
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ if (!this.spawnLevel.levelUnloadStateLock.acquireRead()) {
|
||||
+ LOGGER.warn("Could not fetch read reference lock for level {}! Falling back to overworld!", this.spawnLevel);
|
||||
+
|
||||
+ this.spawnLevel = net.minecraft.server.MinecraftServer.getServer().overworld();
|
||||
+ if (!this.spawnLevel.levelUnloadStateLock.acquireRead()) {
|
||||
+ throw new java.lang.IllegalStateException();
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end
|
||||
// Paper end - PlayerSpawnLocationEvent
|
||||
ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(spawnPosition));
|
||||
this.chunkLoadFuture = ((ca.spottedleaf.moonrise.patches.chunk_system.MoonriseChunkLoadCounter)this.chunkLoadCounter).trackLoadWithRadius(this.spawnLevel, spawnChunk, 3, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ca.spottedleaf.concurrentutil.util.Priority.HIGH, () -> { Preparing.this.spawnLevel.getChunkSource().addTicketWithRadius(TicketType.PLAYER_SPAWN, spawnChunk, 3); }); // Paper - rewrite chunk system
|
||||
+ this.chunkLoadFuture.whenComplete((_,_) -> this.spawnLevel.levelUnloadStateLock.releaseRead()); // Luminol - Level hot unload apis
|
||||
PrepareSpawnTask.this.loadListener.start(LevelLoadListener.Stage.LOAD_PLAYER_CHUNKS, this.chunkLoadCounter.totalChunks());
|
||||
PrepareSpawnTask.this.loadListener.updateFocus(this.spawnLevel.dimension(), spawnChunk);
|
||||
}
|
||||
@@ -291,7 +316,7 @@ public class PrepareSpawnTask implements ConfigurationTask {
|
||||
}
|
||||
|
||||
private final class Ready implements PrepareSpawnTask.State {
|
||||
- private final ServerLevel spawnLevel;
|
||||
+ private ServerLevel spawnLevel; // Luminol - Level hot unloaad apis - Make public
|
||||
private final Vec3 spawnPosition;
|
||||
private final Vec2 spawnAngle;
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 33c9692a59c58c44a77b1077553e2bda88cb8305..e8047a06a2df17fde9965508c1ebcf1fc4d25989 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -392,6 +392,9 @@ public abstract class Entity
|
||||
public void inactiveTick() {
|
||||
}
|
||||
// Paper end - EAR 2
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ public me.earthme.luminol.utils.TeleportRecord lastTeleportRecord;
|
||||
+ // Luminol end
|
||||
// CraftBukkit end
|
||||
|
||||
// Paper start
|
||||
@@ -4534,6 +4537,17 @@ public abstract class Entity
|
||||
}
|
||||
}
|
||||
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ if (!destination.levelUnloadStateLock.acquireRead()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ final java.util.function.Consumer<Entity> finalTeleportComplete = entity -> {
|
||||
+ destination.levelUnloadStateLock.releaseRead();
|
||||
+
|
||||
+ if (teleportComplete != null) teleportComplete.accept(entity);
|
||||
+ };
|
||||
+ // Luminol end
|
||||
+
|
||||
// TODO any events that can modify go HERE
|
||||
|
||||
// check for same region
|
||||
@@ -4552,6 +4566,14 @@ public abstract class Entity
|
||||
}
|
||||
|
||||
for (EntityTreeNode entity : passengerTree.getFullTree()) {
|
||||
+ // Luminol start - Level hot unload apis
|
||||
+ entity.root.lastTeleportRecord = me.earthme.luminol.utils.TeleportRecord.create(
|
||||
+ (ServerLevel) entity.root.level,
|
||||
+ entity.root.position,
|
||||
+ entity.root.yRot,
|
||||
+ entity.root.xRot
|
||||
+ );
|
||||
+ // Luminol end
|
||||
entity.root.teleportSyncSameRegion(pos, yaw, pitch, velocity);
|
||||
}
|
||||
|
||||
@@ -4567,8 +4589,8 @@ public abstract class Entity
|
||||
// performs add/remove from world logic which will also perform add/remove tracker logic
|
||||
}
|
||||
|
||||
- if (teleportComplete != null) {
|
||||
- teleportComplete.accept(this);
|
||||
+ if (finalTeleportComplete != null) { // Luminol - Level hot unload apis
|
||||
+ finalTeleportComplete.accept(this); // Luminol - Level hot unload apis
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -4585,7 +4607,7 @@ public abstract class Entity
|
||||
node.root = node.root.transformForAsyncTeleport(destination, pos, yaw, pitch, velocity);
|
||||
}
|
||||
|
||||
- passengerTree.root.placeInAsync(originWorld, destination, teleportFlags, passengerTree, teleportComplete);
|
||||
+ passengerTree.root.placeInAsync(originWorld, destination, teleportFlags, passengerTree, finalTeleportComplete); // Luminol - Level hot unload apis
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -4864,6 +4886,13 @@ public abstract class Entity
|
||||
ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(initialPosition),
|
||||
ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(initialPosition)
|
||||
);
|
||||
+ // Luminol start - Level hot load/unload apis
|
||||
+ // let's acquire read reference first
|
||||
+ if (!destination.levelUnloadStateLock.acquireRead()) {
|
||||
+ // failed, destination is under unloading process
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Luminol end
|
||||
|
||||
// first, remove entity/passengers from world
|
||||
EntityTreeNode passengerTree = this.detachPassengers();
|
||||
@@ -4921,6 +4950,10 @@ public abstract class Entity
|
||||
if (info.postTeleportTransition() != null) {
|
||||
info.postTeleportTransition().onTransition(teleported);
|
||||
}
|
||||
+ // Luminol start - Level hot load/unload apis
|
||||
+ // all done, release the read reference
|
||||
+ destination.levelUnloadStateLock.releaseRead();
|
||||
+ // Luminol end
|
||||
|
||||
if (teleportComplete != null) {
|
||||
teleportComplete.accept(teleported);
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Tue, 21 Apr 2026 01:32:38 +0800
|
||||
Subject: [PATCH] Kaiiju: Do not pathfind outside region
|
||||
|
||||
Co-authored by: Sofiane H. Djerbi <46628754+kugge@users.noreply.github.com>
|
||||
As part of: Kaiiju (https://github.com/KaiijuMC/Kaiiju/blob/c2b7aec8f7b418a39a2ec408e6411e6f752379da/patches/server/0028-Don-t-pathfind-outside-region.patch)
|
||||
Licensed under: GPL-3.0 (https://github.com/KaiijuMC/Kaiiju/blob/c2b7aec8f7b418a39a2ec408e6411e6f752379da/LICENSE)
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java b/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java
|
||||
index b40da004b5281a041ee896ae176bfb9c4660f353..ffb8a725c41d49a0f0e023ab37bb77062d67eccc 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java
|
||||
@@ -117,7 +117,9 @@ public class MoveToTargetSink extends Behavior<Mob> {
|
||||
|
||||
private boolean tryComputePath(final Mob body, final WalkTarget walkTarget, final long timestamp) {
|
||||
BlockPos targetPos = walkTarget.getTarget().currentBlockPosition();
|
||||
+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(body.level(), targetPos)) // Kaiiju - Don't pathfind outside region
|
||||
this.path = body.getNavigation().createPath(targetPos, 0);
|
||||
+ else this.path = null; // Kaiiju - Don't pathfind outside region
|
||||
this.speedModifier = walkTarget.getSpeedModifier();
|
||||
Brain<?> brain = body.getBrain();
|
||||
if (this.reachedTarget(body, walkTarget)) {
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Sat, 8 Aug 2026 01:27:42 +0800
|
||||
Subject: [PATCH] Kaiiju: Entity tick and removal limiter
|
||||
|
||||
Co-authored by: Xymb <xymb@endcrystal.me>
|
||||
As part of: Kaiiju (https://github.com/KaiijuMC/Kaiiju/blob/c2b7aec8f7b418a39a2ec408e6411e6f752379da/patches/server/0021-Entity-ticking-throttling-removal-to-prevent-lag.patch)
|
||||
Licensed under: GPL-3.0 (https://github.com/KaiijuMC/Kaiiju/blob/c2b7aec8f7b418a39a2ec408e6411e6f752379da/LICENSE)
|
||||
|
||||
diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||
index c8f13da82c55cc5c1fe1c922a87e3eccb1117937..981458f6697a79dbc9fc8cf41c088c98e556c6dd 100644
|
||||
--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||
+++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java
|
||||
@@ -349,6 +349,7 @@ public final class RegionizedWorldData {
|
||||
private final IteratorSafeOrderedReferenceSet<Mob> navigatingMobs = new IteratorSafeOrderedReferenceSet<>();
|
||||
public ReferenceList<Entity> trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
|
||||
public boolean iteratingTrackerEntities;
|
||||
+ public final dev.kaiijumc.kaiiju.KaiijuEntityThrottler entityThrottler = new dev.kaiijumc.kaiiju.KaiijuEntityThrottler(); // Kaiiju
|
||||
|
||||
// block ticking
|
||||
private final ObjectLinkedOpenHashSet<BlockEventData> blockEvents = new ObjectLinkedOpenHashSet<>();
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index def5d4ce012dba5f819680d671235173467bfe7a..1c01ec9597c47b7296f498a897f1fd2333c8c4d4 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -917,6 +917,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
||||
}
|
||||
|
||||
foliaProfiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ACTIVATE_ENTITIES); try { // Folia - profiler
|
||||
+ if (dev.kaiijumc.kaiiju.KaiijuEntityLimits.enabled) regionizedWorldData.entityThrottler.tickLimiterStart(); // Kaiiju
|
||||
io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR
|
||||
} finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ACTIVATE_ENTITIES); } // Folia - profiler
|
||||
foliaProfiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ENTITY_TICK); try { // Folia - profiler
|
||||
@@ -938,6 +939,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
||||
|
||||
entity.stopRiding();
|
||||
}
|
||||
+ // Kaiiju start
|
||||
+ if (dev.kaiijumc.kaiiju.KaiijuEntityLimits.enabled) {
|
||||
+ dev.kaiijumc.kaiiju.KaiijuEntityThrottler.EntityThrottlerReturn throttle = regionizedWorldData.entityThrottler.tickLimiterShouldSkip(entity);
|
||||
+ if (throttle.remove && !entity.hasCustomName()) entity.remove(Entity.RemovalReason.DISCARDED);
|
||||
+ if (throttle.skip) return;
|
||||
+ }
|
||||
+ // Kaiiju end
|
||||
|
||||
profiler.push("tick");
|
||||
this.guardEntityTick(this::tickNonPassenger, entity);
|
||||
@@ -947,6 +955,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
||||
}
|
||||
}
|
||||
);
|
||||
+ if (dev.kaiijumc.kaiiju.KaiijuEntityLimits.enabled) regionizedWorldData.entityThrottler.tickLimiterFinish(regionizedWorldData); // Kaiiju
|
||||
} finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ENTITY_TICK); } // Folia - profiler
|
||||
if (this.paperConfig().unsupportedSettings.ticking.blockEntities) { // Paper - option to disable ticking
|
||||
profiler.popPush("blockEntities");
|
||||
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
|
||||
index 6efaa78faca15c7a48bdffb24480d1bac29f3ba8..31619890f1bd4f458b6f9a31fac8cefaafe09e8e 100644
|
||||
--- a/net/minecraft/world/entity/EntityType.java
|
||||
+++ b/net/minecraft/world/entity/EntityType.java
|
||||
@@ -73,6 +73,7 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
|
||||
private final float spawnDimensionsScale;
|
||||
private final FeatureFlagSet requiredFeatures;
|
||||
private final boolean allowedInPeaceful;
|
||||
+ public volatile dev.kaiijumc.kaiiju.KaiijuEntityLimits.EntityLimit entityLimit;
|
||||
|
||||
public static Identifier getKey(final EntityType<?> type) {
|
||||
return BuiltInRegistries.ENTITY_TYPE.getKey(type);
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Sat, 18 Apr 2026 09:21:31 +0800
|
||||
Subject: [PATCH] Kaiiju: Vanilla end portal teleportation
|
||||
|
||||
Co-authored by: Sofiane H. Djerbi <46628754+kugge@users.noreply.github.com>
|
||||
As part of: Kaiiju (https://github.com/KaiijuMC/Kaiiju/blob/c2b7aec8f7b418a39a2ec408e6411e6f752379da/patches/server/0024-Vanilla-end-portal-teleportation.patch)
|
||||
Licensed under: GPL-3.0 (https://github.com/KaiijuMC/Kaiiju/blob/c2b7aec8f7b418a39a2ec408e6411e6f752379da/LICENSE)
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index e8047a06a2df17fde9965508c1ebcf1fc4d25989..3b98ef4310d9f996437af9f12ab3de2cf6f4dd63 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -4672,15 +4672,19 @@ public abstract class Entity
|
||||
targetPos, 16, // load 16 blocks to be safe from block physics
|
||||
ca.spottedleaf.concurrentutil.util.Priority.HIGH,
|
||||
(chunks) -> {
|
||||
- net.minecraft.world.level.levelgen.feature.EndPlatformFeature.createEndPlatform(destination, targetPos.below(), true, null);
|
||||
-
|
||||
+ //net.minecraft.world.level.levelgen.feature.EndPlatformFeature.createEndPlatform(destination, targetPos.below(), true, null); // Kaiiju - Vanilla end teleportation - moved down
|
||||
+ // Kaiiju start - Vanilla end teleportation
|
||||
+ Vec3 finalPos;
|
||||
+ if (this instanceof Player) finalPos = Vec3.atBottomCenterOf(targetPos.below());
|
||||
+ else finalPos = Vec3.atBottomCenterOf(targetPos);
|
||||
+ // Kaiiju end
|
||||
// the portal obsidian is placed at targetPos.y - 2, so if we want to place the entity
|
||||
// on the obsidian, we need to spawn at targetPos.y - 1
|
||||
portalInfoCompletable.complete(
|
||||
new net.minecraft.world.level.portal.TeleportTransition(
|
||||
- destination, Vec3.atBottomCenterOf(targetPos.below()), Vec3.ZERO, Direction.WEST.toYRot(), 0.0f,
|
||||
+ destination, finalPos, this.getDeltaMovement(), Direction.WEST.toYRot(), 0.0f, // Kaiiju - Vanilla end teleportation
|
||||
false, false,
|
||||
- Relative.union(Relative.DELTA, Set.of(Relative.X_ROT)),
|
||||
+ /*Relative.union(Relative.DELTA, Set.of(Relative.X_ROT))*/Set.of(), // Kaiiju - Vanilla end teleportation
|
||||
TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET),
|
||||
org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL,
|
||||
TeleportTransition.PassengerTeleportationMode.POSITION_RIDER
|
||||
@@ -4696,11 +4700,15 @@ public abstract class Entity
|
||||
ca.spottedleaf.concurrentutil.util.Priority.HIGH,
|
||||
(chunks) -> {
|
||||
BlockPos adjustedSpawn = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, spawnPos);
|
||||
-
|
||||
+ // Kaiiju start - Vanilla end teleportation
|
||||
+ Vec3 finalPos;
|
||||
+ if (this instanceof Player) finalPos = Vec3.atBottomCenterOf(adjustedSpawn.below());
|
||||
+ else finalPos = Vec3.atBottomCenterOf(adjustedSpawn);
|
||||
+ // Kaiiju end
|
||||
// done
|
||||
portalInfoCompletable.complete(
|
||||
new net.minecraft.world.level.portal.TeleportTransition(
|
||||
- destination, Vec3.atBottomCenterOf(adjustedSpawn), Vec3.ZERO, 0.0f, 0.0f,
|
||||
+ destination, finalPos, this.getDeltaMovement(), 0.0f, 0.0f, // Kaiiju - Vanilla end teleportation
|
||||
false, false,
|
||||
Relative.union(Relative.DELTA, Relative.ROTATION),
|
||||
TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET),
|
||||
@@ -4881,6 +4889,10 @@ public abstract class Entity
|
||||
return false;
|
||||
}
|
||||
|
||||
+ // Kaiiju start - sync end platform spawning & entity teleportation
|
||||
+ final java.util.function.Consumer<Entity> tpComplete = type == PortalType.END && destination.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END ?
|
||||
+ e -> {net.minecraft.world.level.levelgen.feature.EndPlatformFeature.createEndPlatform(destination, ServerLevel.END_SPAWN_POINT.below(), true, null); if (teleportComplete != null) {teleportComplete.accept(e);}} : teleportComplete;
|
||||
+ // Kaiiju end
|
||||
Vec3 initialPosition = this.position();
|
||||
ChunkPos initialPositionChunk = new ChunkPos(
|
||||
ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(initialPosition),
|
||||
@@ -4955,9 +4967,14 @@ public abstract class Entity
|
||||
destination.levelUnloadStateLock.releaseRead();
|
||||
// Luminol end
|
||||
|
||||
- if (teleportComplete != null) {
|
||||
+ // Kaiiju start - vanilla end teleportation
|
||||
+ /*if (teleportComplete != null) {
|
||||
teleportComplete.accept(teleported);
|
||||
+ }*/
|
||||
+ if (tpComplete != null){
|
||||
+ tpComplete.accept(teleported);
|
||||
}
|
||||
+ // Kaiiju end
|
||||
}
|
||||
);
|
||||
});
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Sat, 8 Aug 2026 01:29:57 +0800
|
||||
Subject: [PATCH] Async protocol switching optimization
|
||||
|
||||
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index 40f54536422fa38bd84017fc634808016b4de58b..ecaa296f576c5c90fda89e0406d6552628ef5de3 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -1067,4 +1067,127 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
}
|
||||
// Paper end - Optimize network
|
||||
+ // Luminol start - async protocol switcher
|
||||
+ public <T extends PacketListener> void setupInboundProtocolAsync(
|
||||
+ ProtocolInfo<T> protocol,
|
||||
+ T packetListener,
|
||||
+ @Nullable Runnable callback,
|
||||
+ boolean resumeAutoReading
|
||||
+ ) {
|
||||
+ this.validateListener(protocol, packetListener);
|
||||
+ if (protocol.flow() != this.getReceiving()) {
|
||||
+ throw new IllegalStateException("Invalid inbound protocol: " + protocol.id());
|
||||
+ } else {
|
||||
+ this.packetListener = packetListener;
|
||||
+ this.disconnectListener = null;
|
||||
+
|
||||
+ UnconfiguredPipelineHandler.InboundConfigurationTask configMessage = UnconfiguredPipelineHandler.setupInboundProtocol(protocol);
|
||||
+ BundlerInfo bundlerInfo = protocol.bundlerInfo();
|
||||
+ if (bundlerInfo != null) {
|
||||
+ PacketBundlePacker newBundler = new PacketBundlePacker(bundlerInfo);
|
||||
+ configMessage = configMessage.andThen(context -> context.pipeline().addAfter("decoder", "bundler", newBundler));
|
||||
+ }
|
||||
+
|
||||
+ // Here we could execute it in event loop async to prevent waiting io task on main
|
||||
+ // stop reading new packets to prevent some packets came into pipeline too early
|
||||
+ this.channel.config().setAutoRead(false);
|
||||
+
|
||||
+ // do our configuration task
|
||||
+ final UnconfiguredPipelineHandler.InboundConfigurationTask finalInboundConfigurationTask = configMessage;
|
||||
+ Runnable toExecute = () -> this.channel.writeAndFlush(finalInboundConfigurationTask).addListener(future -> {
|
||||
+ try {
|
||||
+ if (future.isSuccess()) {
|
||||
+ if (callback != null) callback.run(); // retire callback if there have one
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final Throwable ex = future.cause();
|
||||
+
|
||||
+ // here we process our exceptions like that blocking one
|
||||
+ if (ex instanceof ClosedChannelException) {
|
||||
+ LOGGER.info("Connection closed during protocol change");
|
||||
+ } else {
|
||||
+ this.channel.pipeline().fireExceptionCaught(ex);
|
||||
+ }
|
||||
+ }finally {
|
||||
+ // reset auto back and resume reading if needed
|
||||
+ if (resumeAutoReading) {
|
||||
+ this.channel.config().setAutoRead(true);
|
||||
+ this.channel.read();
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ // we need to do this inside the event loop
|
||||
+ if (!this.channel.eventLoop().inEventLoop()) {
|
||||
+ this.channel.eventLoop().execute(toExecute);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ toExecute.run();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void setupOutboundProtocolAsync(
|
||||
+ ProtocolInfo<?> protocol,
|
||||
+ @Nullable Runnable callback,
|
||||
+ boolean resumeAutoReading
|
||||
+ ) {
|
||||
+ if (protocol.flow() != this.getSending()) {
|
||||
+ throw new IllegalStateException("Invalid outbound protocol: " + protocol.id());
|
||||
+ } else {
|
||||
+ UnconfiguredPipelineHandler.OutboundConfigurationTask configMessage = UnconfiguredPipelineHandler.setupOutboundProtocol(protocol);
|
||||
+ BundlerInfo bundlerInfo = protocol.bundlerInfo();
|
||||
+ if (bundlerInfo != null) {
|
||||
+ PacketBundleUnpacker newUnbundler = new PacketBundleUnpacker(bundlerInfo);
|
||||
+ configMessage = configMessage.andThen(
|
||||
+ context -> context.pipeline().addAfter("encoder", "unbundler", newUnbundler)
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ boolean isLoginProtocol = protocol.id() == ConnectionProtocol.LOGIN;
|
||||
+
|
||||
+ // Here we could execute it in event loop async to prevent waiting io task on main
|
||||
+ // stop reading new packets to prevent some packets came into pipeline too early
|
||||
+ this.channel.config().setAutoRead(false);
|
||||
+
|
||||
+ // do our configuration task
|
||||
+ final UnconfiguredPipelineHandler.OutboundConfigurationTask finalOutboundConfigurationTask = configMessage;
|
||||
+ final Runnable writeTask = () -> this.channel.writeAndFlush(
|
||||
+ finalOutboundConfigurationTask.andThen(context -> this.sendLoginDisconnect = isLoginProtocol)
|
||||
+ ).addListener(future -> {
|
||||
+ try {
|
||||
+ if (future.isSuccess()) {
|
||||
+ if (callback != null) callback.run(); // retire callback if there have one
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final Throwable ex = future.cause();
|
||||
+
|
||||
+ // here we process our exceptions like that blocking one
|
||||
+ if (ex instanceof ClosedChannelException) {
|
||||
+ LOGGER.info("Connection closed during protocol change");
|
||||
+ } else {
|
||||
+ this.channel.pipeline().fireExceptionCaught(ex);
|
||||
+ }
|
||||
+ }finally {
|
||||
+ // reset auto back and resume reading if needed
|
||||
+ if (resumeAutoReading) {
|
||||
+ this.channel.config().setAutoRead(true);
|
||||
+ this.channel.read(); // read once
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ // we need to do this inside the event loop
|
||||
+ if (!this.channel.eventLoop().inEventLoop()) {
|
||||
+ this.channel.eventLoop().execute(writeTask);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ writeTask.run();
|
||||
+ }
|
||||
+ }
|
||||
+ // Luminol end
|
||||
+
|
||||
}
|
||||
diff --git a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
index 2d3b0243f061aeaa979ddfc89c0361ecc29edcde..e074fe9eb6a1e6cb30b7de522fcac673dcb81960 100644
|
||||
--- a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -197,8 +197,9 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
public void handleConfigurationFinished(final ServerboundFinishConfigurationPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.server.packetProcessor());
|
||||
this.finishCurrentTask(JoinWorldTask.TYPE);
|
||||
- this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess())));
|
||||
+ // this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()))); // Luminol - Async protocol switch - move down
|
||||
|
||||
+ Runnable afterSwitch = () -> { // Luminol - Async protocol switch
|
||||
try {
|
||||
PlayerList playerList = this.server.getPlayerList();
|
||||
if (playerList.getPlayer(this.gameProfile.id()) != null) {
|
||||
@@ -265,6 +266,18 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
LOGGER.error("Couldn't place player in world", e);
|
||||
this.disconnect(DISCONNECT_REASON_INVALID_DATA);
|
||||
}
|
||||
+ // Luminol start - Async protocol switch
|
||||
+ };
|
||||
+ if (!me.earthme.luminol.config.modules.optimizations.AsyncProtocolChangeConfig.enabled) {
|
||||
+ this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess())));
|
||||
+ afterSwitch.run(); // directly run callback as we won't process any packet this time
|
||||
+ } else {
|
||||
+ this.connection.setupOutboundProtocolAsync(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess())), () -> {
|
||||
+ // push back
|
||||
+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(afterSwitch);
|
||||
+ }, false); // we will start auto read once we set up inbound handler at placeNewPlayer in PlayerList
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 9be6d486082d344fb91fd74207eee83ca2f8e869..40b409ad07eaa03473712ba83bc4ccd9a5c0f932 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2902,7 +2902,13 @@ public class ServerGamePacketListenerImpl
|
||||
} // Folia end - rewrite login process - move connection ownership to global region
|
||||
this.waitingForSwitchToConfig = true; // Folia - rewrite login process - fix bad ordering of this field write - moved down
|
||||
this.send(ClientboundStartConfigurationPacket.INSTANCE);
|
||||
+ if (!me.earthme.luminol.config.modules.optimizations.AsyncProtocolChangeConfig.enabled) { // Luminol - Async protocol switch
|
||||
this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND);
|
||||
+ // Luminol start - Async protcol switch
|
||||
+ } else {
|
||||
+ this.connection.setupOutboundProtocolAsync(ConfigurationProtocols.CLIENTBOUND, null, true);
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3787,12 +3793,26 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
final ServerConfigurationPacketListenerImpl listener = new ServerConfigurationPacketListenerImpl(this.server, this.connection, this.createCookie(this.player.clientInformation())); // Paper
|
||||
+ if (!me.earthme.luminol.config.modules.optimizations.AsyncProtocolChangeConfig.enabled) { // Luminol - Async protocol switch
|
||||
this.connection
|
||||
.setupInboundProtocol(
|
||||
ConfigurationProtocols.SERVERBOUND,
|
||||
listener // Paper
|
||||
);
|
||||
new io.papermc.paper.event.connection.configuration.PlayerConnectionReconfigureEvent(listener.paperConnection).callEvent(); // Paper
|
||||
+ } // Luminol - Async protocol switch - add "{"
|
||||
+ // Luminol start - Async protocol switch - move up
|
||||
+ else
|
||||
+ this.connection.setupInboundProtocolAsync(
|
||||
+ ConfigurationProtocols.SERVERBOUND,
|
||||
+ listener,
|
||||
+ () -> {
|
||||
+ new io.papermc.paper.event.connection.configuration.PlayerConnectionReconfigureEvent(listener.paperConnection).callEvent(); // Paper
|
||||
+ },
|
||||
+ true
|
||||
+ );
|
||||
+ // Luminol end
|
||||
+ // new io.papermc.paper.event.connection.configuration.PlayerConnectionReconfigureEvent(listener.paperConnection).callEvent(); // Paper // Luminol - Async protocol switch - move up
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index f2329d1a9d9d4bf4c9d771e25e54f2f9ef65a76c..deee051c103f9797f4612e06c12f293ec54724ac 100644
|
||||
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -435,12 +435,30 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
public void handleLoginAcknowledgement(final ServerboundLoginAcknowledgedPacket packet) {
|
||||
net.minecraft.network.protocol.PacketUtils.ensureRunningOnSameThread(packet, this, this.server.packetProcessor()); // CraftBukkit
|
||||
Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet");
|
||||
- this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND);
|
||||
+ /*this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); // Luminol - Async protocol switch - Rewrite
|
||||
CommonListenerCookie cookie = CommonListenerCookie.createInitial(Objects.requireNonNull(this.authenticatedProfile), this.transferred);
|
||||
ServerConfigurationPacketListenerImpl configPacketListener = new ServerConfigurationPacketListenerImpl(this.server, this.connection, cookie);
|
||||
this.connection.setupInboundProtocol(ConfigurationProtocols.SERVERBOUND, configPacketListener);
|
||||
configPacketListener.startConfiguration();
|
||||
- this.state = ServerLoginPacketListenerImpl.State.ACCEPTED;
|
||||
+ this.state = ServerLoginPacketListenerImpl.State.ACCEPTED;*/ // Luminol - Async protocol switch - Rewrite
|
||||
+
|
||||
+ // Luminol start - Async protocol switch
|
||||
+ CommonListenerCookie cookie = CommonListenerCookie.createInitial(Objects.requireNonNull(this.authenticatedProfile), this.transferred);
|
||||
+ ServerConfigurationPacketListenerImpl configPacketListener = new ServerConfigurationPacketListenerImpl(this.server, this.connection, cookie);
|
||||
+
|
||||
+ Runnable afterSwitch = () -> io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(configPacketListener::startConfiguration); // push back to main thread
|
||||
+
|
||||
+ if (!me.earthme.luminol.config.modules.optimizations.AsyncProtocolChangeConfig.enabled) {
|
||||
+ this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND);
|
||||
+ this.connection.setupInboundProtocol(ConfigurationProtocols.SERVERBOUND, configPacketListener);
|
||||
+ afterSwitch.run();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ this.connection.setupInboundProtocolAsync(ConfigurationProtocols.SERVERBOUND, configPacketListener, () -> {
|
||||
+ this.connection.setupOutboundProtocolAsync(ConfigurationProtocols.CLIENTBOUND, afterSwitch, true); // start auto read when everything is ready
|
||||
+ }, false); // we will resume auto reading once the outbound protocol is also setup
|
||||
+ // Luminol end
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 259eb7574841b1b885093b534440f8a40db4e8e2..2975a879320faed5f6591489f86d3f909072cbaa 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -237,9 +237,11 @@ public abstract class PlayerList {
|
||||
// only after setting the connection listener to game type, add the connection to this regions list
|
||||
level.getCurrentWorldData().addConnection(player);
|
||||
// Folia end - rewrite login process
|
||||
+ if (!me.earthme.luminol.config.modules.optimizations.AsyncProtocolChangeConfig.enabled) { // Luminol - Async protocol switch // we will run async switch once these main thread logics became done
|
||||
connection.setupInboundProtocol(
|
||||
GameProtocols.SERVERBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()), playerConnection), playerConnection
|
||||
);
|
||||
+ } // Luminol - Async protocol switch
|
||||
playerConnection.suspendFlushing();
|
||||
GameRules gameRules = level.getGameRules();
|
||||
boolean immediateRespawn = gameRules.get(GameRules.IMMEDIATE_RESPAWN);
|
||||
@@ -403,6 +405,17 @@ public abstract class PlayerList {
|
||||
);
|
||||
}
|
||||
// Paper end - Send empty chunk
|
||||
+ // Luminol start - Async protocol switch
|
||||
+ if (me.earthme.luminol.config.modules.optimizations.AsyncProtocolChangeConfig.enabled) {
|
||||
+ // auto read will be enabled once the async switch is done
|
||||
+ connection.setupInboundProtocolAsync(
|
||||
+ GameProtocols.SERVERBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()), playerConnection),
|
||||
+ playerConnection,
|
||||
+ null, // we don't need to do anything more
|
||||
+ true // start auto read which we have disabled in configuration handler
|
||||
+ );
|
||||
+ }
|
||||
+ // Luminol end
|
||||
}
|
||||
|
||||
public void updateEntireScoreboard(final ServerScoreboard scoreboard, final ServerPlayer player) {
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Sat, 18 Apr 2026 09:08:52 +0800
|
||||
Subject: [PATCH] Add config for server mod name
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 8bc18bf35537d5bbf2dacef34886b9a95d44a340..daf45761bdc88848ba81b7595b5abd5635dfd607 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -2085,7 +2085,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
public String getServerModName() {
|
||||
- return io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper
|
||||
+ return me.earthme.luminol.config.modules.misc.ServerModNameConfig.fakeVanilla ? "vanilla" : me.earthme.luminol.config.modules.misc.ServerModNameConfig.serverModName; // Paper // Luminol - Add config for server mod name
|
||||
}
|
||||
|
||||
public ServerClockManager clockManager() {
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Sat, 18 Apr 2026 09:09:33 +0800
|
||||
Subject: [PATCH] Add config for offline mode warning
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 1145d5839e621a02b7972c2ff1142f51db2237de..81934fb56744dbbb3fdd100e8ec83cb634034d04 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -304,7 +304,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord";
|
||||
String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/";
|
||||
// Paper end - Add Velocity IP Forwarding Support
|
||||
- if (!this.usesAuthentication()) {
|
||||
+ if (!this.usesAuthentication() && !me.earthme.luminol.config.modules.misc.DisableWarningConfig.disableOfflineModeWarning) { //Luminol - Add config for offline mod warning
|
||||
LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
|
||||
LOGGER.warn("The server will make no attempt to authenticate usernames. Beware.");
|
||||
// Spigot start
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Fri, 17 Apr 2026 22:47:34 +0800
|
||||
Subject: [PATCH] Add config for cpu affinity
|
||||
|
||||
|
||||
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
index f8344f640f119e3865f2718d1abd0ede9bdb8aa8..58e557923dfe6cee39ec45e7f5aa43a5ded9f107 100644
|
||||
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||
@@ -66,7 +66,7 @@ public final class TickRegionScheduler {
|
||||
|
||||
@Override
|
||||
public Thread newThread(final Runnable run) {
|
||||
- final Thread ret = new TickThreadRunner(this.threadGroup, run, "Folia Region Scheduler Thread #" + this.idGenerator.getAndIncrement());
|
||||
+ final Thread ret = new TickThreadRunner(this.threadGroup, me.earthme.luminol.config.modules.optimizations.CpuAffinityConfig.wrapForTickRegion(run), "Folia Region Scheduler Thread #" + this.idGenerator.getAndIncrement()); // Luminol - cpu affinity
|
||||
ret.setUncaughtExceptionHandler(TickRegionScheduler.this::uncaughtException);
|
||||
return ret;
|
||||
}
|
||||
-243
@@ -1,243 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Sat, 7 Feb 2026 23:57:50 +0800
|
||||
Subject: [PATCH] Leaves: Catch update suppression crash
|
||||
|
||||
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/network/PacketProcessor.java b/net/minecraft/network/PacketProcessor.java
|
||||
index cf162ec136309d05c5aa03042652ab3932935917..469ffd54eb5af980f49061bbec0a72f4e888f8a3 100644
|
||||
--- a/net/minecraft/network/PacketProcessor.java
|
||||
+++ b/net/minecraft/network/PacketProcessor.java
|
||||
@@ -107,7 +107,20 @@ public class PacketProcessor implements AutoCloseable {
|
||||
final int packetTimerId = profiler.getOrCreateTimerAndStart(() -> "Packet Handler: ".concat(io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(ListenerAndPacket.this.packet.getClass().getName()))); try { // Folia - profiler
|
||||
this.packet.handle(this.listener);
|
||||
} finally { profiler.stopTimer(packetTimerId); } // Folia - profiler
|
||||
- } catch (Exception var3) {
|
||||
+ // Leaves start - update suppression crash fix
|
||||
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
|
||||
+ if (this.listener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) {
|
||||
+ exception.providePlayer(gamePacketListener.player);
|
||||
+ }
|
||||
+ exception.consume();
|
||||
+ } catch (Exception var3) {
|
||||
+ if (var3.getCause() instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) {
|
||||
+ if (this.listener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) {
|
||||
+ exception.providePlayer(gamePacketListener.player);
|
||||
+ }
|
||||
+ exception.consume();
|
||||
+ }
|
||||
+ // Leaves end - update suppression crash fix
|
||||
if (var3 instanceof ReportedException reportedException && reportedException.getCause() instanceof OutOfMemoryError) {
|
||||
throw PacketUtils.makeReportedException(var3, this.packet, this.listener);
|
||||
}
|
||||
diff --git a/net/minecraft/network/protocol/PacketUtils.java b/net/minecraft/network/protocol/PacketUtils.java
|
||||
index ab80a66646a7ebe2862221ac342b06c14fcfc734..7834f3da4d0ff4a5cdec46b023d7348369a12e96 100644
|
||||
--- a/net/minecraft/network/protocol/PacketUtils.java
|
||||
+++ b/net/minecraft/network/protocol/PacketUtils.java
|
||||
@@ -34,6 +34,7 @@ public class PacketUtils {
|
||||
}
|
||||
|
||||
public static <T extends PacketListener> ReportedException makeReportedException(Exception exception, Packet<T> packet, T packetListener) {
|
||||
+
|
||||
if (exception instanceof ReportedException reportedException) {
|
||||
fillCrashReport(reportedException.getReport(), packetListener, packet);
|
||||
return reportedException;
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 24f83a6875219aaf4b29e2461afcd0478a391014..9457d86461b032ff2dac338620c3d4a54e6c7071 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1978,11 +1978,27 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
try {
|
||||
profiler.startTimer(serverLevel.tickTimerId); try { // Folia - profiler
|
||||
serverLevel.tick(hasTimeLeft, region); // Folia - region threading
|
||||
+ // Leaves start - update suppression crash fix
|
||||
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
|
||||
+ exception.provideLevel(serverLevel);
|
||||
+ exception.consume();
|
||||
} finally { profiler.stopTimer(serverLevel.tickTimerId); } // Folia - profiler
|
||||
} catch (Throwable var7) {
|
||||
- CrashReport crashReport = CrashReport.forThrowable(var7, "Exception ticking world");
|
||||
- serverLevel.fillReportDetails(crashReport);
|
||||
- throw new ReportedException(crashReport);
|
||||
+ org.leavesmc.leaves.util.UpdateSuppressionException updateSuppressionException = null;
|
||||
+ if (var7 instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) {
|
||||
+ updateSuppressionException = exception;
|
||||
+ } else if (var7.getCause() instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) {
|
||||
+ updateSuppressionException = exception;
|
||||
+ }
|
||||
+ if (updateSuppressionException != null) {
|
||||
+ updateSuppressionException.provideLevel(serverLevel);
|
||||
+ updateSuppressionException.consume();
|
||||
+ } else {
|
||||
+ // Leaves end - update suppression crash fix
|
||||
+ CrashReport crashReport = CrashReport.forThrowable(var7, "Exception ticking world");
|
||||
+ serverLevel.fillReportDetails(crashReport);
|
||||
+ throw new ReportedException(crashReport);
|
||||
+ }
|
||||
}
|
||||
|
||||
profilerFiller.pop();
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 9345bdb2770e7c27488c547012020337fc651edc..447b3e6149716a3ca4b9721746ea471c94c56e67 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -894,7 +894,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// Kaiiju end
|
||||
|
||||
profilerFiller.push("tick");
|
||||
- this.guardEntityTick(this::tickNonPassenger, entity);
|
||||
+ // Lophine start - update suppression crash fix
|
||||
+ if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) {
|
||||
+ try {
|
||||
+ this.guardEntityTick(this::tickNonPassenger, entity); // Lophine changed
|
||||
+ // Leaves start - update suppression crash fix - for dragon dupe
|
||||
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
|
||||
+ exception.provideLevel(this);
|
||||
+ exception.consume();
|
||||
+ // Leaves end - update suppression crash fix - for dragon dupe
|
||||
+ }
|
||||
+ } else {
|
||||
+ this.guardEntityTick(this::tickNonPassenger, entity);
|
||||
+ }
|
||||
+ // Lophine end - update suppression crash fix
|
||||
profilerFiller.pop();
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index ca751564d9189e873d4a53be9a2c68b2a04a8624..e6ec0788b88d3431c06134c879b4bae9c769dac1 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1108,6 +1108,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
|
||||
+ // Leaves start - update suppression crash fix
|
||||
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
|
||||
+ exception.providePlayer(this);
|
||||
+ exception.provideLevel(this.level());
|
||||
+ exception.consume();
|
||||
+ // Leaves start - update suppression crash fix
|
||||
} catch (Throwable var4) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(var4, "Ticking player");
|
||||
CrashReportCategory crashReportCategory = crashReport.addCategory("Player being ticked");
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 5ac53fcdca5fa6aae0452840e78d67653ceececb..26de0d418e0dcbb4ecd88630d75c677fdc7ff93d 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1427,9 +1427,19 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
|
||||
this.walkingStepSound(pos, state);
|
||||
}
|
||||
|
||||
+ // Leaves start - update suppression crash fix
|
||||
if (broadcastGameEvent) {
|
||||
- this.level().gameEvent(GameEvent.STEP, this.position(), GameEvent.Context.of(this, state));
|
||||
+ try {
|
||||
+ this.level().gameEvent(net.minecraft.world.level.gameevent.GameEvent.STEP, this.position(), net.minecraft.world.level.gameevent.GameEvent.Context.of(this, state));
|
||||
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) {
|
||||
+ exception.provideBlock(level, pos, state.getBlock());
|
||||
+ if (this instanceof net.minecraft.server.level.ServerPlayer player) {
|
||||
+ exception.providePlayer(player);
|
||||
+ }
|
||||
+ exception.consume();
|
||||
+ }
|
||||
}
|
||||
+ // Leaves end - update suppression crash fix
|
||||
|
||||
return true;
|
||||
} else {
|
||||
diff --git a/net/minecraft/world/level/block/ShulkerBoxBlock.java b/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
index cb0471b06c33d1f79ba5b7a9b6036ba6b089d2be..46d6c6e3befc70a6878e12a4d75575e6d48d10ca 100644
|
||||
--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
@@ -181,7 +181,17 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
|
||||
|
||||
@Override
|
||||
protected int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos, Direction direction) {
|
||||
- return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
|
||||
+ // Leaves start - update suppression crash fix
|
||||
+ try {
|
||||
+ return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
|
||||
+ } catch (ClassCastException ex) {
|
||||
+ if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) {
|
||||
+ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, null, this, null, ex);
|
||||
+ } else {
|
||||
+ throw ex;
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaves end - update suppression crash fix
|
||||
}
|
||||
|
||||
public static Block getBlockByColor(@Nullable DyeColor color) {
|
||||
diff --git a/net/minecraft/world/level/block/state/StateHolder.java b/net/minecraft/world/level/block/state/StateHolder.java
|
||||
index c020d1944a25e2cd247e30a97c35bf93731d694a..74967f20099ea58cea1f9fc0f2387d8c45b54748 100644
|
||||
--- a/net/minecraft/world/level/block/state/StateHolder.java
|
||||
+++ b/net/minecraft/world/level/block/state/StateHolder.java
|
||||
@@ -104,7 +104,16 @@ public abstract class StateHolder<O, S> implements ca.spottedleaf.moonrise.patch
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
- throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner);
|
||||
+ // Leaves start - update suppression crash fix
|
||||
+ IllegalArgumentException iae = new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner);
|
||||
+ if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) {
|
||||
+ org.leavesmc.leaves.util.UpdateSuppressionException exception = new org.leavesmc.leaves.util.UpdateSuppressionException(null, null, null, null, iae);
|
||||
+ if (exception.getStackTrace()[1].getClassName().startsWith("net.minecraft")) {
|
||||
+ throw exception;
|
||||
+ }
|
||||
+ }
|
||||
+ throw iae;
|
||||
+ // Leaves end - update suppression crash fix
|
||||
// Paper end - optimise blockstate property access
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 77577d0df9b14a7ad55b2866c2ac31863226458b..5551d80a81c2878136f96b3e695c4888c7105a49 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -383,7 +383,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
if (blockState == state) {
|
||||
return null;
|
||||
} else {
|
||||
- Block block = state.getBlock();
|
||||
+ Block block = state.getBlock(); try { // Leaves start - update suppression crash fix
|
||||
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(i, y, i2, state);
|
||||
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(i, y, i2, state);
|
||||
this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(i, y, i2, state);
|
||||
@@ -457,6 +457,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
this.markUnsaved();
|
||||
return blockState;
|
||||
}
|
||||
+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException e) { e.provideBlock(level, pos, block); throw e; } // Leaves - update suppression crash fix
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/redstone/NeighborUpdater.java b/net/minecraft/world/level/redstone/NeighborUpdater.java
|
||||
index af21821513f11011e7bf3841d2f79cb99e4cd517..32488203ff074b675f5c8831d157b1d91bae48a9 100644
|
||||
--- a/net/minecraft/world/level/redstone/NeighborUpdater.java
|
||||
+++ b/net/minecraft/world/level/redstone/NeighborUpdater.java
|
||||
@@ -63,9 +63,22 @@ public interface NeighborUpdater {
|
||||
} finally { if (levelChunk != null) levelChunk.getChunkHot().stopTickingAndCount(); } // KioCG
|
||||
// Spigot start
|
||||
} catch (StackOverflowError ex) {
|
||||
+ // Leaves start - update suppression crash fix
|
||||
+ if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) {
|
||||
+ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, level, neighborBlock, null, ex);
|
||||
+ }
|
||||
level.lastPhysicsProblem = pos.immutable();
|
||||
// Spigot end
|
||||
} catch (Throwable var9) {
|
||||
+ if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) {
|
||||
+ if (var9 instanceof org.leavesmc.leaves.util.UpdateSuppressionException ue) {
|
||||
+ ue.provideBlock(level, pos, neighborBlock);
|
||||
+ throw ue;
|
||||
+ } else {
|
||||
+ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, level, neighborBlock, null, var9);
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaves end - update suppression crash fix
|
||||
CrashReport crashReport = CrashReport.forThrowable(var9, "Exception while updating neighbours");
|
||||
CrashReportCategory crashReportCategory = crashReport.addCategory("Block being updated");
|
||||
crashReportCategory.setDetail(
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Tue, 21 Apr 2026 01:47:51 +0800
|
||||
Subject: [PATCH] Add config for unsafe teleportation
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
index 480b6b2405706fd4d7158d0e160adafd84099887..137389f7ee97fc3a15c8f5f87c058065af91264e 100644
|
||||
--- a/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -70,7 +70,7 @@ public class FallingBlockEntity extends Entity {
|
||||
public int fallDamageMax = 40;
|
||||
public float fallDamagePerDistance = 0.0F;
|
||||
public @Nullable CompoundTag blockData;
|
||||
- public boolean forceTickAfterTeleportToDuplicate;
|
||||
+ public boolean forceTickAfterTeleportToDuplicate = me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled; // Luminol - Unsafe teleportation
|
||||
protected static final EntityDataAccessor<BlockPos> DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS);
|
||||
public boolean autoExpire = true; // Paper - Expand FallingBlock API
|
||||
|
||||
@@ -384,7 +384,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; // Paper
|
||||
+ 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
|
||||
return newEntity;
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/EndPortalBlock.java b/net/minecraft/world/level/block/EndPortalBlock.java
|
||||
index 123df098fa987030fe3789f36ff95aeee2979834..35b0632faf2709f65f731cd42e575ee967937254 100644
|
||||
--- a/net/minecraft/world/level/block/EndPortalBlock.java
|
||||
+++ b/net/minecraft/world/level/block/EndPortalBlock.java
|
||||
@@ -76,6 +76,12 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal {
|
||||
if (level.paperConfig().misc.disableEndCredits) {player.seenCredits = true; return;} // Paper - Option to disable end credits
|
||||
player.showEndCredits();
|
||||
} else {
|
||||
+ // Luminol start - unsafe teleportation
|
||||
+ if (me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled && !(entity instanceof net.minecraft.world.entity.player.Player)) {
|
||||
+ entity.endPortalLogicAsync(pos);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Luminol end
|
||||
entity.setAsInsidePortal(this, pos);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bacteriawa <A3167717663@hotmail.com>
|
||||
Date: Sat, 15 Nov 2025 01:12:39 +0800
|
||||
Subject: [PATCH] Leaves: CCE update suppression
|
||||
|
||||
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/ShulkerBoxBlock.java b/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
index 46d6c6e3befc70a6878e12a4d75575e6d48d10ca..77840814806c7d07b58cd716cf7ec095e894498a 100644
|
||||
--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
@@ -183,7 +183,9 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
|
||||
protected int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos, Direction direction) {
|
||||
// Leaves start - update suppression crash fix
|
||||
try {
|
||||
- return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
|
||||
+ return fun.bm.lophine.config.modules.experiment.RedStoneConfig.cce ?
|
||||
+ AbstractContainerMenu.getRedstoneSignalFromContainer((net.minecraft.world.Container) level.getBlockEntity(pos)) : // Leaves - make cce happy(?)
|
||||
+ AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
|
||||
} catch (ClassCastException ex) {
|
||||
if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) {
|
||||
throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, null, this, null, ex);
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 20:04:06 +0800
|
||||
Subject: [PATCH] Add config for vanilla random
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 3b98ef4310d9f996437af9f12ab3de2cf6f4dd63..a7f4a9f8bca00fda1b57e2245c57726bb1ce41ed 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -298,7 +298,7 @@ public abstract class Entity
|
||||
public double yOld;
|
||||
public double zOld;
|
||||
public boolean noPhysics;
|
||||
- protected final RandomSource random = SHARED_RANDOM; // Paper - Share random for entities to make them more random
|
||||
+ protected final RandomSource random = me.earthme.luminol.config.modules.fixes.VanillaRandomSourceConfig.useLegacyRandomSourceForPlayers ? RandomSource.create() : SHARED_RANDOM; // Paper - Share random for entities to make them more random // Luminol - Add config for vanilla random SHARED_RANDOM
|
||||
public int tickCount;
|
||||
private int remainingFireTicks;
|
||||
private final EntityFluidInteraction fluidInteraction = new EntityFluidInteraction(Set.of(FluidTags.WATER, FluidTags.LAVA));
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||
Date: Wed, 14 Jun 2023 12:07:07 +0800
|
||||
Subject: [PATCH] Leaves: Redstone ignore upwards update
|
||||
|
||||
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/ComparatorBlock.java b/net/minecraft/world/level/block/ComparatorBlock.java
|
||||
index 578e7c8dc601f53cf2a068685c6901bfaf47e763..0686aa5425c00e10beb381f3c3ff3c554603cd49 100644
|
||||
--- a/net/minecraft/world/level/block/ComparatorBlock.java
|
||||
+++ b/net/minecraft/world/level/block/ComparatorBlock.java
|
||||
@@ -58,6 +58,7 @@ public class ComparatorBlock extends DiodeBlock implements EntityBlock {
|
||||
BlockState neighborState,
|
||||
RandomSource random
|
||||
) {
|
||||
+ if (fun.bm.lophine.config.modules.experiment.RedStoneConfig.redstoneIgnoreUpwardsUpdate && direction == Direction.DOWN) return state; // Leaves - behavior to 1.20.1
|
||||
return direction == Direction.DOWN && !this.canSurviveOn(level, neighborPos, neighborState)
|
||||
? Blocks.AIR.defaultBlockState()
|
||||
: super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random);
|
||||
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
index ba253a9af6141d8ea99c064e3cc0c6486c221098..48f9e234e4025633cbc41d334d88ada36c2e0d7b 100644
|
||||
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
@@ -178,7 +178,7 @@ public class RedStoneWireBlock extends Block {
|
||||
RandomSource random
|
||||
) {
|
||||
if (direction == Direction.DOWN) {
|
||||
- return !this.canSurviveOn(level, neighborPos, neighborState) ? Blocks.AIR.defaultBlockState() : state;
|
||||
+ return fun.bm.lophine.config.modules.experiment.RedStoneConfig.redstoneIgnoreUpwardsUpdate ? state : !this.canSurviveOn(level, neighborPos, neighborState) ? Blocks.AIR.defaultBlockState() : state; // Leaves - behavior to 1.19
|
||||
} else if (direction == Direction.UP) {
|
||||
return this.getConnectionState(level, state, pos);
|
||||
} else {
|
||||
@@ -238,7 +238,7 @@ public class RedStoneWireBlock extends Block {
|
||||
BlockPos blockPos = pos.relative(direction);
|
||||
BlockState blockState = level.getBlockState(blockPos);
|
||||
if (nonNormalCubeAbove) {
|
||||
- boolean flag = blockState.getBlock() instanceof TrapDoorBlock || this.canSurviveOn(level, blockPos, blockState);
|
||||
+ boolean flag = (!fun.bm.lophine.config.modules.experiment.RedStoneConfig.redstoneIgnoreUpwardsUpdate && blockState.getBlock() instanceof TrapDoorBlock) || this.canSurviveOn(level, blockPos, blockState); // Leaves - behavior to 1.19
|
||||
if (flag && shouldConnectTo(level.getBlockState(blockPos.above()))) {
|
||||
if (blockState.isFaceSturdy(level, blockPos, direction.getOpposite())) {
|
||||
return RedstoneSide.UP;
|
||||
diff --git a/net/minecraft/world/level/block/RepeaterBlock.java b/net/minecraft/world/level/block/RepeaterBlock.java
|
||||
index 87e1a32376adc5a15f035b62bc1f672c507cd230..26c10c1fecb976f3ef0338aa78603d454d1b3fe8 100644
|
||||
--- a/net/minecraft/world/level/block/RepeaterBlock.java
|
||||
+++ b/net/minecraft/world/level/block/RepeaterBlock.java
|
||||
@@ -68,6 +68,7 @@ public class RepeaterBlock extends DiodeBlock {
|
||||
BlockState neighborState,
|
||||
RandomSource random
|
||||
) {
|
||||
+ if (fun.bm.lophine.config.modules.experiment.RedStoneConfig.redstoneIgnoreUpwardsUpdate && direction == Direction.DOWN) return state; // Leaves - behavior to 1.20.1
|
||||
if (direction == Direction.DOWN && !this.canSurviveOn(level, neighborPos, neighborState)) {
|
||||
return Blocks.AIR.defaultBlockState();
|
||||
} else {
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrHua269 <mrhua269@gmail.com>
|
||||
Date: Sat, 18 Apr 2026 09:12:26 +0800
|
||||
Subject: [PATCH] Add config for watchdog timeout
|
||||
|
||||
|
||||
diff --git a/io/papermc/paper/threadedregions/FoliaWatchdogThread.java b/io/papermc/paper/threadedregions/FoliaWatchdogThread.java
|
||||
index e9ca1a15049b0211d10401cb78e953b93afaf6c7..fe1560579f9c9572082d52cf910f5916957f5601 100644
|
||||
--- a/io/papermc/paper/threadedregions/FoliaWatchdogThread.java
|
||||
+++ b/io/papermc/paper/threadedregions/FoliaWatchdogThread.java
|
||||
@@ -65,7 +65,7 @@ public final class FoliaWatchdogThread extends Thread {
|
||||
|
||||
for (final RunningTick tick : ticks) {
|
||||
final long elapsed = now - tick.lastPrint;
|
||||
- if (elapsed <= TimeUnit.SECONDS.toNanos(5L)) {
|
||||
+ if (elapsed <= TimeUnit.MILLISECONDS.toNanos(me.earthme.luminol.config.modules.misc.FoliaWatchogConfig.tickRegionTimeOutMs)) { // Luminol - Add config for watchdog timeout
|
||||
continue;
|
||||
}
|
||||
tick.lastPrint = now;
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||
Date: Sun, 28 Jun 2026 20:10:51 +0800
|
||||
Subject: [PATCH] Add config to disable entity tick catchers
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index dc28223684091cd0d8dbf7ff01626b20e4f1b662..6fd7bfa561f71cfd043d7a1092d77b01bb320640 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -1591,6 +1591,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
), null, 1L);
|
||||
// Luminol end
|
||||
} catch (Throwable t) {
|
||||
+ if (me.earthme.luminol.config.modules.experiment.DisableEntityCatchConfig.enabled) throw t; // Luminol
|
||||
// Paper start - Prevent block entity and entity crashes
|
||||
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", io.papermc.paper.util.MCUtil.getLevelName(entity.level()), entity.getX(), entity.getY(), entity.getZ());
|
||||
MinecraftServer.LOGGER.error(msg, t);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user