Initial import of Luminol Core.
This commit is contained in:
commit
6892c0e423
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# https://help.github.com/articles/dealing-with-line-endings/
|
||||||
|
#
|
||||||
|
# Linux start script should use lf
|
||||||
|
/gradlew text eol=lf
|
||||||
|
|
||||||
|
# These are Windows script files and should use crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
|
||||||
|
# Binary files should be left untouched
|
||||||
|
*.jar binary
|
||||||
14
.github/FUNDING.yml
vendored
Normal file
14
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
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
|
||||||
68
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
68
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
name: Bug反馈 Bug report
|
||||||
|
description:
|
||||||
|
报告Bug,插件不兼容情况,以及其他相关问题。
|
||||||
|
Report issues with plugin incompatbility or other behavior related issues.
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
请详细描述您所遇到的Bug。确保您**真的**遇到了**服务端**Bug,而非原版特性或客户端Bug。
|
||||||
|
Please describe the bug you encountered in detail. Make sure you're **actually** hitting a **server-side** bug, not a vanilla feature or client-side bug.<br>
|
||||||
|
如果您确定的话,就按照下面的模板填充信息,并提交反馈。
|
||||||
|
If you are sure, follow the template below to fill in the information and submit your feedback.<br>
|
||||||
|
如果此bug被尝试修复,您可以帮助我们测试并回复。若bug的确被修复,您可以关闭issue来让开发者确认。
|
||||||
|
If this bug is tried to fix, you can help us test and reply. If the bug is fixed, you can close the issue to let the developer confirm.
|
||||||
|
- type: input
|
||||||
|
id: luminolMC-version
|
||||||
|
attributes:
|
||||||
|
label: 服务端版本 LuminolMC Version
|
||||||
|
description:
|
||||||
|
LuminolMC服务端发行版本 LuminolMC server release version (contains the git commit's hash)<br>
|
||||||
|
通过执行`/version`命令将获取到的内容复制到这里。 Run `/version` on your server and paste the full, unmodified output here.
|
||||||
|
placeholder: >
|
||||||
|
e.g. git-Luminol-"0635a89" (MC: 1.20.4)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected-behavior
|
||||||
|
attributes:
|
||||||
|
label: 预期的行为 Expected behavior
|
||||||
|
description: 你期望看到的情况是什么样。What you expected to see.
|
||||||
|
placeholder: e.g. 使用 /tpsbar [NAME] 命令可以切换TPSBAR的开关
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: actual-behavior
|
||||||
|
attributes:
|
||||||
|
label: 观测到的实际行为 Observed/Actual behavior
|
||||||
|
description: 你实际看到的。 What you actually saw.
|
||||||
|
placeholder: e.g. 使用 /tpsbar [NAME] 命令切换不了TPSBAR
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: reproduce
|
||||||
|
attributes:
|
||||||
|
label: 复现步骤 Steps/models to reproduce
|
||||||
|
description:
|
||||||
|
这里应该有一个图片、视频或其他信息来展现你的问题。<br>
|
||||||
|
This may include a build schematic, a video, or detailed instructions to help reconstruct the issue.
|
||||||
|
placeholder: e.g. 登录其他账号,使用 /tpsbar [NAME] 命令切换不了TPSBAR
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: plugin-list
|
||||||
|
attributes:
|
||||||
|
label: 插件与数据包列表。 Plugin and Datapack List.
|
||||||
|
description:
|
||||||
|
服务器上的所有插件和数据包列表。
|
||||||
|
All plugins and datapacks running on your server.<br>
|
||||||
|
执行命令`/plugins`查看插件列表。执行命令`/datapack list`查看数据包列表。
|
||||||
|
To list plugins, run `/plugins`. For datapacks, run `/datapack list`.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: other
|
||||||
|
attributes:
|
||||||
|
label: 更多详细信息。 The more information.
|
||||||
31
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
31
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
name: 新的需求 Feature Request
|
||||||
|
description:
|
||||||
|
为Luminol提供新的想法。
|
||||||
|
Suggest an idea for Luminol.
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
感谢您为 Luminol 提交新的需求!请尽可能详细地描述,以便我们可以更轻松地考虑和审查请求。
|
||||||
|
Thank you for filling out a feature request for Luminol! Please be as detailed as possible so that we may consider and review the request easier.<br>
|
||||||
|
请搜索所有问题以避免重复的功能请求。如果您期望的功能已存在,请回复如果您有什么要补充的。
|
||||||
|
We ask that you search all the issues to avoid a duplicate feature request. If one exists, please reply if you have anything to add.<br>
|
||||||
|
在请求新功能之前,请确保您使用的是最新版本并且您请求的功能不在 Luminol 中。
|
||||||
|
Before requesting a new feature, please make sure you are using the latest version and that the feature you are requesting is not already in Paper.<br>
|
||||||
|
我们的开发人员可能没有过多时间来测试新功能的可用性,如新功能进入Test状态,您可以帮助我们进行测试并回复。
|
||||||
|
Our developers may not have much time to test the usability of new functions. If the new functions enter the Test state, you can help us test and reply.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: feature
|
||||||
|
attributes:
|
||||||
|
label: 描述你希望添加的功能。 Describe the feature you'd like.
|
||||||
|
placeholder: e.g. 添加新的PATH
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: othre
|
||||||
|
attributes:
|
||||||
|
label: 其他 Other
|
||||||
|
description: 添加其他的信息。 Add any other context or screenshots about the feature request below.
|
||||||
12
.github/dependabot.yml
vendored
Normal file
12
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
# Enable version updates for github actions
|
||||||
|
- package-ecosystem: "github-actions" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
152
.github/workflows/build.yml
vendored
Normal file
152
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
name: Luminol CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
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"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
force-push:
|
||||||
|
description: "Force disable push to repo if you enter 2, push to repo if you enter 1, default push if not released else skip push repo"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
comments:
|
||||||
|
description: "Add comments to release"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
permissions: write-all
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: default
|
||||||
|
steps:
|
||||||
|
- name: Checkout Git Repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Set Up JDK
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: zulu
|
||||||
|
java-version: 21
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v5
|
||||||
|
|
||||||
|
- name: Configure Git User Details
|
||||||
|
run: git config --global user.email "ci@luminolmc.com" && git config --global user.name "LuminolMC CI"
|
||||||
|
|
||||||
|
- name: Apply All Patches
|
||||||
|
run: ./gradlew --refresh-dependencies applyAllPatches
|
||||||
|
|
||||||
|
- name: Build Paperclip Jar
|
||||||
|
run: ./gradlew --refresh-dependencies createMojmapPaperclipJar
|
||||||
|
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: ${{ env.project_id_b }} CI Artifacts
|
||||||
|
path: luminol-server/build/libs/*-paperclip-*-mojmap.jar
|
||||||
|
|
||||||
|
- name: Set Environment
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
run: sh scripts/SetENV.sh
|
||||||
|
|
||||||
|
- name: Check If Release Exists
|
||||||
|
if: github.event_name != 'pull_request' && env.flag_release == 'true'
|
||||||
|
run: |
|
||||||
|
git fetch --tags
|
||||||
|
if [ -n "$(git tag -l "${{ env.tag }}")" ]; then
|
||||||
|
echo "Release already exists"
|
||||||
|
release_exists=true
|
||||||
|
else
|
||||||
|
echo "Release does not exist"
|
||||||
|
release_exists=false
|
||||||
|
fi
|
||||||
|
if [ "$release_exists" == "true" ]; then
|
||||||
|
counter=1
|
||||||
|
while [ -n "$(git tag -l "${{ env.tag }}-${counter}")" ]; do
|
||||||
|
counter=$((counter + 1))
|
||||||
|
done
|
||||||
|
echo "tag=${{ env.tag }}-${counter}" >> $GITHUB_ENV
|
||||||
|
echo "release_count= - ${counter}" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
echo "release_exists=${release_exists}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Check If Branch In Expectations
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
run: |
|
||||||
|
if [[ "$GITHUB_REF_NAME" == ver/* ]] || [[ "$GITHUB_REF_NAME" == exp/* ]] || [[ "$GITHUB_REF_NAME" == dev/* ]]; then
|
||||||
|
echo "Branch is in expected prefixes"
|
||||||
|
echo "unexpect=false" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "Branch is NOT in expected prefixes"
|
||||||
|
echo "unexpect=true" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Publish To Repo
|
||||||
|
if: ( github.event_name != 'pull_request' && !( env.unexpect == 'true' ) && env.flag_release == 'true' && env.release_exists != 'true' && !( inputs.force-release == '2' )) || inputs.force-push == '1'
|
||||||
|
continue-on-error: true
|
||||||
|
run: ./gradlew --refresh-dependencies generateDevelopmentBundle publish -PpublishDevBundle=true
|
||||||
|
env:
|
||||||
|
PRIVATE_MAVEN_REPO_PASSWORD: ${{ secrets.PRIVATE_MAVEN_REPO_PASSWORD }}
|
||||||
|
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'
|
||||||
|
run: |
|
||||||
|
if [ "${{ inputs.comments }}" == "" ]; then
|
||||||
|
echo "No comments provided"
|
||||||
|
echo "flag_comment=false" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "Comments provided: ${{ inputs.comments }}"
|
||||||
|
echo "flag_comment=true" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Create Release - No Comment
|
||||||
|
if: env.flag_comment == 'false'
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
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 }})
|
||||||
|
This release is automatically compiled by GitHub Actions
|
||||||
|
### Branch Info
|
||||||
|
> ${{ github.ref_name }}
|
||||||
|
### Commit Message
|
||||||
|
${{ env.commit_msg }}
|
||||||
|
artifacts: ${{ env.jar_dir }}
|
||||||
|
generateReleaseNotes: true
|
||||||
|
prerelease: ${{ env.pre }}
|
||||||
|
makeLatest: ${{ env.make_latest }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Create Release - With Comment
|
||||||
|
if: env.flag_comment == 'true'
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
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 }})
|
||||||
|
This release is automatically compiled by GitHub Actions
|
||||||
|
### Comments
|
||||||
|
> ${{ inputs.comments }}
|
||||||
|
### Branch Info
|
||||||
|
> ${{ github.ref_name }}
|
||||||
|
### Commit Message
|
||||||
|
${{ env.commit_msg }}
|
||||||
|
artifacts: ${{ env.jar_dir }}
|
||||||
|
generateReleaseNotes: true
|
||||||
|
prerelease: ${{ env.pre }}
|
||||||
|
makeLatest: ${{ env.make_latest }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Ignore Gradle project-specific cache directory
|
||||||
|
.gradle
|
||||||
|
|
||||||
|
# Ignore Gradle build output directory
|
||||||
|
build
|
||||||
|
|
||||||
|
/run
|
||||||
|
|
||||||
|
/luminol-server/build.gradle.kts
|
||||||
|
/luminol-api/build.gradle.kts
|
||||||
|
/folia-server/build.gradle.kts
|
||||||
|
/folia-server/src/minecraft
|
||||||
|
/folia-api/build.gradle.kts
|
||||||
|
/paper-server
|
||||||
|
/paper-api
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Neko Core: smoke-test scratch dir
|
||||||
|
/smoke-run/
|
||||||
31
LICENSE.md
Normal file
31
LICENSE.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Luminol inherits its licensing from the included upstream projects.
|
||||||
|
|
||||||
|
Luminol从上游继承了许可证。
|
||||||
|
|
||||||
|
As such, Luminol is licensed under the
|
||||||
|
[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.
|
||||||
|
|
||||||
|
因此,Luminol中应当遵守[GNU通用公共许可证-第3版](licenses/GPL.md) 的许可;
|
||||||
|
因为Luminol从上游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.
|
||||||
|
|
||||||
|
任何 _未在下面列出_ 的作者都应该被认为他们的修改基于[原始GPL许可证](licenses/GPL.md)。
|
||||||
|
|
||||||
|
In the interest of promoting a better Minecraft platform for everyone, contributors
|
||||||
|
may choose to release their code under the more permissive [MIT License](licenses/MIT.md).
|
||||||
|
|
||||||
|
为了向所有人推广一个更好的Minecraft平台,贡献者可以选择在更宽松的[MIT许可证](licenses/MIT.md)下发布他们的代码。
|
||||||
|
|
||||||
|
The authors listed below have chosen to release their code under that more permissive
|
||||||
|
[MIT License](licenses/MIT.md). Any contributor who wants their name added below
|
||||||
|
should submit a pull request to this project to add their name.
|
||||||
|
|
||||||
|
下面列出的作者选择在更宽松的[MIT许可证](licenses/MIT.md)下发布他们的代码。
|
||||||
|
任何希望使用[MIT许可证](licenses/MIT.md)发布的作者都应该向此项目提交一个拉取请求以在下方添加他们的名字。
|
||||||
|
|
||||||
|
```text
|
||||||
|
Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||||
|
```
|
||||||
231
NEKO_CORE_改动与使用说明.md
Normal file
231
NEKO_CORE_改动与使用说明.md
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
# Neko Core 改动与使用说明
|
||||||
|
|
||||||
|
本文档基于当前工作区变更状态整理,目标是说明:
|
||||||
|
|
||||||
|
- 这个服务端改了什么
|
||||||
|
- 如何构建与使用
|
||||||
|
- 做了哪些优化
|
||||||
|
- 当前已知限制与建议
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 项目定位与结果
|
||||||
|
|
||||||
|
当前分支是在 `Luminol 1.21.8` 基础上,完成了 `Neko Core` 定制化改造,已实现:
|
||||||
|
|
||||||
|
- 构建链路可用(`applyAllPatches` 可通过)
|
||||||
|
- `luminol-server` 可编译
|
||||||
|
- 可产出并启动可运行包(`paperclip/bundler`)
|
||||||
|
- 新增后端切换命令,可在游戏内切换碰撞加速后端(含 `FFM`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 本次主要改动(按模块)
|
||||||
|
|
||||||
|
## 2.1 构建与打包链路
|
||||||
|
|
||||||
|
涉及文件:
|
||||||
|
|
||||||
|
- `build.gradle.kts`
|
||||||
|
- `luminol-server/build.gradle.kts`
|
||||||
|
- `luminol-server/build.gradle.kts.patch`
|
||||||
|
|
||||||
|
主要改动:
|
||||||
|
|
||||||
|
- 锁定/适配 `hyacinthusweight` 构建链路,保证 patch + mache 流程可运行。
|
||||||
|
- 修复 `macheRemapJar` 参数链路(显式 remapper、mappings、params 的可用输入)。
|
||||||
|
- 修复打包任务名与类型适配:
|
||||||
|
- 使用 `createBundlerJar` / `createPaperclipJar`(替代旧命名)。
|
||||||
|
- 统一到 Java 25 构建运行方案,确保插件与打包任务兼容。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.2 补丁与上游对齐
|
||||||
|
|
||||||
|
涉及目录:
|
||||||
|
|
||||||
|
- `luminol-api/paper-patches/features/*.patch`
|
||||||
|
- `luminol-server/paper-patches/features/*.patch`
|
||||||
|
- `folia-api`(工作区变更)
|
||||||
|
- `folia-server`(工作区变更)
|
||||||
|
|
||||||
|
主要改动:
|
||||||
|
|
||||||
|
- 对漂移的 feature patch 做了重建与兼容修复,恢复补丁应用链路。
|
||||||
|
- 修复了因补丁上下文漂移导致的 `apply...FeaturePatches` 失败问题。
|
||||||
|
- 保留了当前能通过构建的 patch 状态。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.3 品牌与命令
|
||||||
|
|
||||||
|
涉及文件:
|
||||||
|
|
||||||
|
- `luminol-server/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java`
|
||||||
|
- `luminol-server/src/main/java/me/earthme/luminol/commands/CommandRegister.java`
|
||||||
|
- `luminol-server/src/main/java/me/earthme/luminol/commands/backend/NekoBackendCommand.java`(新增目录/文件)
|
||||||
|
|
||||||
|
主要改动:
|
||||||
|
|
||||||
|
- 默认服务端名改为 `Neko Core`。
|
||||||
|
- 注册并启用 `/nekobackend` 命令。
|
||||||
|
|
||||||
|
`/nekobackend` 子命令:
|
||||||
|
|
||||||
|
- `status`:查看当前生效后端和关键配置
|
||||||
|
- `set <AUTO|GPU|FFM|JAVA|VANILLA>`:运行时切换后端
|
||||||
|
- `reload`:重载后端选择器
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.4 配置系统重构(优化模块)
|
||||||
|
|
||||||
|
涉及文件:
|
||||||
|
|
||||||
|
- `luminol-server/src/main/java/me/earthme/luminol/config/modules/optimizations/AcceleratedCollisionConfig.java`
|
||||||
|
- `AfkEntityTrackingConfig.java`
|
||||||
|
- `EntityLimiterConfig.java`
|
||||||
|
- `ExplosionOptimizerConfig.java`
|
||||||
|
- `MobAiReducerConfig.java`
|
||||||
|
- `SkipZeroDeltaPacketsConfig.java`
|
||||||
|
- `VehicleMotionConfig.java`
|
||||||
|
|
||||||
|
主要改动:
|
||||||
|
|
||||||
|
- 统一到 Luminol 现行配置风格(`IConfigModule` + 注解字段)。
|
||||||
|
- 修复历史“伪 API”配置写法导致的编译与运行不一致问题。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.5 优化逻辑实现与兼容修复
|
||||||
|
|
||||||
|
涉及文件:
|
||||||
|
|
||||||
|
- `collision/*`(`CollisionBackendSelector`、`RegionCollisionHandler`、`backend/*`)
|
||||||
|
- `afktracking/AfkTrackingManager.java`
|
||||||
|
- `entitylimiter/LuminolEntityLimiter.java`
|
||||||
|
- `mobaireducer/*`(`MobAiReducerHandler`、`OptimizedBreedGoal`、`OptimizedTemptGoal`)
|
||||||
|
- `explosion/LuminolExplosionOptimizer.java`
|
||||||
|
- `org/leavesmc/.../LeavesPluginMeta.java`
|
||||||
|
- `src/minecraft/java/...` 与 `src/minecraft/resources`
|
||||||
|
|
||||||
|
主要改动:
|
||||||
|
|
||||||
|
- 恢复并对齐 `FFM/GPU/JAVA/VANILLA` 后端选择逻辑。
|
||||||
|
- 修复若干上游 API 变化导致的编译点(实体、世界、门户位置转换、插件元数据等)。
|
||||||
|
- 调整部分优化逻辑为当前上游可编译/可运行版本。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 优化了什么(功能视角)
|
||||||
|
|
||||||
|
## 3.1 碰撞加速(AR / Accelerated Recoiling 体系)
|
||||||
|
|
||||||
|
- 支持多后端:
|
||||||
|
- `FFM`(Foreign Function & Memory)
|
||||||
|
- `GPU`
|
||||||
|
- `JAVA`
|
||||||
|
- `VANILLA`(回退)
|
||||||
|
- `AUTO`(自动选择)
|
||||||
|
- 可通过游戏内命令热切换后端(`/nekobackend set ...`)。
|
||||||
|
|
||||||
|
## 3.2 AFK 追踪优化
|
||||||
|
|
||||||
|
- 保留 AFK 追踪入口与配置化能力。
|
||||||
|
- 对不兼容的底层字段访问做了兼容处理,避免构建失败。
|
||||||
|
|
||||||
|
## 3.3 实体限制与 AI 优化
|
||||||
|
|
||||||
|
- 实体上限限制器、溢出清理、AI 目标逻辑等可配置能力保留。
|
||||||
|
- 对上游访问权限/签名变化做了兼容调整。
|
||||||
|
|
||||||
|
## 3.4 爆炸与网络细节优化
|
||||||
|
|
||||||
|
- 包含爆炸优化、零位移包处理、载具运动相关优化配置入口。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 使用方法
|
||||||
|
|
||||||
|
## 4.1 构建
|
||||||
|
|
||||||
|
建议环境:
|
||||||
|
|
||||||
|
- JDK: Java 25(当前链路已按此验证)
|
||||||
|
- OS: Windows(已验证)
|
||||||
|
|
||||||
|
在仓库根目录执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew applyAllPatches
|
||||||
|
./gradlew :luminol-server:createPaperclipJar
|
||||||
|
```
|
||||||
|
|
||||||
|
产物路径:
|
||||||
|
|
||||||
|
- `luminol-server/build/libs/luminol-paperclip-1.21.8-R0.1-SNAPSHOT.jar`
|
||||||
|
- `luminol-server/build/libs/luminol-bundler-1.21.8-R0.1-SNAPSHOT.jar`
|
||||||
|
- `luminol-server/build/libs/luminol-server-1.21.8-R0.1-SNAPSHOT.jar`
|
||||||
|
|
||||||
|
## 4.2 启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java -jar luminol-paperclip-1.21.8-R0.1-SNAPSHOT.jar --nogui
|
||||||
|
```
|
||||||
|
|
||||||
|
首次启动需同意 EULA:
|
||||||
|
|
||||||
|
- 编辑 `eula.txt` 为 `eula=true`
|
||||||
|
|
||||||
|
## 4.3 游戏内后端控制(AR)
|
||||||
|
|
||||||
|
```text
|
||||||
|
/nekobackend status
|
||||||
|
/nekobackend set FFM
|
||||||
|
/nekobackend set GPU
|
||||||
|
/nekobackend set JAVA
|
||||||
|
/nekobackend set VANILLA
|
||||||
|
/nekobackend set AUTO
|
||||||
|
/nekobackend reload
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
- `set` 会立即切换并更新运行态配置字段。
|
||||||
|
- 如果某后端初始化失败,会自动回退(可用 `status` 确认当前实际后端)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 关键配置项(示例)
|
||||||
|
|
||||||
|
路径:`luminol_config` 下对应优化配置(按模块名)。
|
||||||
|
|
||||||
|
重点建议关注:
|
||||||
|
|
||||||
|
- `accelerated_collision.enabled`
|
||||||
|
- `accelerated_collision.backend`(`AUTO/GPU/FFM/JAVA/VANILLA`)
|
||||||
|
- `accelerated_collision.max_collision`
|
||||||
|
- `accelerated_collision.grid_size`
|
||||||
|
- `accelerated_collision.density_threshold`
|
||||||
|
- `accelerated_collision.max_threads`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 已知注意事项
|
||||||
|
|
||||||
|
- 本次改造包含大量上游漂移兼容修复,后续升级 Minecraft/Folia 版本时,建议优先重跑 patch 重建流程再改业务逻辑。
|
||||||
|
- `FFM` 后端依赖 native 库资源加载,若切到 `FFM` 失败,请先检查平台库文件是否打入最终 jar 的 `natives/<platform>/` 目录。
|
||||||
|
- 若打包时报 `paperclip` 产物文件占用,先关闭仍在运行的服务端 Java 进程再重试。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 快速验收清单
|
||||||
|
|
||||||
|
- 能执行 `:luminol-server:createPaperclipJar`
|
||||||
|
- `paperclip` 可启动并通过 EULA 后进入 `Done (...)`
|
||||||
|
- 进服后 `/nekobackend status` 可返回当前状态
|
||||||
|
- `/nekobackend set FFM` 可执行并反馈切换结果
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
如需,我可以在下一步补一版「面向运维发布」的精简版文档(只保留部署、参数、回滚、排障)。
|
||||||
193
README.md
Normal file
193
README.md
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
<div align="center">
|
||||||
|
|
||||||
|
# 🐱 Neko Core
|
||||||
|
|
||||||
|
**喵核心** · 为高负载生存 / 战争服打造的 Folia 定制服务端
|
||||||
|
|
||||||
|
*碰撞加速 · 网络优化 · 实时可观测 · 一键调优*
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
`AUTO` · `GPU` · `FFM` · `JAVA` · `VANILLA` —— 碰撞后端,游戏内热切换
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 这是什么
|
||||||
|
|
||||||
|
**Neko Core** 是在 [Luminol 1.21.8](https://github.com/LuminolMC/Luminol)(Folia 分支)之上的定制服务端,把三套各自为政的优化整合成一个能打的整体:
|
||||||
|
|
||||||
|
| 体系 | 来自 | 解决什么 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| 🚀 **AR 碰撞加速** | AcceleratedRecoiling | 高实体密度下的碰撞计算瓶颈 |
|
||||||
|
| 🌐 **网络优化** | Kitin | 弱网卡顿、带宽爆炸、地形/粒子刷屏 |
|
||||||
|
| 🧹 **LagFixer / ESU** | LagFixer + ESU | 实体堆积、爆炸卡服、挂机跟踪、冗余发包 |
|
||||||
|
|
||||||
|
> 构建基线 **Java 25**,全程对照 **Paper/Folia 原版**做实测,数字不掺水。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚡ 性能亮点:AR 碰撞加速
|
||||||
|
|
||||||
|
不是"叠加一层 native",而是**真正替换掉原版那次昂贵的空间查询**——tick 前用 native 广相位算出 per-region 碰撞图(线程隔离,Folia 安全),`pushEntities` 直接 O(1) 查图,原版推挤/拥挤伤害逻辑完全保留。
|
||||||
|
|
||||||
|
**实测**(对照已优化的 Paper/Folia 原版,MSPT 越低越好):
|
||||||
|
|
||||||
|
```
|
||||||
|
场景:8000 实体散布 场景:3000 实体密集
|
||||||
|
┌──────────┬─────────┬─────────┐ ┌──────────┬─────────┬─────────┐
|
||||||
|
│ 后端 │ MSPT │ vs 原版 │ │ 后端 │ MSPT │ vs 原版 │
|
||||||
|
├──────────┼─────────┼─────────┤ ├──────────┼─────────┼─────────┤
|
||||||
|
│ FFM 🥇 │ 78.5ms │ 3.19× │ │ FFM 🥇 │ 24.1ms │ 3.05× │
|
||||||
|
│ JAVA │ 204.6ms │ 1.23× │ │ VANILLA │ 73.6ms │ 1.00× │
|
||||||
|
│ VANILLA │ 250.8ms │ 1.00× │ │ JAVA │ 94.0ms │ 0.78× │
|
||||||
|
└──────────┴─────────┴─────────┘ └──────────┴─────────┴─────────┘
|
||||||
|
FFM 稳定 ~3× 领先原版
|
||||||
|
```
|
||||||
|
|
||||||
|
> 📌 不是"数十倍"——因为对照组是**已经有空间索引优化的 Paper/Folia**,不是裸原版。3× 是实打实可复现的硬提升。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 功能一览
|
||||||
|
|
||||||
|
### 🚀 碰撞加速(默认开)
|
||||||
|
- 多后端:`AUTO / GPU / FFM / JAVA / VANILLA`,启动优先 FFM、失败自动回退
|
||||||
|
- FFM:批量内存拷贝 + 零分配路径 + 碰撞数削峰
|
||||||
|
- 密度门控:只有局部密集的实体走加速,稀疏实体走原版(零行为偏差)
|
||||||
|
|
||||||
|
### 🌐 网络优化(`config/Network.yml`)
|
||||||
|
- **区块惰性加载** — 小范围反复横跳不重发地形包
|
||||||
|
- **高频实体包减量** — 船/矿车在农场不再每 tick 强制同步;高速 TNT/掉落物/经验球跳过冗余包
|
||||||
|
- **粒子限流打包** — 视野/距离/遮挡剔除后再发,治领地特效刷屏
|
||||||
|
- **区块发送限速 + QoS** — 全局限速 + 按 IP/域名/线路分组限流、级联限流
|
||||||
|
- **玩家自适应限流** — 按延迟/抖动动态收紧弱网玩家的发送率与跟踪范围
|
||||||
|
- **多端口监听** — 额外端口可单独配 PROXY Protocol v2(FRP 与直连共存)
|
||||||
|
|
||||||
|
### 🧹 LagFixer / ESU(默认关,按需开)
|
||||||
|
- **EntityLimiter** — 每区块实体上限 + 周期溢出清扫(带削峰:单次清扫有移除上限,爆发不卡)。生成闸门用 per-chunk/per-tick 计数缓存,实体爆发时不再全 region 扫描(O(N²)→O(N))
|
||||||
|
- **EntityCull 视锥剔除** 👁️ — 玩家视野锥外、且超出近距豁免半径的实体**不发包给该客户端**(背后的怪不占带宽/不卡客户端)。转身即恢复(每 tick 重判),近距离始终可见防贴脸突现。多人混战 / 刷怪海减客户端压力专用
|
||||||
|
- **MobAiThrottle** 🧟 — 远离玩家的怪物寻路/索敌降频(按非活跃时长分级),玩家靠近立即恢复。**惊变100天 / 刷怪海专治**,移动控制仍每 tick 不抽搐
|
||||||
|
- **MobAiReducer** — 精简生物 AI 目标
|
||||||
|
- **ExplosionOptimizer** — 爆炸威力上限 / 防连锁 / 管理模式
|
||||||
|
- **AFK 实体跟踪降频** — 全员挂机且实体远时降频,活动即恢复
|
||||||
|
- **ESU 零位移包裁剪** — 跳过零位移/零旋转的实体移动包
|
||||||
|
- **ESU 生物 velocity 包降频** 🚦 — 走路的怪不再每 tick 发速度包(变化太小/发得太频就跳过,~20包/秒→7包/秒);击退/爆炸/坠落立即发,玩家与投射物不受影响。丧尸海/混战第二大带宽源
|
||||||
|
|
||||||
|
### 📊 实时可观测
|
||||||
|
- **出站带宽实时监控** — 当前 Mbps、峰值、本次累计用量
|
||||||
|
- **内置 spark profiler** 🔥 — 原生集成(Folia 安全),`/spark` 直接可用:`profiler` 采样找热点、`health` 看 TPS/MSPT/CPU/内存。无需装插件,战争爆发时一条命令定位瓶颈
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎮 命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 碰撞后端
|
||||||
|
/nekobackend status # 当前后端与关键配置
|
||||||
|
/nekobackend set <AUTO|GPU|FFM|JAVA|VANILLA> # 运行时热切换
|
||||||
|
/nekobackend reload # 重载后端选择器
|
||||||
|
|
||||||
|
# 实时带宽
|
||||||
|
/nekobackend bandwidth # 出站带宽:现在 / 峰值 / 累计
|
||||||
|
|
||||||
|
# 内置 spark profiler(无需插件,Folia 安全)
|
||||||
|
/spark profiler --timeout 60 # 采样 60s 找 MSPT 热点(出网页报告)
|
||||||
|
/spark health # TPS / tick 时长 / CPU / 内存
|
||||||
|
/spark tps # 实时 TPS
|
||||||
|
|
||||||
|
# 一键开关优化模块(无需改配置重启)
|
||||||
|
/nekobackend toggle <module> <on|off>
|
||||||
|
# module ∈ entity_limiter / entity_cull / explosion_optimizer / afk_entity_tracking /
|
||||||
|
# mob_ai_reducer / mob_ai_throttle / skip_zero_delta_packets
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 构建与启动
|
||||||
|
|
||||||
|
**环境:JDK 25**。在 `Luminol-ver-1.21.8` 目录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew applyAllPatches
|
||||||
|
./gradlew :luminol-server:jar :luminol-server:createBundlerJar :luminol-server:createPaperclipJar \
|
||||||
|
--no-daemon --no-configuration-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
启动(推荐 paperclip):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java -jar NekoCore-paperclip-1.21.8-R0.1-SNAPSHOT.jar --nogui
|
||||||
|
```
|
||||||
|
|
||||||
|
首启自动生成 `config/Network.yml`;碰撞与 LagFixer/ESU 配置在 `luminol_config/`。
|
||||||
|
|
||||||
|
> 📦 已构建好的产物见 **[Releases](https://github.com/dmz7p4xmqh-coder/Luminol-Core/releases)**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ 使用须知
|
||||||
|
|
||||||
|
- **追求原版还原度**:AR 的实体挤压表现与原版不完全一致,可将后端设为 `VANILLA`。
|
||||||
|
- **任何优化异常**:把对应模块 `enabled` 置 `false`(或 `/nekobackend toggle ... off`)即可回退,无需回滚 jar。
|
||||||
|
- **性能数字**:来自本机无头环境实测,对照组为已优化的 Paper/Folia 碰撞(非裸原版)。真实大型服收益理论更高,但需生产环境验证。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 更新日志
|
||||||
|
|
||||||
|
| 版本 | 内容 |
|
||||||
|
| :--- | :--- |
|
||||||
|
| **v1.0.8** | 🚦 ESU 生物 velocity 包降频:走路的怪不再每 tick 发速度包,丧尸海/混战第二大带宽源;`/nekobackend toggle entity_velocity_packet` 开关 |
|
||||||
|
| **v1.0.7** | 🐛 修复插件兼容性:服务端版本号在缺少 folia-api 元数据时退化成 `Unknown-Version`,导致按语义版本解析版本号的插件(如 SkinsRestorer)启动崩溃(`parseInt("")`)。现回退到合法版本号 `1.21.8-R0.1-SNAPSHOT` |
|
||||||
|
| **v1.0.6** | ⚡ 修复 EntityLimiter 生成闸门的 O(N²):原本每生成一个实体都全 region 扫一遍(实体爆发时限制器自己成卡顿源),改为 per-chunk/per-tick 计数缓存,爆发场景 O(N²)→O(N) |
|
||||||
|
| **v1.0.5** | 👁️ EntityCull 视锥/距离剔除:视野外远处实体不发包给客户端,`/nekobackend toggle entity_cull on` 游戏内开关 |
|
||||||
|
| **v1.0.4** | 🔥 内置 spark profiler 原生集成(Folia 安全),`/spark` 开服即用;修复启动日志在 Windows GBK 控制台的乱码 |
|
||||||
|
| **v1.0.3** | 🧟 MobAiThrottle:远离玩家的怪物 AI 降频(惊变100天 / 刷怪海专治) |
|
||||||
|
| **v1.0.2** | EntityLimiter 溢出清扫削峰 + `/nekobackend toggle` 模块热开关 |
|
||||||
|
| **v1.0.1** | 出站带宽实时监控(当前 / 峰值 / 累计 Mbps) |
|
||||||
|
| **v1.0.0** | 首版:AR 碰撞加速 + Kitin 网络优化 + LagFixer/ESU 整合 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🙏 致谢上游
|
||||||
|
|
||||||
|
Neko Core 站在巨人的肩膀上,向以下项目致敬:
|
||||||
|
|
||||||
|
- [**Luminol**](https://github.com/LuminolMC/Luminol) — 本项目的基底(Folia 分支 + 可配置原版特性 + API)
|
||||||
|
- [**Folia** / **Paper**](https://github.com/PaperMC/Folia) — 区域化多线程服务端核心
|
||||||
|
- [**AcceleratedRecoiling**](https://github.com/) — 碰撞加速架构灵感
|
||||||
|
- [**Kitin**](https://github.com/SucIXR/Kitin) — 网络优化体系
|
||||||
|
- **LagFixer** / **ESU** — 实体限制与发包优化
|
||||||
|
|
||||||
|
各上游许可(GPL/LGPL)均予以尊重,相关署名保留在对应源码中。
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>📎 Luminol API 接入(点击展开)</summary>
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
repositories {
|
||||||
|
maven { url = "https://repo.menthamc.org/repository/maven-public/" }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
compileOnly("me.earthme.luminol:luminol-api:$VERSION")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
**🐱 Neko Core** · 让你的服务器跑得像猫一样轻
|
||||||
|
|
||||||
|
*Built with [Claude Code](https://claude.com/claude-code)*
|
||||||
|
|
||||||
|
</div>
|
||||||
104
build.gradle.kts
Normal file
104
build.gradle.kts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
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 "2.0.15"
|
||||||
|
}
|
||||||
|
|
||||||
|
paperweight {
|
||||||
|
upstreams.register("folia") {
|
||||||
|
repo = github("PaperMC", "Folia")
|
||||||
|
ref = providers.gradleProperty("foliaRef")
|
||||||
|
|
||||||
|
patchFile {
|
||||||
|
path = "folia-server/build.gradle.kts"
|
||||||
|
outputFile = file("luminol-server/build.gradle.kts")
|
||||||
|
patchFile = file("luminol-server/build.gradle.kts.patch")
|
||||||
|
}
|
||||||
|
patchFile {
|
||||||
|
path = "folia-api/build.gradle.kts"
|
||||||
|
outputFile = file("luminol-api/build.gradle.kts")
|
||||||
|
patchFile = file("luminol-api/build.gradle.kts.patch")
|
||||||
|
}
|
||||||
|
patchRepo("paperApi") {
|
||||||
|
upstreamPath = "paper-api"
|
||||||
|
patchesDir = file("luminol-api/paper-patches")
|
||||||
|
outputDir = file("paper-api")
|
||||||
|
}
|
||||||
|
patchDir("foliaApi") {
|
||||||
|
upstreamPath = "folia-api"
|
||||||
|
excludes = listOf("build.gradle.kts", "build.gradle.kts.patch", "paper-patches")
|
||||||
|
patchesDir = file("luminol-api/folia-patches")
|
||||||
|
outputDir = file("folia-api")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
|
||||||
|
val menthaMavenPublicUrl = "https://repo.menthamc.org/repository/maven-public/";
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
apply(plugin = "java-library")
|
||||||
|
apply(plugin = "maven-publish")
|
||||||
|
|
||||||
|
extensions.configure<JavaPluginExtension> {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(25)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven(paperMavenPublicUrl)
|
||||||
|
maven(menthaMavenPublicUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
"testRuntimeOnly"("org.junit.platform:junit-platform-launcher")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<AbstractArchiveTask>().configureEach {
|
||||||
|
isPreserveFileTimestamps = false
|
||||||
|
isReproducibleFileOrder = true
|
||||||
|
}
|
||||||
|
tasks.withType<JavaCompile>().configureEach {
|
||||||
|
options.encoding = Charsets.UTF_8.name()
|
||||||
|
options.release = 21
|
||||||
|
options.isFork = true
|
||||||
|
}
|
||||||
|
tasks.withType<Javadoc>().configureEach {
|
||||||
|
options.encoding = Charsets.UTF_8.name()
|
||||||
|
}
|
||||||
|
tasks.withType<ProcessResources>().configureEach {
|
||||||
|
filteringCharset = Charsets.UTF_8.name()
|
||||||
|
}
|
||||||
|
tasks.withType<Test> {
|
||||||
|
testLogging {
|
||||||
|
showStackTraces = true
|
||||||
|
exceptionFormat = TestExceptionFormat.FULL
|
||||||
|
events(TestLogEvent.STANDARD_OUT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions.configure<PublishingExtension> {
|
||||||
|
repositories {
|
||||||
|
maven("https://repo.menthamc.org/repository/maven-snapshots/") {
|
||||||
|
name = "MenthaMC"
|
||||||
|
credentials(PasswordCredentials::class) {
|
||||||
|
username = System.getenv("PRIVATE_MAVEN_REPO_USERNAME")
|
||||||
|
password = System.getenv("PRIVATE_MAVEN_REPO_PASSWORD")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<Javadoc>().configureEach {
|
||||||
|
options {
|
||||||
|
(this as StandardJavadocDocletOptions).apply {
|
||||||
|
addStringOption("-add-modules", "jdk.incubator.vector")
|
||||||
|
addStringOption("Xdoclint:none", "-quiet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
docs/CONTRIBUTING.md
Normal file
90
docs/CONTRIBUTING.md
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
为Luminol贡献代码
|
||||||
|
===============
|
||||||
|
|
||||||
|
[English](./CONTRIBUTING_EN.md) | **中文**
|
||||||
|
|
||||||
|
我们很开心您想为我们的项目做出贡献!一般来说,我们对PR的审核是十分宽松的;
|
||||||
|
但是如果您可以遵守下列的规则,我们可以更快地完成审核。
|
||||||
|
|
||||||
|
## 使用个人账户进行 Fork
|
||||||
|
|
||||||
|
我们会定期尝试合并已有的 PR,如果有一些小问题,会尝试帮您解决这些问题。
|
||||||
|
|
||||||
|
但是如果您使用了组织账号进行 PR,我们就不能对您的 PR 进行修改了。因此我们只能关闭你的PR然后进行手动合并。
|
||||||
|
|
||||||
|
所以,请不要使用组织账号进行 Fork!
|
||||||
|
|
||||||
|
您可以看看 [这个 Issue](https://github.com/isaacs/github/issues/1681) 来了解一下我们为什么无法修改组织账号的 PR。
|
||||||
|
|
||||||
|
## 开发环境
|
||||||
|
|
||||||
|
在开始开发之前,您首先需要拥有以下软件作为开发环境:
|
||||||
|
|
||||||
|
- `git`
|
||||||
|
- `JDK 21 或更高版本`
|
||||||
|
|
||||||
|
特别提醒:在操作前,您需要启用系统和Git的长路径支持,以下为部分平台的相关描述。
|
||||||
|
|
||||||
|
[`Windows`](https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation)
|
||||||
|
[`Git for Windows`](https://gitforwindows.org/faq.html#i-get-errors-trying-to-check-out-files-with-long-path-names)
|
||||||
|
|
||||||
|
## 了解补丁(Patches)
|
||||||
|
|
||||||
|
Luminol 使用和 Folia 一样的补丁系统,并为了针对不同部分的修改分成了两个目录:
|
||||||
|
|
||||||
|
- `luminol-api` - 对 `Folia-API` / `Paper-API` / `Spigot-API` / `Bukkit-API` 进行的修改。
|
||||||
|
- `luminol-server` - 对 Minecraft 标准服务器原有逻辑进行的修改。
|
||||||
|
|
||||||
|
补丁系统是基于 git 的,你可以在这里了解 git 的基本内容: <https://git-scm.com/docs/gittutorial>
|
||||||
|
|
||||||
|
如果你已经 Fork 了主储存库,那么下面你应该这么做:
|
||||||
|
|
||||||
|
1. 将你的仓库 clone 到本地;
|
||||||
|
2. 在你的 IDE 或 终端 内执行 Gradle 的 `applyAllPatches` 任务,如果是在终端内,你可以执行 `./gradlew applyAllPatches`;
|
||||||
|
3. 在执行操作后,仓库根目录下应该存在以下目录对: `luminol-api` 和 `luminol-server` , `folia-api` 和 `folia-server` , 以及 `paper-api` 和 `paper-server`(下文称作 `*-api` 和 `*-server` );
|
||||||
|
4. 进入 仓库根目录下的 `*-api` 和 `*-server` 文件夹进行修改。
|
||||||
|
|
||||||
|
以下为对上述各个文件夹的简单描述,详细描述可以参考[这里](https://github.com/Toffikk/paperweight-examples/blob/18241979c88068d5b061d95ad69c98ecb201c246/README.md):
|
||||||
|
|
||||||
|
1. API部分
|
||||||
|
|
||||||
|
- `luminol-api` :对新增API的修改
|
||||||
|
- `folia-api` :对folia-API的修改应当在此文件夹下进行
|
||||||
|
- `paper-api` :对paper-API/spigot-API/bukkit-API的修改应该在此文件夹下进行
|
||||||
|
|
||||||
|
2. Server部分
|
||||||
|
|
||||||
|
- `luminol-server` :对Minecraft原版服务器的修改和新增文件应当在此文件夹下进行
|
||||||
|
- `folia-server` :对folia-Server的修改应当在此文件夹下进行
|
||||||
|
- `paper-server` :对于paper对服务器逻辑的修改应当在此文件夹下进行
|
||||||
|
|
||||||
|
顺便一提,仓库根目录下的 `*-api` 和 `*-server` 并不是正常的 git 仓库:
|
||||||
|
|
||||||
|
- 在应用补丁前,基点将会指向未被更改的源码
|
||||||
|
- 在基点后的每一个提交都是一个补丁
|
||||||
|
- 只有在 Folia 最后一个提交后的提交才会被视为 luminol 补丁
|
||||||
|
|
||||||
|
## 增加补丁
|
||||||
|
|
||||||
|
按照以下步骤增加一个补丁是非常简单的:
|
||||||
|
|
||||||
|
1. 对 `*-api` 和 `*-server` 进行修改;
|
||||||
|
2. 使用 git 添加你的修改,比如 `git add .`(不要提交新建的文件的修改);
|
||||||
|
3. 使用 `git commit -m <提交信息>` 进行提交;
|
||||||
|
4. 运行 Gradle 任务 `fixupPaperApiFilePatches` 生成新建文件的补丁文件(注意不要提交);
|
||||||
|
5. 运行 Gradle 任务 `rebuildAllServerPatches` 将你的提交转化为一个补丁;
|
||||||
|
6. 将你生成的补丁文件进行推送。
|
||||||
|
|
||||||
|
这样做以后,你就可以将你的补丁文件进行 PR 提交。
|
||||||
|
|
||||||
|
## 修改补丁
|
||||||
|
|
||||||
|
你可以使用以下方法来修改一个补丁的内容:
|
||||||
|
|
||||||
|
1. 在 HEAD 上直接进行修改;
|
||||||
|
2. 使用 `git commit -a --fixup <hash>` 来进行一个更正提交;(不要提交对在luminol新建文件的修改)
|
||||||
|
- 如果你想要更改提交信息,你也可以用 `--squash` 来代替 `--fixup`。
|
||||||
|
3. 使用 `git rebase -i --autosquash base` 来进行自动变基,你只需要输入 `:q` 来关闭确认页面即可;
|
||||||
|
4. 运行 Gradle 任务 `fixupPaperApiFilePatches` 来修改已被修改的在luminol新建文件的补丁(注意不要提交);
|
||||||
|
5. 运行 Gradle 任务 `rebuildAllServerPatches` 来修改已被修改的补丁;
|
||||||
|
6. 将修改后的补丁 PR 发回储存库。
|
||||||
93
docs/CONTRIBUTING_EN.md
Normal file
93
docs/CONTRIBUTING_EN.md
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
Contributing to Luminol
|
||||||
|
=======================
|
||||||
|
|
||||||
|
**English** | [中文](./CONTRIBUTING.md)
|
||||||
|
|
||||||
|
We're glad that you want to contribute to our project!
|
||||||
|
In general, our review of pull requests is very lenient.
|
||||||
|
And if you can follow the rules below, we can complete the review faster.
|
||||||
|
|
||||||
|
## Please fork using your personal account
|
||||||
|
|
||||||
|
We regularly merge existing PRs.
|
||||||
|
If there are some small problems, we'll help you solve them by editing your PR.
|
||||||
|
|
||||||
|
But, if your PR is from an organization, we can NOT edit your PR, so we must merge your PR manually.
|
||||||
|
|
||||||
|
So, don't use organization accounts for fork!
|
||||||
|
|
||||||
|
See also [This issue](https://github.com/isaacs/github/issues/1681), and then you'll know why we can't edit PRs from organizations.
|
||||||
|
|
||||||
|
## Development Environment
|
||||||
|
|
||||||
|
Before coding, you need these pieces of software / tools as Dev Environment.
|
||||||
|
|
||||||
|
- `git`
|
||||||
|
- `JDK 21 or higher`
|
||||||
|
|
||||||
|
PS: You need to enable long path support in your System and Git before start, some of the platform's resolution here.
|
||||||
|
|
||||||
|
[`Windows`](https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation)
|
||||||
|
[`Git for Windows`](https://gitforwindows.org/faq.html#i-get-errors-trying-to-check-out-files-with-long-path-names)
|
||||||
|
|
||||||
|
## Understanding "Patches"
|
||||||
|
|
||||||
|
Luminol uses as the same patching system as Paper,
|
||||||
|
and has been divided into two directories for the purpose of modifying different parts of it:
|
||||||
|
|
||||||
|
- `luminol-api` - Modifications to `Folia-API` / `Paper-API` / `Spigot-API` / `Bukkit-API`.
|
||||||
|
- `luminol-server` - Modifications to Minecraft Vanilla Server's source logic.
|
||||||
|
|
||||||
|
The patching system is based on git, and you can learn about it at here: <https://git-scm.com/docs/gittutorial>
|
||||||
|
|
||||||
|
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: `luminol-api` and `luminol-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):
|
||||||
|
|
||||||
|
1. API part
|
||||||
|
|
||||||
|
- `luminol-api` : Modifications to the new API
|
||||||
|
- `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
|
||||||
|
|
||||||
|
- `luminol-server` : Changes and new files to the Minecraft vanilla 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
|
||||||
|
|
||||||
|
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 Folia will be considered as Luminol patches.
|
||||||
|
|
||||||
|
## Adding new patches
|
||||||
|
|
||||||
|
It's very easy to add patches by following the steps below:
|
||||||
|
|
||||||
|
1. Modify the code of `*-api` and `*-server`
|
||||||
|
2. Add these changes to the local git repository (For example, `git add .`)
|
||||||
|
3. Commit these changes using `git commit -m <Commit Message>` (PS: do not commit new-created files)
|
||||||
|
4. Run Gradle's task `fixupPaperApiFilePatches` to generate newly created files to new patches (PS: do not commit again before you run this task)
|
||||||
|
5. Run Gradle's task `rebuildAllServerPatches` to convert your commits to a new patch
|
||||||
|
6. Push your patches to your repository
|
||||||
|
|
||||||
|
After pushing, you can open a PR to submit your patches.
|
||||||
|
|
||||||
|
## Modifying patches
|
||||||
|
|
||||||
|
You can modify an existing patch by following the steps below:
|
||||||
|
|
||||||
|
1. Modify code at HEAD
|
||||||
|
2. Run `git commit -a --fixup <hash>` in your terminal to make a fix-up commit (PS: do not commit changes of luminol-created files)
|
||||||
|
- If you want to edit the commit message, replace `--fixup` with `--squash`
|
||||||
|
3. Run `git rebase -i --autosquash base` to rebase automatically, then just type `:q` to close the confirm page
|
||||||
|
4. Run Gradle's task `fixupPaperApiFilePatches` to regenerate luminol-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
|
||||||
12
docs/README.md
Normal file
12
docs/README.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Neko Core 配置文档
|
||||||
|
|
||||||
|
逐条说明 Neko Core 在 Luminol/Folia 之上新增或定制的配置项。
|
||||||
|
|
||||||
|
| 文档 | 配置文件 | 内容 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| optimizations.md | luminol_config/optimizations/*.toml | 碰撞加速、实体限制、视锥剔除、AI 降频、爆炸优化、ESU 发包 |
|
||||||
|
| network.md | config/Network.yml | 区块惰加载、实体/粒子/区块发包优化、QoS 限流、多端口监听 |
|
||||||
|
| misc.md | luminol_config/misc/*.toml | 服务端品牌名 |
|
||||||
|
|
||||||
|
游戏内热开关:/nekobackend toggle <module> <on|off>,module 见 optimizations.md。
|
||||||
|
其它命令:status / set <后端> / reload / bandwidth。
|
||||||
12
docs/misc.md
Normal file
12
docs/misc.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# 杂项配置
|
||||||
|
|
||||||
|
位置:luminol_config/misc/*.toml。
|
||||||
|
|
||||||
|
## server_mod_name — 服务端品牌名
|
||||||
|
|
||||||
|
控制 Bukkit.getName() / 客户端 brand 显示的服务端名称。
|
||||||
|
|
||||||
|
- name(默认 "Neko Core"):服务端品牌名,显示在版本信息里。
|
||||||
|
- vanilla_spoof(默认 false):true=对外伪装成 "vanilla"。部分插件/客户端可能据此判断服务端能力,开启前确认无依赖。
|
||||||
|
|
||||||
|
> v1.0.7 修复了一个相关兼容性 bug:jar 缺 folia-api 元数据时服务端版本号曾退化成 "Unknown-Version",导致按语义版本解析的插件(如 SkinsRestorer)崩溃;现已回退到合法版本号。
|
||||||
46
docs/network.md
Normal file
46
docs/network.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# 网络优化配置
|
||||||
|
|
||||||
|
位置:config/Network.yml(Kitin 体系 YAML,移植自 Kitin)。多数项可 /nekobackend reload,多端口监听需重启。
|
||||||
|
|
||||||
|
## network.chunk-lazy-loading — 区块惰加载(默认 true)
|
||||||
|
|
||||||
|
玩家在小范围反复横跳时不重复重发已加载的地形区块包,省地形带宽。
|
||||||
|
|
||||||
|
- network.chunk-lazy-loading(默认 true):是否启用区块惰加载。
|
||||||
|
|
||||||
|
## network.reduce-high-frequency-entity-sync-packets — 高频实体同步包减量
|
||||||
|
|
||||||
|
某些实体(农场里的船/矿车、潜影贝)静止时也每 tick 强制同步,浪费带宽;此项改为按需同步。
|
||||||
|
|
||||||
|
- entitys(默认 $AbstractMinecart, $AbstractBoat, shulker):要减量的实体列表。$AbstractMinecart=所有矿车,$AbstractBoat=所有船,其余写实体 id(支持 * 通配、# 标签)。
|
||||||
|
|
||||||
|
## network.particle — 粒子限流打包
|
||||||
|
|
||||||
|
领地特效/大量粒子刷屏时,先做视野/距离/遮挡剔除再打包发送。
|
||||||
|
|
||||||
|
- player-max-particles-per-packet(默认 250):单包最多携带粒子数,超出拆包。
|
||||||
|
- player-min-optimize-threshold(默认 50):单次粒子数超此值才启动优化。
|
||||||
|
- global-max-delay-ticks(默认 10):粒子打包最大延迟 tick,攒一攒一起发。
|
||||||
|
- global-max-packet-particles-per-tick(默认 499):每 tick 全局最多发送粒子总数。
|
||||||
|
|
||||||
|
## network.chunk-send — 区块发送限速 + QoS
|
||||||
|
|
||||||
|
控制区块包发送速率,并可按 IP/域名/线路分组限流。
|
||||||
|
|
||||||
|
- use-vanilla-chunk-sender(默认 false):true=用原版区块发送器(关闭 Neko 限速与 ACK 发送器),排查兼容问题时可开。
|
||||||
|
- global-max-chunk-send-rate(默认 -1):全局每秒最大区块发送数,-1=不限。
|
||||||
|
- global-chunk-send-burst-factor(默认 0.05):突发因子,允许短时超速的比例。
|
||||||
|
- qos-groups(默认空):分组限流。每个命名段一组,子选项:rate(该组每秒上限,-1不限)、bind-address(匹配本地绑定 IP)、upstream(上游线路标识)、virtual-host(匹配域名)。例:给 FRP 入口和直连分别限速。
|
||||||
|
|
||||||
|
## network.extra-listeners — 多端口监听(需重启)
|
||||||
|
|
||||||
|
额外监听端口,每个端口可单独配 PROXY Protocol v2,让 FRP 与直连共存。
|
||||||
|
|
||||||
|
- port(必填):监听端口 0~65535。
|
||||||
|
- bind-address(默认 0.0.0.0):绑定地址。
|
||||||
|
- proxy-protocol(默认 false):该端口是否启用 PROXY Protocol v2(FRP 等需要)。
|
||||||
|
- 注意:启动时绑定 socket,不可热重载,改完需重启。
|
||||||
|
|
||||||
|
## 实时带宽监控
|
||||||
|
|
||||||
|
/nekobackend bandwidth 显示当前 Mbps、峰值、本次累计出站用量。
|
||||||
158
docs/optimizations.md
Normal file
158
docs/optimizations.md
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
# 优化模块配置
|
||||||
|
|
||||||
|
位置:luminol_config/optimizations/*.toml。每个模块一段,逐条说明。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## accelerated_collision — AR 碰撞加速(默认开)
|
||||||
|
|
||||||
|
native 广相位替换原版昂贵的实体碰撞空间查询。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| enabled | true | 是否启用碰撞加速 |
|
||||||
|
| backend | FFM | 后端:AUTO/GPU/FFM/JAVA/VANILLA。FFM 最快,失败自动回退 |
|
||||||
|
| max_collision | 32 | 每个实体每 tick 最多处理的碰撞交互数(削峰) |
|
||||||
|
| grid_size | 1 | 空间哈希网格的格子边长(格) |
|
||||||
|
| density_window | 4 | 密度平滑窗口(tick) |
|
||||||
|
| density_threshold | 16 | 局部实体密度达到此值才走加速,稀疏走原版(零行为偏差) |
|
||||||
|
| max_threads | 1 | FFM 后端最大工作线程,0=所有 CPU |
|
||||||
|
|
||||||
|
游戏内:/nekobackend set <后端> 热切换。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## entity_limiter — 每区块实体上限 + 溢出清扫(默认关)
|
||||||
|
|
||||||
|
限制每区块同类实体数量,超出生成时拦截,并周期清扫溢出。生成闸门用 per-chunk/per-tick 计数缓存,实体爆发不会 O(N^2) 卡顿(v1.0.6)。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| enabled | false | 是否启用 |
|
||||||
|
| creatures | 200 | 每区块生物上限 |
|
||||||
|
| items | 100 | 每区块掉落物上限 |
|
||||||
|
| vehicles | 50 | 每区块载具(船/矿车)上限 |
|
||||||
|
| projectiles | 50 | 每区块投射物上限 |
|
||||||
|
| whitelist | ARMOR_STAND,ITEM_FRAME,GLOW_ITEM_FRAME | 豁免实体类型(不计数、不清除) |
|
||||||
|
| overflow_enabled | true | 是否启用周期溢出清扫 |
|
||||||
|
| overflow_interval_seconds | 30 | 清扫间隔(秒) |
|
||||||
|
| overflow_multiplier | 1.5 | 清扫阈值 = 上限 × 此值(超出才清) |
|
||||||
|
| overflow_creatures | true | 清扫是否包含生物 |
|
||||||
|
| overflow_items | true | 清扫是否包含掉落物 |
|
||||||
|
| overflow_vehicles | false | 清扫是否包含载具 |
|
||||||
|
| overflow_projectiles | true | 清扫是否包含投射物 |
|
||||||
|
| spare_named | true | 跳过自定义命名(改名牌)的实体 |
|
||||||
|
| overflow_max_per_sweep | 2000 | 单次清扫最多移除数(削峰),0=无限 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## entity_cull — 视锥/距离实体剔除(默认关)
|
||||||
|
|
||||||
|
玩家视野锥外、且超出近距豁免半径的实体不发包给该客户端,省带宽和客户端压力。转身即恢复,近距离始终可见。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| enabled | false | 是否启用 |
|
||||||
|
| half_fov_degrees | 70 | 视野锥半角(度)。70≈140 度锥,比客户端 FOV 宽,留转身余量 |
|
||||||
|
| near_radius | 16 | 此半径内的实体永远发送,防贴脸突现 |
|
||||||
|
| cull_players | false | 是否也剔除其他玩家(PvP 默认不剔) |
|
||||||
|
| cull_vehicles | false | 是否剔除船/矿车(默认不剔) |
|
||||||
|
| vertical_culling | false | 是否也按俯仰角(垂直)剔除(默认否) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## entity_velocity_packet — ESU 生物 velocity 包降频(默认开)
|
||||||
|
|
||||||
|
走路的怪不再每 tick 发速度包。客户端靠位置包插值,velocity 只为平滑,微小变化无感。投射物/玩家不受影响。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| enabled | true | 是否启用 |
|
||||||
|
| min_delta_sqr | 0.003 | 速度变化平方小于此值则跳过。0=只用间隔限制 |
|
||||||
|
| min_interval_ticks | 3 | 同一怪两个速度包的最小间隔 tick(非冲击时)。3≈最多 7 包/秒 |
|
||||||
|
| impulse_delta_sqr | 0.04 | 速度变化平方≥此值视为冲击(击退/爆炸/坠落),立即发 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## mob_ai_throttle — 远怪 AI 降频(默认关)
|
||||||
|
|
||||||
|
离玩家越远的怪,寻路/索敌跑得越稀。复用 EAR 非活跃时长信号,玩家靠近立即恢复。专治惊变100天/刷怪海。移动控制仍每 tick,不抽搐。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| enabled | false | 是否启用 |
|
||||||
|
| inactive_ticks_tier1 | 20 | 无玩家附近超过此 tick 进入一级降频(约 1 秒) |
|
||||||
|
| tier1_interval | 2 | 一级:每 2 tick 跑一次完整 AI |
|
||||||
|
| inactive_ticks_tier2 | 100 | 进入二级降频阈值(约 5 秒) |
|
||||||
|
| tier2_interval | 4 | 二级:每 4 tick 一次 |
|
||||||
|
| inactive_ticks_tier3 | 400 | 进入三级(最深)降频阈值(约 20 秒) |
|
||||||
|
| tier3_interval | 8 | 三级:每 8 tick 一次。越大越省但反应越慢 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## mob_ai_reducer — 精简生物 AI 目标(默认开)
|
||||||
|
|
||||||
|
裁剪生物的 AI goal/target 选择器,保留必要行为。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| enabled | true | 是否启用 |
|
||||||
|
| animals | true | 是否精简动物 AI |
|
||||||
|
| monsters | false | 是否精简怪物 AI(默认否,怪物要保持攻击性) |
|
||||||
|
| villagers | false | 是否精简村民 AI(默认否,村民交易/补货依赖 AI) |
|
||||||
|
| disable_collides | false | 是否禁用被精简实体的碰撞推挤 |
|
||||||
|
| silent | false | 是否让被精简实体静音 |
|
||||||
|
| keep_dedicated | true | 保留专用/关键 goal |
|
||||||
|
| ai_list_mode | false | 白名单模式(只保留 ai_goal_list 里的 goal) |
|
||||||
|
| ai_goal_list | RandomLookAroundGoal,FloatGoal | 白名单模式下保留的 goal 类名 |
|
||||||
|
| breed_enabled | true | 是否保留繁殖行为 |
|
||||||
|
| breed_range | 8.0 | 繁殖触发检测半径 |
|
||||||
|
| tempt_enabled | true | 是否保留被食物吸引(tempt)行为 |
|
||||||
|
| tempt_range | 10.0 | tempt 触发半径 |
|
||||||
|
| tempt_trigger_both_hands | true | 双手持食物都能触发 tempt |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## afk_entity_tracking — 挂机实体跟踪降频(默认关)
|
||||||
|
|
||||||
|
全员挂机且实体较远时降低实体跟踪更新频率;有人活动立即恢复。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| enabled | false | 是否启用 |
|
||||||
|
| afk_threshold_seconds | 60 | 玩家无操作超过此秒数判定为挂机 |
|
||||||
|
| always_track_radius | 7.0 | 此半径内的实体始终全速跟踪 |
|
||||||
|
| update_interval_ticks | 5 | 降频后实体更新间隔(tick) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## explosion_optimizer — 爆炸优化(默认关)
|
||||||
|
|
||||||
|
限制爆炸威力、防连锁爆炸、可选管理模式(大爆炸只模拟效果不真算)。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| enabled | false | 是否启用 |
|
||||||
|
| yield_limit_enabled | true | 是否限制爆炸威力上限 |
|
||||||
|
| yield_limit_default | 4.0 | 默认威力上限 |
|
||||||
|
| yield_limit_per_type | END_CRYSTAL=6.0, WITHER_SKULL=1.0 | 按爆炸源类型单独设上限 |
|
||||||
|
| anti_chain_enabled | true | 是否防连锁爆炸 |
|
||||||
|
| anti_chain_radius | 8.0 | 连锁检测半径 |
|
||||||
|
| anti_chain_cooldown_ticks | 10 | 连锁冷却时长(tick) |
|
||||||
|
| management_enabled | false | 管理模式:超阈值的大爆炸只模拟效果不真实破坏 |
|
||||||
|
| management_threshold | 6.0 | 进入管理模式的威力阈值 |
|
||||||
|
| simulate_damage | true | 管理模式下是否仍对实体造成伤害 |
|
||||||
|
| simulate_knockback | true | 管理模式下是否仍施加击退 |
|
||||||
|
| simulate_sound | true | 管理模式下是否仍播放爆炸音效 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## skip_zero_delta_packets — ESU 零位移包裁剪(默认开)
|
||||||
|
|
||||||
|
跳过完全没变化的实体移动/旋转包(零信息冗余包)。
|
||||||
|
|
||||||
|
| 选项 | 默认 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| skip_zero_move | true | 跳过零位移的相对移动包 |
|
||||||
|
| skip_zero_rotation | true | 跳过旋转未变的旋转包 |
|
||||||
|
| skip_zero_move_and_rotation | true | 跳过位移和旋转都未变的复合包 |
|
||||||
79
folia-server/build.gradle.kts.patch
Normal file
79
folia-server/build.gradle.kts.patch
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
--- a/paper-server/build.gradle.kts
|
||||||
|
+++ b/paper-server/build.gradle.kts
|
||||||
|
@@ -25,6 +_,18 @@
|
||||||
|
paperweight {
|
||||||
|
minecraftVersion = providers.gradleProperty("mcVersion")
|
||||||
|
gitFilePatches = false
|
||||||
|
+
|
||||||
|
+ val fork = forks.register("folia") {
|
||||||
|
+ upstream.patchDir("paperServer") {
|
||||||
|
+ upstreamPath = "paper-server"
|
||||||
|
+ excludes = setOf("src/minecraft", "patches", "build.gradle.kts")
|
||||||
|
+ patchesDir = rootDirectory.dir("folia-server/paper-patches")
|
||||||
|
+ outputDir = rootDirectory.dir("paper-server")
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ activeFork = fork
|
||||||
|
+
|
||||||
|
|
||||||
|
spigot {
|
||||||
|
enabled = true
|
||||||
|
@@ -107,7 +_,19 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-val log4jPlugins = sourceSets.create("log4jPlugins")
|
||||||
|
+sourceSets {
|
||||||
|
+ main {
|
||||||
|
+ java { srcDir("../paper-server/src/main/java"); srcDir("../paper-server/src/generated/java") }
|
||||||
|
+ resources { srcDir("../paper-server/src/main/resources") }
|
||||||
|
+ }
|
||||||
|
+ test {
|
||||||
|
+ java { srcDir("../paper-server/src/test/java") }
|
||||||
|
+ resources { srcDir("../paper-server/src/test/resources") }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+val log4jPlugins = sourceSets.create("log4jPlugins") {
|
||||||
|
+ java { srcDir("../paper-server/src/log4jPlugins/java") }
|
||||||
|
+}
|
||||||
|
configurations.named(log4jPlugins.compileClasspathConfigurationName) {
|
||||||
|
extendsFrom(configurations.compileClasspath.get())
|
||||||
|
}
|
||||||
|
@@ -129,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
- implementation(project(":paper-api"))
|
||||||
|
+ implementation(project(":folia-api"))
|
||||||
|
implementation("ca.spottedleaf:concurrentutil:0.0.3")
|
||||||
|
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
|
||||||
|
@@ -200,14 +_,14 @@
|
||||||
|
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
|
||||||
|
attributes(
|
||||||
|
"Main-Class" to "org.bukkit.craftbukkit.Main",
|
||||||
|
- "Implementation-Title" to "Paper",
|
||||||
|
+ "Implementation-Title" to "Folia",
|
||||||
|
"Implementation-Version" to implementationVersion,
|
||||||
|
"Implementation-Vendor" to date,
|
||||||
|
- "Specification-Title" to "Paper",
|
||||||
|
+ "Specification-Title" to "Folia",
|
||||||
|
"Specification-Version" to project.version,
|
||||||
|
"Specification-Vendor" to "Paper Team",
|
||||||
|
- "Brand-Id" to "papermc:paper",
|
||||||
|
- "Brand-Name" to "Paper",
|
||||||
|
+ "Brand-Id" to "papermc:folia",
|
||||||
|
+ "Brand-Name" to "Folia",
|
||||||
|
"Build-Number" to (build ?: ""),
|
||||||
|
"Build-Time" to buildTime.toString(),
|
||||||
|
"Git-Branch" to gitBranch,
|
||||||
|
@@ -371,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
fill {
|
||||||
|
- project("paper")
|
||||||
|
+ project("folia")
|
||||||
|
versionFamily(paperweight.minecraftVersion.map { it.split(".", "-").takeWhile { part -> part.toIntOrNull() != null }.take(2).joinToString(".") })
|
||||||
|
version(paperweight.minecraftVersion)
|
||||||
|
|
||||||
19713
folia-server/minecraft-patches/features/0001-Region-Threading-Base.patch
Normal file
19713
folia-server/minecraft-patches/features/0001-Region-Threading-Base.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,42 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Thu, 9 Mar 2023 20:50:15 -0800
|
||||||
|
Subject: [PATCH] Max pending logins
|
||||||
|
|
||||||
|
Should help the floodgates on launch
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||||
|
index 8998637bcf1eaeaefa2d6e46a883f761d389a5d0..d6c18d79dc9c0e7ac67a9346008243ace03f71e8 100644
|
||||||
|
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||||
|
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||||
|
@@ -98,7 +98,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||||
|
if (this.server.getPlayerList().pushPendingJoin(name, uniqueId, this.connection)) {
|
||||||
|
// Folia end - region threading - rewrite login process
|
||||||
|
this.verifyLoginAndFinishConnectionSetup(Objects.requireNonNull(this.authenticatedProfile));
|
||||||
|
- } // Folia - region threading - rewrite login process
|
||||||
|
+ } else { --this.tick; } // Folia - region threading - rewrite login process // Folia - max concurrent logins
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state == ServerLoginPacketListenerImpl.State.WAITING_FOR_DUPE_DISCONNECT
|
||||||
|
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||||
|
index b37ef4ccedfed4bb13f9cda50b1fc5ff7f371664..0de42ad1eefb2258a2520f899f9e62625eab1939 100644
|
||||||
|
--- a/net/minecraft/server/players/PlayerList.java
|
||||||
|
+++ b/net/minecraft/server/players/PlayerList.java
|
||||||
|
@@ -150,6 +150,17 @@ public abstract class PlayerList {
|
||||||
|
conflictingId = this.connectionById.get(byId);
|
||||||
|
|
||||||
|
if (conflictingName == null && conflictingId == null) {
|
||||||
|
+ // Folia start - max concurrent login
|
||||||
|
+ int loggedInCount = 0;
|
||||||
|
+ for (Connection value : this.connectionById.values()) {
|
||||||
|
+ if (value.getPacketListener() instanceof ServerGamePacketListenerImpl) {
|
||||||
|
+ ++loggedInCount;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if ((this.connectionById.size() - loggedInCount) >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ // Folia end - max concurrent login
|
||||||
|
this.connectionByName.put(userName, conn);
|
||||||
|
this.connectionById.put(byId, conn);
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Fri, 10 Mar 2023 00:16:26 -0800
|
||||||
|
Subject: [PATCH] Add chunk system throughput counters to /tps
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
|
||||||
|
index 96ccb8f657d755b2e58a8dd0cda00ca0df4886b2..fd48134ab73d3096bc86402b4eb393c8153fceab 100644
|
||||||
|
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
|
||||||
|
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java
|
||||||
|
@@ -30,6 +30,9 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
|
||||||
|
private final ChunkAccess fromChunk;
|
||||||
|
private final PrioritisedExecutor.PrioritisedTask convertToFullTask;
|
||||||
|
|
||||||
|
+ public static final io.papermc.paper.util.IntervalledCounter chunkLoads = new io.papermc.paper.util.IntervalledCounter(java.util.concurrent.TimeUnit.SECONDS.toNanos(15L));
|
||||||
|
+ public static final io.papermc.paper.util.IntervalledCounter chunkGenerates = new io.papermc.paper.util.IntervalledCounter(java.util.concurrent.TimeUnit.SECONDS.toNanos(15L));
|
||||||
|
+
|
||||||
|
public ChunkFullTask(final ChunkTaskScheduler scheduler, final ServerLevel world, final int chunkX, final int chunkZ,
|
||||||
|
final NewChunkHolder chunkHolder, final ChunkAccess fromChunk, final Priority priority) {
|
||||||
|
super(scheduler, world, chunkX, chunkZ);
|
||||||
|
@@ -43,6 +46,20 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
|
||||||
|
return ChunkStatus.FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public static double genRate(final long time) {
|
||||||
|
+ synchronized (chunkGenerates) {
|
||||||
|
+ chunkGenerates.updateCurrentTime(time);
|
||||||
|
+ return chunkGenerates.getRate();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static double loadRate(final long time) {
|
||||||
|
+ synchronized (chunkLoads) {
|
||||||
|
+ chunkLoads.updateCurrentTime(time);
|
||||||
|
+ return chunkLoads.getRate();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final PlatformHooks platformHooks = PlatformHooks.get();
|
||||||
|
@@ -59,6 +76,17 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
|
||||||
|
((ChunkSystemPoiManager)this.world.getPoiManager()).moonrise$checkConsistency(this.fromChunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ final long time = System.nanoTime();
|
||||||
|
+ if (this.fromChunk instanceof ImposterProtoChunk wrappedFull) {
|
||||||
|
+ synchronized (chunkLoads) {
|
||||||
|
+ chunkLoads.updateAndAdd(1L, time);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ synchronized (chunkGenerates) {
|
||||||
|
+ chunkGenerates.updateAndAdd(1L, time);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (this.fromChunk instanceof ImposterProtoChunk wrappedFull) {
|
||||||
|
chunk = wrappedFull.getWrapped();
|
||||||
|
} else {
|
||||||
|
diff --git a/io/papermc/paper/threadedregions/commands/CommandServerHealth.java b/io/papermc/paper/threadedregions/commands/CommandServerHealth.java
|
||||||
|
index ebe2592a78e996fa2d415663bd6436effec1ca29..5e6b490ee58a90fd7c02fa09093830c0d9c67f6b 100644
|
||||||
|
--- a/io/papermc/paper/threadedregions/commands/CommandServerHealth.java
|
||||||
|
+++ b/io/papermc/paper/threadedregions/commands/CommandServerHealth.java
|
||||||
|
@@ -170,6 +170,9 @@ public final class CommandServerHealth extends Command {
|
||||||
|
totalUtil += (report == null ? 0.0 : report.utilisation());
|
||||||
|
}
|
||||||
|
|
||||||
|
+ final double genRate = ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkFullTask.genRate(currTime);
|
||||||
|
+ final double loadRate = ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkFullTask.loadRate(currTime);
|
||||||
|
+
|
||||||
|
totalUtil += globalTickReport.utilisation();
|
||||||
|
|
||||||
|
tpsByRegion.sort(null);
|
||||||
|
@@ -284,6 +287,12 @@ public final class CommandServerHealth extends Command {
|
||||||
|
.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("Gen rate: ", PRIMARY))
|
||||||
|
+ .append(Component.text(TWO_DECIMAL_PLACES.get().format(genRate) + "\n", INFORMATION))
|
||||||
|
+
|
||||||
|
.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)))
|
||||||
@ -0,0 +1,111 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Mon, 17 Apr 2023 19:47:57 -0700
|
||||||
|
Subject: [PATCH] Prevent block updates in non-loaded or non-owned chunks
|
||||||
|
|
||||||
|
This is to prevent block physics from tripping thread checks by
|
||||||
|
far exceeding the bounds of the current region. While this does
|
||||||
|
add explicit block update suppression techniques, it's better
|
||||||
|
than the server crashing.
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||||
|
index 402a90890b9754c9c1a1d209a13cda8c9498f05c..1976a443e7c59e1e18d8a411513df39c83ad1095 100644
|
||||||
|
--- a/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/net/minecraft/world/level/Level.java
|
||||||
|
@@ -2045,7 +2045,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||||
|
public void updateNeighbourForOutputSignal(BlockPos pos, Block block) {
|
||||||
|
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||||
|
BlockPos blockPos = pos.relative(direction);
|
||||||
|
- if (this.hasChunkAt(blockPos)) {
|
||||||
|
+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this, blockPos, 16) && this.hasChunkAt(blockPos)) { // Folia - block updates in unloaded chunks
|
||||||
|
BlockState blockState = this.getBlockState(blockPos);
|
||||||
|
if (blockState.is(Blocks.COMPARATOR)) {
|
||||||
|
this.neighborChanged(blockState, blockPos, block, null, false);
|
||||||
|
diff --git a/net/minecraft/world/level/block/DetectorRailBlock.java b/net/minecraft/world/level/block/DetectorRailBlock.java
|
||||||
|
index 73bc347616b40f55664dfcbc805dfac5d1e0452e..ec273a242c67d13906d543831e0cd5def2cae931 100644
|
||||||
|
--- a/net/minecraft/world/level/block/DetectorRailBlock.java
|
||||||
|
+++ b/net/minecraft/world/level/block/DetectorRailBlock.java
|
||||||
|
@@ -128,8 +128,8 @@ public class DetectorRailBlock extends BaseRailBlock {
|
||||||
|
RailState railState = new RailState(level, pos, state);
|
||||||
|
|
||||||
|
for (BlockPos blockPos : railState.getConnections()) {
|
||||||
|
- BlockState blockState = level.getBlockState(blockPos);
|
||||||
|
- level.neighborChanged(blockState, blockPos, blockState.getBlock(), null, false);
|
||||||
|
+ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, blockPos, 16) ? null : level.getBlockState(blockPos); // Folia - block updates in unloaded chunks
|
||||||
|
+ if (blockState != null) level.neighborChanged(blockState, blockPos, blockState.getBlock(), null, false); // Folia - block updates in unloaded chunks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/block/PoweredRailBlock.java b/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||||
|
index e4c4a6b4a6ea41b1fdb006cfc70dfb68dcd056c0..abc39a31b29ed4f68398851de7a1209fef895769 100644
|
||||||
|
--- a/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||||
|
+++ b/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||||
|
@@ -102,8 +102,8 @@ public class PoweredRailBlock extends BaseRailBlock {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isSameRailWithPower(Level level, BlockPos state, boolean searchForward, int recursionCount, RailShape shape) {
|
||||||
|
- BlockState blockState = level.getBlockState(state);
|
||||||
|
- if (!blockState.is(this)) {
|
||||||
|
+ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, state, 16) ? null : level.getBlockState(state); // Folia - block updates in unloaded chunks
|
||||||
|
+ if (blockState == null || !blockState.is(this)) { // Folia - block updates in unloaded chunks
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
RailShape railShape = blockState.getValue(SHAPE);
|
||||||
|
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||||
|
index fde784fac9ee933d811d70701cb71684c816e966..4b37335e91a51b9a58ce0bce94b61ab5afbc6486 100644
|
||||||
|
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||||
|
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||||
|
@@ -211,8 +211,9 @@ public class RedStoneWireBlock extends Block {
|
||||||
|
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
|
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||||
|
+ BlockState currState; mutableBlockPos.setWithOffset(pos, direction); // Folia - block updates in unloaded chunks
|
||||||
|
RedstoneSide redstoneSide = state.getValue(PROPERTY_BY_DIRECTION.get(direction));
|
||||||
|
- if (redstoneSide != RedstoneSide.NONE && !level.getBlockState(mutableBlockPos.setWithOffset(pos, direction)).is(this)) {
|
||||||
|
+ if (redstoneSide != RedstoneSide.NONE && (currState = (level instanceof net.minecraft.server.level.ServerLevel serverLevel && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(serverLevel, pos, 16) ? null : level.getBlockStateIfLoaded(mutableBlockPos.setWithOffset(pos, direction)))) != null && !currState.is(this)) { // Folia - block updates in unloaded chunks
|
||||||
|
mutableBlockPos.move(Direction.DOWN);
|
||||||
|
BlockState blockState = level.getBlockState(mutableBlockPos);
|
||||||
|
if (blockState.is(this)) {
|
||||||
|
diff --git a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
||||||
|
index e7ea9df8f404a6176435204a91edeefab8070c89..285fa83ee583595274f228e5981a67f67012d410 100644
|
||||||
|
--- a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
||||||
|
+++ b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
||||||
|
@@ -122,7 +122,8 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
||||||
|
public boolean runNext(Level level) {
|
||||||
|
Direction direction = NeighborUpdater.UPDATE_ORDER[this.idx++];
|
||||||
|
BlockPos blockPos = this.sourcePos.relative(direction);
|
||||||
|
- BlockState blockState = level.getBlockState(blockPos);
|
||||||
|
+ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, blockPos, 16) ? null : level.getBlockState(blockPos); // Folia - block updates in unloaded chunks
|
||||||
|
+ if (blockState != null) { // Folia - block updates in unloaded chunks
|
||||||
|
Orientation orientation = null;
|
||||||
|
if (level.enabledFeatures().contains(FeatureFlags.REDSTONE_EXPERIMENTS)) {
|
||||||
|
if (this.orientation == null) {
|
||||||
|
@@ -135,6 +136,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
||||||
|
}
|
||||||
|
|
||||||
|
NeighborUpdater.executeUpdate(level, blockState, blockPos, this.sourceBlock, orientation, false, this.sourcePos); // Paper - Add source block to BlockPhysicsEvent
|
||||||
|
+ } // Folia - block updates in unloaded chunks
|
||||||
|
if (this.idx < NeighborUpdater.UPDATE_ORDER.length && NeighborUpdater.UPDATE_ORDER[this.idx] == this.skipDirection) {
|
||||||
|
this.idx++;
|
||||||
|
}
|
||||||
|
@@ -151,7 +153,9 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
||||||
|
implements CollectingNeighborUpdater.NeighborUpdates {
|
||||||
|
@Override
|
||||||
|
public boolean runNext(Level level) {
|
||||||
|
+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, this.pos, 16) && level.getChunkIfLoaded(this.pos) != null) { // Folia - block updates in unloaded chunks
|
||||||
|
NeighborUpdater.executeShapeUpdate(level, this.direction, this.pos, this.neighborPos, this.neighborState, this.updateFlags, this.updateLimit);
|
||||||
|
+ } // Folia - block updates in unloaded chunks
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -159,8 +163,8 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
||||||
|
record SimpleNeighborUpdate(BlockPos pos, Block block, @Nullable Orientation orientation) implements CollectingNeighborUpdater.NeighborUpdates {
|
||||||
|
@Override
|
||||||
|
public boolean runNext(Level level) {
|
||||||
|
- BlockState blockState = level.getBlockState(this.pos);
|
||||||
|
- NeighborUpdater.executeUpdate(level, blockState, this.pos, this.block, this.orientation, false);
|
||||||
|
+ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, this.pos, 16) ? null : level.getBlockStateIfLoaded(this.pos); // Folia - block updates in unloaded chunks
|
||||||
|
+ if (blockState != null) NeighborUpdater.executeUpdate(level, blockState, this.pos, this.block, this.orientation, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Sun, 23 Apr 2023 07:08:26 -0700
|
||||||
|
Subject: [PATCH] Block reading in-world tile entities on worldgen threads
|
||||||
|
|
||||||
|
The returned TE may be in the world, in which case it is unsafe
|
||||||
|
for the current thread to modify or access its contents.
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||||
|
index d1331b580b3d27c77244b22a4ad15e719f686c8f..b430bb3c1bca935312bf6183b9f502c683b27c1f 100644
|
||||||
|
--- a/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||||
|
@@ -91,6 +91,11 @@ public class ImposterProtoChunk extends ProtoChunk implements ca.spottedleaf.moo
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||||
|
+ // Folia start - block reading possibly in-world block data for worldgen threads
|
||||||
|
+ if (!this.allowWrites && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ // Folia end - block reading possibly in-world block data for worldgen threads
|
||||||
|
return this.wrapped.getBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Sun, 25 Jun 2023 13:57:30 -0700
|
||||||
|
Subject: [PATCH] Sync vehicle position to player position on player data load
|
||||||
|
|
||||||
|
This allows the player to be re-positioned before logging into
|
||||||
|
the world without causing thread checks to trip on Folia.
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
index 3d70e4daddd81c96546a4fc84086bc9e81bc3915..8ecdf803e1489375bc9dd955cd6031de724463f9 100644
|
||||||
|
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
@@ -753,8 +753,18 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||||
|
Optional<ValueInput> optional = input.child("RootVehicle");
|
||||||
|
if (!optional.isEmpty()) {
|
||||||
|
ServerLevel serverLevel = this.level();
|
||||||
|
+ Vec3 playerPos = this.position(); // Paper - force sync root vehicle to player position
|
||||||
|
Entity entity = EntityType.loadEntityRecursive(
|
||||||
|
- optional.get().childOrEmpty("Entity"), serverLevel, EntitySpawnReason.LOAD, entity2 -> !serverLevel.addWithUUID(entity2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity2 // Paper - Entity#getEntitySpawnReason
|
||||||
|
+ // Paper start - force sync root vehicle to player position
|
||||||
|
+ optional.get().childOrEmpty("Entity"), serverLevel, EntitySpawnReason.LOAD, (Entity entity2) -> {
|
||||||
|
+ // Paper start - force sync root vehicle to player position
|
||||||
|
+ if (entity2.distanceToSqr(ServerPlayer.this) > (5.0 * 5.0)) {
|
||||||
|
+ entity2.setPosRaw(playerPos.x, playerPos.y, playerPos.z, true);
|
||||||
|
+ }
|
||||||
|
+ // Paper end - force sync root vehicle to player position
|
||||||
|
+ return !serverLevel.addWithUUID(entity2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity2; // Paper - Entity#getEntitySpawnReason
|
||||||
|
+ }
|
||||||
|
+ // Paper end - force sync root vehicle to player position
|
||||||
|
);
|
||||||
|
if (entity != null) {
|
||||||
|
UUID uuid = optional.get().read("Attach", UUIDUtil.CODEC).orElse(null);
|
||||||
2040
folia-server/minecraft-patches/features/0007-Region-profiler.patch
Normal file
2040
folia-server/minecraft-patches/features/0007-Region-profiler.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,186 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Fri, 30 Aug 2024 18:34:32 -0700
|
||||||
|
Subject: [PATCH] Add watchdog thread
|
||||||
|
|
||||||
|
When regions take too long, having the server print the stacktrace
|
||||||
|
of the ticking region should help debug the cause.
|
||||||
|
|
||||||
|
diff --git a/io/papermc/paper/threadedregions/FoliaWatchdogThread.java b/io/papermc/paper/threadedregions/FoliaWatchdogThread.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..e9ca1a15049b0211d10401cb78e953b93afaf6c7
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/io/papermc/paper/threadedregions/FoliaWatchdogThread.java
|
||||||
|
@@ -0,0 +1,104 @@
|
||||||
|
+package io.papermc.paper.threadedregions;
|
||||||
|
+
|
||||||
|
+import com.mojang.logging.LogUtils;
|
||||||
|
+import io.papermc.paper.threadedregions.TickRegionScheduler.RegionScheduleHandle;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import org.bukkit.Bukkit;
|
||||||
|
+import org.slf4j.Logger;
|
||||||
|
+import org.spigotmc.WatchdogThread;
|
||||||
|
+import java.lang.management.ManagementFactory;
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.LinkedHashSet;
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.concurrent.TimeUnit;
|
||||||
|
+
|
||||||
|
+public final class FoliaWatchdogThread extends Thread {
|
||||||
|
+
|
||||||
|
+ private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
+
|
||||||
|
+ public static final class RunningTick {
|
||||||
|
+
|
||||||
|
+ public final long start;
|
||||||
|
+ public final RegionScheduleHandle handle;
|
||||||
|
+ public final Thread thread;
|
||||||
|
+
|
||||||
|
+ private long lastPrint;
|
||||||
|
+
|
||||||
|
+ public RunningTick(final long start, final RegionScheduleHandle handle, final Thread thread) {
|
||||||
|
+ this.start = start;
|
||||||
|
+ this.handle = handle;
|
||||||
|
+ this.thread = thread;
|
||||||
|
+ this.lastPrint = start;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private final LinkedHashSet<RunningTick> ticks = new LinkedHashSet<>();
|
||||||
|
+
|
||||||
|
+ public FoliaWatchdogThread() {
|
||||||
|
+ super("Folia Watchdog Thread");
|
||||||
|
+ this.setDaemon(true);
|
||||||
|
+ this.setUncaughtExceptionHandler((final Thread thread, final Throwable throwable) -> {
|
||||||
|
+ LOGGER.error("Uncaught exception in thread '" + thread.getName() + "'", throwable);
|
||||||
|
+ });
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void run() {
|
||||||
|
+ for (;;) {
|
||||||
|
+ try {
|
||||||
|
+ Thread.sleep(1000L);
|
||||||
|
+ } catch (final InterruptedException ex) {}
|
||||||
|
+
|
||||||
|
+ if (MinecraftServer.getServer() == null || MinecraftServer.getServer().hasStopped()) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final List<RunningTick> ticks;
|
||||||
|
+ synchronized (this.ticks) {
|
||||||
|
+ if (this.ticks.isEmpty()) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ ticks = new ArrayList<>(this.ticks);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final long now = System.nanoTime();
|
||||||
|
+
|
||||||
|
+ for (final RunningTick tick : ticks) {
|
||||||
|
+ final long elapsed = now - tick.lastPrint;
|
||||||
|
+ if (elapsed <= TimeUnit.SECONDS.toNanos(5L)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ tick.lastPrint = now;
|
||||||
|
+
|
||||||
|
+ final double totalElapsedS = (double)(now - tick.start) / 1.0E9;
|
||||||
|
+
|
||||||
|
+ if (tick.handle instanceof TickRegions.ConcreteRegionTickHandle region) {
|
||||||
|
+ LOGGER.error(
|
||||||
|
+ "Tick region located in world '" + region.region.world.getWorld().getName() + "' around chunk '"
|
||||||
|
+ + region.region.region.getCenterChunk() + "' has not responded in " + totalElapsedS + "s:"
|
||||||
|
+ );
|
||||||
|
+ } else {
|
||||||
|
+ // assume global
|
||||||
|
+ LOGGER.error("Global region has not responded in " + totalElapsedS + "s:");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ WatchdogThread.dumpThread(
|
||||||
|
+ ManagementFactory.getThreadMXBean().getThreadInfo(tick.thread.threadId(), Integer.MAX_VALUE),
|
||||||
|
+ Bukkit.getServer().getLogger()
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void addTick(final RunningTick tick) {
|
||||||
|
+ synchronized (this.ticks) {
|
||||||
|
+ this.ticks.add(tick);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void removeTick(final RunningTick tick) {
|
||||||
|
+ synchronized (this.ticks) {
|
||||||
|
+ this.ticks.remove(tick);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||||
|
index e392457ccc06d3c6ad794f3c480d301a46083054..fa6b8d756195c1b430cc11214a901bd42eebc98d 100644
|
||||||
|
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||||
|
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
|
||||||
|
@@ -34,6 +34,13 @@ public final class TickRegionScheduler {
|
||||||
|
public static final int TICK_RATE = 20;
|
||||||
|
public static final long TIME_BETWEEN_TICKS = 1_000_000_000L / TICK_RATE; // ns
|
||||||
|
|
||||||
|
+ // Folia start - watchdog
|
||||||
|
+ public static final FoliaWatchdogThread WATCHDOG_THREAD = new FoliaWatchdogThread();
|
||||||
|
+ static {
|
||||||
|
+ WATCHDOG_THREAD.start();
|
||||||
|
+ }
|
||||||
|
+ // Folia end - watchdog
|
||||||
|
+
|
||||||
|
private final SchedulerThreadPool scheduler;
|
||||||
|
|
||||||
|
public TickRegionScheduler(final int threads) {
|
||||||
|
@@ -327,6 +334,8 @@ public final class TickRegionScheduler {
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean ret;
|
||||||
|
+ final FoliaWatchdogThread.RunningTick runningTick = new FoliaWatchdogThread.RunningTick(tickStart, this, Thread.currentThread()); // Folia - watchdog
|
||||||
|
+ WATCHDOG_THREAD.addTick(runningTick); // Folia - watchdog
|
||||||
|
try {
|
||||||
|
ret = this.runRegionTasks(() -> {
|
||||||
|
return !RegionScheduleHandle.this.cancelled.get() && canContinue.getAsBoolean();
|
||||||
|
@@ -336,6 +345,7 @@ public final class TickRegionScheduler {
|
||||||
|
// don't release region for another tick
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
+ WATCHDOG_THREAD.removeTick(runningTick); // Folia - watchdog
|
||||||
|
final long tickEnd = System.nanoTime();
|
||||||
|
final long cpuEnd = MEASURE_CPU_TIME ? THREAD_MX_BEAN.getCurrentThreadCpuTime() : 0L;
|
||||||
|
|
||||||
|
@@ -401,6 +411,8 @@ public final class TickRegionScheduler {
|
||||||
|
this.currentTickingThread = Thread.currentThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ final FoliaWatchdogThread.RunningTick runningTick = new FoliaWatchdogThread.RunningTick(tickStart, this, Thread.currentThread()); // Folia - region threading
|
||||||
|
+ WATCHDOG_THREAD.addTick(runningTick); // Folia - region threading
|
||||||
|
try {
|
||||||
|
// next start isn't updated until the end of this tick
|
||||||
|
this.tickRegion(tickCount, tickStart, scheduledEnd);
|
||||||
|
@@ -409,6 +421,7 @@ public final class TickRegionScheduler {
|
||||||
|
// regionFailed will schedule a shutdown, so we should avoid letting this region tick further
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
+ WATCHDOG_THREAD.removeTick(runningTick); // Folia - region threading
|
||||||
|
final long tickEnd = System.nanoTime();
|
||||||
|
final long cpuEnd = MEASURE_CPU_TIME ? THREAD_MX_BEAN.getCurrentThreadCpuTime() : 0L;
|
||||||
|
|
||||||
|
diff --git a/io/papermc/paper/threadedregions/TickRegions.java b/io/papermc/paper/threadedregions/TickRegions.java
|
||||||
|
index b1c07e582dbf0a203cf734fdbcd8387a422af3a6..988fe74578065c9464f5639e5cc6af79619edef5 100644
|
||||||
|
--- a/io/papermc/paper/threadedregions/TickRegions.java
|
||||||
|
+++ b/io/papermc/paper/threadedregions/TickRegions.java
|
||||||
|
@@ -330,9 +330,9 @@ public final class TickRegions implements ThreadedRegionizer.RegionCallbacks<Tic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- private static final class ConcreteRegionTickHandle extends TickRegionScheduler.RegionScheduleHandle {
|
||||||
|
+ public static final class ConcreteRegionTickHandle extends TickRegionScheduler.RegionScheduleHandle { // Folia - watchdog
|
||||||
|
|
||||||
|
- private final TickRegionData region;
|
||||||
|
+ public final TickRegionData region; // Folia - watchdog
|
||||||
|
|
||||||
|
private ConcreteRegionTickHandle(final TickRegionData region, final long start) {
|
||||||
|
super(region, start);
|
||||||
3983
folia-server/paper-patches/features/0001-Region-Threading-Base.patch
Normal file
3983
folia-server/paper-patches/features/0001-Region-Threading-Base.patch
Normal file
File diff suppressed because it is too large
Load Diff
1037
folia-server/paper-patches/features/0002-Update-Logo.patch
Normal file
1037
folia-server/paper-patches/features/0002-Update-Logo.patch
Normal file
File diff suppressed because it is too large
Load Diff
84
folia-server/paper-patches/features/0003-Build-changes.patch
Normal file
84
folia-server/paper-patches/features/0003-Build-changes.patch
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Fri, 10 Jan 2025 22:35:07 -0800
|
||||||
|
Subject: [PATCH] Build changes
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||||
|
index 6abc57669e87f7f98f3b76af3c0e50825fea6eb1..90a5178b5025378197b69514d782de5d6090cb6b 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||||
|
@@ -593,7 +593,7 @@ public class Metrics {
|
||||||
|
boolean logFailedRequests = config.getBoolean("logFailedRequests", false);
|
||||||
|
// Only start Metrics, if it's enabled in the config
|
||||||
|
if (config.getBoolean("enabled", true)) {
|
||||||
|
- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger());
|
||||||
|
+ Metrics metrics = new Metrics("Folia", serverUUID, logFailedRequests, Bukkit.getLogger()); // Folia - we have our own bstats page
|
||||||
|
|
||||||
|
metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> {
|
||||||
|
String minecraftVersion = Bukkit.getVersion();
|
||||||
|
@@ -607,11 +607,11 @@ public class Metrics {
|
||||||
|
final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion();
|
||||||
|
if (implVersion != null) {
|
||||||
|
final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1);
|
||||||
|
- paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash);
|
||||||
|
+ paperVersion = "git-Folia-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); // Folia - we have our own bstats page
|
||||||
|
} else {
|
||||||
|
paperVersion = "unknown";
|
||||||
|
}
|
||||||
|
- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion));
|
||||||
|
+ metrics.addCustomChart(new Metrics.SimplePie("folia_version", () -> paperVersion)); // Folia - we have our own bstats page
|
||||||
|
|
||||||
|
metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
|
||||||
|
Map<String, Map<String, Integer>> map = new HashMap<>();
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||||
|
index d0554ed6631535815e5932930911e3fe1dee8710..1783f9ea48154dcc8971fc5ef088f5a8c0f0b2ff 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
|
||||||
|
@@ -49,7 +49,7 @@ public class PaperVersionFetcher implements VersionFetcher {
|
||||||
|
if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
|
||||||
|
updateMessage = text("You are running a development version without access to version information", color(0xFF5300));
|
||||||
|
} else {
|
||||||
|
- updateMessage = getUpdateStatusMessage("PaperMC/Paper", build);
|
||||||
|
+ updateMessage = getUpdateStatusMessage("PaperMC/Folia", build); // Folia
|
||||||
|
}
|
||||||
|
final @Nullable Component history = this.getHistory();
|
||||||
|
|
||||||
|
@@ -86,7 +86,7 @@ public class PaperVersionFetcher implements VersionFetcher {
|
||||||
|
private static int fetchDistanceFromSiteApi(final ServerBuildInfo build, final int jenkinsBuild) {
|
||||||
|
try {
|
||||||
|
try (final BufferedReader reader = Resources.asCharSource(
|
||||||
|
- URI.create("https://api.papermc.io/v2/projects/paper/versions/" + build.minecraftVersionId()).toURL(),
|
||||||
|
+ URI.create("https://api.papermc.io/v2/projects/folia/versions/" + build.minecraftVersionId()).toURL(), // Folia
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
).openBufferedStream()) {
|
||||||
|
final JsonObject json = new Gson().fromJson(reader, JsonObject.class);
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||||
|
index 74ffdc823e66fc5ec027c4b7c462382bcbfe2be2..10a0be7a4db1a51579d113d279af7a9effe7f438 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||||
|
@@ -42,9 +42,9 @@ public record ServerBuildInfoImpl(
|
||||||
|
this(
|
||||||
|
getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID)
|
||||||
|
.map(Key::key)
|
||||||
|
- .orElse(BRAND_PAPER_ID),
|
||||||
|
+ .orElse(Key.key("papermc", "folia")), // Folia
|
||||||
|
getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME)
|
||||||
|
- .orElse(BRAND_PAPER_NAME),
|
||||||
|
+ .orElse("Folia"), // Folia
|
||||||
|
SharedConstants.getCurrentVersion().id(),
|
||||||
|
SharedConstants.getCurrentVersion().name(),
|
||||||
|
getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER)
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||||
|
index 774556a62eb240da42e84db4502e2ed43495be17..e9b6ca3aa25e140467ae866d572483050ea3fa0e 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||||
|
@@ -11,7 +11,7 @@ public final class Versioning {
|
||||||
|
public static String getBukkitVersion() {
|
||||||
|
String result = "Unknown-Version";
|
||||||
|
|
||||||
|
- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties");
|
||||||
|
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/dev.folia/folia-api/pom.properties"); // Folia
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
if (stream != null) {
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||||
|
Date: Sat, 25 Mar 2023 19:03:42 +0100
|
||||||
|
Subject: [PATCH] Fix tests by removing them
|
||||||
|
|
||||||
|
We don't care about this one, some commands just need to be removed.
|
||||||
|
|
||||||
|
diff --git a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
|
||||||
|
index fe08e446e86d53cef6eecc33cd484e93adc42871..e374c240a9dadb52933272a09569c60bf86289a2 100644
|
||||||
|
--- a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
|
||||||
|
+++ b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java
|
||||||
|
@@ -37,6 +37,7 @@ public class MinecraftCommandPermissionsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
+ if (true) return; // Folia - Fix tests by removing them
|
||||||
|
CraftDefaultPermissions.registerCorePermissions();
|
||||||
|
Set<String> perms = collectMinecraftCommandPerms();
|
||||||
|
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Tue, 3 Oct 2023 06:03:34 -0700
|
||||||
|
Subject: [PATCH] Region profiler
|
||||||
|
|
||||||
|
Profiling for a region starts with the /profiler command.
|
||||||
|
The usage for /profiler:
|
||||||
|
/profiler <world> <block x> <block z> <time in s> [radius, default 100 blocks]
|
||||||
|
|
||||||
|
Any region within the radius of the specified block coordinates
|
||||||
|
will be profiled. The profiling will stop after the specified
|
||||||
|
time has passed.
|
||||||
|
|
||||||
|
Once the profiler finishes, it will place a report in
|
||||||
|
the directory ./profiler/<id>.
|
||||||
|
|
||||||
|
Since regions can split into smaller regions, or merge into
|
||||||
|
other regions, the profiler will track this information. If
|
||||||
|
a profiled region splits, then all of the regions it splits
|
||||||
|
into are attached to the same profiler instance. If a profiled
|
||||||
|
region merges into another region, then the merged region is
|
||||||
|
profiled. This information is tracked and logged into the
|
||||||
|
"journal.txt" file contained in the report directory. The
|
||||||
|
journal tracks the region ids for the merge/split operations.
|
||||||
|
|
||||||
|
Region profiling is placed into the "region-X.txt" file where
|
||||||
|
X is the region id inside the profile directory. The header
|
||||||
|
of the file describes some stats about the region, namely
|
||||||
|
total profiling duration, ticks, utilisation, TPS, and MSPT.
|
||||||
|
|
||||||
|
Then, the timing tree is follows. The format is as specified:
|
||||||
|
|
||||||
|
There are two types of data recorded: Timers and Counters.
|
||||||
|
|
||||||
|
Timers are specified as follows:
|
||||||
|
<indent><name> X% total, Y% parent, self A% total, self B% children, avg D sum E, Fms raw sum
|
||||||
|
The above specifies the format for a named timer.
|
||||||
|
|
||||||
|
The <indent> specifies the number of parent timers.
|
||||||
|
|
||||||
|
"X" represents the percentage of time the timer took relative
|
||||||
|
to the entire profiling instance.
|
||||||
|
|
||||||
|
"Y" represents the percentage of time the timer took relative
|
||||||
|
to its _parents_ timer. For example:
|
||||||
|
```
|
||||||
|
Full Tick 100.000% total, 100.000% parent, self 0.889% total, self 0.889% children, avg 200.000 sum 200, 401.300ms raw sum
|
||||||
|
|+++Tick World: minecraft:overworld 81.409% total, 81.409% parent, self 1.873% total, self 2.301% children, avg 1.000 sum 200, 326.694ms raw sum
|
||||||
|
|---|---Entity Tick 56.784% total, 69.751% parent, self 6.049% total, self 10.652% children, avg 1.000 sum 200, 227.874ms raw sum
|
||||||
|
```
|
||||||
|
"Entity Tick" measured 69.751% of the time for the "Tick World: minecraft:overworld" timer.
|
||||||
|
|
||||||
|
"A" represents the self time relative to the entire profiling instance.
|
||||||
|
The self time is the amount of time for a timer that is _not_ measured
|
||||||
|
by a child timer.
|
||||||
|
|
||||||
|
"B" represents the self time relative to its _parents_ timer.
|
||||||
|
|
||||||
|
"D" represents the average number of times the timer is invoked relative to
|
||||||
|
its parent.
|
||||||
|
For example:
|
||||||
|
```
|
||||||
|
|---|---|---Entity Tick: bat 2.642% total, 7.343% parent, self 2.642% total, self 100.000% children, avg 14.975 sum 2,995, 23.127ms raw sum
|
||||||
|
```
|
||||||
|
In this case, an average of 14.975 bats were ticked for every
|
||||||
|
time the "Entity Tick" timer was invoked.
|
||||||
|
|
||||||
|
"E" represents the total number of times the timer is invoked.
|
||||||
|
|
||||||
|
"F" represents the total raw time accumulated by the timer.
|
||||||
|
|
||||||
|
Counters are specified as follows:
|
||||||
|
<indent>#<name> avg X sum Y
|
||||||
|
|
||||||
|
The X is the average number of times the counter is invoked
|
||||||
|
relative to the parent, exactly similar to the D field of Timers,
|
||||||
|
where Y is the total number of times the counter is invoked.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java
|
||||||
|
index b2da36202e59dfa23165528145d0fe08bb3966fb..4ccc2ce3743c260a86b27e951979eb8d5d5ae1db 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/command/PaperCommands.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java
|
||||||
|
@@ -25,6 +25,7 @@ public final class PaperCommands {
|
||||||
|
COMMANDS.put("paper", new PaperCommand("paper"));
|
||||||
|
COMMANDS.put("mspt", new MSPTCommand("mspt"));
|
||||||
|
COMMANDS.put("tps", new io.papermc.paper.threadedregions.commands.CommandServerHealth()); // Folia - region threading
|
||||||
|
+ COMMANDS.put("profiler", new io.papermc.paper.threadedregions.commands.CommandProfiler()); // Folia - region threading - profiler
|
||||||
|
|
||||||
|
COMMANDS.forEach((s, command) -> {
|
||||||
|
server.server.getCommandMap().register(s, "Paper", command);
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||||
|
Date: Fri, 30 Aug 2024 18:34:32 -0700
|
||||||
|
Subject: [PATCH] Add watchdog thread
|
||||||
|
|
||||||
|
When regions take too long, having the server print the stacktrace
|
||||||
|
of the ticking region should help debug the cause.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
index c77748061f1c8bb2b0dc8dbd80f608d431752015..eafdb55d7418606dbca0b3bc4787501fed872c0a 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
@@ -156,7 +156,7 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- private static void dumpThread(ThreadInfo thread, Logger logger) {
|
||||||
|
+ public static void dumpThread(ThreadInfo thread, Logger logger) { // Folia - watchdog - public
|
||||||
|
logger.log(Level.SEVERE, "------------------------------");
|
||||||
|
|
||||||
|
logger.log(Level.SEVERE, "Current Thread: " + thread.getThreadName());
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Euphyllia Bierque <bierque.euphyllia@gmail.com>
|
||||||
|
Date: Tue, 28 Jan 2025 16:35:13 -0800
|
||||||
|
Subject: [PATCH] Add TPS From Region
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 9b182315682b5795b2cb6438ea440591ddddc5a3..d2db175fd7bfc5ff38e3945c8744858265212b1d 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -3253,4 +3253,69 @@ public final class CraftServer implements Server {
|
||||||
|
public void allowPausing(final Plugin plugin, final boolean value) {
|
||||||
|
this.console.addPluginAllowingSleep(plugin.getName(), value);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Folia start - region TPS API
|
||||||
|
+ /**
|
||||||
|
+ * Gets the TPS from the region which owns the specified location, or {@code null} if no region owns
|
||||||
|
+ * the specified location.
|
||||||
|
+ *
|
||||||
|
+ * @param location The location for which to get the TPS
|
||||||
|
+ * @return TPS (5s, 15s, 1m, 5m, 15m), or null if the region doesn't exist
|
||||||
|
+ */
|
||||||
|
+ @Override
|
||||||
|
+ public double[] getRegionTPS(Location location) {
|
||||||
|
+ Preconditions.checkArgument(location != null, "Location cannot be null");
|
||||||
|
+
|
||||||
|
+ return this.getRegionTPS(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Gets the TPS from the region which owns the specified chunk, or {@code null} if no region owns
|
||||||
|
+ * the specified location.
|
||||||
|
+ *
|
||||||
|
+ * @param chunk - The specified chunk
|
||||||
|
+ * @return TPS (5s, 15s, 1m, 5m, 15m), or null if the region doesn't exist
|
||||||
|
+ */
|
||||||
|
+ @Override
|
||||||
|
+ public double[] getRegionTPS(org.bukkit.Chunk chunk) {
|
||||||
|
+ Preconditions.checkArgument(chunk != null, "Chunk cannot be null");
|
||||||
|
+
|
||||||
|
+ return this.getRegionTPS(chunk.getWorld(), chunk.getX(), chunk.getZ());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Gets the TPS from the region which owns the specified chunk, or {@code null} if no region owns
|
||||||
|
+ * the specified location.
|
||||||
|
+ *
|
||||||
|
+ * @param world - World containing the chunk
|
||||||
|
+ * @param chunkX - X-coordinate of the chunk
|
||||||
|
+ * @param chunkZ - Z-coordinate of the chunk
|
||||||
|
+ * @return TPS (5s, 15s, 1m, 5m, 15m), or null if the region doesn't exist
|
||||||
|
+ */
|
||||||
|
+ @Override
|
||||||
|
+ public double[] getRegionTPS(World world, int chunkX, int chunkZ) {
|
||||||
|
+ Preconditions.checkArgument(world != null, "World cannot be null");
|
||||||
|
+
|
||||||
|
+ return getTPSFromRegion(((CraftWorld)world).getHandle(), chunkX, chunkZ);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static double[] getTPSFromRegion(ServerLevel world, int chunkX, int chunkZ) {
|
||||||
|
+ io.papermc.paper.threadedregions.ThreadedRegionizer.ThreadedRegion<io.papermc.paper.threadedregions.TickRegions.TickRegionData, io.papermc.paper.threadedregions.TickRegions.TickRegionSectionData>
|
||||||
|
+ region = world.regioniser.getRegionAtSynchronised(chunkX, chunkZ);
|
||||||
|
+ if (region == null) {
|
||||||
|
+ return null;
|
||||||
|
+ } else {
|
||||||
|
+ io.papermc.paper.threadedregions.TickRegions.TickRegionData regionData = region.getData();
|
||||||
|
+ final long currTime = System.nanoTime();
|
||||||
|
+ final io.papermc.paper.threadedregions.TickRegionScheduler.RegionScheduleHandle regionScheduleHandle = regionData.getRegionSchedulingHandle();
|
||||||
|
+ return new double[] {
|
||||||
|
+ regionScheduleHandle.getTickReport5s(currTime).tpsData().segmentAll().average(),
|
||||||
|
+ regionScheduleHandle.getTickReport15s(currTime).tpsData().segmentAll().average(),
|
||||||
|
+ regionScheduleHandle.getTickReport1m(currTime).tpsData().segmentAll().average(),
|
||||||
|
+ regionScheduleHandle.getTickReport5m(currTime).tpsData().segmentAll().average(),
|
||||||
|
+ regionScheduleHandle.getTickReport15m(currTime).tpsData().segmentAll().average(),
|
||||||
|
+ };
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Folia end - region TPS API
|
||||||
|
}
|
||||||
12
gradle.properties
Normal file
12
gradle.properties
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
group=me.earthme.luminol
|
||||||
|
version=1.21.8-R0.1-SNAPSHOT
|
||||||
|
mcVersion=1.21.8
|
||||||
|
release=2
|
||||||
|
# 0 for skip release, 1 for pre-release, 2 for release
|
||||||
|
|
||||||
|
foliaRef=612d9bd8569fe1a6008a05325af3fad66ef1cef7
|
||||||
|
|
||||||
|
org.gradle.configuration-cache=true
|
||||||
|
org.gradle.caching=true
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.vfs.watch=false
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
251
gradlew
vendored
Normal file
251
gradlew
vendored
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
94
gradlew.bat
vendored
Normal file
94
gradlew.bat
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
676
licenses/GPL.md
Normal file
676
licenses/GPL.md
Normal file
@ -0,0 +1,676 @@
|
|||||||
|
### GNU GENERAL PUBLIC LICENSE
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||||
|
<https://fsf.org/>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this
|
||||||
|
license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
### Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom
|
||||||
|
to share and change all versions of a program--to make sure it remains
|
||||||
|
free software for all its users. We, the Free Software Foundation, use
|
||||||
|
the GNU General Public License for most of our software; it applies
|
||||||
|
also to any other work released this way by its authors. You can apply
|
||||||
|
it to your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you
|
||||||
|
have certain responsibilities if you distribute copies of the
|
||||||
|
software, or if you modify it: responsibilities to respect the freedom
|
||||||
|
of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the
|
||||||
|
manufacturer can do so. This is fundamentally incompatible with the
|
||||||
|
aim of protecting users' freedom to change the software. The
|
||||||
|
systematic pattern of such abuse occurs in the area of products for
|
||||||
|
individuals to use, which is precisely where it is most unacceptable.
|
||||||
|
Therefore, we have designed this version of the GPL to prohibit the
|
||||||
|
practice for those products. If such problems arise substantially in
|
||||||
|
other domains, we stand ready to extend this provision to those
|
||||||
|
domains in future versions of the GPL, as needed to protect the
|
||||||
|
freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish
|
||||||
|
to avoid the special danger that patents applied to a free program
|
||||||
|
could make it effectively proprietary. To prevent this, the GPL
|
||||||
|
assures that patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
### TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
#### 0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds
|
||||||
|
of works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of
|
||||||
|
an exact copy. The resulting work is called a "modified version" of
|
||||||
|
the earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user
|
||||||
|
through a computer network, with no transfer of a copy, is not
|
||||||
|
conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices" to
|
||||||
|
the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
#### 1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. "Object code" means any non-source form of
|
||||||
|
a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users can
|
||||||
|
regenerate automatically from other parts of the Corresponding Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that same
|
||||||
|
work.
|
||||||
|
|
||||||
|
#### 2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not convey,
|
||||||
|
without conditions so long as your license otherwise remains in force.
|
||||||
|
You may convey covered works to others for the sole purpose of having
|
||||||
|
them make modifications exclusively for you, or provide you with
|
||||||
|
facilities for running those works, provided that you comply with the
|
||||||
|
terms of this License in conveying all material for which you do not
|
||||||
|
control copyright. Those thus making or running the covered works for
|
||||||
|
you must do so exclusively on your behalf, under your direction and
|
||||||
|
control, on terms that prohibit them from making any copies of your
|
||||||
|
copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under the
|
||||||
|
conditions stated below. Sublicensing is not allowed; section 10 makes
|
||||||
|
it unnecessary.
|
||||||
|
|
||||||
|
#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such
|
||||||
|
circumvention is effected by exercising rights under this License with
|
||||||
|
respect to the covered work, and you disclaim any intention to limit
|
||||||
|
operation or modification of the work as a means of enforcing, against
|
||||||
|
the work's users, your or third parties' legal rights to forbid
|
||||||
|
circumvention of technological measures.
|
||||||
|
|
||||||
|
#### 4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
#### 5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
- a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
- b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under
|
||||||
|
section 7. This requirement modifies the requirement in section 4
|
||||||
|
to "keep intact all notices".
|
||||||
|
- c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
- d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
#### 6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms of
|
||||||
|
sections 4 and 5, provided that you also convey the machine-readable
|
||||||
|
Corresponding Source under the terms of this License, in one of these
|
||||||
|
ways:
|
||||||
|
|
||||||
|
- a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
- b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the Corresponding
|
||||||
|
Source from a network server at no charge.
|
||||||
|
- c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
- d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
- e) Convey the object code using peer-to-peer transmission,
|
||||||
|
provided you inform other peers where the object code and
|
||||||
|
Corresponding Source of the work are being offered to the
|
||||||
|
public at no charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal,
|
||||||
|
family, or household purposes, or (2) anything designed or sold for
|
||||||
|
incorporation into a dwelling. In determining whether a product is a
|
||||||
|
consumer product, doubtful cases shall be resolved in favor of
|
||||||
|
coverage. For a particular product received by a particular user,
|
||||||
|
"normally used" refers to a typical or common use of that class of
|
||||||
|
product, regardless of the status of the particular user or of the way
|
||||||
|
in which the particular user actually uses, or expects or is expected
|
||||||
|
to use, the product. A product is a consumer product regardless of
|
||||||
|
whether the product has substantial commercial, industrial or
|
||||||
|
non-consumer uses, unless such uses represent the only significant
|
||||||
|
mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to
|
||||||
|
install and execute modified versions of a covered work in that User
|
||||||
|
Product from a modified version of its Corresponding Source. The
|
||||||
|
information must suffice to ensure that the continued functioning of
|
||||||
|
the modified object code is in no case prevented or interfered with
|
||||||
|
solely because modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or
|
||||||
|
updates for a work that has been modified or installed by the
|
||||||
|
recipient, or for the User Product in which it has been modified or
|
||||||
|
installed. Access to a network may be denied when the modification
|
||||||
|
itself materially and adversely affects the operation of the network
|
||||||
|
or violates the rules and protocols for communication across the
|
||||||
|
network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
#### 7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders
|
||||||
|
of that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
- a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
- b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
- c) Prohibiting misrepresentation of the origin of that material,
|
||||||
|
or requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
- d) Limiting the use for publicity purposes of names of licensors
|
||||||
|
or authors of the material; or
|
||||||
|
- e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
- f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions
|
||||||
|
of it) with contractual assumptions of liability to the recipient,
|
||||||
|
for any liability that these contractual assumptions directly
|
||||||
|
impose on those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions; the
|
||||||
|
above requirements apply either way.
|
||||||
|
|
||||||
|
#### 8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your license
|
||||||
|
from a particular copyright holder is reinstated (a) provisionally,
|
||||||
|
unless and until the copyright holder explicitly and finally
|
||||||
|
terminates your license, and (b) permanently, if the copyright holder
|
||||||
|
fails to notify you of the violation by some reasonable means prior to
|
||||||
|
60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
#### 9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or run
|
||||||
|
a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
#### 10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
#### 11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims owned
|
||||||
|
or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within the
|
||||||
|
scope of its coverage, prohibits the exercise of, or is conditioned on
|
||||||
|
the non-exercise of one or more of the rights that are specifically
|
||||||
|
granted under this License. You may not convey a covered work if you
|
||||||
|
are a party to an arrangement with a third party that is in the
|
||||||
|
business of distributing software, under which you make payment to the
|
||||||
|
third party based on the extent of your activity of conveying the
|
||||||
|
work, and under which the third party grants, to any of the parties
|
||||||
|
who would receive the covered work from you, a discriminatory patent
|
||||||
|
license (a) in connection with copies of the covered work conveyed by
|
||||||
|
you (or copies made from those copies), or (b) primarily for and in
|
||||||
|
connection with specific products or compilations that contain the
|
||||||
|
covered work, unless you entered into that arrangement, or that patent
|
||||||
|
license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
#### 12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under
|
||||||
|
this License and any other pertinent obligations, then as a
|
||||||
|
consequence you may not convey it at all. For example, if you agree to
|
||||||
|
terms that obligate you to collect a royalty for further conveying
|
||||||
|
from those to whom you convey the Program, the only way you could
|
||||||
|
satisfy both those terms and this License would be to refrain entirely
|
||||||
|
from conveying the Program.
|
||||||
|
|
||||||
|
#### 13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
#### 14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU General Public License from time to time. Such new versions
|
||||||
|
will be similar in spirit to the present version, but may differ in
|
||||||
|
detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies that a certain numbered version of the GNU General Public
|
||||||
|
License "or any later version" applies to it, you have the option of
|
||||||
|
following the terms and conditions either of that numbered version or
|
||||||
|
of any later version published by the Free Software Foundation. If the
|
||||||
|
Program does not specify a version number of the GNU General Public
|
||||||
|
License, you may choose any version ever published by the Free
|
||||||
|
Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future versions
|
||||||
|
of the GNU General Public License can be used, that proxy's public
|
||||||
|
statement of acceptance of a version permanently authorizes you to
|
||||||
|
choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
#### 15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
|
||||||
|
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
|
||||||
|
PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
|
||||||
|
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
|
||||||
|
CORRECTION.
|
||||||
|
|
||||||
|
#### 16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
|
||||||
|
CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
|
||||||
|
ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
|
||||||
|
NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
|
||||||
|
LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
|
||||||
|
TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
|
||||||
|
PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
#### 17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
### How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these
|
||||||
|
terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest to
|
||||||
|
attach them to the start of each source file to most effectively state
|
||||||
|
the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper
|
||||||
|
mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands \`show w' and \`show c' should show the
|
||||||
|
appropriate parts of the General Public License. Of course, your
|
||||||
|
program's commands might be different; for a GUI interface, you would
|
||||||
|
use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. For more information on this, and how to apply and follow
|
||||||
|
the GNU GPL, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your
|
||||||
|
program into proprietary programs. If your program is a subroutine
|
||||||
|
library, you may consider it more useful to permit linking proprietary
|
||||||
|
applications with the library. If this is what you want to do, use the
|
||||||
|
GNU Lesser General Public License instead of this License. But first,
|
||||||
|
please read <https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
23
licenses/MIT.md
Normal file
23
licenses/MIT.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
### The MIT License (MIT)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the “Software”), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
luminol-api/bin/main/me/earthme/luminol/api/RegionStats.class
Normal file
BIN
luminol-api/bin/main/me/earthme/luminol/api/RegionStats.class
Normal file
Binary file not shown.
BIN
luminol-api/bin/main/me/earthme/luminol/api/ThreadedRegion.class
Normal file
BIN
luminol-api/bin/main/me/earthme/luminol/api/ThreadedRegion.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
luminol-api/bin/main/me/earthme/luminol/api/TickRegionData.class
Normal file
BIN
luminol-api/bin/main/me/earthme/luminol/api/TickRegionData.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
luminol-api/bin/main/org/leavesmc/leaves/plugin/Features.class
Normal file
BIN
luminol-api/bin/main/org/leavesmc/leaves/plugin/Features.class
Normal file
Binary file not shown.
52
luminol-api/build.gradle.kts.patch
Normal file
52
luminol-api/build.gradle.kts.patch
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
--- a/folia-api/build.gradle.kts
|
||||||
|
+++ b/folia-api/build.gradle.kts
|
||||||
|
@@ -51,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") {
|
||||||
|
@@ -101,17 +_,21 @@
|
||||||
|
java {
|
||||||
|
srcDir(generatedDir)
|
||||||
|
srcDir(file("../paper-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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test {
|
||||||
|
java {
|
||||||
|
srcDir(file("../paper-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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -257,3 +_,19 @@
|
||||||
|
dependsOn(scanJarForOldGeneratedCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+// Pufferfish Start
|
||||||
|
+tasks.withType<JavaCompile> {
|
||||||
|
+ val compilerArgs = options.compilerArgs
|
||||||
|
+ compilerArgs.add("--add-modules=jdk.incubator.vector")
|
||||||
|
+}
|
||||||
|
+// Pufferfish End
|
||||||
|
+
|
||||||
|
+// Luminol start - Hide unnecessary warnings
|
||||||
|
+tasks.withType<JavaCompile> {
|
||||||
|
+ val compilerArgs = options.compilerArgs
|
||||||
|
+ compilerArgs.add("-Xlint:-module")
|
||||||
|
+ compilerArgs.add("-Xlint:-removal")
|
||||||
|
+ compilerArgs.add("-Xlint:-dep-ann")
|
||||||
|
+}
|
||||||
|
+// Luminol end
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrHua269 <wangxyper@163.com>
|
||||||
|
Date: Sun, 12 Jan 2025 10:18:38 +0800
|
||||||
|
Subject: [PATCH] Rebrand to Luminol
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java
|
||||||
|
--- a/src/main/java/io/papermc/paper/ServerBuildInfo.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java
|
||||||
|
@@ -19,6 +19,17 @@ public interface ServerBuildInfo {
|
||||||
|
*/
|
||||||
|
Key BRAND_PAPER_ID = Key.key("papermc", "paper");
|
||||||
|
|
||||||
|
+ // Luminol start
|
||||||
|
+ /**
|
||||||
|
+ * The brand id for folia
|
||||||
|
+ */
|
||||||
|
+ Key BRAND_FOLIA_ID = Key.key("papermc", "folia");
|
||||||
|
+ /**
|
||||||
|
+ * The brand id for Luminol.
|
||||||
|
+ */
|
||||||
|
+ Key BRAND_LUMINOL_ID = Key.key("luminolmc", "luminol");
|
||||||
|
+ // Luminol end
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Gets the {@code ServerBuildInfo}.
|
||||||
|
*
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrHua269 <wangxyper@163.com>
|
||||||
|
Date: Tue, 11 Feb 2025 09:16:49 +0800
|
||||||
|
Subject: [PATCH] KioCG Chunk API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/Chunk.java b/src/main/java/org/bukkit/Chunk.java
|
||||||
|
--- a/src/main/java/org/bukkit/Chunk.java
|
||||||
|
+++ b/src/main/java/org/bukkit/Chunk.java
|
||||||
|
@@ -388,4 +388,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
|
||||||
|
--- a/src/main/java/org/bukkit/entity/Player.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/Player.java
|
||||||
|
@@ -3932,4 +3932,6 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
|
||||||
|
*/
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
PlayerGameConnection getConnection();
|
||||||
|
+
|
||||||
|
+ long getNearbyChunkHot(); // KioCG
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
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
|
||||||
|
--- 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
|
||||||
|
--- 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
|
||||||
|
--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||||
|
+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||||
|
@@ -966,7 +966,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,22 @@
|
|||||||
|
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
|
||||||
|
--- 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,60 @@
|
|||||||
|
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
|
||||||
|
--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||||
|
+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
|
||||||
|
@@ -597,7 +597,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
|
||||||
|
@@ -667,9 +669,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
|
||||||
|
--- 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,32 @@
|
|||||||
|
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
|
||||||
|
--- 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
|
||||||
|
// @GeneratedFrom 1.21.8
|
||||||
|
new Color(0x00000000, true),
|
||||||
|
@@ -395,9 +395,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,18 @@
|
|||||||
|
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
|
||||||
|
--- a/src/main/java/org/bukkit/World.java
|
||||||
|
+++ b/src/main/java/org/bukkit/World.java
|
||||||
|
@@ -4473,4 +4473,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,84 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||||
|
Date: Sat, 24 May 2025 01:25:10 +0800
|
||||||
|
Subject: [PATCH] Leaves: Fix SculkCatalyst exp skip
|
||||||
|
|
||||||
|
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||||
|
As part of: Leaves (https://github.com/LeavesMC/Leaves/blob/ea91106ae57fc4cc14e2e0225009cf9919072f7f/leaves-api/paper-patches/features/0007-Fix-SculkCatalyst-exp-skip.patch)
|
||||||
|
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java
|
||||||
|
--- a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java
|
||||||
|
+++ b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java
|
||||||
|
@@ -27,6 +27,7 @@ public class EntityDeathEvent extends EntityEvent implements Cancellable {
|
||||||
|
@Nullable private org.bukkit.SoundCategory deathSoundCategory;
|
||||||
|
private float deathSoundVolume;
|
||||||
|
private float deathSoundPitch;
|
||||||
|
+ private int rewardExp; // Leaves - exp fix
|
||||||
|
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
@@ -35,13 +36,20 @@ public class EntityDeathEvent extends EntityEvent implements Cancellable {
|
||||||
|
this(livingEntity, damageSource, drops, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- @ApiStatus.Internal
|
||||||
|
public EntityDeathEvent(@NotNull final LivingEntity livingEntity, @NotNull DamageSource damageSource, @NotNull final List<ItemStack> drops, final int droppedExp) {
|
||||||
|
+ // Leaves start - exp fix
|
||||||
|
+ this(livingEntity, damageSource, drops, droppedExp, droppedExp);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @ApiStatus.Internal
|
||||||
|
+ public EntityDeathEvent(@NotNull final LivingEntity livingEntity, @NotNull DamageSource damageSource, @NotNull final List<ItemStack> drops, final int droppedExp, final int rewardExp) {
|
||||||
|
super(livingEntity);
|
||||||
|
this.damageSource = damageSource;
|
||||||
|
this.drops = drops;
|
||||||
|
this.dropExp = droppedExp;
|
||||||
|
+ this.rewardExp = rewardExp;
|
||||||
|
}
|
||||||
|
+ // Leaves end - exp fix
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
@@ -230,4 +238,14 @@ public class EntityDeathEvent extends EntityEvent implements Cancellable {
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return HANDLER_LIST;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Leaves start - exp fix
|
||||||
|
+ public int getRewardExp() {
|
||||||
|
+ return rewardExp;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void setRewardExp(int rewardExp) {
|
||||||
|
+ this.rewardExp = rewardExp;
|
||||||
|
+ }
|
||||||
|
+ // Leaves end - exp fix
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java
|
||||||
|
--- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java
|
||||||
|
+++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java
|
||||||
|
@@ -25,6 +25,7 @@ public class PlayerDeathEvent extends EntityDeathEvent {
|
||||||
|
private boolean doExpDrop;
|
||||||
|
private boolean keepLevel = false;
|
||||||
|
private boolean keepInventory = false;
|
||||||
|
+ private boolean useApiExpDropStatus = false; // Leaves - exp fix
|
||||||
|
@Deprecated
|
||||||
|
private final List<ItemStack> itemsToKeep = new ArrayList<>();
|
||||||
|
|
||||||
|
@@ -82,8 +83,15 @@ public class PlayerDeathEvent extends EntityDeathEvent {
|
||||||
|
this.showDeathMessages = true;
|
||||||
|
this.deathMessage = LegacyComponentSerializer.legacySection().deserializeOrNull(deathMessage);
|
||||||
|
this.doExpDrop = doExpDrop;
|
||||||
|
+ this.useApiExpDropStatus = true; // Leaves - exp fix
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Leaves start - exp fix
|
||||||
|
+ public boolean forceUseEventDropStatus() {
|
||||||
|
+ return this.useApiExpDropStatus;
|
||||||
|
+ }
|
||||||
|
+ // Leaves end - exp fix
|
||||||
|
+
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Player getEntity() {
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
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
|
||||||
|
--- a/src/main/java/org/bukkit/entity/Villager.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/Villager.java
|
||||||
|
@@ -408,4 +408,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,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 javax.annotation.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,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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,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,13 @@
|
|||||||
|
/*
|
||||||
|
* 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";
|
||||||
|
}
|
||||||
BIN
luminol-server/bin/main/abomination/IRegionFile.class
Normal file
BIN
luminol-server/bin/main/abomination/IRegionFile.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
luminol-server/bin/main/abomination/LinearRegionFile.class
Normal file
BIN
luminol-server/bin/main/abomination/LinearRegionFile.class
Normal file
Binary file not shown.
BIN
luminol-server/bin/main/com/kiocg/ChunkHot.class
Normal file
BIN
luminol-server/bin/main/com/kiocg/ChunkHot.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user