Compare commits

..

50 Commits

Author SHA1 Message Date
Helvetica Volubi 87ba8b9746 Update Upstream(Luminol) 2025-07-30 21:55:01 +08:00
Helvetica Volubi e71b36e331 [ci skip]docs: refactor format 2025-07-30 16:18:31 +08:00
Helvetica Volubi cfb1ad88f4 Update Upstream(Luminol) 2025-07-28 23:03:43 +08:00
Helvetica Volubi b40276f037 feat: use new limit of 524288 instead of 16384 2025-07-28 17:25:16 +08:00
Helvetica Volubi e1b3a14ece feat: Leaves Vanilla hopper 2025-07-28 01:11:40 +08:00
Helvetica Volubi c257ebd19c fix: fix redstone shear wrench
origin: https://github.com/LeavesMC/Leaves/pull/621
2025-07-27 18:37:33 +08:00
Helvetica Volubi 52b6803d68 feat: leaves disable packet limit 2025-07-27 18:19:20 +08:00
Helvetica Volubi 71f83be588 fix: fix infinite trade 2025-07-27 00:38:31 +08:00
Helvetica Volubi 5733cc4e35 fix: fix a config name error 2025-07-26 18:59:50 +08:00
Helvetica Volubi a8147bb171 Fix quick craft 2025-07-26 13:41:28 +08:00
Helvetica Volubi 17f0269ee6 Update Upstream(Luminol) 2025-07-26 13:31:38 +08:00
Helvetica Volubi f574f277eb feat: use leaves-ver Item overstack util instead of Stackable ShulkerBoxes 2025-07-26 01:20:32 +08:00
Helvetica Volubi 94e7c4e822 Update Upstream(Luminol) 2025-07-26 00:01:35 +08:00
Helvetica Volubi 01582648ee feat: add flipping shears support(#29)
Co-authored-by: violetc <58360096+s-yh-china@users.noreply.github.com>
2025-07-23 20:30:45 +08:00
Helvetica Volubi db9bd6e469 Update Upstream(Luminol) 2025-07-23 19:30:21 +08:00
Helvetica Volubi 0eebea7a21 Update Upstream(Luminol) 2025-07-20 13:16:27 +08:00
Helvetica Volubi 1707673c8d feat: add missing command for unsafe waypoint
Update Upstream(Luminol)
2025-07-18 22:15:13 +08:00
Bacteriawa 7179463c36 Start 1.21.8 2025-07-18 19:19:55 +08:00
Bacteriawa 509e782d1a Update Upstream(Luminol) 2025-07-18 16:58:46 +08:00
Helvetica Volubi bfb5f74600 fix: fix a config name error 2025-07-17 21:43:24 +08:00
Helvetica Volubi a697b179e7 Update Upstream(Luminol) 2025-07-17 00:37:28 +08:00
Helvetica Volubi 904abaa564 Update Upstream(Luminol) 2025-07-16 00:12:42 +08:00
Bacteriawa d1aeaa83f4 Update Upstream(Lumniol) 2025-07-13 22:26:19 +08:00
Helvetica Volubi 145eae3c41 refactor: push update to upstream 2025-07-13 02:53:40 +08:00
Helvetica Volubi 6e61e12285 Update upstream(Luminol) 2025-07-12 14:56:28 +08:00
Klop233 56e870d999 Update Upstream(Luminol) 2025-07-11 11:09:37 +00:00
Helvetica Volubi 7f8135b193 fix: fix #26 & Update upstream(Luminol) 2025-07-10 03:10:32 +08:00
Helvetica Volubi 31096e1a48 Add config to enable unsafe waypoint bar 2025-07-07 18:25:45 +08:00
Helvetica Volubi f261b9fe58 feat: add config to allow infinite trade 2025-07-07 16:40:42 +08:00
Helvetica Volubi 92412e0a72 feat: add Old Explosion Damage Calculator support(#25)
Co-authored by: MC_XiaoHei <xor7xiaohei@gmail.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/3e96b237749a960f297f211d439ffc9ea7fd2381/leaves-server/minecraft-patches/features/0134-Old-wet-tnt-explode-behavior.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
2025-07-07 15:37:26 +08:00
Helvetica Volubi 23f4d70fca Update Upstream(Luminol) 2025-07-07 01:19:23 +08:00
Helvetica Volubi c613aaa191 fix: fix a bug in datapack reload - hot reload unsupported 2025-07-05 18:51:35 +08:00
Helvetica Volubi 692c38f7ac Update upstream(Luminol) 2025-07-04 18:21:23 +08:00
Helvetica Volubi 96683209f5 Add config to enable datapack command - only support some function 2025-07-03 00:36:15 +08:00
Helvetica Volubi 6d9458fa01 Update Upstream(Luminol) 2025-07-02 23:31:19 +08:00
Helvetica Volubi 333a7fc17c Update to 1.21.7 2025-07-01 21:54:38 +08:00
Helvetica Volubi 914d8cc1dd remove Better ShulkerBox and Update Upstream(Luminol) 2025-06-30 13:51:32 +08:00
Helvetica Volubi 6f9e4abcbf Start 1.21.6 2025-06-28 00:41:56 +08:00
Helvetica Volubi 986cce555c fix: refix spawnInvulnerableTime 2025-06-27 21:07:37 +08:00
Helvetica Volubi 34cc8765c6 fix: fix some bugs 2025-06-24 19:56:14 +08:00
Helvetica Volubi a5393833e8 Update Upstream (Luminol)
use our own bState
2025-06-20 00:57:28 +08:00
Helvetica Volubi 878ee153ef fix: fix up Shulker box (#11) (#12) 2025-06-18 20:03:37 +08:00
Helvetica Volubi 71455cca64 feat: old replaceable by mushrooms (#10)
Update upstream (Luminol)
2025-06-18 16:50:23 +08:00
Helvetica Volubi 16f2258eed fix: try fix shulker box clear bug(#5) 2025-06-17 14:51:51 +08:00
Helvetica Volubi 24d4ebdc7c Update Upstream (Luminol) 2025-06-15 20:48:25 +08:00
Helvetica Volubi 4ca6d9fe09 refactor: I18n update 2025-06-14 16:08:19 +08:00
Helvetica Volubi c35817411a feat: add better shulker-box support (#3) 2025-06-14 05:38:58 +08:00
Helvetica Volubi cf491363f6 fix: fix some bugs in local lang 2025-06-12 22:21:15 +08:00
Helvetica Volubi 19b773d256 Update upstream (Luminol)
Rewrite I18n module
2025-06-12 12:53:12 +08:00
Helvetica Volubi 700d270b1d feat: add I18n support 2025-06-12 04:50:06 +08:00
71 changed files with 2130 additions and 1396 deletions
@@ -1,10 +1,12 @@
name: Lophine CI - ver/1.21.5
name: Lophine CI
on:
push:
branches: [ "ver/1.21.5" ]
branches:
- "**"
pull_request:
branches: [ "ver/1.21.5" ]
branches:
- "**"
permissions: write-all
@@ -20,7 +22,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: zulu
java-version: 22
java-version: 21
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
@@ -32,15 +34,15 @@ jobs:
run: git config --global user.email "ci@luminolmc.com" && git config --global user.name "LuminolMC CI"
- name: Apply All Patches
run: ./gradlew applyAllPatches
run: ./gradlew --refresh-dependencies applyAllPatches
- name: CreateMojmapPaperclipJar
run: ./gradlew createMojmapPaperclipJar
run: ./gradlew --refresh-dependencies createMojmapPaperclipJar
- name: Publish to repo
if: github.event_name != 'pull_request' && false # do not push to any repo
continue-on-error: true
run: ./gradlew generateDevelopmentBundle publish -PpublishDevBundle=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 }}
+1 -1
View File
@@ -2,7 +2,7 @@ Lophine inherits its licensing from the included upstream projects.
Lophine从上游继承了许可证。
As such, Lophine is licensed under the
As such, Lophine is licensed under the
[GNU General Public License version 3](licenses/GPL.md); as it inherits it from Luminol,
who in turn inherits it from the original Folia, Paper, Spigot, Bukkit and CraftBukkit projects.
+20 -9
View File
@@ -13,21 +13,27 @@
[English](./README_EN.md) | **中文**
## 特性
- 支持部分Bukkit插件
- 可配置的原版特性
- Tpsbar 支持
- 对单线程区域性能的优化
- 更多有用的功能
- 支持部分Bukkit插件
- 可配置的原版特性
- Tpsbar 支持
- 对单线程区域性能的优化
- 更多有用的功能
## 下载
任何版本都可以在 [Release](https://github.com/LuminolMC/LightingLuminol/releases), 中找到,你也可以通过[以下步骤](./README.md#构建)自己构建。
任何版本都可以在 [Release](https://github.com/LuminolMC/Lophine/releases), 中找到,你也可以通过[以下步骤](./README.md#构建)自己构建。
## 构建
要构建一个paperclip jar,你需要运行以下命令。你可以在lightingluminol-server/build/libs中找到jar(注意:需要`JDK21`
要构建一个paperclip jar,你需要运行以下命令。你可以在lophine-server/build/libs中找到jar(注意:需要`JDK21`
```shell
./gradlew applyAllPatches && ./gradlew createMojmapPaperclipJar
```
## 使用API
使用 Gradle:
```kotlin
@@ -62,27 +68,32 @@ dependencies {
```
## 联系方式
> 如果您对这个项目感兴趣或有任何问题,请随时向我们提问。
**QQ群: [1015048616](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=QML5kIVsniPi1PlZvnjHQT_02EHsZ5Jc&authKey=%2FTCJsZC7JFQ9sxAroPCKuYnlV57Z5fyqp36ewXZk3Sn4iJ9p4MB1JKdc%2FFcX3HOM&noverify=0&group_code=1015048616)** | QQ频道: [点击加入](https://pd.qq.com/s/eq9krf9j) | Telegram: [点击加入](https://t.me/LuminolMinecraft) | Discord: [点击加入](https://discord.gg/Qd7m3V6eDx)
## 关于 Issue
当您遇到任何问题时,请向我们提问,我们将尽力解决,但请记得清楚地描述您的问题并提供足够的日志等信息。
## 贡献代码
可查看 [Contributing](./docs/CONTRIBUTING.md)
## BStats
Temporarily use Luminol's.
![bStats](https://bstats.org/signatures/server-implementation/Luminol.svg "bStats")
![bStats](https://bstats.org/signatures/server-implementation/Lophine.svg "bStats")
## 特别感谢
<b>感谢[LegacyLands](https://github.com/LegacyLands)对本项目的赞助,如果你想开发一些跨folia/非folia平台的插件,[legacy-lands-library](https://github.com/LegacyLands/legacy-lands-library/)将会是个不错的lib</b>
![legacy-lands-logo](public/image/legacy-lands-logo.png)
## 请给我们一个 ⭐Star
> 你的每一个免费的 ⭐Star 就是我们每一个前进的动力。
<a href="https://star-history.com/#LuminolMC/Luminol&LuminolMC/LightingLuminol&LuminolMC/Lophine&Date">
+22 -10
View File
@@ -2,7 +2,8 @@
# Lophine
<h4>LightingLuminol is a Luminol fork with many useful optimizations and configurable vanilla features, aims to provide more function for survival-usable circuit on folia</h4>
<h4>LightingLuminol is a Luminol fork with many useful optimizations and configurable vanilla features, aims to provide
more function for survival-usable circuit on folia</h4>
[![License](https://img.shields.io/github/license/LuminolMC/Lophine?style=flat-square)](LICENSE.md)
[![Issues](https://img.shields.io/github/issues/LuminolMC/Lophine?style=flat-square)](https://github.com/LuminolMC/Lophine/issues)
@@ -13,21 +14,27 @@
**English** | [中文](./README.md)
## Features
- Supported some Bukkit plugin
- Configurable vanilla features
- Tpsbar support
- Useful optimizations to improve the performance of single threaded region
- More functions
- Supported some Bukkit plugin
- Configurable vanilla features
- Tpsbar support
- Useful optimizations to improve the performance of single threaded region
- More functions
## Download
Any versions are available in the [release](https://github.com/LuminolMC/LightingLuminol/releases), also you can build it by yourself through [the following steps](./README_EN.md#Build).
Any versions are available in the [release](https://github.com/LuminolMC/Lophine/releases), also you can build it by yourself through [the following steps](./README_EN.md#Build).
## Build
To build a paperclip jar, you need to run the following command. You can find the jar in build/libs(Note: JDK21 is needed)
To build a paperclip jar, you need to run the following command. You can find the jar in lophine-server/build/libs(Note: `JDK21` is needed)
```shell
./gradlew applyAllPatches && ./gradlew createMojmapPaperclipJar
```
## Using API
For gradle:
```kotlin
@@ -62,26 +69,31 @@ For maven
```
## Contact
> If you are interested in this project or have any issue, feel free to ask us.
**QQ Group: [1015048616](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=hTPlI5j6XB8pgk4sdx6RkjhBPGG1r4IR&authKey=pnu6uCKQP7Sja2CJWC15Qi3BeI%2FAsh8tU4m5muufMBjbB3zz%2BwHBZCTRRdSNKhld&noverify=0&group_code=1015048616)** | QQ Channel: [Click To Join](https://pd.qq.com/s/eq9krf9j) | Telegram: [Click To Join](https://t.me/LuminolMinecraft) | Discord: [Click To Join](https://discord.gg/Qd7m3V6eDx)
## About Issue
When you meet any problems, just ask us, we will do our best to solve it, but remember to state your problem clear and provide enough logs etc.</br>
## Pull Requests
See [Contributing](./docs/CONTRIBUTING_EN.md)
## BStats
Temporarily use Luminol's.
![bStats](https://bstats.org/signatures/server-implementation/Luminol.svg "bStats")
![bStats](https://bstats.org/signatures/server-implementation/Lophine.svg "bStats")
## Special Thanks
Thanks [LegacyLands](https://github.com/LegacyLands) for sponsoring this project.If you want to develop some crossing folia/non-folia platform plugins, [legacy-lands-library](https://github.com/LegacyLands/legacy-lands-library/) will be a nice choice for you
![legacy-lands-logo](public/image/legacy-lands-logo.png)
## Please ⭐star us!
<a href="https://star-history.com/#LuminolMC/Luminol&LuminolMC/LightingLuminol&LuminolMC/Lophine&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=LuminolMC/Luminol%2CLuminolMC/LightingLuminol%2CLuminolMC/Lophine&type=Date&theme=dark" />
+10 -9
View File
@@ -3,7 +3,7 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent
plugins {
java // TODO java launcher tasks
id("io.papermc.paperweight.patcher") version "2.0.0-beta.17"
id("moe.luminolmc.hyacinthusweight.patcher") version "+" // Automatically pulls the latest
}
paperweight {
@@ -41,6 +41,7 @@ paperweight {
}
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
val menthaMavenPublicUrl = "https://repo.menthamc.com/repository/maven-public/";
subprojects {
apply(plugin = "java-library")
@@ -55,6 +56,7 @@ subprojects {
repositories {
mavenCentral()
maven(paperMavenPublicUrl)
maven(menthaMavenPublicUrl)
}
dependencies {
@@ -65,16 +67,15 @@ subprojects {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
tasks.withType<JavaCompile> {
tasks.withType<JavaCompile>().configureEach {
options.encoding = Charsets.UTF_8.name()
options.release = 21
options.isFork = true
options.forkOptions.memoryMaximumSize = "6g" // Prevent OOM during building
}
tasks.withType<Javadoc> {
tasks.withType<Javadoc>().configureEach {
options.encoding = Charsets.UTF_8.name()
}
tasks.withType<ProcessResources> {
tasks.withType<ProcessResources>().configureEach {
filteringCharset = Charsets.UTF_8.name()
}
tasks.withType<Test> {
@@ -90,14 +91,14 @@ subprojects {
maven("https://repo.menthamc.com/repository/maven-snapshots/") {
name = "MenthaMC"
credentials(PasswordCredentials::class) {
username = System.getenv("MAVEN_REPO_USER")
password = System.getenv("MAVEN_REPO_PASSWORD")
username = System.getenv("PRIVATE_MAVEN_REPO_USERNAME")
password = System.getenv("PRIVATE_MAVEN_REPO_PASSWORD")
}
}
}
}
tasks.withType<Javadoc> {
tasks.withType<Javadoc>().configureEach {
options {
(this as StandardJavadocDocletOptions).apply {
addStringOption("-add-modules", "jdk.incubator.vector")
@@ -105,4 +106,4 @@ subprojects {
}
}
}
}
}
+14 -9
View File
@@ -1,5 +1,5 @@
为Lophine贡献代码
===========
===============
[English](./CONTRIBUTING_EN.md) | **中文**
@@ -41,19 +41,24 @@ Lophine 使用和 Folia 一样的补丁系统,并为了针对不同部分的
1. 将你的仓库 clone 到本地;
2. 在你的 IDE 或 终端 内执行 Gradle 的 `applyAllPatches` 任务,如果是在终端内,你可以执行 `./gradlew applyAllPatches`
3. 在执行操作后,仓库根目录下应该存在以下目录对: `lophine-api``lophine-server` `folia-api``folia-server` 以及 `paper-api``paper-server`(下文称作 `*-api``*-server` );
3. 在执行操作后,仓库根目录下应该存在以下目录对: `lophine-api``lophine-server` `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部分
- `lophine-api` :暂无有效文件
- `folia-api` :对folia-API的修改应当在此文件夹下进行
- `paper-api` :对paper-API/spigot-API/bukkit-API的修改应在此文件夹下进行
- `lophine-api` :对新增API的修改
- `luminol-api` :对luminol-API的修改应在此文件夹下进行
- `folia-api` :对folia-API的修改应当在此文件夹下进行
- `paper-api` :对paper-API/spigot-API/bukkit-API的修改应该在此文件夹下进行
2. Server部分
- `lophine-server` :对Minecraft原版服务器的修改应当在此文件夹下进行
- `folia-server` 暂无有效文件
- `paper-server` :对于非原版的对服务器逻辑的修改应当在此文件夹下进行
- `lophine-server` 对Minecraft原版服务器的修改和新增文件应当在此文件夹下进行
- `luminol-server` :对luminol-server的修改应当在此文件夹下进行
- `folia-server` :对folia-Server的修改应当在此文件夹下进行
- `paper-server` :对于paper对服务器逻辑的修改应当在此文件夹下进行
顺便一提,仓库根目录下的 `*-api``*-server` 并不是正常的 git 仓库:
@@ -80,7 +85,7 @@ Lophine 使用和 Folia 一样的补丁系统,并为了针对不同部分的
1. 在 HEAD 上直接进行修改;
2. 使用 `git commit -a --fixup <hash>` 来进行一个更正提交;(不要提交对在lophine新建文件的修改)
- 如果你想要更改提交信息,你也可以用 `--squash` 来代替 `--fixup`
- 如果你想要更改提交信息,你也可以用 `--squash` 来代替 `--fixup`
3. 使用 `git rebase -i --autosquash base` 来进行自动变基,你只需要输入 `:q` 来关闭确认页面即可;
4. 运行 Gradle 任务 `fixupPaperApiFilePatches` 来修改已被修改的在lophine新建文件的补丁(注意不要提交);
5. 运行 Gradle 任务 `rebuildAllServerPatches` 来修改已被修改的补丁;
+12 -8
View File
@@ -1,5 +1,5 @@
Contributing to Lophine
===========
=======================
**English** | [中文](./CONTRIBUTING.md)
@@ -44,20 +44,24 @@ If you have forked the main repository, then you should follow the steps below:
1. Clone your repository to local
2. Run Gradle's `applyAllPatches` task in your IDE or terminal (You can run `./gradlew applyAllPatches` directly in terminal.)
3. After performing the operation, the following directory pairs should exist in the root directory of the warehouse: `lophine-api` and `lophine-server` , `folia-api` and `folia-server` , `paper-api` and `paper-server` (Referred to `*-api` and `*-server` as below)
3. After performing the operation, the following directory pairs should exist in the root directory of the warehouse: `lophine-api` and `lophine-server` , `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
- `lophine-api` : There is no valid file
- `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
- `lophine-api` : Modifications to the new API
- `luminol-api` : Modifications to Luminol API should be carried out in this folder
- `folia-api` : Modifications to Folia API should be carried out in this folder
- `paper-api` : Modifications to Paper API/Spigot API/Bukkit API should be carried out in this folder
2. Server part
- `lophine-server` : Modifications to Minecraft Vanilla Server's source logic should be carried out in this folder
- `folia-server` : There is no valid file
- `paper-server` : Modifications to non-vanilla server logic should be carried out in this folder
- `lophine-server` : Changes and new files to the Minecraft vanilla server should be made in this folder
- `luminol-server` : Changes to luminol-server should be made in this folder
- `folia-server` : Changes to folia-server should be made in this folder
- `paper-server` : Modifications to the server logic for paper should be made in this folder
BTW, `*-api` and `*-server` and are not normal git repositories.
+6 -4
View File
@@ -1,8 +1,10 @@
group=me.earthme.lophine
version=1.21.5-R0.1-SNAPSHOT
mcVersion=1.21.5
group=fun.bm.lophine
version=1.21.8-R0.1-SNAPSHOT
mcVersion=1.21.8
release=2
# 0 for skip release, 1 for pre-release, 2 for release
luminolRef=6eebbe4221f34bf65832b02af01814fc057206b6
luminolRef=f96dd6afba9553b9ec21c59747f64ddfcadf541b
org.gradle.configuration-cache=true
org.gradle.caching=true
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+71 -70
View File
@@ -1,4 +1,5 @@
### GNU GENERAL PUBLIC LICENSE
==============================
Version 3, 29 June 2007
@@ -217,23 +218,23 @@ 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) 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,
@@ -252,42 +253,42 @@ 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 general
public at no charge under subsection 6d.
- 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
@@ -363,23 +364,23 @@ 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.
- 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
+2 -2
View File
@@ -1,5 +1,5 @@
The MIT License (MIT)
=====================
### The MIT License (MIT)
=========================
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
+16 -7
View File
@@ -1,6 +1,6 @@
--- a/luminol-server/build.gradle.kts
+++ b/luminol-server/build.gradle.kts
@@ -54,7 +_,23 @@
@@ -52,7 +_,23 @@
}
}
@@ -23,8 +23,8 @@
+
+ activeFork = lophine
spigot {
buildDataRef = "702e1a0a5072b2c4082371d5228cb30525687efc"
@@ -142,12 +_,16 @@
resources { srcDir("../paper-server/src/main/resources") }
java { srcDir("../folia-server/src/main/java") }
@@ -47,11 +47,11 @@
dependencies {
- implementation(project(":luminol-api")) // Luminol
+ implementation(project(":lophine-api")) // Luminol // Lophine
implementation("com.electronwill.night-config:toml:3.8.2") // Luminol - Night config
// Abomination start
+ implementation(project(":lophine-api")) // Lophine
// Luminol start - Dependenices insert
implementation("com.electronwill.night-config:toml:3.8.2") // Night config
implementation("com.github.luben:zstd-jni:1.5.4-1")
@@ -264,14 +_,14 @@
@@ -277,14 +_,14 @@
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main",
@@ -62,7 +62,7 @@
- "Specification-Title" to "Luminol",
+ "Specification-Title" to "Lophine",
"Specification-Version" to project.version,
"Specification-Vendor" to "Luminol Team",
"Specification-Vendor" to "LuminolMC org",
- "Brand-Id" to "luminolmc:luminol",
- "Brand-Name" to "Luminol",
+ "Brand-Id" to "luminolmc:lophine",
@@ -70,3 +70,12 @@
"Build-Number" to (build ?: ""),
"Build-Time" to buildTime.toString(),
"Git-Branch" to gitBranch,
@@ -448,7 +_,7 @@
}
fill {
- project("luminol")
+ project("lophine")
versionFamily(paperweight.minecraftVersion.map { it.split(".", "-").takeWhile { part -> part.toIntOrNull() != null }.take(2).joinToString(".") })
version(paperweight.minecraftVersion)
@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 8 Jun 2025 00:58:13 +0800
Subject: [PATCH] Rebrand to Lophine
diff --git a/src/main/java/me/earthme/luminol/config/ConfigManager.java b/src/main/java/me/earthme/luminol/config/ConfigManager.java
index 0a3fa2756dae0eea9e2c0fa6bbaa425584763036..6c1cb2866c81a1bc861289aedb2c318f910a8498 100644
--- a/src/main/java/me/earthme/luminol/config/ConfigManager.java
+++ b/src/main/java/me/earthme/luminol/config/ConfigManager.java
@@ -19,6 +19,7 @@ public class ConfigManager {
public static void initConfigs() throws IOException {
configfiles.put("luminol", ConfigsInstance.of(new File("luminol_config"), "luminol", "me.earthme.luminol.config.modules"));
+ configfiles.put("lophine", ConfigsInstance.of(new File("lophine_config"), "lophine", "fun.bm.lophine.config.modules")); // add lophine config to global config
preLoad();
}
diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
index ded1f0667327a70a923ebda55c41b1c9094d3e37..57ddc0832b919b115b85c81ac30f136e32f1e77e 100644
--- a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
+++ b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
@@ -6,7 +6,7 @@ import me.earthme.luminol.config.flags.ConfigInfo;
public class ServerModNameConfig implements IConfigModule {
@ConfigInfo(baseName = "name")
- public static String serverModName = "Luminol";
+ public static String serverModName = "Lophine";
@ConfigInfo(baseName = "vanilla_spoof")
public static boolean fakeVanilla = false;
@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 28 Jul 2025 23:02:47 +0800
Subject: [PATCH] Transformed Configs
diff --git a/src/main/java/me/earthme/luminol/config/modules/experiment/CommandBlockExecutionConfig.java b/src/main/java/me/earthme/luminol/config/modules/experiment/CommandBlockExecutionConfig.java
index 531214d7ab28ece4bf84e82b39d1c9f983f0fb0c..b68fa0427bb975e91e76f73ab4cc089a424937a3 100644
--- a/src/main/java/me/earthme/luminol/config/modules/experiment/CommandBlockExecutionConfig.java
+++ b/src/main/java/me/earthme/luminol/config/modules/experiment/CommandBlockExecutionConfig.java
@@ -5,6 +5,7 @@ import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class CommandBlockExecutionConfig implements IConfigModule {
+ @me.earthme.luminol.config.flags.TransformedConfig(name = "command_block_enabled", category = {"experiment", "command"}, originInstance = "lophine")
@ConfigInfo(baseName = "enabled")
public static boolean enabled = false;
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to disable end crystal check
diff --git a/net/minecraft/world/level/dimension/end/EndDragonFight.java b/net/minecraft/world/level/dimension/end/EndDragonFight.java
index 4fa8371c212dcc02b8cf5fd267b736e1cf3f50c1..d62a9e93dae7b4a7a079e73e80e68e6a81b4c437 100644
index 4fa8371c212dcc02b8cf5fd267b736e1cf3f50c1..4fb9244172b74c3c5fed984d5d3b968f76dd12be 100644
--- a/net/minecraft/world/level/dimension/end/EndDragonFight.java
+++ b/net/minecraft/world/level/dimension/end/EndDragonFight.java
@@ -547,6 +547,8 @@ public class EndDragonFight {
@@ -13,7 +13,7 @@ index 4fa8371c212dcc02b8cf5fd267b736e1cf3f50c1..d62a9e93dae7b4a7a079e73e80e68e6a
blockPos = this.portalLocation;
}
+ // Luminol start - Disable end crystal check
+ if (!me.earthme.lophine.config.modules.misc.DisableEndCrystalCheckConfig.disableCheck) {
+ if (!fun.bm.lophine.config.modules.misc.DisableEndCrystalCheckConfig.disableCheck) {
// Paper start - Perf: Do crystal-portal proximity check before entity lookup
if (placedEndCrystalPos != null) {
// The end crystal must be 0 or 1 higher than the portal origin
@@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 8 Jun 2025 00:58:12 +0800
Subject: [PATCH] Rebrand to Lophine
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
index fcf599846a38beeb8f094d5376c01d5a690f7a2f..9ddcb2b5ced68ff619516ddbac2327c23e316438 100644
--- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java
@@ -108,7 +108,8 @@ public class Main {
JvmProfiler.INSTANCE.start(Environment.SERVER);
}
- me.earthme.luminol.config.LuminolConfig.preLoadConfig(); // Luminol - Luminol config
+ me.earthme.lophine.config.LophineConfig.initConfigs(); // Lophine - Lophine config
+ me.earthme.lophine.config.LophineConfig.preLoad(); // Luminol - Luminol config // Lophine - Lophine config
io.papermc.paper.plugin.PluginInitializerManager.load(optionSet); // Paper
Bootstrap.bootStrap();
Bootstrap.validate();
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 5290b9cb524160717fb40704fb10fc0d0a37941b..ba0cdba050cd3bf9231e15dd9543d34f37d9dae5 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -171,8 +171,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
// Paper end - initialize global and world-defaults configuration
- me.earthme.luminol.config.LuminolConfig.finalizeLoadConfig(); //Luminol - load config file
- me.earthme.luminol.config.LuminolConfig.setupLatch(); //Luminol - load config file
+ me.earthme.lophine.config.LophineConfig.loadConfigFiles(); //Luminol - load config file // Lophine - load config file
if (false) this.server.spark.enableEarlyIfRequested(); // Paper - spark // Luminol - Force disable builtin spark
// Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save
if (this.convertOldUsers()) {
@@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrHua269 <wangxyper@163.com>
Date: Sun, 12 Jan 2025 10:36:31 +0800
Subject: [PATCH] Add config for command block command execution
diff --git a/net/minecraft/world/level/BaseCommandBlock.java b/net/minecraft/world/level/BaseCommandBlock.java
index 91e30f9c83259abc0589f4ee69c429cd4305d6ea..8155da15908fd944d452fd6aaff69cfdfcc7b36b 100644
--- a/net/minecraft/world/level/BaseCommandBlock.java
+++ b/net/minecraft/world/level/BaseCommandBlock.java
@@ -102,7 +102,7 @@ public abstract class BaseCommandBlock implements CommandSource {
}
public boolean performCommand(Level level) {
- if (true) return false; // Folia - region threading
+ if (!me.earthme.lophine.config.modules.experiment.CommandConfig.block) return false; // Folia - region threading // Luminol
if (level.isClientSide || level.getGameTime() == this.lastExecution) {
return false;
} else if ("Searge".equalsIgnoreCase(this.command)) {
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to enable tick command
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index 8e91ec81128bdbd5f78e1f04fe17bcbd6e5dc280..6b4a33189b4dcd4979fb421248f72530c547ac19 100644
index e1842ab8f20271a8b20ab8462b09a4745a612a9a..8405157ec35a443e238fa6866772c839621d73d7 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -299,6 +299,11 @@ public final class RegionizedServer {
@@ -13,19 +13,19 @@ index 8e91ec81128bdbd5f78e1f04fe17bcbd6e5dc280..6b4a33189b4dcd4979fb421248f72530
*/
++this.tickCount;
+ // Luminol start - Add a config to enable tick command
+ if (me.earthme.lophine.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ MinecraftServer.tickRateManager.tick();
+ }
+ // Luminol end - Add a config to enable tick command
// expire invalid click command callbacks
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue((int)this.tickCount);
@@ -321,6 +326,13 @@ public final class RegionizedServer {
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.ADVENTURE_CLICK_MANAGER.handleQueue((int)this.tickCount); // Paper // Folia - region threading - moved to global tick
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue((int)this.tickCount); // Paper // Folia - region threading - moved to global tick
@@ -322,6 +327,13 @@ public final class RegionizedServer {
this.globalTick(world, tickCount);
}
+ // Luminol start - Add a config to enable tick command
+ if (me.earthme.lophine.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ MinecraftServer.tickRateManager.reduceSprintTicks();
+ MinecraftServer.tickRateManager.endTickWork();
+ }
@@ -34,17 +34,17 @@ index 8e91ec81128bdbd5f78e1f04fe17bcbd6e5dc280..6b4a33189b4dcd4979fb421248f72530
// tick connections
this.tickConnections();
@@ -454,7 +466,7 @@ public final class RegionizedServer {
@@ -455,7 +467,7 @@ public final class RegionizedServer {
}
private void tickTime(final ServerLevel world, final int tickCount) {
- if (world.tickTime) {
+ if ((!me.earthme.lophine.config.modules.experiment.CommandConfig.tick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command
+ if ((!fun.bm.lophine.config.modules.experiment.CommandConfig.tick || world.tickRateManager().runsNormally()) && world.tickTime) { // Luminol - Add a config to enable tick command
if (world.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) {
world.setDayTime(world.levelData.getDayTime() + (long)tickCount);
}
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
index fa6b8d756195c1b430cc11214a901bd42eebc98d..1d79465c9b04c5cdfd299278786916cb10e49522 100644
index 0357792de0ed8ec9058d1847c8b45c33ff365af6..4945c11f573a53df2f5be4beb7af6a3f4d32f7d4 100644
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
@@ -31,8 +31,8 @@ public final class TickRegionScheduler {
@@ -58,7 +58,7 @@ index fa6b8d756195c1b430cc11214a901bd42eebc98d..1d79465c9b04c5cdfd299278786916cb
// Folia start - watchdog
public static final FoliaWatchdogThread WATCHDOG_THREAD = new FoliaWatchdogThread();
@@ -375,8 +375,23 @@ public final class TickRegionScheduler {
@@ -394,8 +394,23 @@ public final class TickRegionScheduler {
final long cpuStart = MEASURE_CPU_TIME ? THREAD_MX_BEAN.getCurrentThreadCpuTime() : 0L;
final long tickStart = System.nanoTime();
@@ -66,7 +66,7 @@ index fa6b8d756195c1b430cc11214a901bd42eebc98d..1d79465c9b04c5cdfd299278786916cb
- final int tickCount = Math.max(1, this.tickSchedule.getPeriodsAhead(TIME_BETWEEN_TICKS, tickStart));
+ // Luminol start - Add a config to enable tick command
+ final int tickCount;
+ if (me.earthme.lophine.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ if (MinecraftServer.tickRateManager.isSprinting() && MinecraftServer.tickRateManager.checkShouldSprintThisTick()) {
+ TICK_RATE = net.minecraft.server.commands.TickCommand.MAX_TICKRATE;
+ TIME_BETWEEN_TICKS = (long) (1_000_000_000L / TICK_RATE);
@@ -84,12 +84,12 @@ index fa6b8d756195c1b430cc11214a901bd42eebc98d..1d79465c9b04c5cdfd299278786916cb
if (!this.tryMarkTicking()) {
if (!this.cancelled.get()) {
@@ -416,6 +431,11 @@ public final class TickRegionScheduler {
@@ -435,6 +450,11 @@ public final class TickRegionScheduler {
try {
// next start isn't updated until the end of this tick
this.tickRegion(tickCount, tickStart, scheduledEnd);
+ // Luminol start - Add a config to enable tick command
+ if (me.earthme.lophine.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ MinecraftServer.tickRateManager.endTickWork();
+ }
+ // Luminol end - Add a config to enable tick command
@@ -97,16 +97,16 @@ index fa6b8d756195c1b430cc11214a901bd42eebc98d..1d79465c9b04c5cdfd299278786916cb
this.scheduler.regionFailed(this, false, thr);
// regionFailed will schedule a shutdown, so we should avoid letting this region tick further
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index ea50e3c0c4044f03dc8257680814f808fbf3a177..bd5d8bbb667585c1bf976e2eaa38f2b72eabe9e2 100644
index 8a90aa5c145f53afbb3f2371f97cb09974f30bbb..0d5ed9602492c8393088954105e9a19032067b8b 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -214,7 +214,11 @@ public class Commands {
@@ -243,7 +243,11 @@ public class Commands {
TeleportCommand.register(this.dispatcher);
TellRawCommand.register(this.dispatcher, context);
//TestCommand.register(this.dispatcher, context); // Folia - region threading
- //TickCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ // Luminol start - Add a config to enable tick command
+ if (me.earthme.lophine.config.modules.experiment.CommandConfig.tick) {
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.tick) {
+ TickCommand.register(this.dispatcher); // Folia - region threading - TODO later
+ }
+ // Luminol end - Add a config to enable tick command
@@ -114,10 +114,10 @@ index ea50e3c0c4044f03dc8257680814f808fbf3a177..bd5d8bbb667585c1bf976e2eaa38f2b7
TitleCommand.register(this.dispatcher, context);
//TriggerCommand.register(this.dispatcher); // Folia - region threading - TODO later
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 33d596c0f07d076886c0dd8eb93e901cdb56e438..87625b365e04ce05fa2b6cdf2003c839255c4393 100644
index 2ed2f4cca3a81117c0beaf7a11bbbe8156f6a9ce..6675b83c9f15d0341dcf169ec3ac20f401c5d10b 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -266,7 +266,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -267,7 +267,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private String serverId;
public MinecraftServer.ReloadableResources resources;
private final StructureTemplateManager structureTemplateManager;
@@ -153,7 +153,7 @@ index 40338efd1c0e56d869d03f1d0687e7ff0fcbf11a..d0d90a25a10bbecfffceee1992af88c6
this.sprintTimeSpend = this.sprintTimeSpend + (System.nanoTime() - this.sprintTickStartTime);
}
diff --git a/net/minecraft/server/commands/TickCommand.java b/net/minecraft/server/commands/TickCommand.java
index 6b6c8ce49eda6806c8288d70848dd143ba2c4703..5d09d2c8bb45cc10b2a13100793249adc7b5a7e9 100644
index 126685fb266692082b432ed297a499149e921dfb..9d8f6025c420e651611da17e77a362c738228b72 100644
--- a/net/minecraft/server/commands/TickCommand.java
+++ b/net/minecraft/server/commands/TickCommand.java
@@ -14,7 +14,7 @@ import net.minecraft.server.ServerTickRateManager;
@@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 2 Jul 2025 23:36:25 +0800
Subject: [PATCH] Add config to enable datapack command
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 0d5ed9602492c8393088954105e9a19032067b8b..e2fc15d84fafde6847ecead23c55169449275e1b 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -192,7 +192,9 @@ public class Commands {
if(me.earthme.luminol.config.modules.experiment.CommandDataConfig.enabled) {
DataCommands.register(this.dispatcher); // Folia - region threading - TODO
}
- //DataPackCommand.register(this.dispatcher, context); // Folia - region threading - TODO
+ if (fun.bm.lophine.config.modules.experiment.CommandConfig.datapack) {
+ DataPackCommand.register(this.dispatcher, context); // Folia - region threading - TODO
+ }
//DebugCommand.register(this.dispatcher); // Folia - region threading - TODO
DefaultGameModeCommands.register(this.dispatcher);
//DialogCommand.register(this.dispatcher, context); // Folia - region threading - TODO
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 6675b83c9f15d0341dcf169ec3ac20f401c5d10b..e8c9e739de35313c0212bab97a202fa362fd0887 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2349,6 +2349,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return this.reloadResources(selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.PLUGIN);
}
+ // Lophine start - region thread skip reload // TODO - add reload support
+ public void saveDatapacks(Collection<String> selectedIds) {
+ this.packRepository.setSelected(selectedIds, false); // Paper - add pendingReload flag to determine required pack loading - false as this is *after* a reload (see above)
+ WorldDataConfiguration worldDataConfiguration = new WorldDataConfiguration(
+ getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()
+ );
+ this.worldData.setDataConfiguration(worldDataConfiguration);
+ }
+ // Lophine end - region thread skip reload // TODO - add reload support
+
public CompletableFuture<Void> reloadResources(Collection<String> selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause cause) {
// Paper end - Add ServerResourcesReloadedEvent
CompletableFuture<Void> completableFuture = CompletableFuture.<ImmutableList>supplyAsync(
diff --git a/net/minecraft/server/commands/ReloadCommand.java b/net/minecraft/server/commands/ReloadCommand.java
index b540a3c3a02f7242578a63477e34b9063e86f1d2..9f0adf157872e1c68cd7752a24eacdc636e8d17a 100644
--- a/net/minecraft/server/commands/ReloadCommand.java
+++ b/net/minecraft/server/commands/ReloadCommand.java
@@ -16,6 +16,12 @@ public class ReloadCommand {
private static final Logger LOGGER = LogUtils.getLogger();
public static void reloadPacks(Collection<String> selectedIds, CommandSourceStack source) {
+ // Lophine start - region thread skip reload // TODO - add reload support
+ if (true) {
+ source.getServer().saveDatapacks(selectedIds);
+ return;
+ }
+ // Lophine end - region thread skip reload // TODO - add reload support
source.getServer().reloadResources(selectedIds, io.papermc.paper.event.server.ServerResourcesReloadedEvent.Cause.COMMAND).exceptionally(throwable -> { // Paper - Add ServerResourcesReloadedEvent
LOGGER.warn("Failed to execute reload", throwable);
source.sendFailure(Component.translatable("commands.reload.failure"));
@@ -3,9 +3,12 @@ From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Fri, 11 Apr 2025 16:53:57 +0800
Subject: [PATCH] Add config to revert raid changes
Co-authored by: huanli233 <392352840@qq.com>
Some of changes is a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/b5793e809b6346e16b7ea218496806a312562e27/leaves-server/minecraft-patches/features/0106-Revert-raid-changes.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/effect/BadOmenMobEffect.java b/net/minecraft/world/effect/BadOmenMobEffect.java
index 80f17f33f670018240c854df589cf90cdeab6e70..faf31ef66ab7fcdb4135e4c225312dc353bdb99b 100644
index 80f17f33f670018240c854df589cf90cdeab6e70..985f27d249810bf133a520d937b7006e57f553ec 100644
--- a/net/minecraft/world/effect/BadOmenMobEffect.java
+++ b/net/minecraft/world/effect/BadOmenMobEffect.java
@@ -22,6 +22,11 @@ class BadOmenMobEffect extends MobEffect {
@@ -13,7 +16,7 @@ index 80f17f33f670018240c854df589cf90cdeab6e70..faf31ef66ab7fcdb4135e4c225312dc3
&& level.getDifficulty() != Difficulty.PEACEFUL
&& level.isVillage(serverPlayer.blockPosition())) {
+ // Leaves start - Revert raid changes
+ if (me.earthme.lophine.config.modules.misc.RaidChangesConfig.trigger) {
+ if (fun.bm.lophine.config.modules.misc.RaidChangesConfig.trigger) {
+ return level.getRaids().createOrExtendRaid(serverPlayer, serverPlayer.blockPosition()) == null;
+ }
+ // Leaves end - Revert raid changes
@@ -21,7 +24,7 @@ index 80f17f33f670018240c854df589cf90cdeab6e70..faf31ef66ab7fcdb4135e4c225312dc3
if (raidAt == null || raidAt.getRaidOmenLevel() < raidAt.getMaxRaidOmenLevel()) {
serverPlayer.addEffect(new MobEffectInstance(MobEffects.RAID_OMEN, 600, amplifier));
diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java
index dbb207c638a64b733dc21704033ff55ca1f44f1d..94fdf1b5ce2622e4e654d09562f8a3e032e6add8 100644
index 1910bff3f08147bfd63703097e30b9f88c84e337..26f4d7359f638a11ea2d768d18091e261d6b1791 100644
--- a/net/minecraft/world/entity/raid/Raid.java
+++ b/net/minecraft/world/entity/raid/Raid.java
@@ -340,7 +340,20 @@ public class Raid {
@@ -30,7 +33,7 @@ index dbb207c638a64b733dc21704033ff55ca1f44f1d..94fdf1b5ce2622e4e654d09562f8a3e0
if (flag1) {
- this.waveSpawnPos = this.getValidSpawnPos(level);
+ // Luminol Start - Raid revert
+ if (!me.earthme.lophine.config.modules.misc.RaidChangesConfig.posRevert) {
+ if (!fun.bm.lophine.config.modules.misc.RaidChangesConfig.posRevert) {
+ this.waveSpawnPos = this.getValidSpawnPos(level);
+ } else {
+ int n4 = 0;
@@ -53,7 +56,7 @@ index dbb207c638a64b733dc21704033ff55ca1f44f1d..94fdf1b5ce2622e4e654d09562f8a3e0
- BlockPos blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
+ // Luminol Start - Raid revert
+ BlockPos blockPos;
+ if (!me.earthme.lophine.config.modules.misc.RaidChangesConfig.posRevert) {
+ if (!fun.bm.lophine.config.modules.misc.RaidChangesConfig.posRevert) {
+ blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
+ } else {
+ blockPos = this.waveSpawnPos.isPresent() ? this.waveSpawnPos.get() : this.findRandomSpawnPos(level, i, 20);
@@ -67,7 +70,7 @@ index dbb207c638a64b733dc21704033ff55ca1f44f1d..94fdf1b5ce2622e4e654d09562f8a3e0
}
- if (i > 5) {
+ if (i > (me.earthme.lophine.config.modules.misc.RaidChangesConfig.posRevert ? 3 : 5)) { // Luminol - Raid revert
+ if (i > (fun.bm.lophine.config.modules.misc.RaidChangesConfig.posRevert ? 3 : 5)) { // Luminol - Raid revert
org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(level, this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE); // CraftBukkit
this.stop();
break;
@@ -94,7 +97,7 @@ index dbb207c638a64b733dc21704033ff55ca1f44f1d..94fdf1b5ce2622e4e654d09562f8a3e0
int i3 = this.center.getZ() + Mth.floor(Mth.sin(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
int height = level.getHeight(Heightmap.Types.WORLD_SURFACE, i2, i3);
- if (Mth.abs(height - this.center.getY()) <= 96) {
+ if (me.earthme.lophine.config.modules.misc.RaidChangesConfig.heightCheck || Mth.abs(height - this.center.getY()) <= 96) { // Leaves - Disable height check
+ if (fun.bm.lophine.config.modules.misc.RaidChangesConfig.heightCheck || Mth.abs(height - this.center.getY()) <= 96) { // Leaves - Disable height check
mutableBlockPos.set(i2, height, i3);
if (!level.isVillage(mutableBlockPos) || i <= 7) {
int i4 = 10;
@@ -126,16 +129,16 @@ index dbb207c638a64b733dc21704033ff55ca1f44f1d..94fdf1b5ce2622e4e654d09562f8a3e0
// Folia start - make raids thread-safe
if (!this.ownsRaid(level)) {
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
index f6f36c15120da6c57c0cbea3743a0819252cb6cc..b2bb9b0ff94a7e463ebc4e59fe4378e022e52843 100644
index 3e30989c99cd11c8c94d6fd194d2969e3a7efda6..510514e363f4816a6e286fb9b5488153e03c9e55 100644
--- a/net/minecraft/world/entity/raid/Raider.java
+++ b/net/minecraft/world/entity/raid/Raider.java
@@ -127,6 +127,41 @@ public abstract class Raider extends PatrollingMonster {
@@ -128,6 +128,41 @@ public abstract class Raider extends PatrollingMonster {
currentRaid.removeFromRaid(serverLevel, this, false);
}
+
+ // Leaves start - Revert raid changes
+ if (me.earthme.lophine.config.modules.misc.RaidChangesConfig.effect && !this.hasRaid()) {
+ if (fun.bm.lophine.config.modules.misc.RaidChangesConfig.effect && !this.hasRaid()) {
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
+ net.minecraft.world.entity.player.Player entityhuman = null;
+ if (entity instanceof net.minecraft.world.entity.player.Player player) {
@@ -159,7 +162,7 @@ index f6f36c15120da6c57c0cbea3743a0819252cb6cc..b2bb9b0ff94a7e463ebc4e59fe4378e0
+ }
+
+ i = net.minecraft.util.Mth.clamp(i, 0, 4);
+ net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, me.earthme.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, i, false, false, true);
+ net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, fun.bm.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, i, false, false, true);
+
+ if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DISABLE_RAIDS)) {
+ entityhuman.addEffect(mobeffect1, entityhuman, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true); // CraftBukkit
@@ -171,17 +174,17 @@ index f6f36c15120da6c57c0cbea3743a0819252cb6cc..b2bb9b0ff94a7e463ebc4e59fe4378e0
}
super.die(cause);
@@ -155,7 +190,7 @@ public abstract class Raider extends PatrollingMonster {
@@ -156,7 +191,7 @@ public abstract class Raider extends PatrollingMonster {
}
public boolean hasRaid() {
- return this.level() instanceof ServerLevel serverLevel && (this.getCurrentRaid() != null || serverLevel.getRaidAt(this.blockPosition()) != null);
+ return !me.earthme.lophine.config.modules.misc.RaidChangesConfig.selfCheck && (this.level() instanceof ServerLevel serverLevel && (this.getCurrentRaid() != null || serverLevel.getRaidAt(this.blockPosition()) != null)); // Leaves - Disable raid self check
+ return !fun.bm.lophine.config.modules.misc.RaidChangesConfig.selfCheck && (this.level() instanceof ServerLevel serverLevel && (this.getCurrentRaid() != null || serverLevel.getRaidAt(this.blockPosition()) != null)); // Leaves - Disable raid self check
}
public boolean hasActiveRaid() {
diff --git a/net/minecraft/world/item/component/OminousBottleAmplifier.java b/net/minecraft/world/item/component/OminousBottleAmplifier.java
index 33907bb190ffa22ccf9ea424b1e536297878711a..4b48aa0db9c1ab3e6227d1e1a42ce73db6943b04 100644
index 33907bb190ffa22ccf9ea424b1e536297878711a..2fca459f2c888079322f6b957bbee3ac0e33c4bc 100644
--- a/net/minecraft/world/item/component/OminousBottleAmplifier.java
+++ b/net/minecraft/world/item/component/OminousBottleAmplifier.java
@@ -29,7 +29,7 @@ public record OminousBottleAmplifier(int value) implements ConsumableListener, T
@@ -189,7 +192,7 @@ index 33907bb190ffa22ccf9ea424b1e536297878711a..4b48aa0db9c1ab3e6227d1e1a42ce73d
@Override
public void onConsume(Level level, LivingEntity entity, ItemStack stack, Consumable consumable) {
- entity.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below
+ entity.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, me.earthme.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below // Luminol - Raid effect infinite
+ entity.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, fun.bm.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below // Luminol - Raid effect infinite
}
// Paper start - properly resend entities - collect packets for bundle
@@ -198,7 +201,7 @@ index 33907bb190ffa22ccf9ea424b1e536297878711a..4b48aa0db9c1ab3e6227d1e1a42ce73d
@Override
public void addToTooltip(Item.TooltipContext context, Consumer<Component> tooltipAdder, TooltipFlag flag, DataComponentGetter componentGetter) {
- List<MobEffectInstance> list = List.of(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true));
+ List<MobEffectInstance> list = List.of(new MobEffectInstance(MobEffects.BAD_OMEN, me.earthme.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, this.value, false, false, true)); // Luminol - Raid effect infinite
+ List<MobEffectInstance> list = List.of(new MobEffectInstance(MobEffects.BAD_OMEN, fun.bm.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, this.value, false, false, true)); // Luminol - Raid effect infinite
PotionContents.addPotionTooltip(list, tooltipAdder, 1.0F, context.tickRate());
}
}
@@ -5,15 +5,15 @@ Subject: [PATCH] Add config to enable Cross Region Damage trace
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index c3201cb0ba6f928f658d4c74a1ef2b7e8900b1f6..1764875b9024569671bf2be537afb8b492f79102 100644
index 06e41bca6b964ca71ea7bca547b03cdb3610ba31..b7bc75648634aefc549a69631ab6e401eb902e7d 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1330,6 +1330,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1341,6 +1341,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.awardStat(Stats.ENTITY_KILLED_BY.get(killCredit.getType()));
killCredit.awardKillScore(this, cause);
this.createWitherRose(killCredit);
+ // Luminol Start - Cross Region Damage trace
+ } else if (me.earthme.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ final LivingEntity entitylivingnew = this.getKillCreditOrigin();
+ if (entitylivingnew != null) {
+ this.damageTransferToAsync(entitylivingnew, cause);
@@ -22,7 +22,7 @@ index c3201cb0ba6f928f658d4c74a1ef2b7e8900b1f6..1764875b9024569671bf2be537afb8b4
}
this.level().broadcastEntityEvent(this, (byte)3);
@@ -1353,6 +1360,24 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1364,6 +1371,24 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// Leaves end - exp fix
@@ -48,10 +48,10 @@ index c3201cb0ba6f928f658d4c74a1ef2b7e8900b1f6..1764875b9024569671bf2be537afb8b4
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
this.level()
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 5b5e63c4dc10076ba33a8ddf0ebae96643b1161f..063d682ae6cde044717a32402785b7a20ea8a351 100644
index d55a6989fd68f0bcf7bd05e9420fda1115afa6c0..5369a6597e48ed9f0d8f7f0b9685ce4950df4fe5 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -1191,6 +1191,29 @@ public abstract class LivingEntity extends Entity implements Attackable {
@@ -1216,6 +1216,29 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
}
}
@@ -59,7 +59,7 @@ index 5b5e63c4dc10076ba33a8ddf0ebae96643b1161f..063d682ae6cde044717a32402785b7a2
+ public boolean addEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent, boolean async) {
+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) {
+ return addEffect(effectInstance, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true);
+ } else if (me.earthme.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ postToEntityThreadAddEffect(effectInstance, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true);
+ return true;
+ }
@@ -81,12 +81,12 @@ index 5b5e63c4dc10076ba33a8ddf0ebae96643b1161f..063d682ae6cde044717a32402785b7a2
public boolean canBeAffected(MobEffectInstance effectInstance) {
if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) {
return !effectInstance.is(MobEffects.INFESTED);
@@ -1916,6 +1939,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
@@ -1948,6 +1971,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
final LivingEntity killer = this.getKillCredit();
if (killer != null) {
killer.awardKillScore(this, damageSource);
+ // Luminol Start - Cross Region Damage trace
+ } else if (me.earthme.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ final LivingEntity killernew = this.getKillCreditOrigin();
+ if (killernew != null) {
+ this.damageTransferToAsync(killernew, damageSource);
@@ -95,7 +95,7 @@ index 5b5e63c4dc10076ba33a8ddf0ebae96643b1161f..063d682ae6cde044717a32402785b7a2
}
}); // Paper end
this.postDeathDropItems(deathEvent); // Paper
@@ -1926,6 +1956,18 @@ public abstract class LivingEntity extends Entity implements Attackable {
@@ -1958,6 +1988,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
return deathEvent; // Paper
}
@@ -114,7 +114,7 @@ index 5b5e63c4dc10076ba33a8ddf0ebae96643b1161f..063d682ae6cde044717a32402785b7a2
protected void dropEquipment(ServerLevel level) {
}
protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {} // Paper - method for post death logic that cannot be ran before the event is potentially cancelled
@@ -2524,6 +2566,18 @@ public abstract class LivingEntity extends Entity implements Attackable {
@@ -2556,6 +2598,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
}
}
@@ -134,16 +134,16 @@ index 5b5e63c4dc10076ba33a8ddf0ebae96643b1161f..063d682ae6cde044717a32402785b7a2
return (float)this.getAttributeValue(Attributes.MAX_HEALTH);
}
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
index b2bb9b0ff94a7e463ebc4e59fe4378e022e52843..4b72db3350f2990b00076fffb9df811560db8207 100644
index 510514e363f4816a6e286fb9b5488153e03c9e55..4638af10539a316acae64fb26881c8e699c496e0 100644
--- a/net/minecraft/world/entity/raid/Raider.java
+++ b/net/minecraft/world/entity/raid/Raider.java
@@ -156,7 +156,13 @@ public abstract class Raider extends PatrollingMonster {
net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, me.earthme.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, i, false, false, true);
@@ -157,7 +157,13 @@ public abstract class Raider extends PatrollingMonster {
net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, fun.bm.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, i, false, false, true);
if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DISABLE_RAIDS)) {
- entityhuman.addEffect(mobeffect1, entityhuman, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true); // CraftBukkit
+ if (me.earthme.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ // Luminol start - Raid changes adapt DamageSource trace
+ // Luminol start - Raid changes adapt DamageSource trace
+ if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
+ entityhuman.addEffect(mobeffect1, entityhuman, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true, true);
+ } else {
+ entityhuman.addEffect(mobeffect1, entityhuman, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true); // CraftBukkit
@@ -5,7 +5,7 @@ Subject: [PATCH] Add config to enable Raytracing tracker
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index ee53f78396f4377d3e5c2998826f231208066ef6..607091ecbd4a7261f2c0d839ee4dd1d27fa2190a 100644
index 6868b915bf3deb85783a638d4441a15fea6da2dc..70740381c6501c1a518c52b24381edd16792507f 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -1278,7 +1278,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -18,19 +18,19 @@ index ee53f78396f4377d3e5c2998826f231208066ef6..607091ecbd4a7261f2c0d839ee4dd1d2
double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1);
if (rangeY != -1) {
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 0814ad6820b08a856f7bd261e96143568e772ac4..b7ef7df56e94b6af9398d0a4768747a35ac6f4fd 100644
index 2f733a3f75f9fe637864158a31d7507eac121d45..f7fcb4782b49374df8fe8f4401a4259f037221f7 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -140,7 +140,7 @@ import net.minecraft.world.scores.ScoreHolder;
import net.minecraft.world.scores.Team;
@@ -147,7 +147,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter;
import org.jetbrains.annotations.Contract;
import org.slf4j.Logger;
-public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker
+public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity, dev.tr7zw.entityculling.versionless.access.Cullable { // Paper - rewrite chunk system // Paper - optimise entity tracker // Luminol - Ray tracing entity tracker
// CraftBukkit start
private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger();
private static final int CURRENT_LEVEL = 2;
@@ -6107,4 +6107,46 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public boolean preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; keep initial motion on first snapTo
@@ -6439,4 +6439,46 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// Paper end - Expose entity id counter
public boolean shouldTickHot() { return this.tickCount > 20 * 10 && this.isAlive(); } // KioCG
@@ -59,7 +59,7 @@ index 0814ad6820b08a856f7bd261e96143568e772ac4..b7ef7df56e94b6af9398d0a4768747a3
+
+ @Override
+ public boolean isCulled() {
+ if (!me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.enabled)
+ if (!fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.enabled)
+ return false;
+ return this.culled;
+ }
@@ -71,17 +71,17 @@ index 0814ad6820b08a856f7bd261e96143568e772ac4..b7ef7df56e94b6af9398d0a4768747a3
+
+ @Override
+ public boolean isOutOfCamera() {
+ if (!me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.enabled)
+ if (!fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.enabled)
+ return false;
+ return this.outOfCamera;
+ }
+
}
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
index 6b72ab233508e6df1eca34360ce76d102ee25a41..f39ee4605cc15102d6560afd1dad5f56dd53cf4e 100644
index 6f00ffa05d9597917574357e0069c9b056aa5ce2..5cc7a91e32f17d8d9585ae4844a4ed3b706e3273 100644
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
@@ -1109,6 +1109,9 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
@@ -1119,6 +1119,9 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
public final int passengerTickTimerId;
public final int passengerInactiveTickTimerId;
// Folia end - profiler
@@ -92,53 +92,53 @@ index 6b72ab233508e6df1eca34360ce76d102ee25a41..f39ee4605cc15102d6560afd1dad5f56
public EntityType(
EntityType.EntityFactory<T> factory,
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 543750bee43bfaaaf33f2cec53eb0de05e7a1dd2..34c4c195519de03ec11897160b98c80353eb3d6c 100644
index 2842314c712449625e9275aff7707c916c3ea767..09b549fa9568aa1ae13b1b975db14a6268fdaa46 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -220,6 +220,25 @@ public abstract class Player extends LivingEntity {
@@ -229,6 +229,25 @@ public abstract class Player extends LivingEntity {
return (org.bukkit.craftbukkit.entity.CraftHumanEntity) super.getBukkitEntity();
}
// CraftBukkit end
+ // Luminol start - Raytracing entity tracker
+ public dev.tr7zw.entityculling.CullTask cullTask;
+ {
+ if (!me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.enabled) {
+ if (!fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.enabled) {
+ this.cullTask = null;
+ }else {
+ final com.logisticscraft.occlusionculling.OcclusionCullingInstance culling = new com.logisticscraft.occlusionculling.OcclusionCullingInstance(
+ me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.tracingDistance,
+ fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.tracingDistance,
+ new dev.tr7zw.entityculling.DefaultChunkDataProvider(this.level())
+ );
+
+ this.cullTask = new dev.tr7zw.entityculling.CullTask(
+ culling, this,
+ me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.hitboxLimit,
+ me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.checkIntervalMs
+ fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.hitboxLimit,
+ fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.checkIntervalMs
+ );
+ }
+ }
+ // Luminol end
public Player(Level level, BlockPos pos, float yRot, GameProfile gameProfile) {
public Player(Level level, GameProfile gameProfile) {
super(EntityType.PLAYER, level);
@@ -277,6 +296,26 @@ public abstract class Player extends LivingEntity {
@@ -287,6 +306,26 @@ public abstract class Player extends LivingEntity {
@Override
public void tick() {
+ // Luminol start - Ray tracing entity tracker
+ if (!me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.enabled) {
+ if (!fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.enabled) {
+ if (this.cullTask != null) this.cullTask.signalStop();
+ this.cullTask = null;
+ }else {
+ final com.logisticscraft.occlusionculling.OcclusionCullingInstance culling = new com.logisticscraft.occlusionculling.OcclusionCullingInstance(
+ me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.tracingDistance,
+ fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.tracingDistance,
+ new dev.tr7zw.entityculling.DefaultChunkDataProvider(this.level())
+ );
+
+ this.cullTask = new dev.tr7zw.entityculling.CullTask(
+ culling, this,
+ me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.hitboxLimit,
+ me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.checkIntervalMs
+ fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.hitboxLimit,
+ fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig.checkIntervalMs
+ );
+ }
+ if (this.cullTask != null) this.cullTask.setup();
@@ -148,7 +148,7 @@ index 543750bee43bfaaaf33f2cec53eb0de05e7a1dd2..34c4c195519de03ec11897160b98c803
this.noPhysics = this.isSpectator();
if (this.isSpectator() || this.isPassenger()) {
this.setOnGround(false);
@@ -1415,6 +1454,7 @@ public abstract class Player extends LivingEntity {
@@ -1426,6 +1465,7 @@ public abstract class Player extends LivingEntity {
if (this.containerMenu != null && this.hasContainerOpen()) {
this.doCloseContainer();
}
@@ -0,0 +1,60 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 7 Jul 2025 16:30:54 +0800
Subject: [PATCH] Add config to allow infinite trade
diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
index 79242037e868a140513f032e74e8594c0c6ff41c..8570c5089b605125680f8558ae201550df2d0a47 100644
--- a/net/minecraft/world/entity/npc/Villager.java
+++ b/net/minecraft/world/entity/npc/Villager.java
@@ -490,8 +490,15 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
private void resendOffersToTradingPlayer() {
- MerchantOffers offers = this.getOffers();
+ // Lophine start - infinite trade
+ MerchantOffers offers = this.getOffers().copy();
Player tradingPlayer = this.getTradingPlayer();
+ if (fun.bm.lophine.config.modules.misc.VillagerConfig.villagerInfiniteTrade) {
+ for (MerchantOffer merchantOffer : offers) {
+ merchantOffer.maxUses = 524288;
+ }
+ }
+ // Lophine end - infinite trade
if (tradingPlayer != null && !offers.isEmpty()) {
tradingPlayer.sendMerchantOffers(
tradingPlayer.containerMenu.containerId,
diff --git a/net/minecraft/world/item/trading/Merchant.java b/net/minecraft/world/item/trading/Merchant.java
index 6e2fa442ddcd4ef3c4fe789b9ebac9dd409c9de7..28d743cc7beeb92a33683b8eea84096f94d90fb2 100644
--- a/net/minecraft/world/item/trading/Merchant.java
+++ b/net/minecraft/world/item/trading/Merchant.java
@@ -42,7 +42,14 @@ public interface Merchant {
new SimpleMenuProvider((containerId, inventory, player1) -> new MerchantMenu(containerId, inventory, this), displayName)
);
if (optionalInt.isPresent()) {
- MerchantOffers offers = this.getOffers();
+ // Lophine start - infinite trade
+ MerchantOffers offers = this.getOffers().copy();
+ if (fun.bm.lophine.config.modules.misc.VillagerConfig.villagerInfiniteTrade) {
+ for (MerchantOffer merchantOffer : offers) {
+ merchantOffer.maxUses = 5242884;
+ }
+ }
+ // Lophine end - infinite trade
if (!offers.isEmpty()) {
player.sendMerchantOffers(optionalInt.getAsInt(), offers, level, this.getVillagerXp(), this.showProgressBar(), this.canRestock());
}
diff --git a/net/minecraft/world/item/trading/MerchantOffer.java b/net/minecraft/world/item/trading/MerchantOffer.java
index 64c99df8ff305fa28c75dc03fc5ef8c61634ad84..21ec77d5167cfdf05043ea474165148fb2b0c2d9 100644
--- a/net/minecraft/world/item/trading/MerchantOffer.java
+++ b/net/minecraft/world/item/trading/MerchantOffer.java
@@ -196,7 +196,7 @@ public class MerchantOffer {
}
public boolean isOutOfStock() {
- return this.uses >= this.maxUses;
+ return (this.uses >= this.maxUses && !fun.bm.lophine.config.modules.misc.VillagerConfig.villagerInfiniteTrade); // Lophine - infinite trade
}
public void setToOutOfStock() {
@@ -0,0 +1,92 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 7 Jul 2025 18:19:00 +0800
Subject: [PATCH] Add config to enable unsafe waypoint bar
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index e2fc15d84fafde6847ecead23c55169449275e1b..b0a06cdfaa49237f372ecd131d47289160476b07 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -253,7 +253,11 @@ public class Commands {
TimeCommand.register(this.dispatcher);
TitleCommand.register(this.dispatcher, context);
//TriggerCommand.register(this.dispatcher); // Folia - region threading - TODO later
- //WaypointCommand.register(this.dispatcher, context); // Folia - region threading - TODO later
+ // Lophine start - unsafe waypoint bar
+ if (fun.bm.lophine.config.modules.experiment.WaypointConfig.forceEnableWaypointUnsafe) {
+ WaypointCommand.register(this.dispatcher, context); // Folia - region threading - TODO later
+ }
+ // Lophine end - unsafe waypoint bar
WeatherCommand.register(this.dispatcher);
WorldBorderCommand.register(this.dispatcher);
if (JvmProfiler.INSTANCE.isAvailable()) {
diff --git a/net/minecraft/server/waypoints/ServerWaypointManager.java b/net/minecraft/server/waypoints/ServerWaypointManager.java
index 0f8cacbb8fe55a60e2f0c98bf36c005b29f41a4b..36e9b027ce5213f8914728293633e78e9905c1b2 100644
--- a/net/minecraft/server/waypoints/ServerWaypointManager.java
+++ b/net/minecraft/server/waypoints/ServerWaypointManager.java
@@ -22,7 +22,14 @@ public class ServerWaypointManager implements WaypointManager<WaypointTransmitte
@Override
public void trackWaypoint(WaypointTransmitter waypoint) {
- // Folia - region threading
+ // Lophine start - unsafe waypoint bar
+ if (!fun.bm.lophine.config.modules.experiment.WaypointConfig.forceEnableWaypointUnsafe) return;
+ this.waypoints.add(waypoint);
+
+ for (ServerPlayer serverPlayer : this.players) {
+ this.createConnection(serverPlayer, waypoint);
+ }
+ // Lophine end - unsafe waypoint bar
}
@Override
@@ -50,14 +57,48 @@ public class ServerWaypointManager implements WaypointManager<WaypointTransmitte
public void addPlayer(ServerPlayer player) {
// Folia - region threading
+ // Lophine start - unsafe waypoint bar
+ if (!fun.bm.lophine.config.modules.experiment.WaypointConfig.forceEnableWaypointUnsafe) return;
+ this.players.add(player);
+
+ for (WaypointTransmitter waypointTransmitter : this.waypoints) {
+ this.createConnection(player, waypointTransmitter);
+ }
+
+ if (player.isTransmittingWaypoint()) {
+ this.trackWaypoint((WaypointTransmitter)player);
+ }
+ // Lophine end - unsafe waypoint bar
}
public void updatePlayer(ServerPlayer player) {
// Folia - region threading
+ // Lophine start - unsafe waypoint bar
+ if (!fun.bm.lophine.config.modules.experiment.WaypointConfig.forceEnableWaypointUnsafe) return;
+ Map<WaypointTransmitter, WaypointTransmitter.Connection> map = this.connections.row(player);
+ SetView<WaypointTransmitter> set = Sets.difference(this.waypoints, map.keySet());
+
+ for (Entry<WaypointTransmitter, WaypointTransmitter.Connection> entry : ImmutableSet.copyOf(map.entrySet())) {
+ this.updateConnection(player, entry.getKey(), entry.getValue());
+ }
+
+ for (WaypointTransmitter waypointTransmitter : set) {
+ this.createConnection(player, waypointTransmitter);
+ }
+ // Lophine end - unsafe waypoint bar
}
public void removePlayer(ServerPlayer player) {
// Folia - region threading
+ // Lophine start - unsafe waypoint bar
+ if (!fun.bm.lophine.config.modules.experiment.WaypointConfig.forceEnableWaypointUnsafe) return;
+ this.connections.row(player).values().removeIf(connection -> {
+ connection.disconnect();
+ return true;
+ });
+ this.untrackWaypoint((WaypointTransmitter)player);
+ this.players.remove(player);
+ // Lophine end - unsafe waypoint bar
}
public void breakAllConnections() {
@@ -0,0 +1,62 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 27 Jul 2025 13:48:10 +0800
Subject: [PATCH] Leaves: Disable packet limit
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/6a2b9ee6b330cd18b0a8eb2a824d561fa76012bb/leaves-server/minecraft-patches/features/0043-Disable-packet-limit.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
index 6dc5f3e88a3886b03b99d59b317085fdc3e2fa9a..e556bcaf2a5863073a047947f5962179d054e8d9 100644
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -280,8 +280,8 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
if (this.stopReadingPackets) {
return;
}
- if (this.allPacketCounts != null ||
- io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) {
+ if (!fun.bm.lophine.config.modules.optimizations.NetworkConfig.disablePacketLimit && (this.allPacketCounts != null || // Leaves - can disable
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass()))) { // Leaves - can disable
long time = System.nanoTime();
synchronized (PACKET_LIMIT_LOCK) {
if (this.allPacketCounts != null) {
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 68f0023c4234585a8385a830ed410883c8bd1549..206b4a532eba02b2a1f6f3b832970bc4c94fc45b 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -856,7 +856,7 @@ public class ServerGamePacketListenerImpl
public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) {
// PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); // Paper - AsyncTabCompleteEvent; run this async
// CraftBukkit start
- if (!this.tabSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { // Paper - configurable tab spam limits
+ if (!fun.bm.lophine.config.modules.optimizations.NetworkConfig.disablePacketLimit && !this.tabSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { // Paper - configurable tab spam limits // Leaves - can disable
this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause // Paper - add proper async disconnect
return;
}
@@ -2047,6 +2047,7 @@ public class ServerGamePacketListenerImpl
private static int getSpamThreshold() { return io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.incomingPacketThreshold; } // Paper - Configurable threshold
private boolean checkLimit(long timestamp) {
+ if (fun.bm.lophine.config.modules.optimizations.NetworkConfig.disablePacketLimit) return true; // Leaves - disable
if (this.lastLimitedPacket != -1 && timestamp - this.lastLimitedPacket < getSpamThreshold() && this.limitedPackets++ >= 8) { // Paper - Configurable threshold; raise packet limit to 8
return false;
}
@@ -2586,6 +2587,7 @@ public class ServerGamePacketListenerImpl
// Spigot start - spam exclusions
private void detectRateSpam(String message) {
+ if (fun.bm.lophine.config.modules.optimizations.NetworkConfig.disablePacketLimit) return; // Leaves - disable
// CraftBukkit start - replaced with thread safe throttle
if (org.spigotmc.SpigotConfig.enableSpamExclusions) {
for (String exclude : org.spigotmc.SpigotConfig.spamExclusions) {
@@ -3333,7 +3335,7 @@ public class ServerGamePacketListenerImpl
@Override
public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) {
// Paper start - auto recipe limit
- if (!org.bukkit.Bukkit.isPrimaryThread()) {
+ if (!fun.bm.lophine.config.modules.optimizations.NetworkConfig.disablePacketLimit && !org.bukkit.Bukkit.isPrimaryThread()) { // Leaves - can disable
if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) {
this.disconnectAsync(net.minecraft.network.chat.Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause // Paper - add proper async disconnect
return;
@@ -1,107 +1,111 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 9 Jun 2025 19:23:10 +0800
Subject: [PATCH] Stackable ShulkerBoxes
Date: Sat, 26 Jul 2025 01:11:54 +0800
Subject: [PATCH] Leaves: Item overstack util
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
Some of changes is a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/9d32c5bd3df7c76055aff886ed9efda02e45a45a/leaves-server/minecraft-patches/features/0034-Stackable-ShulkerBoxes.patch)
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/46cccfc39cafbca1681620d03947bc3ad558327f/leaves-server/minecraft-patches/features/0034-Item-overstack-util.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/commands/arguments/item/ItemInput.java b/net/minecraft/commands/arguments/item/ItemInput.java
index 643797124fe5a4489d0b7419b7e600c04f283ef2..3c0d01d444210029b6380417c6ee0e6408f89c18 100644
index 643797124fe5a4489d0b7419b7e600c04f283ef2..04b4100da96aad50f08e8c59200eec934e7e873d 100644
--- a/net/minecraft/commands/arguments/item/ItemInput.java
+++ b/net/minecraft/commands/arguments/item/ItemInput.java
@@ -39,8 +39,9 @@ public class ItemInput {
@@ -39,11 +39,13 @@ public class ItemInput {
public ItemStack createItemStack(int count, boolean allowOversizedStacks) throws CommandSyntaxException {
ItemStack itemStack = new ItemStack(this.item, count);
itemStack.applyComponents(this.components);
- if (allowOversizedStacks && count > itemStack.getMaxStackSize()) {
- throw ERROR_STACK_TOO_BIG.create(this.getItemName(), itemStack.getMaxStackSize());
+ int maxCount = me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemStack); // Lophine - Stackable ShulkerBoxes
+ if (allowOversizedStacks && count > maxCount) { // Lophine - Stackable ShulkerBoxes
+ throw ERROR_STACK_TOO_BIG.create(this.getItemName(), maxCount); // Lophine - Stackable ShulkerBoxes
+ // Leaves start - item over-stack util
+ if (allowOversizedStacks && count > org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack)) {
+ throw ERROR_STACK_TOO_BIG.create(this.getItemName(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack));
} else {
return itemStack;
}
+ // Leaves end - item over-stack util
}
public String serialize(HolderLookup.Provider levelRegistry) {
diff --git a/net/minecraft/server/commands/GiveCommand.java b/net/minecraft/server/commands/GiveCommand.java
index c1c0dea9f5ac3101c2f12714c8dd460457d45cb7..f94fc39297caebd0cb14d7b71c865f13b5c3b17c 100644
index 5a1c21b05545a03fbb00cf734605049870d3eecb..a0459bc6b2241e7fca74bfbfce058882a8ad7f49 100644
--- a/net/minecraft/server/commands/GiveCommand.java
+++ b/net/minecraft/server/commands/GiveCommand.java
@@ -52,7 +52,7 @@ public class GiveCommand {
@@ -55,7 +55,7 @@ public class GiveCommand {
private static int giveItem(CommandSourceStack source, ItemInput item, Collection<ServerPlayer> targets, int count) throws CommandSyntaxException {
ItemStack itemStack = item.createItemStack(1, false);
final Component displayName = itemStack.getDisplayName(); // Paper - get display name early
- int maxStackSize = itemStack.getMaxStackSize();
+ int maxStackSize = me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemStack); // Lophine - Stackable ShulkerBoxes
+ int maxStackSize = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
int i = maxStackSize * 100;
if (count > i) {
source.sendFailure(Component.translatable("commands.give.failed.toomanyitems", i, itemStack.getDisplayName()));
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 4fc3c9f2b04711569c12a0efa027601fdd0a40b5..e1e68cc934f8b5a8606a553f3e0a939c61a70377 100644
index 206b4a532eba02b2a1f6f3b832970bc4c94fc45b..39b5422af26fce5f1d5437ed35676b511bf13241 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3056,7 +3056,7 @@ public class ServerGamePacketListenerImpl
@@ -3078,7 +3078,7 @@ public class ServerGamePacketListenerImpl
} else if (slot.mayPlace(cursor)) {
if (ItemStack.isSameItemSameComponents(clickedItem, cursor)) {
int toPlace = packet.buttonNum() == 0 ? cursor.getCount() : 1;
- toPlace = Math.min(toPlace, clickedItem.getMaxStackSize() - clickedItem.getCount());
+ toPlace = Math.min(toPlace, me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(clickedItem) - clickedItem.getCount()); // Lophine - Stackable ShulkerBoxes
+ toPlace = Math.min(toPlace, org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(clickedItem) - clickedItem.getCount()); // Leaves - item over-stack util
toPlace = Math.min(toPlace, slot.container.getMaxStackSize() - clickedItem.getCount());
if (toPlace == 1) {
action = InventoryAction.PLACE_ONE;
@@ -3092,7 +3092,7 @@ public class ServerGamePacketListenerImpl
@@ -3114,7 +3114,7 @@ public class ServerGamePacketListenerImpl
}
} else if (ItemStack.isSameItemSameComponents(cursor, clickedItem)) {
if (clickedItem.getCount() >= 0) {
- if (clickedItem.getCount() + cursor.getCount() <= cursor.getMaxStackSize()) {
+ if (clickedItem.getCount() + cursor.getCount() <= me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(cursor)) { // Lophine - Stackable ShulkerBoxes
+ if (clickedItem.getCount() + cursor.getCount() <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(cursor)) { // Leaves - item over-stack util
// As of 1.5, this is result slots only
action = InventoryAction.PICKUP_ALL;
}
@@ -3351,6 +3351,7 @@ public class ServerGamePacketListenerImpl
@@ -3325,6 +3325,7 @@ public class ServerGamePacketListenerImpl
this.player.containerMenu.broadcastFullState();
} else {
this.player.containerMenu.broadcastChanges();
+ if (me.earthme.lophine.utils.ShulkerBoxesUtil.shouldCheck()) this.player.containerMenu.broadcastCarriedItem(); // Lophine - Stackable ShulkerBoxes
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.broadcastCarriedItem(); // Leaves - item over-stack util - force send carried item
}
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
}
@@ -3463,7 +3464,7 @@ public class ServerGamePacketListenerImpl
@@ -3435,7 +3436,7 @@ public class ServerGamePacketListenerImpl
}
boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45;
- boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize();
+ boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemStack); // Lophine - Stackable ShulkerBoxes
+ boolean flag2 = itemStack.isEmpty() || itemStack.getCount() <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
if (flag || (flag1 && !ItemStack.matches(this.player.inventoryMenu.getSlot(packet.slotNum()).getItem(), packet.itemStack()))) { // Insist on valid slot
// CraftBukkit start - Call click event
org.bukkit.inventory.InventoryView inventory = this.player.inventoryMenu.getBukkitView();
@@ -3505,6 +3506,7 @@ public class ServerGamePacketListenerImpl
@@ -3477,6 +3478,7 @@ public class ServerGamePacketListenerImpl
this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemStack);
this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemStack);
this.player.inventoryMenu.broadcastChanges();
+ if (me.earthme.lophine.utils.ShulkerBoxesUtil.shouldCheck()) this.player.containerMenu.broadcastCarriedItem(); // Lophine - Stackable ShulkerBoxes
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.sendSingleSlot(packet.slotNum(), itemStack); // Leaves - item over-stack util - force send carried item
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
} else if (flag && flag2) {
if (this.dropSpamThrottler.isUnderThreshold()) {
diff --git a/net/minecraft/world/Container.java b/net/minecraft/world/Container.java
index b382665cc125b8b5c0938e5e55984e4bf91d37ff..8ff16372df12f07e47d81fe45ad7270bb5c2b052 100644
index b382665cc125b8b5c0938e5e55984e4bf91d37ff..86cac164a2bf0e76528396e6aabbfd64cfc29559 100644
--- a/net/minecraft/world/Container.java
+++ b/net/minecraft/world/Container.java
@@ -32,6 +32,12 @@ public interface Container extends Clearable, Iterable<ItemStack> {
return Math.min(this.getMaxStackSize(), stack.getMaxStackSize());
}
+ // Leaves start - stackable shulker boxes
+ // Leaves start - item over-stack util
+ default int getMaxStackLeaves(ItemStack stack) {
+ return Math.min(this.getMaxStackSize(), me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(stack));
+ return Math.min(this.getMaxStackSize(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack));
+ }
+ // Leaves end - stackable shulker boxes
+ // Leaves end - item over-stack util
+
void setChanged();
boolean stillValid(Player player);
diff --git a/net/minecraft/world/SimpleContainer.java b/net/minecraft/world/SimpleContainer.java
index 133e042371bcf84f1935903ec57d204e3b7abd84..201599988e20219b6a99bf1594ad6c0c19e09038 100644
index d907e24d563e27acab2f2bf9711b1755ea9afd19..75170c8d3be477a6ea2a1d62018a6ab630b0e54e 100644
--- a/net/minecraft/world/SimpleContainer.java
+++ b/net/minecraft/world/SimpleContainer.java
@@ -211,7 +211,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
@@ -109,7 +113,7 @@ index 133e042371bcf84f1935903ec57d204e3b7abd84..201599988e20219b6a99bf1594ad6c0c
public void setItem(int index, ItemStack stack) {
this.items.set(index, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - stackable shulker boxes
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
this.setChanged();
}
@@ -118,114 +122,88 @@ index 133e042371bcf84f1935903ec57d204e3b7abd84..201599988e20219b6a99bf1594ad6c0c
private void moveItemsBetweenStacks(ItemStack stack, ItemStack other) {
- int maxStackSize = this.getMaxStackSize(other);
+ int maxStackSize = this.getMaxStackLeaves(other); // Leaves - stackable shulker boxes
+ int maxStackSize = this.getMaxStackLeaves(other); // Leaves - item over-stack util
int min = Math.min(stack.getCount(), maxStackSize - other.getCount());
if (min > 0) {
other.grow(min);
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
index a9cc35b4b253d9a7fd90f811af9be629b164fad0..5c548cb30565d156c6eeb316b0c0ce8be93ad0d7 100644
index b745eb5d9c68547335247910ff2ae8d5fb36349c..0c2bf0f8edb34a9011092ea94e54f7bbcee0bbbc 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -281,10 +281,45 @@ public class ItemEntity extends Entity implements TraceableEntity {
@@ -279,10 +279,15 @@ public class ItemEntity extends Entity implements TraceableEntity {
private boolean isMergable() {
ItemStack item = this.getItem();
- return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < item.getMaxStackSize(); // Paper - Alternative item-despawn-rate
+ return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(item); // Paper - Alternative item-despawn-rate // Lophine - Stackable ShulkerBoxes
+ }
+
+ // Lophine start - Stackable ShulkerBoxes
+ private boolean tryMergeShulkerBox(ItemEntity ote) {
+ ItemStack sf = this.getItem();
+ ItemStack ot = ote.getItem();
+ if (!me.earthme.lophine.utils.ShulkerBoxesUtil.checkShulkerBox(sf)) return false;
+ if (sf.getItem().equals(ot.getItem())
+ && me.earthme.lophine.utils.ShulkerBoxesUtil.emptyShulkerBoxCheck(sf)
+ && me.earthme.lophine.utils.ShulkerBoxesUtil.emptyShulkerBoxCheck(ot)
+ && Objects.equals(sf.getComponents(), ot.getComponents()) // empty block entity tags are cleaned up when spawning
+ && sf.getCount() != me.earthme.lophine.utils.ShulkerBoxesUtil.getShulkerBoxesMaxCountUnsafe()) {
+ int count = Math.min(ot.getCount(), me.earthme.lophine.utils.ShulkerBoxesUtil.getShulkerBoxesMaxCountUnsafe() - sf.getCount());
+ sf.grow(count);
+ this.setItem(sf);
+
+ this.pickupDelay = Math.max(ote.pickupDelay, this.pickupDelay);
+ this.age = Math.min(ote.getAge(), this.age);
+ ot.shrink(count);
+ if (ot.isEmpty()) {
+ ote.discard();
+ }
+ else {
+ ote.setItem(ot);
+ }
+ return true;
+ }
+ return false;
+ return this.isAlive() && this.pickupDelay != 32767 && this.age != -32768 && this.age < this.despawnRate && item.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(item); // Paper - Alternative item-despawn-rate // Leaves - item over-stack util
}
+ // Lophine end - Stackable ShulkerBoxes
private void tryToMerge(ItemEntity itemEntity) {
+ // Lophine start - Stackable ShulkerBoxes
+ if (me.earthme.lophine.utils.ShulkerBoxesUtil.shouldCheck()
+ && this.tryMergeShulkerBox(itemEntity)) {
+ // Leaves start - item over-stack util
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.tryStackItems(this, itemEntity)) {
+ return;
+ }
+ // Lophine end - Stackable ShulkerBoxes
+ // Leaves end - item over-stack util
ItemStack item = this.getItem();
ItemStack item1 = itemEntity.getItem();
if (Objects.equals(this.target, itemEntity.target) && areMergable(item, item1)) {
diff --git a/net/minecraft/world/entity/player/Inventory.java b/net/minecraft/world/entity/player/Inventory.java
index d9cb4f0ed0c4f63362c837aeef3c4194911455c9..9fbd605df26d388c01d2ed9ca6a6138651e7f9a7 100644
index a6bb436dc80daf6901dc027a6011ead4b3ed27e2..71df58ae26325a2d28b6679733c474c0c59f7654 100644
--- a/net/minecraft/world/entity/player/Inventory.java
+++ b/net/minecraft/world/entity/player/Inventory.java
@@ -149,8 +149,8 @@ public class Inventory implements Container, Nameable {
@@ -165,10 +165,12 @@ public class Inventory implements Container, Nameable {
}
private boolean hasRemainingSpaceForItem(ItemStack destination, ItemStack origin) {
+ // Leaves start - item over-stack util
return !destination.isEmpty()
- && destination.isStackable()
- && destination.getCount() < this.getMaxStackSize(destination)
+ && me.earthme.lophine.utils.ShulkerBoxesUtil.isStackable(destination) // Lophine - Stackable ShulkerBoxes
+ && destination.getCount() < me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(destination) // Lophine - Stackable ShulkerBoxes
+ && org.leavesmc.leaves.util.ItemOverstackUtils.isStackable(destination)
+ && destination.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(destination)
&& ItemStack.isSameItemSameComponents(destination, origin); // Paper - check if itemstack is stackable first
+ // Leaves end - item over-stack util
}
@@ -164,7 +164,7 @@ public class Inventory implements Container, Nameable {
// CraftBukkit start - Watch method above! :D
@@ -181,7 +183,7 @@ public class Inventory implements Container, Nameable {
}
if (this.hasRemainingSpaceForItem(itemInSlot, itemStack)) {
- remains -= (itemInSlot.getMaxStackSize() < this.getMaxStackSize() ? itemInSlot.getMaxStackSize() : this.getMaxStackSize()) - itemInSlot.getCount();
+ remains -= (me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemInSlot) < this.getMaxStackSize() ? me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemInSlot) : this.getMaxStackSize()) - itemInSlot.getCount(); // Lophine - Stackable ShulkerBoxes
+ remains -= (org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInSlot) < this.getMaxStackSize() ? org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInSlot) : this.getMaxStackSize()) - itemInSlot.getCount(); // Leaves - item over-stack util
}
if (remains <= 0) {
return itemStack.getCount();
@@ -173,7 +173,7 @@ public class Inventory implements Container, Nameable {
@@ -190,7 +192,7 @@ public class Inventory implements Container, Nameable {
ItemStack itemInOffhand = this.equipment.get(EquipmentSlot.OFFHAND);
if (this.hasRemainingSpaceForItem(itemInOffhand, itemStack)) {
- remains -= (itemInOffhand.getMaxStackSize() < this.getMaxStackSize() ? itemInOffhand.getMaxStackSize() : this.getMaxStackSize()) - itemInOffhand.getCount();
+ remains -= (me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemInOffhand) < this.getMaxStackSize() ? me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemInOffhand) : this.getMaxStackSize()) - itemInOffhand.getCount(); // Lophine - Stackable ShulkerBoxes
+ remains -= (org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInOffhand) < this.getMaxStackSize() ? org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemInOffhand) : this.getMaxStackSize()) - itemInOffhand.getCount(); // Leaves - item over-stack util
}
if (remains <= 0) {
return itemStack.getCount();
@@ -297,7 +297,7 @@ public class Inventory implements Container, Nameable {
@@ -314,7 +316,7 @@ public class Inventory implements Container, Nameable {
this.setItem(slot, item);
}
- int i = this.getMaxStackSize(item) - item.getCount();
+ int i = this.getMaxStackLeaves(item) - item.getCount();
+ int i = this.getMaxStackLeaves(item) - item.getCount(); // Leaves - item over-stack util
int min = Math.min(count, i);
if (min == 0) {
return count;
@@ -403,7 +403,7 @@ public class Inventory implements Container, Nameable {
@@ -420,7 +422,7 @@ public class Inventory implements Container, Nameable {
break;
}
- int i = stack.getMaxStackSize() - this.getItem(slotWithRemainingSpace).getCount();
+ int i = me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(stack) - this.getItem(slotWithRemainingSpace).getCount(); // Lophine - Stackable ShulkerBoxes
+ int i = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack) - this.getItem(slotWithRemainingSpace).getCount(); // Leaves - item over-stack util
if (this.add(slotWithRemainingSpace, stack.split(i)) && sendPacket && this.player instanceof ServerPlayer serverPlayer) {
serverPlayer.connection.send(this.createInventoryUpdatePacket(slotWithRemainingSpace));
}
diff --git a/net/minecraft/world/entity/player/StackedItemContents.java b/net/minecraft/world/entity/player/StackedItemContents.java
index 83ccde54c625d40dc595e000c533f60aa929bd5a..16e9ac7449761c1427a528be60e964ef737ce897 100644
index 83ccde54c625d40dc595e000c533f60aa929bd5a..6779503888e6d311758cffde582b0efbd66a33de 100644
--- a/net/minecraft/world/entity/player/StackedItemContents.java
+++ b/net/minecraft/world/entity/player/StackedItemContents.java
@@ -23,7 +23,7 @@ public class StackedItemContents {
@@ -233,12 +211,12 @@ index 83ccde54c625d40dc595e000c533f60aa929bd5a..16e9ac7449761c1427a528be60e964ef
public void accountStack(ItemStack stack) {
- this.accountStack(stack, stack.getMaxStackSize());
+ this.accountStack(stack, me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(stack)); // Lophine - Stackable Shulker Boxes
+ this.accountStack(stack, org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack)); // Leaves - item over-stack util
}
public void accountStack(ItemStack stack, int maxStackSize) {
diff --git a/net/minecraft/world/entity/vehicle/ContainerEntity.java b/net/minecraft/world/entity/vehicle/ContainerEntity.java
index feebd1610ebd3c26a337259c14f5c774dc72b937..7df6ff842e41763aec2d88d1f8a5f7503932d905 100644
index 02d2efef2dc0f0e12eac0c71fa290af706f7694d..99f109e2653eff10c011f380694bd77a76381cee 100644
--- a/net/minecraft/world/entity/vehicle/ContainerEntity.java
+++ b/net/minecraft/world/entity/vehicle/ContainerEntity.java
@@ -163,7 +163,7 @@ public interface ContainerEntity extends Container, MenuProvider {
@@ -246,62 +224,61 @@ index feebd1610ebd3c26a337259c14f5c774dc72b937..7df6ff842e41763aec2d88d1f8a5f750
this.unpackChestVehicleLootTable(null);
this.getItemStacks().set(slot, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - stackable shulker boxes
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
}
default SlotAccess getChestVehicleSlot(final int index) {
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
index a9cf0ef95b706f05060bbcd2a4f5a03c60f783d2..6c5a01b065c7daa37219a8ab2a471d93e882e756 100644
index 9b6cd35e4dfa894069238a1365db16050aa5542b..7e9bfb433a252bb4211e490365265d35590f2474 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -234,6 +234,14 @@ public abstract class AbstractContainerMenu {
return list;
@@ -295,6 +295,13 @@ public abstract class AbstractContainerMenu {
this.sendAllDataToRemote();
}
+ // Lophine start - Stackable ShulkerBoxes
+ public void boardcastChangesSigleSlot(int slot, ItemStack item) {
+ // Leaves start - item over-stack util
+ public void sendSingleSlot(int slotIndex, ItemStack item) {
+ if (this.synchronizer != null) {
+ this.synchronizer.sendSlotChange(this, slot, item);
+ this.synchronizer.sendSlotChange(this, slotIndex, item);
+ }
+ }
+ // Lophine end - Stackable ShulkerBoxes
+
public void broadcastChanges() {
for (int i = 0; i < this.slots.size(); i++) {
ItemStack item = this.slots.get(i).getItem();
@@ -427,7 +435,7 @@ public abstract class AbstractContainerMenu {
+ // Leaves end - item over-stack util
private void updateDataSlotListeners(int slotIndex, int value) {
for (ContainerListener containerListener : this.containerListeners) {
containerListener.dataChanged(this, slotIndex, value);
@@ -451,7 +458,7 @@ public abstract class AbstractContainerMenu {
&& (this.quickcraftType == 2 || carried1.getCount() >= this.quickcraftSlots.size())
&& this.canDragTo(slot1)) {
int i2 = slot1.hasItem() ? slot1.getItem().getCount() : 0;
- int min = Math.min(itemStack.getMaxStackSize(), slot1.getMaxStackSize(itemStack));
+ int min = Math.min(me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemStack), slot1.getMaxStackSize(itemStack)); // Lophine - Stackable ShulkerBoxes
+ int min = Math.min(org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack), slot1.getMaxStackSize(itemStack)); // Leaves - item over-stack util
int min1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemStack) + i2, min);
count -= min1 - i2;
// slot1.setByPlayer(itemStack.copyWithCount(min1));
@@ -541,7 +549,7 @@ public abstract class AbstractContainerMenu {
@@ -563,7 +570,7 @@ public abstract class AbstractContainerMenu {
slot.setByPlayer(carried2);
}
} else if (ItemStack.isSameItemSameComponents(carried, carried2)) {
- Optional<ItemStack> optional1 = slot.tryRemove(carried.getCount(), carried2.getMaxStackSize() - carried2.getCount(), player);
+ Optional<ItemStack> optional1 = slot.tryRemove(carried.getCount(), me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(carried2) - carried2.getCount(), player); // Lophine - Stackable ShulkerBoxes
+ Optional<ItemStack> optional1 = slot.tryRemove(carried.getCount(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(carried2) - carried2.getCount(), player); // Leaves - item over-stack util
optional1.ifPresent(itemStack2 -> {
carried2.grow(itemStack2.getCount());
slot.onTake(player, itemStack2);
@@ -603,7 +611,7 @@ public abstract class AbstractContainerMenu {
@@ -625,7 +632,7 @@ public abstract class AbstractContainerMenu {
Slot slot2 = this.slots.get(slotId);
if (slot2.hasItem()) {
ItemStack itemStack = slot2.getItem();
- this.setCarried(itemStack.copyWithCount(itemStack.getMaxStackSize()));
+ this.setCarried(itemStack.copyWithCount(me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemStack))); // Lophine - Stackable ShulkerBoxes
+ this.setCarried(itemStack.copyWithCount(org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack))); // Leaves - item over-stack util
}
} else if (clickType == ClickType.THROW && this.getCarried().isEmpty() && slotId >= 0) {
Slot slot2 = this.slots.get(slotId);
@@ -634,15 +642,15 @@ public abstract class AbstractContainerMenu {
@@ -656,15 +663,15 @@ public abstract class AbstractContainerMenu {
int maxStackSize = button == 0 ? 1 : -1;
for (int i3 = 0; i3 < 2; i3++) {
- for (int i4 = count; i4 >= 0 && i4 < this.slots.size() && itemStack.getCount() < itemStack.getMaxStackSize(); i4 += maxStackSize) {
+ for (int i4 = count; i4 >= 0 && i4 < this.slots.size() && itemStack.getCount() < me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemStack); i4 += maxStackSize) { // Lophine - Stackable ShulkerBoxes
+ for (int i4 = count; i4 >= 0 && i4 < this.slots.size() && itemStack.getCount() < org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); i4 += maxStackSize) { // Leaves - item over-stack util
Slot slot3 = this.slots.get(i4);
if (slot3.hasItem()
&& canItemQuickReplace(slot3, itemStack, true)
@@ -310,49 +287,49 @@ index a9cf0ef95b706f05060bbcd2a4f5a03c60f783d2..6c5a01b065c7daa37219a8ab2a471d93
ItemStack item1 = slot3.getItem();
- if (i3 != 0 || item1.getCount() != item1.getMaxStackSize()) {
- ItemStack itemStack1 = slot3.safeTake(item1.getCount(), itemStack.getMaxStackSize() - itemStack.getCount(), player);
+ if (i3 != 0 || item1.getCount() != me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(item1)) { // Lophine - stackable shulker boxes
+ ItemStack itemStack1 = slot3.safeTake(item1.getCount(), me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemStack) - itemStack.getCount(), player); // Lophine - stackable shulker boxes
+ if (i3 != 0 || item1.getCount() != org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(item1)) { // Leaves - item over-stack util
+ ItemStack itemStack1 = slot3.safeTake(item1.getCount(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack) - itemStack.getCount(), player); // Leaves - item over-stack util
itemStack.grow(itemStack1.getCount());
}
}
@@ -744,7 +752,7 @@ public abstract class AbstractContainerMenu {
@@ -766,7 +773,7 @@ public abstract class AbstractContainerMenu {
i = endIndex - 1;
}
- if (stack.isStackable()) {
+ if (me.earthme.lophine.utils.ShulkerBoxesUtil.isStackable(stack)) { // Lophine - Stackable ShulkerBoxes
+ if (org.leavesmc.leaves.util.ItemOverstackUtils.isStackable(stack)) { // Leaves - item over-stack util
while (!stack.isEmpty() && (reverseDirection ? i >= startIndex : i < endIndex)) {
Slot slot = this.slots.get(i);
ItemStack item = slot.getItem();
@@ -845,7 +853,7 @@ public abstract class AbstractContainerMenu {
@@ -867,7 +874,7 @@ public abstract class AbstractContainerMenu {
public static boolean canItemQuickReplace(@Nullable Slot slot, ItemStack stack, boolean stackSizeMatters) {
boolean flag = slot == null || !slot.hasItem();
return !flag && ItemStack.isSameItemSameComponents(stack, slot.getItem())
- ? slot.getItem().getCount() + (stackSizeMatters ? 0 : stack.getCount()) <= stack.getMaxStackSize()
+ ? slot.getItem().getCount() + (stackSizeMatters ? 0 : stack.getCount()) <= me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(stack) // Lophine - Stackable ShulkerBoxes
+ ? slot.getItem().getCount() + (stackSizeMatters ? 0 : stack.getCount()) <= org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack) // Leaves - item over-stack util
: flag;
}
@@ -853,7 +861,7 @@ public abstract class AbstractContainerMenu {
@@ -875,7 +882,7 @@ public abstract class AbstractContainerMenu {
return switch (type) {
case 0 -> Mth.floor((float)stack.getCount() / slots.size());
case 1 -> 1;
- case 2 -> stack.getMaxStackSize();
+ case 2 -> me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(stack); // Lophine - Stackable ShulkerBoxes
+ case 2 -> org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack); // Leaves - item over-stack util
default -> stack.getCount();
};
}
@@ -875,7 +883,7 @@ public abstract class AbstractContainerMenu {
@@ -897,7 +904,7 @@ public abstract class AbstractContainerMenu {
for (int i = 0; i < container.getContainerSize(); i++) {
ItemStack item = container.getItem(i);
if (!item.isEmpty()) {
- f += (float)item.getCount() / container.getMaxStackSize(item);
+ f += (float)item.getCount() / container.getMaxStackLeaves(item); // Leaves - stackable shulker boxes
+ f += Math.clamp((float) item.getCount() / container.getMaxStackSize(item), 0f, 1f); // Leaves - item over-stack util
}
}
diff --git a/net/minecraft/world/inventory/MerchantContainer.java b/net/minecraft/world/inventory/MerchantContainer.java
index 1e5dfb1f9e371fa23cdfa9280797aa0e183d4cd2..cf87267130c0aebd38206556261929d6f6383bc9 100644
index 1e5dfb1f9e371fa23cdfa9280797aa0e183d4cd2..1a593d5bfc4574fd071604105422cd1d395648b8 100644
--- a/net/minecraft/world/inventory/MerchantContainer.java
+++ b/net/minecraft/world/inventory/MerchantContainer.java
@@ -109,7 +109,7 @@ public class MerchantContainer implements Container {
@@ -360,12 +337,12 @@ index 1e5dfb1f9e371fa23cdfa9280797aa0e183d4cd2..cf87267130c0aebd38206556261929d6
public void setItem(int index, ItemStack stack) {
this.itemStacks.set(index, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - stackable shulker boxes
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
if (this.isPaymentSlot(index)) {
this.updateSellItem();
}
diff --git a/net/minecraft/world/inventory/Slot.java b/net/minecraft/world/inventory/Slot.java
index 5ceb8964476b40db4511bec91ff13c4f522a1357..170353b8d1d330e54d9836e78ba2d41d023e0f51 100644
index 5ceb8964476b40db4511bec91ff13c4f522a1357..f416d7976e41a06b5a8be93485eaa233ffceda5c 100644
--- a/net/minecraft/world/inventory/Slot.java
+++ b/net/minecraft/world/inventory/Slot.java
@@ -75,7 +75,7 @@ public class Slot {
@@ -373,41 +350,41 @@ index 5ceb8964476b40db4511bec91ff13c4f522a1357..170353b8d1d330e54d9836e78ba2d41d
public int getMaxStackSize(ItemStack stack) {
- return Math.min(this.getMaxStackSize(), stack.getMaxStackSize());
+ return Math.min(this.getMaxStackSize(), me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(stack)); // Lophine - Stackable ShulkerBoxes
+ return Math.min(this.getMaxStackSize(), org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(stack)); // Leaves - item over-stack util
}
@Nullable
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index 09455150810e4fb6e4637fdb9e2e8a30fe0bc247..5d2571d0199a25087954b4e67bc7551f282c6bd2 100644
index 6154da1158756cff072d7e8cae10e20eafed1eec..93bbe7b473b8150954f06602a9f311867fe9a550 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -165,7 +165,7 @@ public final class ItemStack implements DataComponentHolder {
@@ -162,7 +162,7 @@ public final class ItemStack implements DataComponentHolder {
@Deprecated
@Nullable
private Item item;
- PatchedDataComponentMap components;
+ public PatchedDataComponentMap components; // Leaves - stackable shulker boxes
+ public PatchedDataComponentMap components; // Leaves - item over-stack util
@Nullable
private Entity entityRepresentation;
@@ -192,7 +192,8 @@ public final class ItemStack implements DataComponentHolder {
@@ -189,7 +189,8 @@ public final class ItemStack implements DataComponentHolder {
} else {
Holder<Item> holder = Item.STREAM_CODEC.decode(buffer);
DataComponentPatch dataComponentPatch = codec.decode(buffer);
- return new ItemStack(holder, varInt, dataComponentPatch);
+ ItemStack itemStack = new ItemStack(holder, varInt, dataComponentPatch);
+ return me.earthme.lophine.utils.ShulkerBoxesUtil.decodeMaxStackSize(itemStack);
+ return org.leavesmc.leaves.util.ItemOverstackUtils.decodeMaxStackSize(itemStack);
}
}
@@ -201,13 +202,15 @@ public final class ItemStack implements DataComponentHolder {
@@ -198,13 +199,15 @@ public final class ItemStack implements DataComponentHolder {
if (value.isEmpty() || value.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem()
buffer.writeVarInt(0);
} else {
- buffer.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), value, value.getCount())); // Paper - potentially sanitize count
- Item.STREAM_CODEC.encode(buffer, value.getItemHolder());
+ // Leaves start - stackable shulker boxes
+ final ItemStack itemStack = me.earthme.lophine.utils.ShulkerBoxesUtil.encodeMaxStackSize(value.copy());
+ // Leaves start - item over-stack util
+ final ItemStack itemStack = org.leavesmc.leaves.util.ItemOverstackUtils.encodeMaxStackSize(value.copy());
+ buffer.writeVarInt(io.papermc.paper.util.sanitizer.ItemComponentSanitizer.sanitizeCount(io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession(), itemStack, itemStack.getCount())); // Paper - potentially sanitize count
+ Item.STREAM_CODEC.encode(buffer, itemStack.getItemHolder());
// Paper start - adventure; conditionally render translatable components
@@ -420,50 +397,17 @@ index 09455150810e4fb6e4637fdb9e2e8a30fe0bc247..5d2571d0199a25087954b4e67bc7551f
} finally {
net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(prev);
}
@@ -302,7 +305,7 @@ public final class ItemStack implements DataComponentHolder {
@@ -299,7 +302,7 @@ public final class ItemStack implements DataComponentHolder {
for (ItemStack itemStack : itemContainerContents.nonEmptyItems()) {
int count = itemStack.getCount();
- int maxStackSize = itemStack.getMaxStackSize();
+ int maxStackSize = me.earthme.lophine.utils.ShulkerBoxesUtil.getItemMaxCount(itemStack); // Leaves - stackable shulker boxes
+ int maxStackSize = org.leavesmc.leaves.util.ItemOverstackUtils.getItemStackMaxCount(itemStack); // Leaves - item over-stack util
if (count > maxStackSize) {
return DataResult.error(() -> "Item stack with count of " + count + " was larger than maximum: " + maxStackSize);
}
diff --git a/net/minecraft/world/level/block/AbstractCauldronBlock.java b/net/minecraft/world/level/block/AbstractCauldronBlock.java
index ad3f32888afd8b5f0038445a1b0fcc8cacec9fe2..ee0315ff52914666e3e3cfc38f726512e3301986 100644
--- a/net/minecraft/world/level/block/AbstractCauldronBlock.java
+++ b/net/minecraft/world/level/block/AbstractCauldronBlock.java
@@ -62,9 +62,27 @@ public abstract class AbstractCauldronBlock extends Block {
ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult
) {
CauldronInteraction cauldronInteraction = this.interactions.map().get(stack.getItem());
- return cauldronInteraction.interact(state, level, pos, player, hand, stack, hitResult.getDirection()); // Paper - pass hit direction
+ return wrapInteractor(cauldronInteraction, state, level, pos, player, hand, stack, hitResult.getDirection()); // Paper - pass hit direction // Leaves - stackable shulker boxes
}
+ // Leaves start - stackable shulker boxes
+ private InteractionResult wrapInteractor(CauldronInteraction cauldronBehavior, BlockState blockState, Level world, BlockPos blockPos, Player playerEntity, InteractionHand hand, ItemStack itemStack, net.minecraft.core.Direction hitDirection) {
+ int count = -1;
+ if (me.earthme.lophine.utils.ShulkerBoxesUtil.shouldCheck() && itemStack.getItem() instanceof net.minecraft.world.item.BlockItem bi &&
+ bi.getBlock() instanceof ShulkerBoxBlock) {
+ count = itemStack.getCount();
+ }
+ InteractionResult result = cauldronBehavior.interact(blockState, world, blockPos, playerEntity, hand, itemStack, hitDirection);
+ if (count > 0 && result.consumesAction()) {
+ ItemStack current = playerEntity.getItemInHand(hand);
+ if (current.getItem() instanceof net.minecraft.world.item.BlockItem bi && bi.getBlock() instanceof ShulkerBoxBlock) {
+ current.setCount(count);
+ }
+ }
+ return result;
+ }
+ // Leaves end - stackable shulker boxes
+
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java
index 38b03c7b02bdfc579e5e126c12de3d878e26d188..33e24f2c3b63b2d3b55dfae2f2e55869abeed055 100644
index 38b03c7b02bdfc579e5e126c12de3d878e26d188..caf31218a1aff84367da126ee1dc46b8c8a1e5d1 100644
--- a/net/minecraft/world/level/block/CrafterBlock.java
+++ b/net/minecraft/world/level/block/CrafterBlock.java
@@ -192,7 +192,7 @@ public class CrafterBlock extends BaseEntityBlock {
@@ -471,12 +415,12 @@ index 38b03c7b02bdfc579e5e126c12de3d878e26d188..33e24f2c3b63b2d3b55dfae2f2e55869
Container containerAt = HopperBlockEntity.getContainerAt(level, pos.relative(direction));
ItemStack itemStack = stack.copy();
- if (containerAt != null && (containerAt instanceof CrafterBlockEntity || stack.getCount() > containerAt.getMaxStackSize(stack))) {
+ if (containerAt != null && (containerAt instanceof CrafterBlockEntity || stack.getCount() > containerAt.getMaxStackLeaves(stack))) { // Leaves - stackable shulker boxes
+ if (containerAt != null && (containerAt instanceof CrafterBlockEntity || stack.getCount() > containerAt.getMaxStackLeaves(stack))) { // Leaves - item over-stack util
// CraftBukkit start - InventoryMoveItemEvent
org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
diff --git a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index c5b3b5e5f621f8db152aa190374ae0fe567d6828..0ca27b83151c3e7be3d681aa087fa72fb5bef0c3 100644
index 36a72a11d28f99bfe85868461925b778cc01478e..2a9f204a514d697178fb3ffac25aece0024f0347 100644
--- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -409,7 +409,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
@@ -484,25 +428,25 @@ index c5b3b5e5f621f8db152aa190374ae0fe567d6828..0ca27b83151c3e7be3d681aa087fa72f
boolean flag = !stack.isEmpty() && ItemStack.isSameItemSameComponents(itemStack, stack);
this.items.set(index, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - stackable shulker boxes
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
if (index == 0 && !flag && this.level instanceof ServerLevel serverLevel) {
this.cookingTotalTime = getTotalCookTime(serverLevel, this, this.recipeType, this.cookSpeedMultiplier); // Paper - cook speed multiplier API
this.cookingTimer = 0;
diff --git a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
index c63370fd458fb4f7190b79b1a8174fcc92d88f9c..4cca3fbbb93bb76d5d501dfad6997d909211809e 100644
index 5a094257a31f0500278a706a418e1697f8810ffb..63d6a43dab067aa4c8fb67095c455130196eef9f 100644
--- a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
@@ -148,7 +148,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
@@ -145,7 +145,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
@Override
public void setItem(int slot, ItemStack stack) {
this.getItems().set(slot, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - stackable shulker boxes
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
this.setChanged();
}
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 6f5a47a3e9452f25b318e4a7a628e917da99c96f..52032c6bbc7e1c37a50d9b7334f1830896cb462d 100644
index 5de769e7bd56bb3355c3c711d46ce5e103ea4409..8ba900fda7cce45679cde2b8b3272654129135ca 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -123,7 +123,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -510,7 +454,7 @@ index 6f5a47a3e9452f25b318e4a7a628e917da99c96f..52032c6bbc7e1c37a50d9b7334f18308
this.unpackLootTable(null);
this.getItems().set(index, stack);
- stack.limitSize(this.getMaxStackSize(stack));
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - stackable shulker boxes
+ stack.limitSize(this.getMaxStackLeaves(stack)); // Leaves - item over-stack util
}
@Override
@@ -519,10 +463,10 @@ index 6f5a47a3e9452f25b318e4a7a628e917da99c96f..52032c6bbc7e1c37a50d9b7334f18308
// Spigot start - SPIGOT-6693, SimpleContainer#setItem
ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size
- if (!stack.isEmpty() && stack.getCount() > destination.getMaxStackSize()) {
+ if (!stack.isEmpty() && (stack.getCount() > destination.getMaxStackSize() || stack.getCount() > stack.getMaxStackSize())) {
+ if (!stack.isEmpty() && (stack.getCount() > destination.getMaxStackSize() || stack.getCount() > stack.getMaxStackSize())) { // Leaves - item over-stack util
leftover = stack; // Paper - Make hoppers respect inventory max stack size
- stack = stack.split(destination.getMaxStackSize());
+ stack = stack.split(Math.min(destination.getMaxStackSize(), stack.getMaxStackSize()));
+ stack = stack.split(Math.min(destination.getMaxStackSize(), stack.getMaxStackSize())); // Leaves - item over-stack util
}
// Spigot end
IGNORE_TILE_UPDATES.set(Boolean.TRUE); // Paper - Perf: Optimize Hoppers // Folia - region threading
@@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 18 May 2025 23:48:59 +0800
Subject: [PATCH] Old nether portal collision
This patch should removed in 1.21.6 when mojang revert it.
diff --git a/net/minecraft/world/level/block/NetherPortalBlock.java b/net/minecraft/world/level/block/NetherPortalBlock.java
index 421ea9c748159ac989900427a13abe9b244dc7aa..ecdecf0484137e0f98bf41d09e0dc7dc7715fd35 100644
--- a/net/minecraft/world/level/block/NetherPortalBlock.java
+++ b/net/minecraft/world/level/block/NetherPortalBlock.java
@@ -65,7 +65,7 @@ public class NetherPortalBlock extends Block implements Portal {
@Override
protected VoxelShape getEntityInsideCollisionShape(BlockState state, BlockGetter level, BlockPos pos, Entity entity) {
- return state.getShape(level, pos);
+ return me.earthme.lophine.config.modules.misc.OldFeatureConfig.oldNetherPortalCollision ? Shapes.block() : state.getShape(level, pos); // Lophine - Old nether portal collision
}
@Override
@@ -0,0 +1,153 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 23 Jul 2025 20:28:40 +0800
Subject: [PATCH] Leaves: Redstone Shears Wrench
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/bfde470a867b74d177fe1b9a2a3ed5c49cd126c7/leaves-server/minecraft-patches/features/0009-Redstone-Shears-Wrench.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/item/ShearsItem.java b/net/minecraft/world/item/ShearsItem.java
index 8cf3e51e12f9cf98836657e722edb23943f9e866..155693a18bb641a930a000bc9b1ccfc853e1bae5 100644
--- a/net/minecraft/world/item/ShearsItem.java
+++ b/net/minecraft/world/item/ShearsItem.java
@@ -24,6 +24,30 @@ import net.minecraft.world.level.block.GrowingPlantHeadBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
+// Leaves start - shears wrench
+import net.minecraft.Util;
+import net.minecraft.network.chat.Component;
+import net.minecraft.world.level.block.ComparatorBlock;
+import net.minecraft.world.level.block.DispenserBlock;
+import net.minecraft.world.level.block.HopperBlock;
+import net.minecraft.world.level.block.ObserverBlock;
+import net.minecraft.world.level.block.RepeaterBlock;
+import net.minecraft.world.level.block.CrafterBlock;
+import net.minecraft.world.level.block.LeverBlock;
+import net.minecraft.world.level.block.CocoaBlock;
+import net.minecraft.world.level.block.TrapDoorBlock;
+import net.minecraft.world.level.block.FenceGateBlock;
+import net.minecraft.world.level.block.LightningRodBlock;
+import net.minecraft.world.level.block.RailBlock;
+import net.minecraft.world.level.block.BaseRailBlock;
+import net.minecraft.world.level.block.PoweredRailBlock;
+import net.minecraft.world.level.block.CalibratedSculkSensorBlock;
+import net.minecraft.world.level.block.piston.PistonBaseBlock;
+import net.minecraft.world.level.block.state.StateDefinition;
+import net.minecraft.world.level.block.state.properties.RailShape;
+import net.minecraft.world.level.block.state.properties.Property;
+// Leaves end - shears wrench
+
public class ShearsItem extends Item {
public ShearsItem(Item.Properties properties) {
super(properties);
@@ -80,7 +104,108 @@ public class ShearsItem extends Item {
return InteractionResult.SUCCESS;
} else {
+ // Leaves start - shears wrench
+ Block block = blockState.getBlock();
+ if (fun.bm.lophine.config.modules.misc.RedStoneConfig.shears && (
+ block instanceof ObserverBlock ||
+ block instanceof DispenserBlock ||
+ block instanceof PistonBaseBlock ||
+ block instanceof HopperBlock ||
+ block instanceof RepeaterBlock ||
+ block instanceof ComparatorBlock ||
+ block instanceof CrafterBlock ||
+ block instanceof LeverBlock ||
+ block instanceof CocoaBlock ||
+ block instanceof TrapDoorBlock ||
+ block instanceof FenceGateBlock ||
+ block instanceof LightningRodBlock ||
+ block instanceof CalibratedSculkSensorBlock ||
+ block instanceof BaseRailBlock
+ )) {
+ StateDefinition<Block, BlockState> blockstatelist = block.getStateDefinition();
+ Property<?> iblockstate;
+ if (block instanceof CrafterBlock) iblockstate = blockstatelist.getProperty("orientation");
+ else if (block instanceof BaseRailBlock) iblockstate = blockstatelist.getProperty("shape");
+ else iblockstate = blockstatelist.getProperty("facing");
+ Player player = context.getPlayer();
+
+ if (iblockstate == null || player == null) {
+ return InteractionResult.FAIL;
+ }
+
+ if (block instanceof BaseRailBlock) {
+ if (block instanceof RailBlock) {
+ if (blockState.getValue(RailBlock.SHAPE).isSlope()) {
+ return InteractionResult.FAIL;
+ }
+ } else {
+ if (getNameHelper(blockState, PoweredRailBlock.POWERED).equals("true")) {
+ return InteractionResult.FAIL;
+ }
+ if (blockState.getValue(PoweredRailBlock.SHAPE).isSlope()) {
+ return InteractionResult.FAIL;
+ }
+ }
+ }
+
+ if (block instanceof PistonBaseBlock) {
+ if (getNameHelper(blockState, PistonBaseBlock.EXTENDED).equals("true")) {
+ return InteractionResult.FAIL;
+ }
+ }
+
+ if (block instanceof RepeaterBlock || block instanceof ComparatorBlock) {
+ if (getNameHelper(blockState, ComparatorBlock.POWERED).equals("true")) {
+ return InteractionResult.FAIL;
+ }
+ if (block instanceof RepeaterBlock) {
+ if (getNameHelper(blockState, RepeaterBlock.LOCKED).equals("true")) {
+ return InteractionResult.FAIL;
+ }
+ }
+ }
+
+ if (block instanceof CrafterBlock) {
+ if (getNameHelper(blockState, CrafterBlock.CRAFTING).equals("true")) {
+ return InteractionResult.FAIL;
+ }
+ }
+
+ BlockState iblockdata1 = ShearsItem.cycleState(blockState, iblockstate, player.isSecondaryUseActive());
+ level.setBlock(clickedPos, iblockdata1, 18);
+ ShearsItem.message(player, Component.translatable("item.minecraft.debug_stick.update", iblockstate.getName(), ShearsItem.getNameHelper(iblockdata1, iblockstate)));
+ return InteractionResult.CONSUME;
+ }
+ // Leaves end - shears wrench
+
return super.useOn(context);
}
}
+
+ // Leaves start - shears wrench
+ private static <T extends Comparable<T>> BlockState cycleState(BlockState state, Property<T> property, boolean inverse) {
+ List<T> possibleValues = property.getPossibleValues();
+ if (possibleValues.getFirst() instanceof RailShape) {
+ boolean isRailBlock = state.getBlock() instanceof RailBlock;
+ possibleValues = possibleValues.stream().filter(possibleValue -> {
+ RailShape shape = (RailShape) possibleValue;
+ if (isRailBlock) return !shape.isSlope();
+ return !shape.isSlope() && shape != RailShape.NORTH_EAST && shape != RailShape.NORTH_WEST && shape != RailShape.SOUTH_EAST && shape != RailShape.SOUTH_WEST;
+ }).toList();
+ }
+ return state.setValue(property, ShearsItem.getRelative(possibleValues, state.getValue(property), inverse)); // CraftBukkit - decompile error
+ }
+
+ private static <T> T getRelative(Iterable<T> elements, T current, boolean inverse) {
+ return inverse ? Util.findPreviousInIterable(elements, current) : Util.findNextInIterable(elements, current);
+ }
+
+ private static void message(Player player, Component message) {
+ ((ServerPlayer) player).sendSystemMessage(message, true);
+ }
+
+ private static <T extends Comparable<T>> String getNameHelper(BlockState state, Property<T> property) {
+ return property.getName(state.getValue(property));
+ }
+ // Leaves end - shears wrench
}
@@ -0,0 +1,86 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 28 Jul 2025 01:06:40 +0800
Subject: [PATCH] Leaves: Vanilla hopper
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/2c9f83c7b99178851edf5608b37b8c2adddd93cd/leaves-server/minecraft-patches/features/0095-Vanilla-hopper.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 8ba900fda7cce45679cde2b8b3272654129135ca..9d7ec9f4f18ed263540ccddf16c6c1a92d3477a4 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -280,36 +280,49 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
ItemStack movedItem = origItemStack;
final int originalItemCount = origItemStack.getCount();
final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
- container.setChanged(); // original logic always marks source inv as changed even if no move happens.
- movedItem.setCount(movedItemCount);
- if (!worldData.skipPullModeEventFire) { // Folia - region threading
- movedItem = callPullMoveEvent(hopper, container, movedItem);
- if (movedItem == null) { // cancelled
+ // Leaves start - fix vanilla
+ if (fun.bm.lophine.config.modules.misc.RedStoneConfig.vanillaHopper && movedItem.getCount() <= movedItemCount) {
+ movedItem = origItemStack.copy();
+ final ItemStack remainingItem = addItem(container, hopper, container.removeItem(i, movedItemCount), null);
+ if (remainingItem.isEmpty()) {
+ container.setChanged();
+ return true;
+ }
+ container.setItem(i, movedItem);
+ } else {
+ container.setChanged(); // original logic always marks source inv as changed even if no move happens.
+ movedItem.setCount(movedItemCount);
+
+ if (!worldData.skipPullModeEventFire) {
+ movedItem = callPullMoveEvent(hopper, container, movedItem);
+ if (movedItem == null) { // cancelled
+ origItemStack.setCount(originalItemCount);
+ // Drastically improve performance by returning true.
+ // No plugin could have relied on the behavior of false as the other call
+ // site for IMIE did not exhibit the same behavior
+ return true;
+ }
+ }
+ final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
+ final int remainingItemCount = remainingItem.getCount();
+ if (remainingItemCount != movedItemCount) {
+ origItemStack = origItemStack.copy(true);
origItemStack.setCount(originalItemCount);
- // Drastically improve performance by returning true.
- // No plugin could have relied on the behavior of false as the other call
- // site for IMIE did not exhibit the same behavior
+ if (!origItemStack.isEmpty()) {
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
+ }
+
+ IGNORE_TILE_UPDATES.set(true);
+ container.setItem(i, origItemStack);
+ IGNORE_TILE_UPDATES.set(false);
+ container.setChanged();
return true;
}
- }
-
- final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
- final int remainingItemCount = remainingItem.getCount();
- if (remainingItemCount != movedItemCount) {
- origItemStack = origItemStack.copy(true);
origItemStack.setCount(originalItemCount);
- if (!origItemStack.isEmpty()) {
- origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
- }
- IGNORE_TILE_UPDATES.set(true); // Folia - region threading
- container.setItem(i, origItemStack);
- IGNORE_TILE_UPDATES.set(false); // Folia - region threading
- container.setChanged();
- return true;
}
- origItemStack.setCount(originalItemCount);
+ // Leaves end - fix vanilla
if (level.paperConfig().hopper.cooldownWhenFull) {
applyCooldown(hopper);
@@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sat, 26 Jul 2025 13:40:28 +0800
Subject: [PATCH] Paper: Fix quick craft
Co-authored by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
As a part of : Paper (https://github.com/PaperMC/Paper/pull/11831/files#diff-3991edc9191addaab9f9701589f8fb4a05001c6f3c9ce1f51d22001f8de805ca)
Licensed under: MIT (https://github.com/PaperMC/Paper/blob/main/licenses/MIT.md)
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 5369a6597e48ed9f0d8f7f0b9685ce4950df4fe5..919628d93add71d9b30cae29587a0049cce6973d 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -4012,11 +4012,6 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
return null;
} else {
double d = this.getEyeY() - 0.3F;
- // Paper start
- final ItemStack tmp = stack.copy();
- stack.setCount(0);
- stack = tmp;
- // Paper end
ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), d, this.getZ(), stack);
itemEntity.setPickUpDelay(40);
if (includeThrower) {
@@ -8,25 +8,25 @@ As part of: Purpur (https://github.com/PurpurMC/Purpur/blob/09f547de09fc5d886f18
Licensed under: MIT (https://github.com/PurpurMC/Purpur/blob/09f547de09fc5d886f18f6d99ff389289766ec9d/LICENSE)
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 001483b7098523f3645a95c81fcf0e38b551705e..3a83ba2fab530e9e64d53167d296c1f2ca1b9e4b 100644
index 5c21fc0c749973d17df690fe7e2eab597b198131..f01e3147cb49ee37d8e33d4146aa1a72cf38014f 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -1116,6 +1116,10 @@ public abstract class PlayerList {
@@ -1086,6 +1086,10 @@ public abstract class PlayerList {
player.getBukkitEntity().recalculatePermissions(); // CraftBukkit
this.server.getCommands().sendCommands(player);
} // Paper - Add sendOpLevel API
+
+ // Purpur start - Barrels and enderchests 6 rows
+ player.enderChestSlotCount = me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows < 7 && me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows > 0 ? 9 * me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows : 27;
+ player.enderChestSlotCount = fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows < 7 && fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows > 0 ? 9 * fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows : 27;
+ // Purpur end - Barrels and enderchests 6 rows
}
public boolean isWhiteListed(GameProfile profile) {
// Paper start - whitelist verify event / login event
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 34c4c195519de03ec11897160b98c80353eb3d6c..27e335e01d8f09f05a4fea5f15407dbe3a4555cb 100644
index 09b549fa9568aa1ae13b1b975db14a6268fdaa46..6c933c27ce155eb516a9ede96fb2c3bd19251bfa 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -210,6 +210,7 @@ public abstract class Player extends LivingEntity {
@@ -219,6 +219,7 @@ public abstract class Player extends LivingEntity {
private int currentImpulseContextResetGraceTime = 0;
public boolean affectsSpawning = true; // Paper - Affects Spawning API
public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage
@@ -70,7 +70,7 @@ index 0fffa384f928ab84451331380968fb4650eafe26..d84a10396395939149da88bcb01be59e
return new ChestMenu(MenuType.GENERIC_9x6, containerId, playerInventory, container, 6);
}
diff --git a/net/minecraft/world/inventory/PlayerEnderChestContainer.java b/net/minecraft/world/inventory/PlayerEnderChestContainer.java
index bc2b95973192069fc64581b59583b19df876f55d..d80a3760c0a84df19d0b2063c648f08ecef44f02 100644
index beb74bc8398de8b48f41af7daef14d624826310e..5dd6e89931d397b8afdb84024ed46b0d06dcf347 100644
--- a/net/minecraft/world/inventory/PlayerEnderChestContainer.java
+++ b/net/minecraft/world/inventory/PlayerEnderChestContainer.java
@@ -25,11 +25,18 @@ public class PlayerEnderChestContainer extends SimpleContainer {
@@ -78,7 +78,7 @@ index bc2b95973192069fc64581b59583b19df876f55d..d80a3760c0a84df19d0b2063c648f08e
public PlayerEnderChestContainer(Player owner) {
- super(27);
+ super(me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows < 7 && me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows > 0 ? 9 * me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows : 27);
+ super(fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows < 7 && fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows > 0 ? 9 * fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows : 27);
this.owner = owner;
// CraftBukkit end
}
@@ -94,7 +94,7 @@ index bc2b95973192069fc64581b59583b19df876f55d..d80a3760c0a84df19d0b2063c648f08e
this.activeChest = enderChestBlockEntity;
}
diff --git a/net/minecraft/world/level/block/EnderChestBlock.java b/net/minecraft/world/level/block/EnderChestBlock.java
index 5077a9ff7b78801bdc53536a37aee07b8d86ee4d..c7866aa9a3647d3285eb0996fbc55e1b15a4c40c 100644
index 5077a9ff7b78801bdc53536a37aee07b8d86ee4d..fe374f08b7829b846b2a1c2ac3ca500ca3e48684 100644
--- a/net/minecraft/world/level/block/EnderChestBlock.java
+++ b/net/minecraft/world/level/block/EnderChestBlock.java
@@ -85,8 +85,14 @@ public class EnderChestBlock extends AbstractChestBlock<EnderChestBlockEntity> i
@@ -103,7 +103,7 @@ index 5077a9ff7b78801bdc53536a37aee07b8d86ee4d..c7866aa9a3647d3285eb0996fbc55e1b
new SimpleMenuProvider(
- (containerId, playerInventory, player1) -> ChestMenu.threeRows(containerId, playerInventory, enderChestInventory), CONTAINER_TITLE
- )
+ (containerId, playerInventory, player1) -> switch (me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows) {
+ (containerId, playerInventory, player1) -> switch (fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows) {
+ case 6 -> ChestMenu.sixRows(containerId, playerInventory, enderChestInventory);
+ case 5 -> ChestMenu.fiveRows(containerId, playerInventory, enderChestInventory);
+ case 4 -> ChestMenu.fourRows(containerId, playerInventory, enderChestInventory);
@@ -115,7 +115,7 @@ index 5077a9ff7b78801bdc53536a37aee07b8d86ee4d..c7866aa9a3647d3285eb0996fbc55e1b
// Paper end - Fix InventoryOpenEvent cancellation - moved up;
player.awardStat(Stats.OPEN_ENDERCHEST);
diff --git a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
index 027502d0af5512c31878978c4d05c52fa3029cca..4716015da322ed1f41c9f81d5ff0695914e7b6e3 100644
index d679ab599dfd0bdbdc3ab5530d7fcd1c38baf7fa..6b4e2956222a0ca7f72f73032dc98878fbd257ee 100644
--- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
@@ -56,7 +56,17 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
@@ -124,7 +124,7 @@ index 027502d0af5512c31878978c4d05c52fa3029cca..4716015da322ed1f41c9f81d5ff06959
- private NonNullList<ItemStack> items = NonNullList.withSize(27, ItemStack.EMPTY);
+ // Purpur start - Barrels and enderchests 6 rows
+ private NonNullList<ItemStack> items = NonNullList.withSize(switch (me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.barrelRows) {
+ private NonNullList<ItemStack> items = NonNullList.withSize(switch (fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.barrelRows) {
+ case 6 -> 54;
+ case 5 -> 45;
+ case 4 -> 36;
@@ -143,7 +143,7 @@ index 027502d0af5512c31878978c4d05c52fa3029cca..4716015da322ed1f41c9f81d5ff06959
public int getContainerSize() {
- return 27;
+ // Purpur start - Barrels and enderchests 6 rows
+ return switch (me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.barrelRows) {
+ return switch (fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.barrelRows) {
+ case 6 -> 54;
+ case 5 -> 45;
+ case 4 -> 36;
@@ -161,7 +161,7 @@ index 027502d0af5512c31878978c4d05c52fa3029cca..4716015da322ed1f41c9f81d5ff06959
protected AbstractContainerMenu createMenu(int id, Inventory player) {
- return ChestMenu.threeRows(id, player, this);
+ // Purpur start - Barrels and enderchests 6 rows
+ return switch (me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.barrelRows) {
+ return switch (fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.barrelRows) {
+ case 6 -> ChestMenu.sixRows(id, player, this);
+ case 5 -> ChestMenu.fiveRows(id, player, this);
+ case 4 -> ChestMenu.fourRows(id, player, this);
@@ -5,10 +5,10 @@ Subject: [PATCH] Spawn invulnerable time
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 1764875b9024569671bf2be537afb8b492f79102..473f9de0908d3fb2cfb640ff7c6f7b78c1280721 100644
index b7bc75648634aefc549a69631ab6e401eb902e7d..0e2d575200f3ff3ec1600a0663152e3c37ea67b0 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -221,6 +221,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -232,6 +232,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private int lastSentFood = -99999999;
private boolean lastFoodSaturationZero = true;
public int lastSentExp = -99999999;
@@ -16,20 +16,20 @@ index 1764875b9024569671bf2be537afb8b492f79102..473f9de0908d3fb2cfb640ff7c6f7b78
private ChatVisiblity chatVisibility = ChatVisiblity.FULL;
public ParticleStatus particleStatus = ParticleStatus.ALL;
private boolean canChatColor = true;
@@ -923,6 +924,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -925,6 +926,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.tickClientLoadTimeout();
this.gameMode.tick();
this.wardenSpawnTracker.tick();
+ if (me.earthme.lophine.config.modules.misc.OldFeatureConfig.spawnInvulnerableTime && this.invulnerableTime > 0) --this.spawnInvulnerableTime; // Lophine - spawn invulnerable time
+ if (this.spawnInvulnerableTime > 0) --this.spawnInvulnerableTime; // Lophine - spawn invulnerable time
if (this.invulnerableTime > 0) {
this.invulnerableTime--;
}
@@ -1420,6 +1422,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@@ -1431,6 +1433,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
if (this.isInvulnerableTo(level, damageSource)) {
return false;
} else {
+ // Lophine start - spawn invulnerable time
+ if (me.earthme.lophine.config.modules.misc.OldFeatureConfig.spawnInvulnerableTime) {
+ if (fun.bm.lophine.config.modules.misc.OldFeatureConfig.spawnInvulnerableTime) {
+ if (this.spawnInvulnerableTime > 0 && !damageSource.is(net.minecraft.tags.DamageTypeTags.BYPASSES_INVULNERABILITY)) {
+ return false;
+ }
@@ -0,0 +1,21 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Mon, 7 Jul 2025 15:33:57 +0800
Subject: [PATCH] Old Explosion Damage Calculator
Co-authored by: MC_XiaoHei <xor7xiaohei@gmail.com>
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/3e96b237749a960f297f211d439ffc9ea7fd2381/leaves-server/minecraft-patches/features/0134-Old-wet-tnt-explode-behavior.patch)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index b3e897a4afee742b5055d652ad7047a660d8ea04..cf8869fac003c73024634078b2f7b36cddda640e 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -729,6 +729,7 @@ public class ServerExplosion implements Explosion {
public boolean shouldAffectBlocklikeEntities() {
boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
boolean flag = this.source == null || this.source.getType() != EntityType.BREEZE_WIND_CHARGE && this.source.getType() != EntityType.WIND_CHARGE;
+ if (fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldExplosionDamageCalculator) flag = flag && (this.source == null || !this.source.isInWater()); // Leaves - Old MC TNT wet explosion no item damage
return _boolean ? flag : this.blockInteraction.shouldAffectBlocklikeEntities() && flag;
}
@@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Wed, 18 Jun 2025 14:24:54 +0800
Subject: [PATCH] Old replaceable by mushrooms
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 93d722d437121e605cee0e168ac17ee9bef0610e..cb2a2fbd17157726b285665fdca0ab9663e0d1de 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1111,7 +1111,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
if (worldData.captureTreeGeneration) { // Folia - region threading
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
BlockState type = getBlockState(pos);
- if (!type.isDestroyable()) return false;
+ if (!type.isDestroyable() && !(fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldReplaceableByMushrooms && flags == 3)) return false;
// Paper end - Protect Bedrock and End Portal/Frames from being destroyed
CraftBlockState blockstate = worldData.capturedBlockStates.get(pos); // Folia - region threading
if (blockstate == null) {
diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java
index 834e27ef2f7b342b074ff9e1e390e02f3ca1c399..f5765e3bbf9e735d6f959e1bf6ee1846ee11b4e9 100644
--- a/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -770,6 +770,14 @@ public abstract class BlockBehaviour implements FeatureElement {
return this.solidRender;
}
+ public boolean mushroomCheck(BlockState state) {
+ BlockState blockState = state.asState();
+ if (blockState.canOcclude()) {
+ return !Block.isShapeFullBlock(blockState.getOcclusionShape());
+ }
+ return true;
+ }
+
public final boolean canOcclude() { // Paper - Perf: Final for inlining
return this.canOcclude;
}
diff --git a/net/minecraft/world/level/levelgen/feature/AbstractHugeMushroomFeature.java b/net/minecraft/world/level/levelgen/feature/AbstractHugeMushroomFeature.java
index 3a37d66ab3c27c9abd60f35ef3bf3a93f8d7c3cd..2aad65d76cdd0800ac593a5bb3ce84ad1925eab0 100644
--- a/net/minecraft/world/level/levelgen/feature/AbstractHugeMushroomFeature.java
+++ b/net/minecraft/world/level/levelgen/feature/AbstractHugeMushroomFeature.java
@@ -26,7 +26,7 @@ public abstract class AbstractHugeMushroomFeature extends Feature<HugeMushroomFe
protected void placeMushroomBlock(LevelAccessor level, BlockPos.MutableBlockPos mutablePos, BlockState state) {
BlockState blockState = level.getBlockState(mutablePos);
- if (blockState.isAir() || blockState.is(BlockTags.REPLACEABLE_BY_MUSHROOMS)) {
+ if (blockState.isAir() || blockState.is(BlockTags.REPLACEABLE_BY_MUSHROOMS) || (fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldReplaceableByMushrooms && state.mushroomCheck(blockState))) { // Lophine - old replaceable by mushrooms
this.setBlock(level, mutablePos, state);
}
}
@@ -5,15 +5,15 @@ Subject: [PATCH] Old zombie reinforcement
diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
index 4395947fc8c719864ac2afde5e6bbb53da5129c2..348e2b6020de8584b512ec849a5fba484380930e 100644
index 14d0758aca54d9a25e369dfa8c89c930f27946c9..6f1f26b7f759e56f843e674167470da943785728 100644
--- a/net/minecraft/world/entity/monster/Zombie.java
+++ b/net/minecraft/world/entity/monster/Zombie.java
@@ -342,7 +342,7 @@ public class Zombie extends Monster {
@@ -341,7 +341,7 @@ public class Zombie extends Monster {
int floor = Mth.floor(this.getX());
int floor1 = Mth.floor(this.getY());
int floor2 = Mth.floor(this.getZ());
- EntityType<? extends Zombie> type = this.getType();
+ EntityType<? extends Zombie> type = me.earthme.lophine.config.modules.misc.OldFeatureConfig.oldZombieReinforcement ? EntityType.ZOMBIE : this.getType(); // Lophine - old zombie reinforcement
+ EntityType<? extends Zombie> type = fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldZombieReinforcement ? EntityType.ZOMBIE : this.getType(); // Lophine - old zombie reinforcement
Zombie zombie = type.create(level, EntitySpawnReason.REINFORCEMENT);
if (zombie == null) {
return true;
@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Thu, 12 Jun 2025 04:44:24 +0800
Subject: [PATCH] I18n support
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index c6c6432c2efeb7b95c2894b188cd966321ae3186..1cd9af71ee66df5f277748c0a5a59a30bd57accc 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -172,6 +172,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
// Paper end - initialize global and world-defaults configuration
me.earthme.luminol.config.ConfigManager.loadConfigFiles(); // Luminol - load config file
+ fun.bm.lophine.utils.ServerI18nUtil.init(); // Lophine - I18n support
if (false) this.server.spark.enableEarlyIfRequested(); // Paper - spark // Luminol - Force disable builtin spark
// Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save
if (this.convertOldUsers()) {
@@ -57,18 +57,19 @@ index 22125dbe1765f930fe10fe420be1c275ec553139..d5b070d1a3d84e228960dacd614e0f1a
final @Nullable Component history = this.getHistory();
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
index e3c5f4c31f084294a59830f3e764921433dd80d5..8b08a578102caf078efb15565ae3006c6eb50662 100644
index 4ada790812957657d580cb748077c4961987d0cb..3a539df860305e777e85ed6dc72b5effe76734b4 100644
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
@@ -32,6 +32,7 @@ public record ServerBuildInfoImpl(
@@ -31,7 +31,7 @@ public record ServerBuildInfoImpl(
private static final String ATTRIBUTE_GIT_COMMIT = "Git-Commit";
private static final String BRAND_PAPER_NAME = "Paper";
private static final String BRAND_LUMINOL_NAME = "Luminol";
- private static final String BRAND_LUMINOL_NAME = "Luminol";
+ private static final String BRAND_LOPHINE_NAME = "Lophine";
private static final String BUILD_DEV = "DEV";
@@ -43,9 +44,9 @@ public record ServerBuildInfoImpl(
@@ -43,9 +43,9 @@ public record ServerBuildInfoImpl(
this(
getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID)
.map(Key::key)
@@ -77,10 +78,10 @@ index e3c5f4c31f084294a59830f3e764921433dd80d5..8b08a578102caf078efb15565ae3006c
getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME)
- .orElse(BRAND_LUMINOL_NAME), // Folia // Luminol
+ .orElse(BRAND_LOPHINE_NAME), // Folia // Luminol // Lophine
SharedConstants.getCurrentVersion().getId(),
SharedConstants.getCurrentVersion().getName(),
SharedConstants.getCurrentVersion().id(),
SharedConstants.getCurrentVersion().name(),
getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER)
@@ -62,7 +63,7 @@ public record ServerBuildInfoImpl(
@@ -62,7 +62,7 @@ public record ServerBuildInfoImpl(
@Override
public boolean isBrandCompatible(final @NotNull Key brandId) {
@@ -89,317 +90,8 @@ index e3c5f4c31f084294a59830f3e764921433dd80d5..8b08a578102caf078efb15565ae3006c
}
@Override
diff --git a/src/main/java/me/earthme/luminol/commands/LuminolConfigCommand.java b/src/main/java/me/earthme/luminol/commands/LuminolConfigCommand.java
index fb63e2a3205ea9f7aaee0ff0f4dc0cc1a5268507..645f2f41de74f4461685c753dcd6cfc5dfa8b2ab 100644
--- a/src/main/java/me/earthme/luminol/commands/LuminolConfigCommand.java
+++ b/src/main/java/me/earthme/luminol/commands/LuminolConfigCommand.java
@@ -13,11 +13,17 @@ import java.util.ArrayList;
import java.util.List;
public class LuminolConfigCommand extends Command {
- public LuminolConfigCommand() {
- super("luminolconfig");
- this.setPermission("luminol.commands.luminolconfig");
+ private LuminolConfig config;
+
+ public LuminolConfigCommand(String name) {
+ super(name + "config");
+ this.setPermission(name + ".commands." + name + "config");
this.setDescription("Manage config file");
- this.setUsage("/luminolconfig");
+ this.setUsage("/" + name + "config");
+ }
+
+ public void initConfig(LuminolConfig config) {
+ this.config = config;
}
public void wrongUse(CommandSender sender) {
@@ -38,7 +44,7 @@ public class LuminolConfigCommand extends Command {
result.add("reset");
result.add("reload");
} else if (args.length == 2 && (args[0].equals("query") || args[0].equals("set") || args[0].equals("reset"))) {
- result.addAll(LuminolConfig.completeConfigPath(args[1]));
+ result.addAll(config.completeConfigPath(args[1]));
}
return result;
}
@@ -59,7 +65,7 @@ public class LuminolConfigCommand extends Command {
switch (args[0]) {
case "reload" -> {
- LuminolConfig.reloadAsync().thenAccept(nullValue -> sender.sendMessage(
+ config.reloadAsync().thenAccept(nullValue -> sender.sendMessage(
Component
.text("Reloaded config file!")
.color(TextColor.color(0, 255, 0))
@@ -69,8 +75,8 @@ public class LuminolConfigCommand extends Command {
if (args.length == 2 || args.length > 3) {
wrongUse(sender);
return true;
- } else if (LuminolConfig.setConfig(args[1], args[2])) {
- LuminolConfig.reloadAsync().thenAccept(nullValue -> sender.sendMessage(
+ } else if (config.setConfig(args[1], args[2])) {
+ config.reloadAsync().thenAccept(nullValue -> sender.sendMessage(
Component
.text("Set Config " + args[1] + " to " + args[2] + " successfully!")
.color(TextColor.color(0, 255, 0))
@@ -88,10 +94,10 @@ public class LuminolConfigCommand extends Command {
wrongUse(sender);
return true;
} else {
- LuminolConfig.resetConfig(args[1]);
- LuminolConfig.reloadAsync().thenAccept(nullValue -> sender.sendMessage(
+ config.resetConfig(args[1]);
+ config.reloadAsync().thenAccept(nullValue -> sender.sendMessage(
Component
- .text("Reset Config " + args[1] + " to " + LuminolConfig.getConfig(args[1]) + " successfully!")
+ .text("Reset Config " + args[1] + " to " + config.getConfig(args[1]) + " successfully!")
.color(TextColor.color(0, 255, 0))
));
}
@@ -103,7 +109,7 @@ public class LuminolConfigCommand extends Command {
} else {
sender.sendMessage(
Component
- .text("Config " + args[1] + " is " + LuminolConfig.getConfig(args[1]) + "!")
+ .text("Config " + args[1] + " is " + config.getConfig(args[1]) + "!")
.color(TextColor.color(0, 255, 0))
);
}
diff --git a/src/main/java/me/earthme/luminol/config/LuminolConfig.java b/src/main/java/me/earthme/luminol/config/LuminolConfig.java
index 57b1f606d2f4197e1f68d367bf63e04ce2fe1534..01f109fc02590d22a42676f35f23ae72ed08ac36 100644
--- a/src/main/java/me/earthme/luminol/config/LuminolConfig.java
+++ b/src/main/java/me/earthme/luminol/config/LuminolConfig.java
@@ -29,22 +29,33 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class LuminolConfig {
- public static final Logger logger = LogManager.getLogger();
- private static final File baseConfigFolder = new File("luminol_config");
- private static final File baseConfigFile = new File(baseConfigFolder, "luminol_global_config.toml");
- private static final Set<IConfigModule> allInstanced = new HashSet<>();
- private static final Map<String, Object> stagedConfigMap = new HashMap<>();
- private static final Map<String, Object> defaultvalueMap = new HashMap<>();
- public static boolean alreadyInit = false;
- private static CommentedFileConfig configFileInstance;
-
- public static void setupLatch() {
- Bukkit.getCommandMap().register("luminolconfig", "luminol", new LuminolConfigCommand());
+ public final Logger logger = LogManager.getLogger();
+ private final File baseConfigFolder;
+ private final File baseConfigFile;
+ private final String name;
+ private final String pack;
+ private final Set<IConfigModule> allInstanced = new HashSet<>();
+ private final Map<String, Object> stagedConfigMap = new HashMap<>();
+ private final Map<String, Object> defaultvalueMap = new HashMap<>();
+ public boolean alreadyInit = false;
+ private CommentedFileConfig configFileInstance;
+
+ public LuminolConfig(@NotNull File base, @NotNull String name, @NotNull String pack) {
+ this.baseConfigFolder = base;
+ this.name = name;
+ this.pack = pack;
+ this.baseConfigFile = new File(base, name + "_global_config.toml");
+ }
+
+ public void setupLatch() {
+ LuminolConfigCommand command = new LuminolConfigCommand(name);
+ Bukkit.getCommandMap().register(name + "config", name, command);
+ command.initConfig(this);
alreadyInit = true;
}
- public static void reload() {
- RegionizedServer.ensureGlobalTickThread("Reload luminol config off global region thread!");
+ public void reload() {
+ RegionizedServer.ensureGlobalTickThread("Reload " + name + " config off global region thread!");
dropAllInstanced();
try {
@@ -56,8 +67,8 @@ public class LuminolConfig {
}
@Contract(" -> new")
- public static @NotNull CompletableFuture<Void> reloadAsync() {
- return CompletableFuture.runAsync(LuminolConfig::reload, task -> RegionizedServer.getInstance().addTask(() -> {
+ public @NotNull CompletableFuture<Void> reloadAsync() {
+ return CompletableFuture.runAsync(this::reload, task -> RegionizedServer.getInstance().addTask(() -> {
try {
task.run();
} catch (Exception e) {
@@ -66,17 +77,17 @@ public class LuminolConfig {
}));
}
- public static void dropAllInstanced() {
+ public void dropAllInstanced() {
allInstanced.clear();
}
- public static void finalizeLoadConfig() {
+ public void finalizeLoadConfig() {
for (IConfigModule module : allInstanced) {
module.onLoaded(configFileInstance);
}
}
- public static void preLoadConfig() throws IOException {
+ public void preLoadConfig() throws IOException {
baseConfigFolder.mkdirs();
if (!baseConfigFile.exists()) {
@@ -98,21 +109,21 @@ public class LuminolConfig {
saveConfigs();
}
- private static void loadAllModules() throws IllegalAccessException {
+ private void loadAllModules() throws IllegalAccessException {
for (IConfigModule instanced : allInstanced) {
loadForSingle(instanced);
}
}
- private static void instanceAllModule() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
- for (Class<?> clazz : getClasses("me.earthme.luminol.config.modules")) {
+ private void instanceAllModule() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+ for (Class<?> clazz : getClasses(pack)) {
if (IConfigModule.class.isAssignableFrom(clazz)) {
allInstanced.add((IConfigModule) clazz.getConstructor().newInstance());
}
}
}
- private static void loadForSingle(@NotNull IConfigModule singleConfigModule) throws IllegalAccessException {
+ private void loadForSingle(@NotNull IConfigModule singleConfigModule) throws IllegalAccessException {
final EnumConfigCategory category = singleConfigModule.getCategory();
Field[] fields = singleConfigModule.getClass().getDeclaredFields();
@@ -203,7 +214,7 @@ public class LuminolConfig {
}
}
- public static void removeConfig(String name, String[] keys) {
+ public void removeConfig(String name, String[] keys) {
configFileInstance.remove(name);
Object configAtPath = configFileInstance.get(String.join(".", keys));
if (configAtPath instanceof UnmodifiableConfig && ((UnmodifiableConfig) configAtPath).isEmpty()) {
@@ -211,7 +222,7 @@ public class LuminolConfig {
}
}
- public static void removeConfig(String[] keys) {
+ public void removeConfig(String[] keys) {
configFileInstance.remove(String.join(".", keys));
Object configAtPath = configFileInstance.get(String.join(".", Arrays.copyOfRange(keys, 1, keys.length)));
if (configAtPath instanceof UnmodifiableConfig && ((UnmodifiableConfig) configAtPath).isEmpty()) {
@@ -219,11 +230,11 @@ public class LuminolConfig {
}
}
- public static boolean setConfig(String[] keys, Object value) {
+ public boolean setConfig(String[] keys, Object value) {
return setConfig(String.join(".", keys), value);
}
- public static boolean setConfig(String key, Object value) {
+ public boolean setConfig(String key, Object value) {
if (configFileInstance.contains(key) && configFileInstance.get(key) != null) {
stagedConfigMap.put(key, value);
return true;
@@ -231,7 +242,7 @@ public class LuminolConfig {
return false;
}
- private static Object tryTransform(Class<?> targetType, Object value) {
+ private Object tryTransform(Class<?> targetType, Object value) {
if (!targetType.isAssignableFrom(value.getClass())) {
try {
if (targetType == Integer.class) {
@@ -255,27 +266,27 @@ public class LuminolConfig {
return value;
}
- public static void saveConfigs() {
+ public void saveConfigs() {
configFileInstance.save();
}
- public static void resetConfig(String[] keys) {
+ public void resetConfig(String[] keys) {
resetConfig(String.join(".", keys));
}
- public static void resetConfig(String key) {
+ public void resetConfig(String key) {
stagedConfigMap.put(key, null);
}
- public static String getConfig(String[] keys) {
+ public String getConfig(String[] keys) {
return getConfig(String.join(".", keys));
}
- public static String getConfig(String key) {
+ public String getConfig(String key) {
return configFileInstance.get(key).toString();
}
- public static List<String> completeConfigPath(String partialPath) {
+ public List<String> completeConfigPath(String partialPath) {
List<String> allPaths = getAllConfigPaths(partialPath);
List<String> result = new ArrayList<>();
@@ -295,13 +306,13 @@ public class LuminolConfig {
return result;
}
- private static List<String> getAllConfigPaths(String currentPath) {
+ private List<String> getAllConfigPaths(String currentPath) {
return defaultvalueMap.keySet().stream()
.filter(k -> k.startsWith(currentPath))
.toList();
}
- public static @NotNull Set<Class<?>> getClasses(String pack) {
+ public @NotNull Set<Class<?>> getClasses(String pack) {
Set<Class<?>> classes = new LinkedHashSet<>();
String packageDirName = pack.replace('.', '/');
Enumeration<URL> dirs;
@@ -332,7 +343,7 @@ public class LuminolConfig {
return classes;
}
- private static void findClassesInPackageByFile(String packageName, String packagePath, Set<Class<?>> classes) {
+ private void findClassesInPackageByFile(String packageName, String packagePath, Set<Class<?>> classes) {
File dir = new File(packagePath);
if (!dir.exists() || !dir.isDirectory()) {
@@ -356,7 +367,7 @@ public class LuminolConfig {
}
}
- private static void findClassesInPackageByJar(String packageName, Enumeration<JarEntry> entries, String packageDirName, Set<Class<?>> classes) {
+ private void findClassesInPackageByJar(String packageName, Enumeration<JarEntry> entries, String packageDirName, Set<Class<?>> classes) {
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
index ded1f0667327a70a923ebda55c41b1c9094d3e37..57ddc0832b919b115b85c81ac30f136e32f1e77e 100644
--- a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
+++ b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java
@@ -6,7 +6,7 @@ import me.earthme.luminol.config.flags.ConfigInfo;
public class ServerModNameConfig implements IConfigModule {
@ConfigInfo(baseName = "name")
- public static String serverModName = "Luminol";
+ public static String serverModName = "Lophine";
@ConfigInfo(baseName = "vanilla_spoof")
public static boolean fakeVanilla = false;
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
index 9699d7dcca5cf67f50ad05c0e875de424a4e00c5..1c3b94a2592cff74924cf9b355e30b0fa182b79b 100644
index 9699d7dcca5cf67f50ad05c0e875de424a4e00c5..2c546d470013d4daf3ddf427ab4bda1b51d6e641 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
@@ -11,7 +11,7 @@ public final class Versioning {
@@ -407,7 +99,7 @@ index 9699d7dcca5cf67f50ad05c0e875de424a4e00c5..1c3b94a2592cff74924cf9b355e30b0f
String result = "Unknown-Version";
- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/me.earthme.luminol/luminol-api/pom.properties"); // Folia //Luminol
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/me.earthme.lophine/lophine-api/pom.properties"); // Folia //Luminol
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/fun.bm.lophine/lophine-api/pom.properties"); // Folia //Luminol
Properties properties = new Properties();
if (stream != null) {
@@ -5,17 +5,17 @@ Subject: [PATCH] Purpur-Barrels-and-enderchests-6-rows
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
index c00ddfe41439954fa0fd87c0933f274c8a752eb6..ac0218fcdf9e9c77a30b7f09b2a5e557ef0f7591 100644
index 2f41a92465b9da28e026297cc3528898bb1c8412..fb5300ec1bd19b3dfd6a2b4106440b9f73c48205 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
@@ -150,9 +150,26 @@ public class CraftContainer extends AbstractContainerMenu {
@@ -148,9 +148,26 @@ public class CraftContainer extends AbstractContainerMenu {
case PLAYER:
case CHEST:
case ENDER_CHEST:
- case BARREL:
- this.delegate = new ChestMenu(net.minecraft.world.inventory.MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9);
+ // Purpur start - Barrels and enderchests 6 rows
+ this.delegate = new ChestMenu(switch (me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows) {
+ this.delegate = new ChestMenu(switch (fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.enderchestRows) {
+ case 6 -> net.minecraft.world.inventory.MenuType.GENERIC_9x6;
+ case 5 -> net.minecraft.world.inventory.MenuType.GENERIC_9x5;
+ case 4 -> net.minecraft.world.inventory.MenuType.GENERIC_9x4;
@@ -25,7 +25,7 @@ index c00ddfe41439954fa0fd87c0933f274c8a752eb6..ac0218fcdf9e9c77a30b7f09b2a5e557
+ }, windowId, bottom, top, top.getContainerSize() / 9);
break;
+ case BARREL:
+ this.delegate = new ChestMenu(switch (me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.barrelRows) {
+ this.delegate = new ChestMenu(switch (fun.bm.lophine.config.modules.misc.ContainerExpansionConfig.barrelRows) {
+ case 6 -> net.minecraft.world.inventory.MenuType.GENERIC_9x6;
+ case 5 -> net.minecraft.world.inventory.MenuType.GENERIC_9x5;
+ case 4 -> net.minecraft.world.inventory.MenuType.GENERIC_9x4;
@@ -1,154 +0,0 @@
--- /dev/null
+++ b/src/main/java/dev/tr7zw/entityculling/CullTask.java
@@ -1,0 +_,151 @@
+package dev.tr7zw.entityculling;
+
+import ca.spottedleaf.moonrise.common.util.TickThread;
+import com.logisticscraft.occlusionculling.OcclusionCullingInstance;
+import com.logisticscraft.occlusionculling.util.Vec3d;
+import dev.tr7zw.entityculling.versionless.access.Cullable;
+import me.earthme.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.decoration.ArmorStand;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.phys.AABB;
+import net.minecraft.world.phys.Vec3;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class CullTask implements Runnable {
+
+ private volatile boolean requestCull = false;
+ private volatile boolean scheduleNext = true;
+ private volatile boolean inited = false;
+
+ private final OcclusionCullingInstance culling;
+ private final Player checkTarget;
+
+ private final int hitboxLimit;
+
+ public long lastCheckedTime = 0;
+
+ // reused preallocated vars
+ private final Vec3d lastPos = new Vec3d(0, 0, 0);
+ private final Vec3d aabbMin = new Vec3d(0, 0, 0);
+ private final Vec3d aabbMax = new Vec3d(0, 0, 0);
+
+ private static final Executor backgroundWorker = Executors.newCachedThreadPool(task -> {
+ final TickThread worker = new TickThread("EntityCulling") {
+ @Override
+ public void run() {
+ task.run();
+ }
+ };
+
+ worker.setDaemon(true);
+
+ return worker;
+ });
+
+ private final Executor worker;
+
+ public CullTask(
+ OcclusionCullingInstance culling,
+ Player checkTarget,
+ int hitboxLimit,
+ long checkIntervalMs
+ ) {
+ this.culling = culling;
+ this.checkTarget = checkTarget;
+ this.hitboxLimit = hitboxLimit;
+ this.worker = CompletableFuture.delayedExecutor(checkIntervalMs, TimeUnit.MILLISECONDS, backgroundWorker);
+ }
+
+ public void requestCullSignal() {
+ this.requestCull = true;
+ }
+
+ public void signalStop() {
+ this.scheduleNext = false;
+ }
+
+ public void setup() {
+ if (!this.inited)
+ this.inited = true;
+ else
+ return;
+ this.worker.execute(this);
+ }
+
+ @Override
+ public void run() {
+ try {
+ if (this.checkTarget.tickCount > 10) {
+ // getEyePosition can use a fixed delta as its debug only anyway
+ Vec3 cameraMC = this.checkTarget.getEyePosition(0);
+ if (requestCull || !(cameraMC.x == lastPos.x && cameraMC.y == lastPos.y && cameraMC.z == lastPos.z)) {
+ long start = System.currentTimeMillis();
+
+ requestCull = false;
+
+ lastPos.set(cameraMC.x, cameraMC.y, cameraMC.z);
+ culling.resetCache();
+
+ cullEntities(cameraMC, lastPos);
+
+ lastCheckedTime = (System.currentTimeMillis() - start);
+ }
+ }
+ }finally {
+ if (this.scheduleNext) {
+ this.worker.execute(this);
+ }
+ }
+ }
+
+ private void cullEntities(Vec3 cameraMC, Vec3d camera) {
+ for (Entity entity : this.checkTarget.level().getEntities().getAll()) {
+ if (!(entity instanceof Cullable cullable)) {
+ continue; // Not sure how this could happen outside from mixin screwing up the inject into
+ // Entity
+ }
+
+ if (entity.getType().skipRaytracningCheck) {
+ continue;
+ }
+
+ if (!cullable.isForcedVisible()) {
+ if (entity.isCurrentlyGlowing() || isSkippableArmorstand(entity)) {
+ cullable.setCulled(false);
+ continue;
+ }
+
+ if (!entity.position().closerThan(cameraMC, RayTrackingEntityTrackerConfig.tracingDistance)) {
+ cullable.setCulled(false); // If your entity view distance is larger than tracingDistance just
+ // render it
+ continue;
+ }
+
+ AABB boundingBox = entity.getBoundingBox();
+ if (boundingBox.getXsize() > hitboxLimit || boundingBox.getYsize() > hitboxLimit
+ || boundingBox.getZsize() > hitboxLimit) {
+ cullable.setCulled(false); // Too big to bother to cull
+ continue;
+ }
+
+ aabbMin.set(boundingBox.minX, boundingBox.minY, boundingBox.minZ);
+ aabbMax.set(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ);
+
+ boolean visible = culling.isAABBVisible(aabbMin, aabbMax, camera);
+
+ cullable.setCulled(!visible);
+ }
+ }
+ }
+
+ private boolean isSkippableArmorstand(Entity entity) {
+ if (!RayTrackingEntityTrackerConfig.skipMarkerArmorStands)
+ return false;
+ return entity instanceof ArmorStand && entity.isInvisible();
+ }
+}
@@ -1,45 +0,0 @@
--- /dev/null
+++ b/src/main/java/dev/tr7zw/entityculling/DefaultChunkDataProvider.java
@@ -1,0 +_,42 @@
+package dev.tr7zw.entityculling;
+
+import com.logisticscraft.occlusionculling.DataProvider;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.chunk.ChunkAccess;
+
+public class DefaultChunkDataProvider implements DataProvider {
+ private final Level level;
+
+ public DefaultChunkDataProvider(Level level) {
+ this.level = level;
+ }
+
+ @Override
+ public boolean prepareChunk(int chunkX, int chunkZ) {
+ return this.level.getChunkIfLoaded(chunkX, chunkZ) != null;
+ }
+
+ @Override
+ public boolean isOpaqueFullCube(int x, int y, int z) {
+ BlockPos pos = new BlockPos(x, y, z);
+
+ final ChunkAccess access = this.level.getChunkIfLoaded(pos);
+ if (access == null) {
+ return false;
+ }
+
+ if (this.level.isOutsideBuildHeight(pos)) {
+ return Blocks.VOID_AIR.defaultBlockState().isSolidRender();
+ } else {
+ return access.getBlockState(pos).isSolidRender();// 好孩子不要学坏叔叔这样绕过异步拦截()
+ }
+ }
+
+ @Override
+ public void cleanup() {
+ DataProvider.super.cleanup();
+ }
+
+}
@@ -1,20 +0,0 @@
--- /dev/null
+++ b/src/main/java/dev/tr7zw/entityculling/versionless/access/Cullable.java
@@ -1,0 +_,17 @@
+package dev.tr7zw.entityculling.versionless.access;
+
+public interface Cullable {
+
+ public void setTimeout();
+
+ public boolean isForcedVisible();
+
+ public void setCulled(boolean value);
+
+ public boolean isCulled();
+
+ public void setOutOfCamera(boolean value);
+
+ public boolean isOutOfCamera();
+
+}
@@ -1,35 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/LophineConfig.java
@@ -1,0 +_,32 @@
+package me.earthme.lophine.config;
+
+import me.earthme.luminol.config.LuminolConfig;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class LophineConfig {
+ public static final Map<String, LuminolConfig> configfiles = new HashMap<>();
+ private static final File luminolConfigFolder = new File("luminol_config");
+ private static final File lophineConfigFolder = new File("lophine_config");
+
+ public static void initConfigs() {
+ configfiles.put("luminol", new LuminolConfig(luminolConfigFolder, "luminol", "me.earthme.luminol.config.modules"));
+ configfiles.put("lophine", new LuminolConfig(lophineConfigFolder, "lophine", "me.earthme.lophine.config.modules"));
+ }
+
+ public static void preLoad() throws IOException {
+ for (LuminolConfig config : configfiles.values()) {
+ config.preLoadConfig();
+ }
+ }
+
+ public static void loadConfigFiles() {
+ for (LuminolConfig config : configfiles.values()) {
+ config.finalizeLoadConfig();
+ config.setupLatch();
+ }
+ }
+}
@@ -1,30 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/experiment/CommandConfig.java
@@ -1,0 +_,27 @@
+package me.earthme.lophine.config.modules.experiment;
+
+import me.earthme.luminol.config.EnumConfigCategory;
+import me.earthme.luminol.config.IConfigModule;
+import me.earthme.luminol.config.flags.ConfigInfo;
+
+public class CommandConfig implements IConfigModule {
+ @ConfigInfo(baseName = "command_block_enabled", comments =
+ """
+ Allow to use command block""")
+ public static boolean block = false;
+
+ @ConfigInfo(baseName = "tick_command_enabled", comments =
+ """
+ Allow to use tick command""")
+ public static boolean tick = false;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.EXPERIMENT;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "command";
+ }
+}
@@ -1,25 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/experiment/EntityDamageSourceTraceConfig.java
@@ -1,0 +_,22 @@
+package me.earthme.lophine.config.modules.experiment;
+
+import me.earthme.luminol.config.EnumConfigCategory;
+import me.earthme.luminol.config.IConfigModule;
+import me.earthme.luminol.config.flags.ConfigInfo;
+
+public class EntityDamageSourceTraceConfig implements IConfigModule {
+ @ConfigInfo(baseName = "enabled", comments =
+ """
+ Allow trace damage source cross different Region Scheduler.""")
+ public static boolean enabled = false;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.EXPERIMENT;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "entity_damage_source_trace";
+ }
+}
@@ -1,31 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/experiment/RayTrackingEntityTrackerConfig.java
@@ -1,0 +_,28 @@
+package me.earthme.lophine.config.modules.experiment;
+
+import me.earthme.luminol.config.EnumConfigCategory;
+import me.earthme.luminol.config.IConfigModule;
+import me.earthme.luminol.config.flags.ConfigInfo;
+
+public class RayTrackingEntityTrackerConfig implements IConfigModule {
+ @ConfigInfo(baseName = "enabled")
+ public static boolean enabled = false;
+ @ConfigInfo(baseName = "skip_marker_armor_stands")
+ public static boolean skipMarkerArmorStands = true;
+ @ConfigInfo(baseName = "check_interval_ms")
+ public static int checkIntervalMs = 10;
+ @ConfigInfo(baseName = "tracing_distance")
+ public static int tracingDistance = 48;
+ @ConfigInfo(baseName = "hitbox_limit")
+ public static int hitboxLimit = 50;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.EXPERIMENT;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "ray_tracking_entity_tracker";
+ }
+}
@@ -1,35 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/misc/ContainerExpansionConfig.java
@@ -1,0 +_,32 @@
+package me.earthme.lophine.config.modules.misc;
+
+import me.earthme.luminol.config.EnumConfigCategory;
+import me.earthme.luminol.config.IConfigModule;
+import me.earthme.luminol.config.flags.ConfigInfo;
+
+public class ContainerExpansionConfig implements IConfigModule {
+ @ConfigInfo(baseName = "barrel_rows", comments =
+ """
+ range: 1~6""")
+ public static int barrelRows = 3;
+
+ @ConfigInfo(baseName = "enderchest_rows", comments =
+ """
+ range: 1~6""")
+ public static int enderchestRows = 3;
+
+ @ConfigInfo(baseName = "shulker_stackable_count", comments =
+ """
+ range: 1~64""")
+ public static int shulkerCount = 1;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.MISC;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "container_expansion";
+ }
+}
@@ -1,26 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/misc/DisableEndCrystalCheckConfig.java
@@ -1,0 +_,23 @@
+package me.earthme.lophine.config.modules.misc;
+
+import me.earthme.luminol.config.EnumConfigCategory;
+import me.earthme.luminol.config.IConfigModule;
+import me.earthme.luminol.config.flags.ConfigInfo;
+
+public class DisableEndCrystalCheckConfig implements IConfigModule {
+ @ConfigInfo(baseName = "disable_end_crystal_check", comments =
+ """
+ Disable paper's End Crystal position check.
+ It reverts to vanilla respawn dragon logic.""")
+ public static boolean disableCheck = false;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.MISC;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "end_crystal";
+ }
+}
@@ -1,29 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/misc/OldFeatureConfig.java
@@ -1,0 +_,26 @@
+package me.earthme.lophine.config.modules.misc;
+
+import me.earthme.luminol.config.EnumConfigCategory;
+import me.earthme.luminol.config.IConfigModule;
+import me.earthme.luminol.config.flags.ConfigInfo;
+
+public class OldFeatureConfig implements IConfigModule {
+ @ConfigInfo(baseName = "old_nether_portal_collision")
+ public static boolean oldNetherPortalCollision = false;
+
+ @ConfigInfo(baseName = "spawn_invulnerable_time")
+ public static boolean spawnInvulnerableTime = false;
+
+ @ConfigInfo(baseName = "old_zombie_reinforcement")
+ public static boolean oldZombieReinforcement = false;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.MISC;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "old-feature";
+ }
+}
@@ -1,57 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/misc/RaidChangesConfig.java
@@ -1,0 +_,54 @@
+package me.earthme.lophine.config.modules.misc;
+
+import me.earthme.luminol.config.EnumConfigCategory;
+import me.earthme.luminol.config.IConfigModule;
+import me.earthme.luminol.config.flags.ConfigInfo;
+
+public class RaidChangesConfig implements IConfigModule {
+ @ConfigInfo(baseName = "allow_skip_cooldown", comments =
+ """
+ Allow players with bad omen to skip a
+ 30-second cooldown and trigger attacks directly""")
+ public static boolean trigger = false;
+
+ @ConfigInfo(baseName = "give_bad_omen_when_kill_raid_captain", comments =
+ """
+ Enable players to obtain a bad omen
+ effect when killing the raid captain""")
+ public static boolean effect = false;
+
+ @ConfigInfo(baseName = "bad_omen_infinite", comments =
+ """
+ Enable bad omen effect infinite time
+ --- this config is not old version's function""")
+ public static boolean infinite = false;
+
+ @ConfigInfo(baseName = "skip_height_check", comments =
+ """
+ Disable y <= 96 check.
+ If you enabled use_old_position_find, this config
+ will useless and always behavior of enabled""")
+ public static boolean heightCheck = false;
+
+ @ConfigInfo(baseName = "skip_self_raid_check", comments =
+ """
+ Disable raid self check
+ --- this config is not old version's function""")
+ public static boolean selfCheck = false;
+
+ @ConfigInfo(baseName = "use_old_position_find", comments =
+ """
+ Revert Old raid's find spawn position logic
+ --- This revert MC-274911""")
+ public static boolean posRevert = false;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.MISC;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "revert_raid_changes";
+ }
+}
@@ -1,28 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/config/modules/removed/RemovedConfig.java
@@ -1,0 +_,25 @@
+package me.earthme.lophine.config.modules.removed;
+
+import me.earthme.luminol.config.EnumConfigCategory;
+import me.earthme.luminol.config.IConfigModule;
+import me.earthme.luminol.config.flags.ConfigInfo;
+import me.earthme.luminol.config.flags.DoNotLoad;
+import me.earthme.luminol.config.flags.TransformedConfig;
+
+public class RemovedConfig implements IConfigModule {
+ @TransformedConfig(name = "example", category = {"removed", "example"}, transform = false)
+ @ConfigInfo(baseName = "removed", comments =
+ """
+ RemovedConfig redirect to here, no any function.""")
+ public static boolean enabled = true;
+
+ @Override
+ public EnumConfigCategory getCategory() {
+ return EnumConfigCategory.REMOVED;
+ }
+
+ @Override
+ public String getBaseName() {
+ return "removed_config";
+ }
+}
@@ -1,79 +0,0 @@
--- /dev/null
+++ b/src/main/java/me/earthme/lophine/utils/ShulkerBoxesUtil.java
@@ -1,0 +_,76 @@
+package me.earthme.lophine.utils;
+
+import me.earthme.lophine.config.modules.misc.ContainerExpansionConfig;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.world.item.BlockItem;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.component.CustomData;
+import net.minecraft.world.item.component.ItemContainerContents;
+import net.minecraft.world.level.block.ShulkerBoxBlock;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Optional;
+
+public class ShulkerBoxesUtil {
+ // Lophine - Stackable ShulkerBoxes
+ public static boolean shouldCheck() {
+ return ContainerExpansionConfig.shulkerCount > 1 && ContainerExpansionConfig.shulkerCount <= 64;
+ }
+
+ public static boolean checkShulkerBox(ItemStack itemStack) {
+ return shouldCheck() && itemStack.getItem() instanceof BlockItem b
+ && b.getBlock() instanceof ShulkerBoxBlock;
+ }
+
+ public static int getItemMaxCount(ItemStack itemStack) {
+ if (checkShulkerBox(itemStack)) {
+ return Math.clamp(ContainerExpansionConfig.shulkerCount, 1, 64);
+ }
+ return itemStack.getMaxStackSize();
+ }
+
+ public static int getShulkerBoxesMaxCountUnsafe() {
+ return Math.clamp(ContainerExpansionConfig.shulkerCount, 1, 64);
+ }
+
+ public static boolean emptyShulkerBoxCheck(@NotNull ItemStack stack) {
+ return stack.getComponents().getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).stream().findAny().isEmpty();
+ }
+
+ public static boolean isStackable(ItemStack itemStack) {
+ return getItemMaxCount(itemStack) > 1 && (!itemStack.isDamageableItem() || !itemStack.isDamaged());
+ }
+
+ public static int getItemStackMaxCountReal(ItemStack stack) {
+ CompoundTag nbt = Optional.ofNullable(stack.get(DataComponents.CUSTOM_DATA)).orElse(CustomData.EMPTY).copyTag();
+ return nbt.getInt("Lophine.RealStackSize").orElse(stack.getMaxStackSize());
+ }
+
+ public static ItemStack encodeMaxStackSize(ItemStack itemStack) {
+ int realMaxStackSize = getItemStackMaxCountReal(itemStack);
+ int modifiedMaxStackSize = getItemMaxCount(itemStack);
+ if (itemStack.getMaxStackSize() != modifiedMaxStackSize) {
+ itemStack.set(DataComponents.MAX_STACK_SIZE, modifiedMaxStackSize);
+ CompoundTag nbt = itemStack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
+ nbt.putInt("Lophine.RealStackSize", realMaxStackSize);
+ itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(nbt));
+ }
+ return itemStack;
+ }
+
+ public static ItemStack decodeMaxStackSize(ItemStack itemStack) {
+ int realMaxStackSize = getItemStackMaxCountReal(itemStack);
+ if (itemStack.getMaxStackSize() != realMaxStackSize) {
+ itemStack.set(DataComponents.MAX_STACK_SIZE, realMaxStackSize);
+ CompoundTag nbt = itemStack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
+ nbt.remove("Lophine.RealStackSize");
+ if (nbt.isEmpty()) {
+ itemStack.remove(DataComponents.CUSTOM_DATA);
+ } else {
+ itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(nbt));
+ }
+ }
+ return itemStack;
+ }
+}
@@ -0,0 +1,151 @@
package dev.tr7zw.entityculling;
import ca.spottedleaf.moonrise.common.util.TickThread;
import com.logisticscraft.occlusionculling.OcclusionCullingInstance;
import com.logisticscraft.occlusionculling.util.Vec3d;
import dev.tr7zw.entityculling.versionless.access.Cullable;
import fun.bm.lophine.config.modules.experiment.RayTrackingEntityTrackerConfig;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class CullTask implements Runnable {
private volatile boolean requestCull = false;
private volatile boolean scheduleNext = true;
private volatile boolean inited = false;
private final OcclusionCullingInstance culling;
private final Player checkTarget;
private final int hitboxLimit;
public long lastCheckedTime = 0;
// reused preallocated vars
private final Vec3d lastPos = new Vec3d(0, 0, 0);
private final Vec3d aabbMin = new Vec3d(0, 0, 0);
private final Vec3d aabbMax = new Vec3d(0, 0, 0);
private static final Executor backgroundWorker = Executors.newCachedThreadPool(task -> {
final TickThread worker = new TickThread("EntityCulling") {
@Override
public void run() {
task.run();
}
};
worker.setDaemon(true);
return worker;
});
private final Executor worker;
public CullTask(
OcclusionCullingInstance culling,
Player checkTarget,
int hitboxLimit,
long checkIntervalMs
) {
this.culling = culling;
this.checkTarget = checkTarget;
this.hitboxLimit = hitboxLimit;
this.worker = CompletableFuture.delayedExecutor(checkIntervalMs, TimeUnit.MILLISECONDS, backgroundWorker);
}
public void requestCullSignal() {
this.requestCull = true;
}
public void signalStop() {
this.scheduleNext = false;
}
public void setup() {
if (!this.inited)
this.inited = true;
else
return;
this.worker.execute(this);
}
@Override
public void run() {
try {
if (this.checkTarget.tickCount > 10) {
// getEyePosition can use a fixed delta as its debug only anyway
Vec3 cameraMC = this.checkTarget.getEyePosition(0);
if (requestCull || !(cameraMC.x == lastPos.x && cameraMC.y == lastPos.y && cameraMC.z == lastPos.z)) {
long start = System.currentTimeMillis();
requestCull = false;
lastPos.set(cameraMC.x, cameraMC.y, cameraMC.z);
culling.resetCache();
cullEntities(cameraMC, lastPos);
lastCheckedTime = (System.currentTimeMillis() - start);
}
}
} finally {
if (this.scheduleNext) {
this.worker.execute(this);
}
}
}
private void cullEntities(Vec3 cameraMC, Vec3d camera) {
for (Entity entity : this.checkTarget.level().getEntities().getAll()) {
if (!(entity instanceof Cullable cullable)) {
continue; // Not sure how this could happen outside from mixin screwing up the inject into
// Entity
}
if (entity.getType().skipRaytracningCheck) {
continue;
}
if (!cullable.isForcedVisible()) {
if (entity.isCurrentlyGlowing() || isSkippableArmorstand(entity)) {
cullable.setCulled(false);
continue;
}
if (!entity.position().closerThan(cameraMC, RayTrackingEntityTrackerConfig.tracingDistance)) {
cullable.setCulled(false); // If your entity view distance is larger than tracingDistance just
// render it
continue;
}
AABB boundingBox = entity.getBoundingBox();
if (boundingBox.getXsize() > hitboxLimit || boundingBox.getYsize() > hitboxLimit
|| boundingBox.getZsize() > hitboxLimit) {
cullable.setCulled(false); // Too big to bother to cull
continue;
}
aabbMin.set(boundingBox.minX, boundingBox.minY, boundingBox.minZ);
aabbMax.set(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ);
boolean visible = culling.isAABBVisible(aabbMin, aabbMax, camera);
cullable.setCulled(!visible);
}
}
}
private boolean isSkippableArmorstand(Entity entity) {
if (!RayTrackingEntityTrackerConfig.skipMarkerArmorStands)
return false;
return entity instanceof ArmorStand && entity.isInvisible();
}
}
@@ -0,0 +1,42 @@
package dev.tr7zw.entityculling;
import com.logisticscraft.occlusionculling.DataProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.chunk.ChunkAccess;
public class DefaultChunkDataProvider implements DataProvider {
private final Level level;
public DefaultChunkDataProvider(Level level) {
this.level = level;
}
@Override
public boolean prepareChunk(int chunkX, int chunkZ) {
return this.level.getChunkIfLoaded(chunkX, chunkZ) != null;
}
@Override
public boolean isOpaqueFullCube(int x, int y, int z) {
BlockPos pos = new BlockPos(x, y, z);
final ChunkAccess access = this.level.getChunkIfLoaded(pos);
if (access == null) {
return false;
}
if (this.level.isOutsideBuildHeight(pos)) {
return Blocks.VOID_AIR.defaultBlockState().isSolidRender();
} else {
return access.getBlockState(pos).isSolidRender();// 好孩子不要学坏叔叔这样绕过异步拦截()
}
}
@Override
public void cleanup() {
DataProvider.super.cleanup();
}
}
@@ -0,0 +1,17 @@
package dev.tr7zw.entityculling.versionless.access;
public interface Cullable {
public void setTimeout();
public boolean isForcedVisible();
public void setCulled(boolean value);
public boolean isCulled();
public void setOutOfCamera(boolean value);
public boolean isOutOfCamera();
}
@@ -0,0 +1,28 @@
package fun.bm.lophine.config.modules.experiment;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class CommandConfig implements IConfigModule {
@ConfigInfo(baseName = "tick_command_enabled", comments =
"""
Allow to use tick command""")
public static boolean tick = false;
@ConfigInfo(baseName = "datapack_command_enabled", comments =
"""
Allow to use datapack command
--- datapack hot-update unsupported, please restart server""")
public static boolean datapack = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.EXPERIMENT;
}
@Override
public String getBaseName() {
return "command";
}
}
@@ -0,0 +1,22 @@
package fun.bm.lophine.config.modules.experiment;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class EntityDamageSourceTraceConfig implements IConfigModule {
@ConfigInfo(baseName = "enabled", comments =
"""
Allow trace damage source cross different Region Scheduler.""")
public static boolean enabled = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.EXPERIMENT;
}
@Override
public String getBaseName() {
return "entity_damage_source_trace";
}
}
@@ -0,0 +1,28 @@
package fun.bm.lophine.config.modules.experiment;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class RayTrackingEntityTrackerConfig implements IConfigModule {
@ConfigInfo(baseName = "enabled")
public static boolean enabled = false;
@ConfigInfo(baseName = "skip_marker_armor_stands")
public static boolean skipMarkerArmorStands = true;
@ConfigInfo(baseName = "check_interval_ms")
public static int checkIntervalMs = 10;
@ConfigInfo(baseName = "tracing_distance")
public static int tracingDistance = 48;
@ConfigInfo(baseName = "hitbox_limit")
public static int hitboxLimit = 50;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.EXPERIMENT;
}
@Override
public String getBaseName() {
return "ray_tracking_entity_tracker";
}
}
@@ -0,0 +1,24 @@
package fun.bm.lophine.config.modules.experiment;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.config.flags.TransformedConfig;
public class WaypointConfig implements IConfigModule {
@TransformedConfig(name = "enable-waypoint", category = {"experiment", "waypoint bar"})
@ConfigInfo(baseName = "enabled", comments =
"""
Enable waypoint bar unsafe""")
public static boolean forceEnableWaypointUnsafe = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.EXPERIMENT;
}
@Override
public String getBaseName() {
return "waypoint_bar";
}
}
@@ -0,0 +1,37 @@
package fun.bm.lophine.config.modules.misc;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class ContainerExpansionConfig implements IConfigModule {
@ConfigInfo(baseName = "barrel_rows", comments =
"""
range: 1~6""")
public static int barrelRows = 3;
@ConfigInfo(baseName = "enderchest_rows", comments =
"""
range: 1~6""")
public static int enderchestRows = 3;
@ConfigInfo(baseName = "shulker_stackable_count", comments =
"""
range: 1~64""")
public static int shulkerCount = 1;
@ConfigInfo(baseName = "same_nbt_shulker_stackable", comments =
"""
range: 1~64""")
public static boolean nbtShulkerStackable = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.MISC;
}
@Override
public String getBaseName() {
return "container_expansion";
}
}
@@ -0,0 +1,23 @@
package fun.bm.lophine.config.modules.misc;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class DisableEndCrystalCheckConfig implements IConfigModule {
@ConfigInfo(baseName = "disable_end_crystal_check", comments =
"""
Disable paper's End Crystal position check.
It reverts to vanilla respawn dragon logic.""")
public static boolean disableCheck = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.MISC;
}
@Override
public String getBaseName() {
return "end_crystal";
}
}
@@ -0,0 +1,29 @@
package fun.bm.lophine.config.modules.misc;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class OldFeatureConfig implements IConfigModule {
@ConfigInfo(baseName = "spawn_invulnerable_time")
public static boolean spawnInvulnerableTime = false;
@ConfigInfo(baseName = "old_zombie_reinforcement")
public static boolean oldZombieReinforcement = false;
@ConfigInfo(baseName = "old_replaceable_by_mushrooms")
public static boolean oldReplaceableByMushrooms = false;
@ConfigInfo(baseName = "old_explosion_damage_calculator")
public static boolean oldExplosionDamageCalculator = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.MISC;
}
@Override
public String getBaseName() {
return "old-feature";
}
}
@@ -0,0 +1,54 @@
package fun.bm.lophine.config.modules.misc;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class RaidChangesConfig implements IConfigModule {
@ConfigInfo(baseName = "allow_skip_cooldown", comments =
"""
Allow players with bad omen to skip a
30-second cooldown and trigger attacks directly""")
public static boolean trigger = false;
@ConfigInfo(baseName = "give_bad_omen_when_kill_raid_captain", comments =
"""
Enable players to obtain a bad omen
effect when killing the raid captain""")
public static boolean effect = false;
@ConfigInfo(baseName = "bad_omen_infinite", comments =
"""
Enable bad omen effect infinite time
--- this config is not old version's function""")
public static boolean infinite = false;
@ConfigInfo(baseName = "skip_height_check", comments =
"""
Disable y <= 96 check.
If you enabled use_old_position_find, this config
will useless and always behavior of enabled""")
public static boolean heightCheck = false;
@ConfigInfo(baseName = "skip_self_raid_check", comments =
"""
Disable raid self check
--- this config is not old version's function""")
public static boolean selfCheck = false;
@ConfigInfo(baseName = "use_old_position_find", comments =
"""
Revert Old raid's find spawn position logic
--- This revert MC-274911""")
public static boolean posRevert = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.MISC;
}
@Override
public String getBaseName() {
return "revert_raid_changes";
}
}
@@ -0,0 +1,27 @@
package fun.bm.lophine.config.modules.misc;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.config.flags.TransformedConfig;
public class RedStoneConfig implements IConfigModule {
@TransformedConfig(name = "allow_skip_cooldown", category = {"misc", "redstone"})
@ConfigInfo(baseName = "shears_rotate", comments =
"""
Allows you to use the Shears to right-click to rotate the block.""")
public static boolean shears = false;
@ConfigInfo(baseName = "vanilla_hopper")
public static boolean vanillaHopper = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.MISC;
}
@Override
public String getBaseName() {
return "redstone";
}
}
@@ -0,0 +1,23 @@
package fun.bm.lophine.config.modules.misc;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class VillagerConfig implements IConfigModule {
@ConfigInfo(baseName = "villager-infinite-trade", comments =
"""
Allow villager infinite trade (limit of 524288 times)
---- we won't edit saved data, only edit in send data to client.""")
public static boolean villagerInfiniteTrade = false;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.MISC;
}
@Override
public String getBaseName() {
return "villager-config";
}
}
@@ -0,0 +1,22 @@
package fun.bm.lophine.config.modules.optimizations;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class LanguageConfig implements IConfigModule {
@ConfigInfo(baseName = "lang", comments = """
Please use the key from https://minecraft.wiki/w/Language
Sample of format: en_us zh_cn zh_hk zh_tw""")
public static String lang = "en_us";
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.OPTIMIZATIONS;
}
@Override
public String getBaseName() {
return "language";
}
}
@@ -0,0 +1,21 @@
package fun.bm.lophine.config.modules.optimizations;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
public class NetworkConfig implements IConfigModule {
@ConfigInfo(baseName = "unlimit-packet", comments = """
Disable packet limit""")
public static boolean disablePacketLimit = true;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.OPTIMIZATIONS;
}
@Override
public String getBaseName() {
return "network";
}
}
@@ -0,0 +1,25 @@
package fun.bm.lophine.config.modules.removed;
import me.earthme.luminol.config.EnumConfigCategory;
import me.earthme.luminol.config.IConfigModule;
import me.earthme.luminol.config.flags.ConfigInfo;
import me.earthme.luminol.config.flags.TransformedConfig;
public class RemovedConfig implements IConfigModule {
@TransformedConfig(name = "old_nether_portal_collision", category = {"misc", "old-feature"}, transform = false)
@TransformedConfig(name = "better_shulker_box", category = {"misc", "container_expansion"}, transform = false)
@ConfigInfo(baseName = "removed", comments =
"""
RemovedConfig redirect to here, no any function.""")
public static boolean enabled = true;
@Override
public EnumConfigCategory getCategory() {
return EnumConfigCategory.REMOVED;
}
@Override
public String getBaseName() {
return "removed_config";
}
}
@@ -0,0 +1,252 @@
package fun.bm.lophine.utils;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import fun.bm.lophine.config.modules.optimizations.LanguageConfig;
import net.minecraft.DetectedVersion;
import net.minecraft.locale.DeprecatedTranslationsInfo;
import net.minecraft.locale.Language;
import net.minecraft.network.chat.FormattedText;
import net.minecraft.network.chat.Style;
import net.minecraft.util.FormattedCharSequence;
import net.minecraft.util.StringDecomposer;
import org.apache.commons.io.FileUtils;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.logging.Logger;
/*
* authored by: Helvetica Volubi <suisuroru@blue-millennium.fun>
* modified by: Lumine1909 <133463833+Lumine1909@users.noreply.github.com>
* Some of diff form Leaves
*/
public class ServerI18nUtil {
private static final Logger logger = Logger.getLogger("LangLoader");
private static final String VERSION = DetectedVersion.BUILT_IN.name();
private static final String BASE_PATH = "cache/lophine/" + VERSION + "/";
private static final String manifestUrl = "https://launchermeta.mojang.com/mc/game/version_manifest.json";
private static final String resourceBaseUrl = "https://resources.download.minecraft.net/";
private static String langPath;
private static String assetsPath;
private static String versionPath;
private static String manifestPath;
private static String langJsonPath;
public static void init() {
if (Objects.equals(LanguageConfig.lang, "en_us")) {
return;
}
langPath = BASE_PATH + "lang/" + LanguageConfig.lang + ".json";
assetsPath = BASE_PATH + "assets.json";
versionPath = BASE_PATH + VERSION + ".json";
manifestPath = BASE_PATH + "manifest.json";
langJsonPath = "minecraft/lang/" + LanguageConfig.lang + ".json";
logger.info("Starting load language: " + LanguageConfig.lang);
CompletableFuture.runAsync(() -> loadI18n(LanguageConfig.lang, 2));
}
private static void loadI18n(String lang, int retryTime) {
try {
if (!Files.exists(Path.of(langPath))) {
downloadLang(true);
}
Language.inject(createLangInstance());
logger.info("Successfully loaded language: " + lang);
} catch (Exception e) {
logger.warning("Failed to load language file for " + lang + "\n" + e);
if (retryTime > 0) {
cleanCache();
loadI18n(lang, retryTime - 1);
} else {
logger.severe("Failed to load for many times, use default lang \"en_us\" instead");
cleanCache();
}
}
}
private static void downloadLang(boolean fetchFromAssets) throws Exception {
JsonObject json;
if (!Files.exists(Path.of(assetsPath)) || (json = loadJson(assetsPath)) == null) {
if (fetchFromAssets) {
downloadAssets(true);
downloadLang(false);
}
return;
}
JsonObject langEntry = json.getAsJsonObject("objects").getAsJsonObject(langJsonPath);
String hash = langEntry.get("hash").getAsString();
if (hash == null || hash.length() < 2) {
throw new IllegalArgumentException("Invalid hash value");
}
String langUrl = resourceBaseUrl + hash.substring(0, 2) + "/" + hash;
fetchAndSave(langUrl, langPath);
}
private static void downloadAssets(boolean fetchFromVersion) throws Exception {
JsonObject json;
if (!Files.exists(Path.of(versionPath)) || (json = loadJson(versionPath)) == null) {
if (fetchFromVersion) {
downloadVersion(true);
downloadAssets(false);
}
return;
}
JsonObject assetIndex = json.getAsJsonObject("assetIndex");
String assetUrl = assetIndex.get("url").getAsString();
fetchAndSave(assetUrl, assetsPath);
}
private static void downloadVersion(boolean fetchFromManifest) throws Exception {
JsonObject json;
if (!Files.exists(Path.of(manifestPath)) || (json = loadJson(manifestPath)) == null) {
if (fetchFromManifest) {
fetchAndSave(manifestUrl, manifestPath);
downloadVersion(false);
}
return;
}
String versionUrl = null;
for (JsonElement element : json.getAsJsonArray("versions")) {
String id = element.getAsJsonObject().get("id").getAsString();
String url = element.getAsJsonObject().get("url").getAsString();
if (VERSION.equals(id)) {
versionUrl = url;
break;
}
}
if (versionUrl == null) {
throw new RuntimeException("Could not find version URL");
}
fetchAndSave(versionUrl, versionPath);
}
private static String createHttpResponse(String path) throws IOException, InterruptedException {
try {
HttpResponse<String> response;
try (HttpClient httpClient = HttpClient.newHttpClient()) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(path))
.build();
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
}
int responseCode = response.statusCode();
if (responseCode != 200) {
logger.info("Unexpected response code: " + responseCode);
logger.info("Response body: " + response.body());
throw new UnsupportedEncodingException("Unexpected response code");
} else {
return response.body();
}
} catch (Exception e) {
logger.warning("Error in getting info: " + e.getMessage());
throw e;
}
}
private static byte[] fetch(String urlString) throws IOException, InterruptedException {
String ret = createHttpResponse(urlString);
return ret.getBytes();
}
private static void fetchAndSave(String url, String savePath) throws IOException, InterruptedException {
byte[] data = fetch(url);
Path outputPath = Path.of(savePath);
Files.createDirectories(outputPath.getParent());
Files.write(outputPath, data, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
}
private static void cleanCache() {
try {
FileUtils.deleteDirectory(Path.of(BASE_PATH).toFile());
} catch (IOException e) {
logger.severe("Cache cleanup failed: " + e);
}
}
private static JsonObject loadJson(String path) {
try {
byte[] data = Files.readAllBytes(Paths.get(path));
return JsonParser.parseString(new String(data)).getAsJsonObject();
} catch (JsonSyntaxException e) {
logger.warning("Corrupt json file: " + e);
throw e;
} catch (Exception e) {
logger.warning("Failed to load local JSON: " + e);
return null;
}
}
private static Language createLangInstance() throws IOException {
DeprecatedTranslationsInfo deprecatedTranslationsInfo = DeprecatedTranslationsInfo.loadFromDefaultResource();
Map<String, String> map = new HashMap<>();
parseTranslations(map::put);
deprecatedTranslationsInfo.applyToMap(map);
final Map<String, String> map1 = Map.copyOf(map);
return new Language() {
@Override
public @NotNull String getOrDefault(@NotNull String key, @NotNull String defaultValue) {
return map1.getOrDefault(key, defaultValue);
}
@Override
public boolean has(@NotNull String id) {
return map1.containsKey(id);
}
@Override
public boolean isDefaultRightToLeft() {
return false;
}
@Override
public @NotNull FormattedCharSequence getVisualOrder(@NotNull FormattedText text) {
return sink -> text.visit(
(style, content) -> StringDecomposer.iterateFormatted(content, style, sink) ? Optional.empty() : FormattedText.STOP_ITERATION,
Style.EMPTY
)
.isPresent();
}
};
}
private static void parseTranslations(BiConsumer<String, String> output) throws IOException {
Path filePath = Path.of(langPath);
try (InputStream fileStream = Files.newInputStream(filePath)) {
Language.loadFromJson(fileStream, output);
} catch (NoSuchFileException noSuchFileException) {
logger.warning("Couldn't find language file: " + langPath);
throw noSuchFileException;
} catch (Exception e) {
logger.warning("Failed to load language from filesystem " + filePath + "\n" + e);
throw e;
}
}
}
@@ -0,0 +1,203 @@
package org.leavesmc.leaves.util;
import fun.bm.lophine.config.modules.misc.ContainerExpansionConfig;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.item.component.ItemContainerContents;
import net.minecraft.world.level.block.ShulkerBoxBlock;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
public class ItemOverstackUtils {
private static final List<ItemUtil> overstackUtils = List.of(
new ShulkerBox()
// new CurseEnchantedBook()
);
public static int getItemStackMaxCount(ItemStack stack) {
int size;
for (ItemUtil util : overstackUtils) {
if ((size = util.getMaxServerStackCount(stack)) != -1) {
return size;
}
}
return stack.getMaxStackSize();
}
public static int getNetworkMaxCount(ItemStack stack) {
int size;
for (ItemUtil util : overstackUtils) {
if ((size = util.getMaxClientStackCount(stack)) != -1) {
return size;
}
}
return stack.getMaxStackSize();
}
public static boolean tryStackItems(ItemEntity self, ItemEntity other) {
for (ItemUtil util : overstackUtils) {
if (util.tryStackItems(self, other)) {
return true;
}
}
return false;
}
public static boolean hasOverstackingItem() {
return overstackUtils.stream().anyMatch(ItemUtil::isEnabled);
}
public static int getItemStackMaxCountReal(ItemStack stack) {
CompoundTag nbt = Optional.ofNullable(stack.get(DataComponents.CUSTOM_DATA)).orElse(CustomData.EMPTY).copyTag();
return nbt.getInt("Leaves.RealStackSize").orElse(stack.getMaxStackSize());
}
public static ItemStack encodeMaxStackSize(ItemStack itemStack) {
int realMaxStackSize = getItemStackMaxCountReal(itemStack);
int modifiedMaxStackSize = getNetworkMaxCount(itemStack);
if (itemStack.getMaxStackSize() != modifiedMaxStackSize) {
itemStack.set(DataComponents.MAX_STACK_SIZE, modifiedMaxStackSize);
CompoundTag nbt = itemStack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
nbt.putInt("Leaves.RealStackSize", realMaxStackSize);
itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(nbt));
}
return itemStack;
}
public static ItemStack decodeMaxStackSize(ItemStack itemStack) {
int realMaxStackSize = getItemStackMaxCountReal(itemStack);
if (itemStack.getMaxStackSize() != realMaxStackSize) {
itemStack.set(DataComponents.MAX_STACK_SIZE, realMaxStackSize);
CompoundTag nbt = itemStack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
nbt.remove("Leaves.RealStackSize");
if (nbt.isEmpty()) {
itemStack.remove(DataComponents.CUSTOM_DATA);
} else {
itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(nbt));
}
}
return itemStack;
}
public static boolean isStackable(ItemStack itemStack) {
return getItemStackMaxCount(itemStack) > 1 && (!itemStack.isDamageableItem() || !itemStack.isDamaged());
}
private interface ItemUtil {
boolean isEnabled();
boolean tryStackItems(ItemEntity self, ItemEntity other);
// number -> modified count, -1 -> I don't care
int getMaxServerStackCount(ItemStack stack);
// number -> modified count, -1 -> I don't care
default int getMaxClientStackCount(ItemStack stack) {
return getMaxServerStackCount(stack);
}
}
private static class ShulkerBox implements ItemUtil {
public static boolean shulkerBoxCheck(@NotNull ItemStack stack1, @NotNull ItemStack stack2) {
if (ContainerExpansionConfig.nbtShulkerStackable) {
return Objects.equals(stack1.getComponents(), stack2.getComponents());
}
return shulkerBoxNoItem(stack1) && shulkerBoxNoItem(stack2) && Objects.equals(stack1.getComponents(), stack2.getComponents());
}
public static boolean shulkerBoxNoItem(@NotNull ItemStack stack) {
return stack.getComponents().getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).stream().findAny().isEmpty();
}
@Override
public boolean isEnabled() {
return ContainerExpansionConfig.shulkerCount > 1;
}
@Override
public boolean tryStackItems(ItemEntity self, ItemEntity other) {
ItemStack selfStack = self.getItem();
if (!isEnabled() ||
!(selfStack.getItem() instanceof BlockItem blockItem) ||
!(blockItem.getBlock() instanceof ShulkerBoxBlock)
) {
return false;
}
ItemStack otherStack = other.getItem();
if (selfStack.getItem() == otherStack.getItem()
&& shulkerBoxCheck(selfStack, otherStack)
&& selfStack.getCount() != ContainerExpansionConfig.shulkerCount) {
int amount = Math.min(otherStack.getCount(), ContainerExpansionConfig.shulkerCount - selfStack.getCount());
selfStack.grow(amount);
self.setItem(selfStack);
self.pickupDelay = Math.max(other.pickupDelay, self.pickupDelay);
self.age = Math.min(other.getAge(), self.age);
otherStack.shrink(amount);
if (otherStack.isEmpty()) {
other.discard();
} else {
other.setItem(otherStack);
}
return true;
}
return false;
}
@Override
public int getMaxServerStackCount(ItemStack stack) {
if (isEnabled() && stack.getItem() instanceof BlockItem bi &&
bi.getBlock() instanceof ShulkerBoxBlock && (ContainerExpansionConfig.nbtShulkerStackable || shulkerBoxNoItem(stack))) {
return ContainerExpansionConfig.shulkerCount;
}
return -1;
}
}
// only use shulker box part
/* public static class CurseEnchantedBook implements ItemUtil {
public static boolean isCursedEnchantedBook(ItemStack stack) {
ItemEnchantments enchantments = stack.getOrDefault(DataComponents.STORED_ENCHANTMENTS, ItemEnchantments.EMPTY);
if (enchantments.size() != 1) {
return false;
}
return stack.getBukkitStack().getEnchantmentLevel(org.bukkit.enchantments.Enchantment.BINDING_CURSE) == 1 ||
stack.getBukkitStack().getEnchantmentLevel(org.bukkit.enchantments.Enchantment.BINDING_CURSE) == 1;
}
@Override
public boolean isEnabled() {
return LeavesConfig.modify.oldMC.allowGrindstoneOverstacking;
}
@Override
public boolean tryStackItems(ItemEntity self, ItemEntity other) {
return false;
}
@Override
public int getMaxServerStackCount(ItemStack stack) {
return -1;
}
@Override
public int getMaxClientStackCount(ItemStack stack) {
if (isEnabled() && isCursedEnchantedBook(stack)) {
return 2;
}
return -1;
}
}*/
}
+13 -3
View File
@@ -8,11 +8,21 @@ project_id_b="Lophine"
commitid=$(git log --pretty='%h' -1)
mcversion=$(prop mcVersion)
grdversion=$(prop version)
preVersion=$(prop preVersion)
release=$(prop release)
release_tag="$mcversion-$commitid"
jarName="$project_id-$mcversion-paperclip.jar"
jarName_dir="lophine-server/build/libs/$jarName"
make_latest=$([ $preVersion = "true" ] && echo "false" || echo "true")
pre=false
make_latest=false
if [ "$release" = "1" ]; then
pre=true
make_latest=false
elif [ "$release" = "2" ]; then
pre=false
make_latest=true
fi
mv lophine-server/build/libs/$project_id-paperclip-$grdversion-mojmap.jar $jarName_dir
@@ -21,7 +31,7 @@ echo "project_id_b=$project_id_b" >> $GITHUB_ENV
echo "commit_id=$commitid" >> $GITHUB_ENV
echo "commit_msg=$(git log --pretty='> [%h] %s' -1)" >> $GITHUB_ENV
echo "mcversion=$mcversion" >> $GITHUB_ENV
echo "pre=$preVersion" >> $GITHUB_ENV
echo "pre=$pre" >> $GITHUB_ENV
echo "tag=$release_tag" >> $GITHUB_ENV
echo "jar=$jarName" >> $GITHUB_ENV
echo "jar_dir=$jarName_dir" >> $GITHUB_ENV
+1
View File
@@ -3,6 +3,7 @@ pluginManagement {
gradlePluginPortal()
mavenLocal()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.menthamc.com/repository/maven-public/")
}
}