diff --git a/.editorconfig b/.editorconfig index 35f64eb9a..98a181da1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -29,9 +29,16 @@ ij_java_names_count_to_use_import_on_demand = 999999 ij_java_imports_layout = *,|,$* ij_java_generate_final_locals = true ij_java_generate_final_parameters = true - -[test-plugin/**/*.java] +ij_java_method_parameters_new_line_after_left_paren = true +ij_java_method_parameters_right_paren_on_new_line = true ij_java_use_fq_class_names = false +ij_java_class_names_in_javadoc = 1 -[Purpur-Server/src/main/resources/data/**/*.json] +[purpur-server/src/minecraft/java/**/*.java] +ij_java_use_fq_class_names = true + +[purpur-server/src/minecraft/resources/data/**/*.json] indent_size = 2 + +[paper-api/src/generated/**/*.java] +ij_java_imports_layout = $*,|,* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fa85615bb..c073a7728 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,17 +17,16 @@ jobs: distribution: temurin java-version: 21 cache: 'gradle' - - uses: gradle/wrapper-validation-action@v2 - - uses: gradle/actions/setup-gradle@v3 + - uses: gradle/actions/setup-gradle@v4 - name: Configure Git run: git config --global user.email "no-reply@github.com" && git config --global user.name "Github Actions" - name: Apply Patches - run: ./gradlew applyPatches --no-daemon --stacktrace + run: ./gradlew applyAllPatches --no-daemon --stacktrace - name: Build run: ./gradlew build --no-daemon --stacktrace - name: Rebuild on Failure if: ${{ failure() }} run: | - ./gradlew clean cleanCache - ./gradlew applyPatches --no-daemon --stacktrace + ./gradlew clean cleanCache --refresh-dependencies + ./gradlew applyAllPatches --no-daemon --stacktrace ./gradlew build --no-daemon --stacktrace diff --git a/.gitignore b/.gitignore index 1fd301e1d..707f5e4b7 100644 --- a/.gitignore +++ b/.gitignore @@ -50,12 +50,12 @@ manifest.mf *~ # other stuff -run/ +/run -build-data/ -Purpur-API -Purpur-MojangAPI -Purpur-Server -paper-api-generator +/purpur-server/build.gradle.kts +/purpur-server/src/minecraft +/paper-server +/purpur-api/build.gradle.kts +/paper-api *.jar test-plugin.settings.gradle.kts diff --git a/.idea/runConfigurations/Run_Purpur_Paperclip_Jar.xml b/.idea/runConfigurations/Run_Purpur_Paperclip_Jar.xml index 05a5aa732..72f5fa6c4 100644 --- a/.idea/runConfigurations/Run_Purpur_Paperclip_Jar.xml +++ b/.idea/runConfigurations/Run_Purpur_Paperclip_Jar.xml @@ -1,6 +1,6 @@ - - + \ No newline at end of file diff --git a/.idea/runConfigurations/Upstream_Paper__rebuildAllServerPatches_.xml b/.idea/runConfigurations/Upstream_Paper__rebuildAllServerPatches_.xml new file mode 100644 index 000000000..7e0110e69 --- /dev/null +++ b/.idea/runConfigurations/Upstream_Paper__rebuildAllServerPatches_.xml @@ -0,0 +1,26 @@ + + + + + + + true + true + false + false + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Upstream_Paper__rebuildPatches_.xml b/.idea/runConfigurations/Upstream_Paper__rebuildPaperApiPatches_.xml similarity index 78% rename from .idea/runConfigurations/Upstream_Paper__rebuildPatches_.xml rename to .idea/runConfigurations/Upstream_Paper__rebuildPaperApiPatches_.xml index 0188aeb0f..f8c41e541 100644 --- a/.idea/runConfigurations/Upstream_Paper__rebuildPatches_.xml +++ b/.idea/runConfigurations/Upstream_Paper__rebuildPaperApiPatches_.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6538e3a35..2d4c58015 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,18 +11,12 @@ of any minor nitpicks we might have. Often, it's better for us to solve these problems for you than make you go back and forth trying to fix them yourself. Unfortunately, if you use an organization for your PR, it prevents Purpur from -modifying it. This requires us to manually merge your PR, resulting in us -closing the PR instead of marking it as merged. - -We much prefer to have PRs show as merged, so please do not use repositories -on organizations for PRs. - -See for more information on the -issue. +modifying it. To avoid this, please do not use repositories on organizations +for PRs. ## Requirements -To get started with PRing changes, you'll need the following software, most of +To get started with making changes, you'll need the following software, most of which can be obtained in (most) package managers such as `apt` (Debian / Ubuntu; you will most likely use this for WSL), `homebrew` (macOS / Linux), and more: @@ -42,77 +36,94 @@ If you're compiling with Docker, you can use Adoptium's [`eclipse-temurin`](https://hub.docker.com/_/eclipse-temurin/) images like so: ```console -# docker run -it -v "$(pwd)":/data --rm eclipse-temurin:21.0.3_9-jdk bash +# docker run -it -v "$(pwd)":/data --rm eclipse-temurin:21.0.5_11-jdk bash Pulling image... root@abcdefg1234:/# javac -version -javac 21.0.3 +javac 21.0.5 ``` ## Understanding Patches -Paper is mostly patches and extensions to Spigot. These patches/extensions are -split into different directories which target certain parts of the code. These -directories are: +Unlike the Purpur API and its implementation, modifications to Paper and Minecraft source files +are done through patches. These patches/extensions are split into three different sets of two +categories, which are formatted like so: -- `Purpur-API` - Modifications to `Paper-API`; -- `Purpur-Server` - Modifications to `Paper-Server`. +Under `purpur-api`: -Because the entire structure is based on patches and git, a basic understanding +- `paper-patches` (applies to the `paper-server/` git repo) + - `sources`: Per-file patches to Paper API classes; + - `features`: Larger feature patches that modify multiple Paper API classes. + +Under `purpur-server`: + +- `minecraft-patches` (applies to the `purpur-server//` git repo) + - `sources`: Per-file patches to Minecraft classes; + - `resources`: Per-file patches to Minecraft data files; + - `features`: Larger feature patches that modify multiple classes. +- `paper-patches` + - `sources`: Per-file patches to Paper Server classes; + - `features`: Larger feature patches that modify multiple Paper Server classes. + +Because this entire structure is based on patches and git, a basic understanding of how to use git is required. A basic tutorial can be found here: . Assuming you have already forked the repository: 1. Clone your fork to your local machine; -2. Type `./gradlew applyPatches` in a terminal to apply the changes from upstream. - On Windows, replace the `./` with `.\` at the beginning for all `gradlew` commands; -3. cd into `Purpur-Server` for server changes, and `Purpur-API` for API changes. - +2. Type `./gradlew applyAllPatches` in a terminal to apply the patches to both paper and minecraft classes. + On Windows, remove `./` from the beginning of `gradlew` commands; +3. cd into `purpur-server` for server changes, `purpur-api` for API changes, + `paper-api` for Paper API changes, and `paper-server` for Paper Server changes. -`Purpur-Server` and `Purpur-API` aren't git repositories in the traditional sense: +`purpur-server/src/minecraft/java` and `purpur-server/src/minecraft/java/resources` are not git repositories in the traditional sense. +Its initial commits are the decompiled and deobfuscated Minecraft source and resource files. The per-file +patches are applied on top of these files as a single, large commit, which is then followed +by the individual feature-patch commits. `paper-api/` and `paper-server/` +follow the same concept; each paper "project" has its own git repository that also includes it's own feature and per-file patches. -- `base` points to the unmodified source before Purpur patches have been applied. -- Each commit after `base` is a patch. +## Understanding the Gradle Tasks -## Adding Patches +It can be overwhelming when you look over all the available gradle tasks, but it's pretty straightforward. +Each "project" that includes a local git repository has the following available gradle tasks attached to it: -Adding patches to Purpur is very simple: +- `./gradlew apply[project]FeaturePatches` - Applies [project] feature patches +- `./gradlew apply[project]FilePatches` - Applies [project] file patches +- `./gradlew apply[project]Patches` - Applies all [project] patches +- `./gradlew fixup[project]FilePatches` - Puts the currently tracked source changes into the [project] file patches commit +- `./gradlew rebuild[project]FeaturePatches` - Rebuilds [project] feature patches +- `./gradlew rebuild[project]FilePatches` - Rebuilds [project] file patches +- `./gradlew rebuild[project]Patches` - Rebuilds all [project] patches -1. Modify `Purpur-Server` and/or `Purpur-API` with the appropriate changes; -1. Type `git add .` inside these directories to add your changes; -1. Run `git commit` with the desired patch message; -1. Run `./gradlew rebuildPatches` in the main directory to convert your commit into a new - patch; -1. PR the generated patch file(s) back to this repository. +Some additional useful tasks are listed below: -Your commit will be converted into a patch that you can then PR into Purpur. +- `./gradlew applyAllPatches` - Applies all patches defined in the paperweight-patcher project and the server project. (equivalent to running `applyPaperPatches` and then `applyAllServerPatches` in a second Gradle invocation) +- `./gradlew applyAllServerFeaturePatches` - Applies all Minecraft and upstream server feature patches (equivalent to `applyMinecraftFeaturePatches applyServerFeaturePatches`) +- `./gradlew applyAllServerFilePatches` - Applies all Minecraft and upstream server file patches (equivalent to `applyMinecraftFilePatches applyServerFilePatches`) +- `./gradlew applyAllServerPatches` - Applies all Minecraft and upstream server patches (equivalent to `applyMinecraftPatches applyServerPatches`) -> ❗ Please note that if you have some specific implementation detail you'd like -> to document, you should do so in the patch message *or* in comments. +- `./gradlew rebuildPaperSingleFilePatches` - Fixups and rebuilds all paper single-file patches. This is how you'd make changes to the `build.gradle.kts` files located under `purpur-api` and `purpur-server` -## Modifying Patches +## Modifying (per-file) patches -Modifying previous patches is a bit more complex: +This is generally what you need to do when editing files. Updating our +per-file patches is as easy as: +1. Making your changes; +2. Running `./gradlew fixup[project]FilePatches` in the root directory; +3. If nothing went wrong, rebuilding patches with `./gradlew rebuild[project]FilePatches`; -### Method 1 +### Resolving rebase conflicts +If you run into conflicts while running `fixup[project]FilePatches`, you need to go a more +manual route: This method works by temporarily resetting your `HEAD` to the desired commit to edit it using `git rebase`. -> ❗ While in the middle of an edit, you will not be able to compile unless you -> *also* reset the opposing module(s) to a related commit. In the API's case, -> you must reset the Server, and reset the API if you're editing the Server. -> Note also that either module _may_ not compile when doing so. This is not -> ideal nor intentional, but it happens. Feel free to fix this in a PR to us! - -1. If you have changes you are working on, type `git stash` to store them for +0. If you have changes you are working on, type `git stash` to store them for later; - You can type `git stash pop` to get them back at any point. -1. Type `git rebase -i base`; +1. cd into the relevant local git repo and run `git rebase -i base`; - It should show something like [this](https://gist.github.com/zachbr/21e92993cb99f62ffd7905d7b02f3159) in the text editor you get. @@ -120,31 +131,47 @@ edit it using `git rebase`. If you don't know how to use `vim` and don't want to learn, enter `:q!` and press enter. Before redoing this step, do `export EDITOR=nano` for an easier editor to use. -1. Replace `pick` with `edit` for the commit/patch you want to modify, and +1. Replace `pick` with `edit` for the commit/patch you want to modify (in this + case the very first commit, `purpur File Patches`), and "save" the changes; - - Only do this for **one** commit at a time. 1. Make the changes you want to make to the patch; -1. Type `git add .` to add your changes; -1. Type `git commit --amend` to commit; - - **Make sure to add `--amend`** or else a new patch will be created. - - You can also modify the commit message and author here. -1. Type `git rebase --continue` to finish rebasing; -1. Type `./gradlew rebuildPatches` in the root directory; - - This will modify the appropriate patches based on your commits. -1. PR your modified patch file(s) back to this repository. +1. Run `git add .` to add your changes; +1. Run `git commit --amend` to commit; +1. Run `git rebase --continue` to finish rebasing; +1. Run `./gradlew rebuild[project]FilePatches` in the root directory; -### Method 2 - Fixup commits +## Adding larger feature patches -If you are simply editing a more recent commit or your change is small, simply -making the change at HEAD and then moving the commit after you have tested it -may be easier. +Feature patches are exclusively used for large-scale changes that are hard to +track and maintain and that can be optionally dropped, such as the more involved +optimizations we have. This makes it easier to update Purpur during Minecraft updates, +since we can temporarily drop these patches and reapply them later. -This method has the benefit of being able to compile to test your change without -messing with your HEADs. +There is only a very small chance that you will have to use this system, but adding +such patches is very simple: + +1. Modify the relevant local git repo with the appropriate changes; +1. Run `git add .` inside that directory to add your changes; +1. Run `git commit` with the desired patch message; +1. Run `./gradlew rebuild[project]FeaturePatches` in the root directory. + +Your commit will be converted into a patch that you can then PR into Purpur. + +> ❗ Please note that if you have some specific implementation detail you'd like +> to document, you should do so in the patch message *or* in comments. + +## Modifying larger feature patches + +One way of modifying feature patches is to reset to the patch commit and follow +the instructions from the [rebase section](#resolving-rebase-conflicts). If you +are sure there won't be any conflicts from later patches, you can also use the +fixup method. + +### Fixup method #### Manual method -1. Make your change while at HEAD; +1. Make your changes; 1. Make a temporary commit. You don't need to make a message for this; 1. Type `git rebase -i base`, move (cut) your temporary commit and move it under the line of the patch you wish to modify; @@ -153,14 +180,14 @@ messing with your HEADs. message. 1. `s`/`squash`: Merge your changes into the patch and use your commit message and subject. -1. Type `./gradlew rebuildPatches` in the root directory; +1. Run `./gradlew rebuild[project]Patches` in the root directory; - This will modify the appropriate patches based on your commits. -1. PR your modified patch file(s) back to this repository. #### Automatic method -1. Make your change while at HEAD; -1. Make a fixup commit. `git commit -a --fixup `; +1. Make your changes; +1. Make a fixup commit: `git commit -a --fixup `; + - If you want to modify a per-file patch, use `git commit -a --fixup file` - You can also use `--squash` instead of `--fixup` if you want the commit message to also be changed. - You can get the hash by looking at `git log` or `git blame`; your IDE can @@ -170,25 +197,24 @@ messing with your HEADs. 1. Rebase with autosquash: `git rebase -i --autosquash base`. This will automatically move your fixup commit to the right place, and you just need to "save" the changes. -1. Type `./gradlew rebuildPatches` in the root directory; - - This will modify the appropriate patches based on your commits. -1. PR your modified patch file(s) back to this repository. +1. Run `./gradlew rebuild[project]Patches` in the root directory. This will modify the + appropriate patches based on your commits. ## Rebasing PRs -Steps to rebase a PR to include the latest changes from `master`. -These steps assume the `origin` remote is your fork of this repository and `upstream` is the official Purpur repository. +Steps to rebase a PR to include the latest changes from `main`. +These steps assume the `origin` remote is your fork of this repository and `upstream` is the official PurpurMC repository. -1. Pull the latest changes from upstreams master: `git checkout master && git pull upstream master`. -1. Checkout feature/fix branch and rebase on master: `git checkout patch-branch && git rebase master`. +1. Fetch the latest changes from upstream's main: `git fetch upstream`. +1. Checkout your feature/fix branch and rebase on main: `git switch patch-branch && git rebase upstream/main`. 1. Apply updated patches: `./gradlew applyPatches`. 1. If there are conflicts, fix them. -1. If your PR creates new patches instead of modifying existing ones, in both the `Purpur-Server` and `Purpur-API` directories, ensure your newly-created patch is the last commit by either: +1. If your PR creates new feature patches instead of modifying existing ones, ensure your newly-created patch is the last commit by either: * Renaming the patch file with a large 4-digit number in front (e.g. 9999-Patch-to-add-some-new-stuff.patch), and re-applying patches. * Running `git rebase --interactive base` and moving the commits to the end. 1. Rebuild patches: `./gradlew rebuildPatches`. 1. Commit modified patches. -1. Force push changes: `git push --force`. +1. Force push changes: `git push --force`. Make sure you're not deleting any of your commits or changes here! ## PR Policy @@ -203,8 +229,9 @@ when making and submitting changes. ## Formatting -All modifications to non-Purpur files should be marked. The one exception to this is -when modifying javadoc comments, which should not have these markers. +All modifications to Minecraft files and Paper files should be marked. For historical reasons, +API and API-implementation contain a lot of these too, but they are no longer +required. - You need to add a comment with a short and identifiable description of the patch: `// Purpur start - ` @@ -216,16 +243,19 @@ when modifying javadoc comments, which should not have these markers. with `// Purpur end - `. - One-line changes should have `// Purpur - ` at the end of the line. +> [!NOTE] These comments are incredibly important to be able to keep track of changes +> across files and to remember what they are for, even a decade into the future. + Here's an example of how to mark changes by Purpur: ```java -entity.getWorld().dontBeStupid(); // Purpur - Was beStupid(), which is bad +entity.getWorld().dontBeStupid(); // Purpur - Move away from beStupid() entity.getFriends().forEach(Entity::explode); entity.updateFriends(); // Purpur start - Use plugin-set spawn // entity.getWorld().explode(entity.getWorld().getSpawn()); -Location spawnLocation = ((CraftWorld)entity.getWorld()).getSpawnLocation(); +Location spawnLocation = ((CraftWorld) entity.getWorld()).getSpawnLocation(); entity.getWorld().explode(new BlockPosition(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ())); // Purpur end - Use plugin-set spawn ``` @@ -236,29 +266,49 @@ into most IDEs and formatters by default. There are a few notes, however: There are exceptions, especially in Spigot-related files - When in doubt or the code around your change is in a clearly different style, use the same style as the surrounding code. -- `var` usage is heavily discouraged, as it makes reading patch files a lot harder - and can lead to confusion during updates due to changed return types. The only - exception to this is if a line would otherwise be way too long/filled with hard - to parse generics in a case where the base type itself is already obvious +- Usage of the `var` keyword is discouraged, as it makes reading patch files a + lot harder and can lead to confusion during updates due to changed return types. + The only exception to this is if a line would otherwise be way too long/filled with + hard to parse generics in a case where the base type itself is already obvious. ### Imports -When adding new imports to a class in a file not created by the current patch, use the fully qualified class name +When adding new imports to a Minecraft or Paper class, use the fully qualified class name instead of adding a new import to the top of the file. If you are using a type a significant number of times, you -can add an import with a comment. However, if its only used a couple of times, the FQN is preferred to prevent future +can add an import with a comment. However, if it's only used a couple of times, the FQN is preferred to prevent future patch conflicts in the import section of the file. + ```java -import org.bukkit.event.Event; +import net.minecraft.server.MinecraftServer; // don't add import here, use FQN like below -public class SomeEvent extends Event { +public class SomeVanillaClass { public final org.bukkit.Location newLocation; // Purpur - add location } ``` +### Nullability annotations + +We are in the process of switching nullability annotation libraries, so you might need to use one or the other: + +**For classes we add**: Fields, method parameters and return types that are nullable should be marked via the +`@Nullable` annotation from `org.jspecify.annotations`. Whenever you create a new class, add `@NullMarked`, meaning types +are assumed to be non-null by default. For less obvious placing such as on generics or arrays, see the [JSpecify docs](https://jspecify.dev/docs/user-guide/). + +**For other classes**: Keep using both `@Nullable` and `@NotNull` from `org.jetbrains.annotations`. These +will be replaced later. + +## Access Transformers +Sometimes, Vanilla code already contains a field, method, or type you want to access +but the visibility is too low (e.g. a private field in an entity class). Purpur can use access transformers +to change the visibility or remove the final modifier from fields, methods, and classes. Inside the `build-data/purpur.at` +file, you can add ATs that are applied when you `./gradlew applyPatches`. You can read about the format of ATs +[here](https://mcforge.readthedocs.io/en/latest/advanced/accesstransformers/#access-modifiers). + + ## Obfuscation Helpers @@ -380,12 +431,6 @@ object: return this.level.purpurConfig.useInhabitedTime ? this.inhabitedTime : 0; ``` -#### Committing changes -All changes to the `PurpurConfig` and `PurpurWorldConfig` files -should be done in the commit that created them. So do an interactive rebase -or fixup to apply just those changes to that commit, then add a new commit -that includes the logic that uses that option in the server somewhere. - ## Testing API changes ### Using the Purpur Test Plugin @@ -416,36 +461,9 @@ If you use Maven to build your plugin: ## Frequently Asked Questions -### I can't find the NMS file I need! - -By default, Purpur (and upstream) only import files we make changes to. If you -would like to make changes to a file that isn't present in `Purpur-Server`'s -source directory, you just need to add it to our import script ran during the -patching process. - -1. Save (rebuild) any patches you are in the middle of working on! Their - progress will be lost if you do not; -1. Identify the name(s) of the file(s) you want to import. - - A complete list of all possible file names can be found at - `./Purpur-Server/.gradle/caches/paperweight/mc-dev-sources/net/minecraft/`. You might find - [MappingViewer] useful if you need to translate between Mojang and Spigot mapped names. -1. Open the file at `./build-data/dev-imports.txt` and add the name of your file to - the script. Follow the instructions there; -1. Re-patch the server `./gradlew applyPatches`; -1. Edit away! - -> ❗ This change is temporary! **DO NOT COMMIT CHANGES TO THIS FILE!** -> Once you have made your changes to the new file, and rebuilt patches, you may -> undo your changes to `dev-imports.txt`. - -Any file modified in a patch file gets automatically imported, so you only need -this temporarily to import it to create the first patch. - -To undo your changes to the file, type `git checkout build-data/dev-imports.txt`. - ### My commit doesn't need a build, what do I do? -Well, quite simple: You add `[ci skip]` to the start of your commit subject. +Quite simple: You add `[ci skip]` to the start of your commit subject. This case most often applies to changes to files like `README.md`, this very file (`CONTRIBUTING.md`), the `LICENSE.md` file, and so forth. @@ -455,11 +473,11 @@ file (`CONTRIBUTING.md`), the `LICENSE.md` file, and so forth. This only applies if you're running Windows. If you're running a prior Windows release, either update to Windows 10/11 or move to macOS/Linux/BSD. -In order to speed up patching process on Windows, it's recommended you get WSL -2. This is available in Windows 10 v2004, build 19041 or higher. (You can check - your version by running `winver` in the run window (Windows key + R)). If you're - using an out of date version of Windows 10, update your system with the - [Windows 10 Update Assistant](https://www.microsoft.com/en-us/software-download/windows10) or [Windows 11 Update Assistant](https://www.microsoft.com/en-us/software-download/windows11). +In order to speed up patching process on Windows, it's recommended you get WSL 2. +This is available in Windows 10 v2004, build 19041 or higher. (You can check +your version by running `winver` in the run window (Windows key + R)). If you're +using an out of date version of Windows 10, update your system with the +[Windows 10 Update Assistant](https://www.microsoft.com/en-us/software-download/windows10) or [Windows 11 Update Assistant](https://www.microsoft.com/en-us/software-download/windows11). To set up WSL 2, follow the information here: @@ -473,5 +491,3 @@ everything like usual. > ❗ Do not use the `/mnt/` directory in WSL! Instead, mount the WSL directories > in Windows like described here: > - -[MappingViewer]: https://mappings.cephx.dev/ diff --git a/README.md b/README.md index 74d937f47..f8cce85a3 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Join us on Discord: ## Downloads Downloads can be obtained from the [downloads page](https://purpurmc.org/downloads/) or the [downloads API](https://api.purpurmc.org). -[![Build Status](https://img.shields.io/github/actions/workflow/status/PurpurMC/Purpur/build.yml?branch=ver%2F1.20.6&event=push&label=Downloads&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9bxSIVh1YQcYhQnSyIiuimVShChVArtOpgcukXNGlIUlwcBdeCgx+LVQcXZ10dXAVB8APE0clJ0UVK/F9SaBHjwXE/3t173L0D/PUyU82OMUDVLCOViAuZ7KrQ9YogwujDEGYkZupzopiE5/i6h4+vdzGe5X3uz9Gj5EwG+ATiWaYbFvEG8dSmpXPeJ46woqQQnxOPGnRB4keuyy6/cS447OeZESOdmieOEAuFNpbbmBUNlXiSOKqoGuX7My4rnLc4q+Uqa96TvzCU01aWuU5zEAksYgkiBMioooQyLMRo1UgxkaL9uId/wPGL5JLJVQIjxwIqUCE5fvA/+N2tmZ8Yd5NCcaDzxbY/hoGuXaBRs+3vY9tunACBZ+BKa/krdWD6k/RaS4seAb3bwMV1S5P3gMsdoP9JlwzJkQI0/fk88H5G35QFwrdA95rbW3Mfpw9AmrpK3gAHh8BIgbLXPd4dbO/t3zPN/n4Ax9dyyerighsAAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfmCBMWBjFhOpnxAAACyklEQVQ4y32TXWgdZRCGn8k5Z3e/bzcJRFuoDRqIIPGniaSl1qgXKYhiLUgleFESW1qQ4g94oVKQJmga0ILRBuvfheJFIbY3SmzRFsWgQrTQFlRoKSVXgcMxJiS7++1ukvHiNKGU6FzNDO8MMw8zwn9Yz5c6anKeChxiMk599aq8sZ5Obk3sGNd7G5aZCHJ+Oj8gAwD9I3rSJmyvzLHz+HG5frO+vOaNa3NXiUkKQj9hQ1jQgWrlyCCV6gIdtmBjoJwbPqgL+R08PDQkCUADwD0TerqzxFTJY++vz0l7c0q/F7P5+aNUqyvM2CU2RAV7hsek3XPs3/QHF7/YrSfrDVQrxrErdESNNTYByAp3NmWUTYaGGSuho+QltAGYRdqilChMeKbO4Ijang5+CVJmbcr20PG3n9NiY6ZOvCW9ACMHdDLIeDDIqTWmtAQJV6OMyhOTsqWBQQo/hvP7pFcWeDxwtAQxGqbEq3isI7EOjRy3NyuPPHtOur0UXWMQZXgAX78uP3sJpTBmyHfsGDmotdF+rQWObq/gnSCm9PQ3chnA3qgRgL5jmjXlTM/n7Ny8yJXRY2IA3tur0yaHF8blLoAzj2kaNNBpZvk2iGntuiZBHWLOtXJC3hbzV5SxtDq6yZmzCXOrsRezHNa4YBzlKGN6bQXryD96W+4PU14zGbw/oLMf79EPbAI2g7M9+smP3fqPKVAT81LnFWnzM1y9gYC9gWtwTD6MEsq+Y8Lm7DMZ7cZxt5/T5xd8Fy5SfuC6fA4QZjdd8eEX9eLwAZ1StHKiT1MARStnHtWZH7bpjKIVgKutmipq50O94Mr6+9oKR8ekyy7x5qd9/NmYslynK4WfUjWOqiAFgElZmY+41BTzcrAkW9d9ptO9etgU7I8S3vVyDtkY/JzPwoxXzCJjt6Uy+r/fuGq/3affezkPRSniJ0y2zsqT6+n+BfRHKWgwbKNIAAAAAElFTkSuQmCC)](https://purpurmc.org/downloads/) +[![Build Status](https://img.shields.io/github/actions/workflow/status/PurpurMC/Purpur/build.yml?branch=ver%2F1.21.4&event=push&label=Downloads&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9bxSIVh1YQcYhQnSyIiuimVShChVArtOpgcukXNGlIUlwcBdeCgx+LVQcXZ10dXAVB8APE0clJ0UVK/F9SaBHjwXE/3t173L0D/PUyU82OMUDVLCOViAuZ7KrQ9YogwujDEGYkZupzopiE5/i6h4+vdzGe5X3uz9Gj5EwG+ATiWaYbFvEG8dSmpXPeJ46woqQQnxOPGnRB4keuyy6/cS447OeZESOdmieOEAuFNpbbmBUNlXiSOKqoGuX7My4rnLc4q+Uqa96TvzCU01aWuU5zEAksYgkiBMioooQyLMRo1UgxkaL9uId/wPGL5JLJVQIjxwIqUCE5fvA/+N2tmZ8Yd5NCcaDzxbY/hoGuXaBRs+3vY9tunACBZ+BKa/krdWD6k/RaS4seAb3bwMV1S5P3gMsdoP9JlwzJkQI0/fk88H5G35QFwrdA95rbW3Mfpw9AmrpK3gAHh8BIgbLXPd4dbO/t3zPN/n4Ax9dyyerighsAAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfmCBMWBjFhOpnxAAACyklEQVQ4y32TXWgdZRCGn8k5Z3e/bzcJRFuoDRqIIPGniaSl1qgXKYhiLUgleFESW1qQ4g94oVKQJmga0ILRBuvfheJFIbY3SmzRFsWgQrTQFlRoKSVXgcMxJiS7++1ukvHiNKGU6FzNDO8MMw8zwn9Yz5c6anKeChxiMk599aq8sZ5Obk3sGNd7G5aZCHJ+Oj8gAwD9I3rSJmyvzLHz+HG5frO+vOaNa3NXiUkKQj9hQ1jQgWrlyCCV6gIdtmBjoJwbPqgL+R08PDQkCUADwD0TerqzxFTJY++vz0l7c0q/F7P5+aNUqyvM2CU2RAV7hsek3XPs3/QHF7/YrSfrDVQrxrErdESNNTYByAp3NmWUTYaGGSuho+QltAGYRdqilChMeKbO4Ijang5+CVJmbcr20PG3n9NiY6ZOvCW9ACMHdDLIeDDIqTWmtAQJV6OMyhOTsqWBQQo/hvP7pFcWeDxwtAQxGqbEq3isI7EOjRy3NyuPPHtOur0UXWMQZXgAX78uP3sJpTBmyHfsGDmotdF+rQWObq/gnSCm9PQ3chnA3qgRgL5jmjXlTM/n7Ny8yJXRY2IA3tur0yaHF8blLoAzj2kaNNBpZvk2iGntuiZBHWLOtXJC3hbzV5SxtDq6yZmzCXOrsRezHNa4YBzlKGN6bQXryD96W+4PU14zGbw/oLMf79EPbAI2g7M9+smP3fqPKVAT81LnFWnzM1y9gYC9gWtwTD6MEsq+Y8Lm7DMZ7cZxt5/T5xd8Fy5SfuC6fA4QZjdd8eEX9eLwAZ1StHKiT1MARStnHtWZH7bpjKIVgKutmipq50O94Mr6+9oKR8ekyy7x5qd9/NmYslynK4WfUjWOqiAFgElZmY+41BTzcrAkW9d9ptO9etgU7I8S3vVyDtkY/JzPwoxXzCJjt6Uy+r/fuGq/3affezkPRSniJ0y2zsqT6+n+BfRHKWgwbKNIAAAAAElFTkSuQmCC)](https://purpurmc.org/downloads/) Downloads API endpoints: * List versions of Minecraft with builds available: @@ -67,7 +67,7 @@ Maven org.purpurmc.purpur purpur-api - 1.20.6-R0.1-SNAPSHOT + 1.21.4-R0.1-SNAPSHOT provided ``` @@ -80,7 +80,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("org.purpurmc.purpur:purpur-api:1.20.5-R0.1-SNAPSHOT") + compileOnly("org.purpurmc.purpur:purpur-api:1.21.4-R0.1-SNAPSHOT") } ``` diff --git a/build-data/dev-imports.txt b/build-data/dev-imports.txt index b818b96e2..1d9862a95 100644 --- a/build-data/dev-imports.txt +++ b/build-data/dev-imports.txt @@ -8,3 +8,7 @@ # To import classes from the vanilla Minecraft jar use `minecraft` as the artifactId: # minecraft net.minecraft.world.level.entity.LevelEntityGetterAdapter # minecraft net/minecraft/world/level/entity/LevelEntityGetter.java +# To import minecraft data files, like the default chat type, use `mc_data` as the prefix: +# mc_data chat_type/chat.json +# mc_data dimension_type/overworld.json +# diff --git a/build-data/purpur.at b/build-data/purpur.at new file mode 100644 index 000000000..a8a06867e --- /dev/null +++ b/build-data/purpur.at @@ -0,0 +1,10 @@ +# This file is auto generated, any changes may be overridden! +# See CONTRIBUTING.md on how to add access transformers. +protected net.minecraft.world.entity.Entity dimensions +public net.minecraft.world.entity.Entity updateInWaterStateAndDoWaterCurrentPushing()V +public net.minecraft.world.entity.LivingEntity canGlide()Z +public net.minecraft.world.entity.monster.Shulker MAX_SCALE +public net.minecraft.world.entity.player.Player canGlide()Z +public net.minecraft.world.level.block.entity.FuelValues values +public-f net.minecraft.world.entity.EntityType dimensions +public-f net.minecraft.world.level.block.state.BlockBehaviour explosionResistance diff --git a/build.gradle.kts b/build.gradle.kts index 44d772656..55d26f597 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,28 +2,49 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent plugins { - java - `maven-publish` - id("io.papermc.paperweight.patcher") version "1.6.3" -} - -allprojects { - apply(plugin = "java") - apply(plugin = "maven-publish") - - java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } - } + java // TODO java launcher tasks + id("io.papermc.paperweight.patcher") version "2.0.0-beta.14" } val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" +paperweight { + upstreams.paper { + ref = providers.gradleProperty("paperCommit") + + patchFile { + path = "paper-server/build.gradle.kts" + outputFile = file("purpur-server/build.gradle.kts") + patchFile = file("purpur-server/build.gradle.kts.patch") + } + patchFile { + path = "paper-api/build.gradle.kts" + outputFile = file("purpur-api/build.gradle.kts") + patchFile = file("purpur-api/build.gradle.kts.patch") + } + patchDir("paperApi") { + upstreamPath = "paper-api" + excludes = setOf("build.gradle.kts") + patchesDir = file("purpur-api/paper-patches") + outputDir = file("paper-api") + } + } +} + subprojects { - tasks.withType().configureEach { + apply(plugin = "java-library") + apply(plugin = "maven-publish") + + extensions.configure { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + tasks.withType { options.encoding = Charsets.UTF_8.name() options.release = 21 + options.isFork = true } tasks.withType { options.encoding = Charsets.UTF_8.name() @@ -38,67 +59,18 @@ subprojects { events(TestLogEvent.STANDARD_OUT) } } + tasks.withType().configureEach { + isPreserveFileTimestamps = false + isReproducibleFileOrder = true + } repositories { mavenCentral() maven(paperMavenPublicUrl) - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") // TODO - Adventure snapshot maven("https://jitpack.io") } -} -repositories { - mavenCentral() - maven(paperMavenPublicUrl) { - content { - onlyForConfigurations(configurations.paperclip.name) - } - } -} - -dependencies { - remapper("net.fabricmc:tiny-remapper:0.10.1:fat") - decompiler("org.vineflower:vineflower:1.10.1") - paperclip("io.papermc:paperclip:3.0.3") -} - -paperweight { - serverProject = project(":purpur-server") - - remapRepo = paperMavenPublicUrl - decompileRepo = paperMavenPublicUrl - - usePaperUpstream(providers.gradleProperty("paperCommit")) { - withPaperPatcher { - apiPatchDir = layout.projectDirectory.dir("patches/api") - apiOutputDir = layout.projectDirectory.dir("Purpur-API") - - serverPatchDir = layout.projectDirectory.dir("patches/server") - serverOutputDir = layout.projectDirectory.dir("Purpur-Server") - } - - patchTasks.register("generatedApi") { - isBareDirectory = true - upstreamDirPath = "paper-api-generator/generated" - patchDir = layout.projectDirectory.dir("patches/generated-api") - outputDir = layout.projectDirectory.dir("paper-api-generator/generated") - } - } -} - -tasks.generateDevelopmentBundle { - apiCoordinates = "org.purpurmc.purpur:purpur-api" - mojangApiCoordinates = "io.papermc.paper:paper-mojangapi" - libraryRepositories = listOf( - "https://repo.maven.apache.org/maven2/", - paperMavenPublicUrl, - "https://repo.purpurmc.org/snapshots", - "https://s01.oss.sonatype.org/content/repositories/snapshots/", // TODO - Adventure snapshot - ) -} - -allprojects { - publishing { + extensions.configure { repositories { maven("https://repo.purpurmc.org/snapshots") { name = "purpur" @@ -108,14 +80,6 @@ allprojects { } } -publishing { - publications.create("devBundle") { - artifact(tasks.generateDevelopmentBundle) { - artifactId = "dev-bundle" - } - } -} - tasks.register("printMinecraftVersion") { doLast { println(providers.gradleProperty("mcVersion").get().trim()) diff --git a/gradle.properties b/gradle.properties index 84f8a3a7a..c9076a35f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ group = org.purpurmc.purpur -version = 1.20.6-R0.1-SNAPSHOT +version = 1.21.4-R0.1-SNAPSHOT -mcVersion = 1.20.6 -paperCommit = eee55d019fe80372c2e08ccd1d0a94c066cda926 +mcVersion = 1.21.4 +paperCommit = 54b2e9d9738ce32e2f415c321f20e3fc07063c14 +org.gradle.configuration-cache = true org.gradle.caching = true org.gradle.parallel = true org.gradle.vfs.watch = false -org.gradle.jvmargs = -Xmx3G diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f..7f93135c4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a4..cea7a793a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a426..0adc8e1a5 100755 --- a/gradlew +++ b/gradlew @@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 25da30dbd..93e3f59f1 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. goto fail diff --git a/patches/dropped-api/0011-LivingEntity-safeFallDistance.patch b/patches/1-20-6/dropped-api/0011-LivingEntity-safeFallDistance.patch similarity index 100% rename from patches/dropped-api/0011-LivingEntity-safeFallDistance.patch rename to patches/1-20-6/dropped-api/0011-LivingEntity-safeFallDistance.patch diff --git a/patches/dropped-api/0032-Potion-NamespacedKey.patch b/patches/1-20-6/dropped-api/0032-Potion-NamespacedKey.patch similarity index 100% rename from patches/dropped-api/0032-Potion-NamespacedKey.patch rename to patches/1-20-6/dropped-api/0032-Potion-NamespacedKey.patch diff --git a/patches/dropped-api/0041-Add-item-packet-serialize-event.patch b/patches/1-20-6/dropped-api/0041-Add-item-packet-serialize-event.patch similarity index 100% rename from patches/dropped-api/0041-Add-item-packet-serialize-event.patch rename to patches/1-20-6/dropped-api/0041-Add-item-packet-serialize-event.patch diff --git a/patches/dropped-api/0049-Add-hover-lines-API.patch b/patches/1-20-6/dropped-api/0049-Add-hover-lines-API.patch similarity index 100% rename from patches/dropped-api/0049-Add-hover-lines-API.patch rename to patches/1-20-6/dropped-api/0049-Add-hover-lines-API.patch diff --git a/patches/dropped-server/0013-LivingEntity-safeFallDistance.patch b/patches/1-20-6/dropped-server/0013-LivingEntity-safeFallDistance.patch similarity index 100% rename from patches/dropped-server/0013-LivingEntity-safeFallDistance.patch rename to patches/1-20-6/dropped-server/0013-LivingEntity-safeFallDistance.patch diff --git a/patches/dropped-server/0220-Potion-NamespacedKey.patch b/patches/1-20-6/dropped-server/0220-Potion-NamespacedKey.patch similarity index 100% rename from patches/dropped-server/0220-Potion-NamespacedKey.patch rename to patches/1-20-6/dropped-server/0220-Potion-NamespacedKey.patch diff --git a/patches/dropped-server/0236-Configurable-food-attributes.patch b/patches/1-20-6/dropped-server/0236-Configurable-food-attributes.patch similarity index 100% rename from patches/dropped-server/0236-Configurable-food-attributes.patch rename to patches/1-20-6/dropped-server/0236-Configurable-food-attributes.patch diff --git a/patches/dropped-server/0255-Send-client-custom-name-of-BE.patch b/patches/1-20-6/dropped-server/0255-Send-client-custom-name-of-BE.patch similarity index 100% rename from patches/dropped-server/0255-Send-client-custom-name-of-BE.patch rename to patches/1-20-6/dropped-server/0255-Send-client-custom-name-of-BE.patch diff --git a/patches/dropped-server/0263-Allay-respect-item-NBT.patch b/patches/1-20-6/dropped-server/0263-Allay-respect-item-NBT.patch similarity index 100% rename from patches/dropped-server/0263-Allay-respect-item-NBT.patch rename to patches/1-20-6/dropped-server/0263-Allay-respect-item-NBT.patch diff --git a/patches/dropped-server/0271-Add-item-packet-serialize-event.patch b/patches/1-20-6/dropped-server/0271-Add-item-packet-serialize-event.patch similarity index 100% rename from patches/dropped-server/0271-Add-item-packet-serialize-event.patch rename to patches/1-20-6/dropped-server/0271-Add-item-packet-serialize-event.patch diff --git a/patches/dropped-server/0292-Add-hover-lines-API.patch b/patches/1-20-6/dropped-server/0292-Add-hover-lines-API.patch similarity index 100% rename from patches/dropped-server/0292-Add-hover-lines-API.patch rename to patches/1-20-6/dropped-server/0292-Add-hover-lines-API.patch diff --git a/patches/api/0015-LivingEntity-broadcastItemBreak.patch b/patches/1-21-1/dropped-api/0016-LivingEntity-broadcastItemBreak.patch similarity index 90% rename from patches/api/0015-LivingEntity-broadcastItemBreak.patch rename to patches/1-21-1/dropped-api/0016-LivingEntity-broadcastItemBreak.patch index 439fc7df5..7157d3d5f 100644 --- a/patches/api/0015-LivingEntity-broadcastItemBreak.patch +++ b/patches/1-21-1/dropped-api/0016-LivingEntity-broadcastItemBreak.patch @@ -5,7 +5,7 @@ Subject: [PATCH] LivingEntity#broadcastItemBreak diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index b777e530122549455dcce6fac8d4a151c1c0af42..aba9952b2256b058eb413ce93f3305c861a200db 100644 +index 5c29956c6db53440322330ff723c7087193641f1..e1079c5c4be99e75a646c090189678dd131f210e 100644 --- a/src/main/java/org/bukkit/entity/LivingEntity.java +++ b/src/main/java/org/bukkit/entity/LivingEntity.java @@ -1447,4 +1447,13 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource diff --git a/patches/server/0040-End-gateway-should-check-if-entity-can-use-portal.patch b/patches/1-21-1/dropped-server/0040-End-gateway-should-check-if-entity-can-use-portal.patch similarity index 100% rename from patches/server/0040-End-gateway-should-check-if-entity-can-use-portal.patch rename to patches/1-21-1/dropped-server/0040-End-gateway-should-check-if-entity-can-use-portal.patch diff --git a/patches/server/0084-LivingEntity-broadcastItemBreak.patch b/patches/1-21-1/dropped-server/0082-LivingEntity-broadcastItemBreak.patch similarity index 85% rename from patches/server/0084-LivingEntity-broadcastItemBreak.patch rename to patches/1-21-1/dropped-server/0082-LivingEntity-broadcastItemBreak.patch index d815a2657..1e339efeb 100644 --- a/patches/server/0084-LivingEntity-broadcastItemBreak.patch +++ b/patches/1-21-1/dropped-server/0082-LivingEntity-broadcastItemBreak.patch @@ -5,10 +5,10 @@ Subject: [PATCH] LivingEntity#broadcastItemBreak diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index aa351df679f300018367244c7ccb3e5a59e9276f..11bd76d79bbfff68734d8ee1095f21c5c50e7bde 100644 +index a1e715629313346f670bce92483996122b0f1d7b..386647f6000c71c59ab8d7875219eefdc5a3d7ef 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -1173,4 +1173,12 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { +@@ -1181,4 +1181,12 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { this.getHandle().setYBodyRot(bodyYaw); } // Paper end - body yaw API diff --git a/patches/server/0094-Allow-infinite-and-mending-enchantments-together.patch b/patches/1-21-1/dropped-server/0094-Allow-infinite-and-mending-enchantments-together.patch similarity index 100% rename from patches/server/0094-Allow-infinite-and-mending-enchantments-together.patch rename to patches/1-21-1/dropped-server/0094-Allow-infinite-and-mending-enchantments-together.patch diff --git a/patches/server/0142-Allow-infinity-on-crossbows.patch b/patches/1-21-1/dropped-server/0142-Allow-infinity-on-crossbows.patch similarity index 100% rename from patches/server/0142-Allow-infinity-on-crossbows.patch rename to patches/1-21-1/dropped-server/0142-Allow-infinity-on-crossbows.patch diff --git a/patches/server/0282-Add-mending-multiplier.patch b/patches/1-21-1/dropped-server/0282-Add-mending-multiplier.patch similarity index 89% rename from patches/server/0282-Add-mending-multiplier.patch rename to patches/1-21-1/dropped-server/0282-Add-mending-multiplier.patch index ce3c80474..53fb2e556 100644 --- a/patches/server/0282-Add-mending-multiplier.patch +++ b/patches/1-21-1/dropped-server/0282-Add-mending-multiplier.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add mending multiplier diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -index ce608784e0e35b67dde377436aaf42c956ce0644..f5debc8ddc496cd3e2d8b253511ee5cc9a723b38 100644 +index 7130d483ccdce26526e715bd7e68d2e896e6215f..40d168d225932717b8ac8bdd27dfe2a202bc2808 100644 --- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java +++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -@@ -366,13 +366,15 @@ public class ExperienceOrb extends Entity { +@@ -372,13 +372,15 @@ public class ExperienceOrb extends Entity { } } @@ -27,7 +27,7 @@ index ce608784e0e35b67dde377436aaf42c956ce0644..f5debc8ddc496cd3e2d8b253511ee5cc public int getValue() { return this.value; diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 8c7508fc6163a73740aedbe9c4dee2d21c4fa0fa..03819b5d991d91c2e7f5e2eae50e1a7e4197336b 100644 +index 02b8333222668c3419296ec5513c1c4e8e8d1a79..3c614b8f62c0d3839ebc4e948c952d52c4f66819 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java @@ -119,6 +119,7 @@ public class PurpurWorldConfig { diff --git a/patches/server/0225-Shears-can-have-looting-enchantment.patch b/patches/1-21-3/dropped-server/0224-Shears-can-have-looting-enchantment.patch similarity index 62% rename from patches/server/0225-Shears-can-have-looting-enchantment.patch rename to patches/1-21-3/dropped-server/0224-Shears-can-have-looting-enchantment.patch index 059266542..c68a2bdb9 100644 --- a/patches/server/0225-Shears-can-have-looting-enchantment.patch +++ b/patches/1-21-3/dropped-server/0224-Shears-can-have-looting-enchantment.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Shears can have looting enchantment diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -index a024c697a65bbab27408da1d6a75e531d9719b47..e4fab82b369f2c2ea0d8c8acd814d06140d551fc 100644 +index 44b79a7c2f8b95a484d1999fa2167ce588f7985b..68632372c8704058f35f12e0ae6cdd98ebd55937 100644 --- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -@@ -105,7 +105,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { +@@ -104,7 +104,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { if (ishearable.readyForShearing()) { // CraftBukkit start // Paper start - Add drops to shear events @@ -31,7 +31,7 @@ index 2ee48ac3b665db2b02bcb1a30ec972d43a3725b0..59e8f5431ce5026209e1428b5fa5b548 } // Paper end - custom shear drops diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index 06fac8dae42451f912c2db14d792461cee3dba83..a7c95199234231db14faa4a07953bcde57d9861d 100644 +index 06fac8dae42451f912c2db14d792461cee3dba83..e5a84dd5f1a375dd44b9d14dc7f44339bd8ddf3a 100644 --- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java @@ -161,7 +161,7 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder drops = this.generateDefaultDrops(); -+ java.util.List drops = this.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getMobLooting(player)); // Purpur ++ java.util.List drops = this.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.LOOTING, itemstack)); // Purpur org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); if (event != null) { if (event.isCancelled()) { @@ -61,19 +61,19 @@ index 06fac8dae42451f912c2db14d792461cee3dba83..a7c95199234231db14faa4a07953bcde } return dropEntities; diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -index 9e617b3f1ec4eac5f83bdf19a3563cdc81b008d8..6b1244d3957e7f62c96ffd34692b8916337839fd 100644 +index ca63c98bc45584812c0fb2af84a63aa08daa9a9e..17b49186293578c06144a476473324a9a1f6fcbb 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java +++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -297,7 +297,7 @@ public class Sheep extends Animal implements Shearable { +@@ -296,7 +296,7 @@ public class Sheep extends Animal implements Shearable { if (!this.level().isClientSide && this.readyForShearing()) { // CraftBukkit start // Paper start - custom shear drops - java.util.List drops = this.generateDefaultDrops(); -+ java.util.List drops = this.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getMobLooting(player)); // Purpur ++ java.util.List drops = this.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.LOOTING, itemstack)); // Purpur org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); if (event != null) { if (event.isCancelled()) { -@@ -322,12 +322,13 @@ public class Sheep extends Animal implements Shearable { +@@ -321,12 +321,13 @@ public class Sheep extends Animal implements Shearable { @Override public void shear(SoundSource shearedSoundCategory) { // Paper start - custom shear drops @@ -90,19 +90,19 @@ index 9e617b3f1ec4eac5f83bdf19a3563cdc81b008d8..6b1244d3957e7f62c96ffd34692b8916 for (int j = 0; j < count; ++j) { dropEntities.add(new ItemStack(Sheep.ITEM_BY_DYE.get(this.getColor()))); diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index 69cdccca01fe7d10e6d958e16d91efe08f699505..3b74931ae4e3a869d8db38c119e57b44af887859 100644 +index b3bb0d55da0278d4981830f7073bb326bc836215..7bd2d2b9bb1275fa8e4bdc6d498a59e47838930f 100644 --- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java +++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -189,7 +189,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -190,7 +190,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { // CraftBukkit start // Paper start - custom shear drops - java.util.List drops = this.generateDefaultDrops(); -+ java.util.List drops = this.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getMobLooting(player)); // Purpur ++ java.util.List drops = this.generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.LOOTING, itemstack)); // Purpur org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); if (event != null) { if (event.isCancelled()) { -@@ -222,11 +222,20 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -223,11 +223,20 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM @Override public void shear(SoundSource shearedSoundCategory) { // Paper start - custom shear drops @@ -126,35 +126,90 @@ index 69cdccca01fe7d10e6d958e16d91efe08f699505..3b74931ae4e3a869d8db38c119e57b44 } diff --git a/src/main/java/net/minecraft/world/entity/monster/Bogged.java b/src/main/java/net/minecraft/world/entity/monster/Bogged.java -index e9f9b041ae7195e9d23bd446454b1d8c47a1ace1..03b1023e182744a84d324bdad082cc1b9e574e30 100644 +index 71efea7a6bfb5662890dae5faae27a3c80afad2b..f3aae2c50d05a05ad4aef36d432b87b431ba07e8 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Bogged.java +++ b/src/main/java/net/minecraft/world/entity/monster/Bogged.java -@@ -159,7 +159,7 @@ public class Bogged extends AbstractSkeleton implements Shearable { +@@ -104,7 +104,7 @@ public class Bogged extends AbstractSkeleton implements Shearable { + if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { + // CraftBukkit start + // Paper start - expose drops in event +- java.util.List drops = generateDefaultDrops(); ++ java.util.List drops = generateDefaultDrops(net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.LOOTING, itemstack)); // Purpur + final org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); + if (event != null) { + if (event.isCancelled()) { +@@ -171,7 +171,7 @@ public class Bogged extends AbstractSkeleton implements Shearable { + @Override + public void shear(SoundSource shearedSoundCategory) { + // Paper start - shear drop API +- this.shear(shearedSoundCategory, generateDefaultDrops()); ++ this.shear(shearedSoundCategory, generateDefaultDrops(0)); // Purpur + } + + @Override +@@ -184,7 +184,7 @@ public class Bogged extends AbstractSkeleton implements Shearable { + + private void spawnShearedMushrooms() { + // Paper start - shear drops API +- this.spawnDrops(generateDefaultDrops()); // Only here for people calling spawnSheardMushrooms. Not used otherwise. ++ this.spawnDrops(generateDefaultDrops(0)); // Only here for people calling spawnSheardMushrooms. Not used otherwise. // Purpur + } + private void spawnDrops(java.util.List drops) { + drops.forEach(stack -> { +@@ -193,14 +193,22 @@ public class Bogged extends AbstractSkeleton implements Shearable { + this.forceDrops = false; + }); + } +- private void generateShearedMushrooms(java.util.function.Consumer stackConsumer) { ++ private void generateShearedMushrooms(java.util.function.Consumer stackConsumer, int looting) { // Purpur + // Paper end - shear drops API + Level world = this.level(); + + if (world instanceof ServerLevel worldserver) { + LootTable loottable = worldserver.getServer().reloadableRegistries().getLootTable(BuiltInLootTables.BOGGED_SHEAR); + LootParams lootparams = (new LootParams.Builder(worldserver)).withParameter(LootContextParams.ORIGIN, this.position()).withParameter(LootContextParams.THIS_ENTITY, this).create(LootContextParamSets.SHEARING); +- ObjectListIterator objectlistiterator = loottable.getRandomItems(lootparams).iterator(); ++ // Purpur start ++ it.unimi.dsi.fastutil.objects.ObjectArrayList randomItemsList = loottable.getRandomItems(lootparams); ++ if (org.purpurmc.purpur.PurpurConfig.allowShearsLooting && looting > 0) { ++ for (int i = 0; i < looting; i++) { ++ randomItemsList.addAll(loottable.getRandomItems(lootparams)); ++ } ++ } ++ ObjectListIterator objectlistiterator = randomItemsList.iterator(); ++ // Purpur end + + while (objectlistiterator.hasNext()) { + ItemStack itemstack = (ItemStack) objectlistiterator.next(); +@@ -213,9 +221,9 @@ public class Bogged extends AbstractSkeleton implements Shearable { // Paper start - shear drops API @Override - public java.util.List generateDefaultDrops() { + public java.util.List generateDefaultDrops(int looting) { // Purpur final java.util.List drops = new java.util.ArrayList<>(); - this.generateShearedMushrooms(drops::add); +- this.generateShearedMushrooms(drops::add); ++ this.generateShearedMushrooms(drops::add, looting); // Purpur return drops; + } + // Paper end - shear drops API diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index cd27c2a3343133d688592791bec2a031410ff93f..91d5c175752f6ee850adada6802c8af8f833d9c7 100644 +index 7ad309e81ec61a6f2553e9ffeb9a986f4d569b37..3d5c89238ee3fbd3c9b33107995ae47733539960 100644 --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -391,6 +391,7 @@ public class PurpurConfig { - - public static boolean allowInfinityMending = false; - public static boolean allowCrossbowInfinity = true; -+ public static boolean allowShearsLooting = false; - public static boolean allowUnsafeEnchants = false; - public static boolean allowInapplicableEnchants = true; - public static boolean allowIncompatibleEnchants = true; -@@ -413,6 +414,7 @@ public class PurpurConfig { +@@ -393,6 +393,7 @@ public class PurpurConfig { + } + } + ++ public static boolean allowShearsLooting = false; + public static boolean allowInapplicableEnchants = false; + public static boolean allowIncompatibleEnchants = false; + public static boolean allowHigherEnchantsLevels = false; +@@ -416,6 +417,7 @@ public class PurpurConfig { + } + set("settings.enchantment.anvil.allow-unsafe-enchants", null); } - allowInfinityMending = getBoolean("settings.enchantment.allow-infinity-and-mending-together", allowInfinityMending); - allowCrossbowInfinity = getBoolean("settings.enchantment.allow-infinity-on-crossbow", allowCrossbowInfinity); + allowShearsLooting = getBoolean("settings.enchantment.allow-looting-on-shears", allowShearsLooting); - allowUnsafeEnchants = getBoolean("settings.enchantment.anvil.allow-unsafe-enchants", allowUnsafeEnchants); allowInapplicableEnchants = getBoolean("settings.enchantment.anvil.allow-inapplicable-enchants", allowInapplicableEnchants); allowIncompatibleEnchants = getBoolean("settings.enchantment.anvil.allow-incompatible-enchants", allowIncompatibleEnchants); + allowHigherEnchantsLevels = getBoolean("settings.enchantment.anvil.allow-higher-enchants-levels", allowHigherEnchantsLevels); diff --git a/patches/server/0255-Remove-Mojang-Profiler.patch b/patches/1-21-3/dropped-server/0247-Remove-Mojang-Profiler.patch similarity index 50% rename from patches/server/0255-Remove-Mojang-Profiler.patch rename to patches/1-21-3/dropped-server/0247-Remove-Mojang-Profiler.patch index 9f7c152f3..6bd55ce39 100644 --- a/patches/server/0255-Remove-Mojang-Profiler.patch +++ b/patches/1-21-3/dropped-server/0247-Remove-Mojang-Profiler.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Remove Mojang Profiler diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 67ec90a2a05269a5912b3c8e64d6d4162a8c6ca2..d3c42c19a051fb3a670e541fc746b55717192a91 100644 +index d8ee4422a13c7f09b84e9bbe8b57f0c139caac32..0ba926b6ff0bd54159765cc7f37d1753ded89dee 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -166,7 +166,7 @@ public class Commands { +@@ -169,7 +169,7 @@ public class Commands { DamageCommand.register(this.dispatcher, commandRegistryAccess); DataCommands.register(this.dispatcher); DataPackCommand.register(this.dispatcher); @@ -17,24 +17,24 @@ index 67ec90a2a05269a5912b3c8e64d6d4162a8c6ca2..d3c42c19a051fb3a670e541fc746b557 DefaultGameModeCommands.register(this.dispatcher); DifficultyCommand.register(this.dispatcher); EffectCommands.register(this.dispatcher, commandRegistryAccess); -@@ -333,9 +333,9 @@ public class Commands { - public void performCommand(ParseResults parseresults, String s, String label) { // CraftBukkit +@@ -351,9 +351,9 @@ public class Commands { + // Paper end CommandSourceStack commandlistenerwrapper = (CommandSourceStack) parseresults.getContext().getSource(); -- commandlistenerwrapper.getServer().getProfiler().push(() -> { -+ /*commandlistenerwrapper.getServer().getProfiler().push(() -> { // Purpur +- Profiler.get().push(() -> { ++ /*Profiler.get().push(() -> { // Purpur return "/" + s; - }); + });*/ // Purpur ContextChain contextchain = this.finishParsing(parseresults, s, commandlistenerwrapper, label); // CraftBukkit // Paper - Add UnknownCommandEvent try { -@@ -364,7 +364,7 @@ public class Commands { +@@ -383,7 +383,7 @@ public class Commands { Commands.LOGGER.error("'/{}' threw an exception", s, exception); } } finally { -- commandlistenerwrapper.getServer().getProfiler().pop(); -+ //commandlistenerwrapper.getServer().getProfiler().pop(); // Purpur +- Profiler.get().pop(); ++ //Profiler.get().pop(); // Purpur } } @@ -83,18 +83,16 @@ index e9775b4506909bee65a74964f0d5391a0513de1d..684f7f202305c09b1037c5d38a52a5ea } } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index f3c66049ab3fe087fa0fa87c2fca36c3c8b5c572..dfeae138e830e95ab823b6349a91160b02622208 100644 +index 2065f03b70bc77fffd8bac4fab6efc89d598f8b4..cb18ba70ea12785a95de90e4f9d1533ab755a576 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -347,13 +347,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + //this.metricsRecorder = InactiveMetricsRecorder.INSTANCE; // Purpur -+ //this.profiler = this.metricsRecorder.getProfiler(); // Purpur + /*this.onMetricsRecordingStopped = (methodprofilerresults) -> { // Purpur this.stopRecordingMetrics(); - }; @@ -106,8 +104,8 @@ index f3c66049ab3fe087fa0fa87c2fca36c3c8b5c572..dfeae138e830e95ab823b6349a91160b this.random = RandomSource.create(); this.port = -1; this.levels = Maps.newLinkedHashMap(); -@@ -973,9 +973,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - return false; - } : this::haveTime); -- this.profiler.popPush("nextTickWait"); -+ //this.profiler.popPush("nextTickWait"); // Purpur - this.mayHaveDelayedTasks = true; - this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + i, this.nextTickTimeNanos); - // Purpur start -@@ -1270,9 +1270,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + return false; +@@ -1365,7 +1365,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && this.tickCount % autosavePeriod == 0; - try { - this.isSaving = true; -@@ -1624,7 +1624,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Purpur -- this.profiler.push(() -> { -+ /*this.profiler.push(() -> { // Purpur +- gameprofilerfiller.push(() -> { ++ /*gameprofilerfiller.push(() -> { // Purpur String s = String.valueOf(worldserver); return s + " " + String.valueOf(worldserver.dimension().location()); @@ -229,119 +243,104 @@ index f3c66049ab3fe087fa0fa87c2fca36c3c8b5c572..dfeae138e830e95ab823b6349a91160b + });*/ // Purpur /* Drop global time updates if (this.tickCount % 20 == 0) { -- this.profiler.push("timeSync"); -+ //this.profiler.push("timeSync"); // Purpur +- gameprofilerfiller.push("timeSync"); ++ //gameprofilerfiller.push("timeSync"); // Purpur this.synchronizeTime(worldserver); -- this.profiler.pop(); -+ //this.profiler.pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } // CraftBukkit end */ -- this.profiler.push("tick"); -+ //this.profiler.push("tick"); // Purpur +- gameprofilerfiller.push("tick"); ++ //gameprofilerfiller.push("tick"); // Purpur try { - //worldserver.timings.doTick.startTiming(); // Spigot // Purpur -@@ -1820,17 +1820,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { this.executeBlocking(() -> { this.saveDebugReport(path.resolve("server")); -@@ -2832,40 +2833,40 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> functions, ResourceLocation label) { -- ProfilerFiller gameprofilerfiller = this.server.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.server.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur Objects.requireNonNull(label); - gameprofilerfiller.push(label::toString); @@ -415,17 +412,17 @@ index a0ec6c3d122ad28d65d37f1b9f82541997b37d37..775b24a9e55528944b629fd85e1f6ebe Iterator iterator = functions.iterator(); while (iterator.hasNext()) { -@@ -65,15 +65,15 @@ public class ServerFunctionManager { +@@ -66,15 +66,15 @@ public class ServerFunctionManager { this.execute(commandfunction, this.getGameLoopSender()); } -- this.server.getProfiler().pop(); -+ //this.server.getProfiler().pop(); // Purpur +- Profiler.get().pop(); ++ //Profiler.get().pop(); // Purpur } public void execute(CommandFunction function, CommandSourceStack source) { -- ProfilerFiller gameprofilerfiller = this.server.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.server.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - gameprofilerfiller.push(() -> { + /*gameprofilerfiller.push(() -> { // Purpur @@ -435,7 +432,7 @@ index a0ec6c3d122ad28d65d37f1b9f82541997b37d37..775b24a9e55528944b629fd85e1f6ebe try { InstantiatedFunction instantiatedfunction = function.instantiate((CompoundTag) null, this.getDispatcher()); -@@ -86,7 +86,7 @@ public class ServerFunctionManager { +@@ -87,7 +87,7 @@ public class ServerFunctionManager { } catch (Exception exception) { ServerFunctionManager.LOGGER.warn("Failed to execute function {}", function.id(), exception); } finally { @@ -444,28 +441,63 @@ index a0ec6c3d122ad28d65d37f1b9f82541997b37d37..775b24a9e55528944b629fd85e1f6ebe } } +diff --git a/src/main/java/net/minecraft/server/commands/PerfCommand.java b/src/main/java/net/minecraft/server/commands/PerfCommand.java +index 8c587f829c5e8c6b6df3150024c4ae704988c47b..8ac4d5dbe7f8febf4226f26a6b035282dcdf1b0f 100644 +--- a/src/main/java/net/minecraft/server/commands/PerfCommand.java ++++ b/src/main/java/net/minecraft/server/commands/PerfCommand.java +@@ -42,6 +42,7 @@ public class PerfCommand { + } + + private static int startProfilingDedicatedServer(CommandSourceStack source) throws CommandSyntaxException { ++ if (true) return removedMessage(source); // Purpur + MinecraftServer minecraftServer = source.getServer(); + if (minecraftServer.isRecordingMetrics()) { + throw ERROR_ALREADY_RUNNING.create(); +@@ -55,6 +56,7 @@ public class PerfCommand { + } + + private static int stopProfilingDedicatedServer(CommandSourceStack source) throws CommandSyntaxException { ++ if (true) return removedMessage(source); // Purpur + MinecraftServer minecraftServer = source.getServer(); + if (!minecraftServer.isRecordingMetrics()) { + throw ERROR_NOT_RUNNING.create(); +@@ -64,6 +66,18 @@ public class PerfCommand { + } + } + ++ // Purpur start ++ private static int removedMessage(CommandSourceStack source) { ++ if (true) { ++ net.kyori.adventure.text.minimessage.MiniMessage mm = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage(); ++ source.getSender().sendMessage(mm.deserialize("Purpur has removed Mojang's Profiler to save your performance. Please use /spark instead")); ++ source.getSender().sendMessage(mm.deserialize("For more information, view its documentation at")); ++ source.getSender().sendMessage(mm.deserialize("https://spark.lucko.me/docs/Command-Usage")); ++ } ++ return 0; ++ } ++ // Purpur end ++ + private static void saveResults(CommandSourceStack source, Path tempProfilingDirectory, MinecraftServer server) { + String string = String.format( + Locale.ROOT, "%s-%s-%s", Util.getFilenameFormattedDateTime(), server.getWorldData().getLevelName(), SharedConstants.getCurrentVersion().getId() diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index bbe4580f7fc7cb6c8eb7055c82e2af7ad2ccd59d..4e6fccec4f5ca14562bf5bae495ac36c14982d85 100644 +index 5b3a886c624b36557cbfaccdc3fb05a46a4ba36a..e16f22dd82b4315da34af3c9a189d9d5fec0fd2f 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -541,20 +541,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -406,16 +406,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } protected void tick(BooleanSupplier shouldKeepTicking) { -- ProfilerFiller gameprofilerfiller = this.level.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.level.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - //try (Timing ignored = this.level.timings.poiUnload.startTiming()) { // Paper // Purpur - gameprofilerfiller.push("poi"); + //gameprofilerfiller.push("poi"); // Purpur this.poiManager.tick(shouldKeepTicking); - //} // Paper // Purpur - gameprofilerfiller.popPush("chunk_unload"); + //gameprofilerfiller.popPush("chunk_unload"); // Purpur if (!this.level.noSave()) { - //try (Timing ignored = this.level.timings.chunkUnload.startTiming()) { // Paper // Purpur this.processUnloads(shouldKeepTicking); - //} // Paper // Purpur } - gameprofilerfiller.pop(); @@ -474,151 +506,157 @@ index bbe4580f7fc7cb6c8eb7055c82e2af7ad2ccd59d..4e6fccec4f5ca14562bf5bae495ac36c public boolean hasWork() { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 07b428ed7837642254b1edd55fd08a7beac7e303..476a04d87a61b021816d2970e86042bde32d95a2 100644 +index 3c711e1df57ac5b0f8795ebb12299d275792b1d4..bb168636cbf23b5b0c7232529e390f434546dc37 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -259,14 +259,14 @@ public class ServerChunkCache extends ChunkSource { - return ifLoaded; - } - // Paper end - Perf: Optimise getChunkAt calls for loaded chunks -- ProfilerFiller gameprofilerfiller = this.level.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.level.getProfiler(); // Purpur - -- gameprofilerfiller.incrementCounter("getChunk"); -+ //gameprofilerfiller.incrementCounter("getChunk"); // Purpur - long k = ChunkPos.asLong(x, z); - - // Paper - rewrite chunk system - there are no correct callbacks to remove items from cache in the new chunk system - -- gameprofilerfiller.incrementCounter("getChunkCacheMiss"); -+ //gameprofilerfiller.incrementCounter("getChunkCacheMiss"); // Purpur - CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); - ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor; - -@@ -459,26 +459,26 @@ public class ServerChunkCache extends ChunkSource { +@@ -442,38 +442,38 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon // CraftBukkit start - modelled on below public void purgeUnload() { - if (true) return; // Paper - tickets will be removed later, this behavior isn't really well accounted for by the chunk system -- this.level.getProfiler().push("purge"); -+ //this.level.getProfiler().push("purge"); // Purpur + if (true) return; // Paper - rewrite chunk system +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("purge"); ++ //gameprofilerfiller.push("purge"); // Purpur this.distanceManager.purgeStaleTickets(); this.runDistanceManagerUpdates(); -- this.level.getProfiler().popPush("unload"); -+ //this.level.getProfiler().popPush("unload"); // Purpur +- gameprofilerfiller.popPush("unload"); ++ //gameprofilerfiller.popPush("unload"); // Purpur this.chunkMap.tick(() -> true); -- this.level.getProfiler().pop(); -+ //this.level.getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur this.clearCache(); } // CraftBukkit end @Override public void tick(BooleanSupplier shouldKeepTicking, boolean tickChunks) { -- this.level.getProfiler().push("purge"); -+ //this.level.getProfiler().push("purge"); // Purpur - //this.level.timings.doChunkMap.startTiming(); // Spigot // Purpur - if (this.level.tickRateManager().runsNormally() || !tickChunks) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("purge"); ++ //gameprofilerfiller.push("purge"); // Purpur + if (this.level.tickRateManager().runsNormally() || !tickChunks || this.level.spigotConfig.unloadFrozenChunks) { // Spigot this.distanceManager.purgeStaleTickets(); } + this.runDistanceManagerUpdates(); - //this.level.timings.doChunkMap.stopTiming(); // Spigot // Purpur -- this.level.getProfiler().popPush("chunks"); -+ //this.level.getProfiler().popPush("chunks"); // Purpur +- gameprofilerfiller.popPush("chunks"); ++ //gameprofilerfiller.popPush("chunks"); // Purpur if (tickChunks) { - //this.level.timings.chunks.startTiming(); // Paper - timings // Purpur - this.chunkMap.level.playerChunkLoader.tick(); // Paper - replace player chunk loader - this is mostly required to account for view distance changes -@@ -488,10 +488,10 @@ public class ServerChunkCache extends ChunkSource { + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().tick(); // Paper - rewrite chunk system + this.tickChunks(); + this.chunkMap.tick(); } - //this.level.timings.doChunkUnload.startTiming(); // Spigot // Purpur -- this.level.getProfiler().popPush("unload"); -+ //this.level.getProfiler().popPush("unload"); // Purpur +- gameprofilerfiller.popPush("unload"); ++ //gameprofilerfiller.popPush("unload"); // Purpur this.chunkMap.tick(shouldKeepTicking); - //this.level.timings.doChunkUnload.stopTiming(); // Spigot // Purpur -- this.level.getProfiler().pop(); -+ //this.level.getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur this.clearCache(); } -@@ -501,17 +501,17 @@ public class ServerChunkCache extends ChunkSource { +@@ -483,34 +483,34 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon this.lastInhabitedUpdate = i; if (!this.level.isDebug()) { -- ProfilerFiller gameprofilerfiller = this.level.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.level.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - gameprofilerfiller.push("pollingChunks"); -- gameprofilerfiller.push("filteringLoadedChunks"); + //gameprofilerfiller.push("pollingChunks"); // Purpur -+ //gameprofilerfiller.push("filteringLoadedChunks"); // Purpur - // Paper - optimise chunk tick iteration - //if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper // Purpur - - // Paper - optimise chunk tick iteration - if (this.level.tickRateManager().runsNormally()) { -- gameprofilerfiller.popPush("naturalSpawnCount"); -+ //gameprofilerfiller.popPush("naturalSpawnCount"); // Purpur - //this.level.timings.countNaturalMobs.startTiming(); // Paper - timings // Purpur - int k = this.distanceManager.getNaturalSpawnChunkCount(); - // Paper start - Optional per player mob spawns -@@ -540,7 +540,7 @@ public class ServerChunkCache extends ChunkSource { - // this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings // Purpur + List list = this.tickingChunks; - this.lastSpawnState = spawnercreature_d; -- gameprofilerfiller.popPush("spawnAndTick"); -+ //gameprofilerfiller.popPush("spawnAndTick"); // Purpur - boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit - - // Paper start - optimise chunk tick iteration -@@ -648,7 +648,7 @@ public class ServerChunkCache extends ChunkSource { - // Paper end - optimise chunk tick iteration - // this.level.timings.chunkTicks.stopTiming(); // Paper // Purpur - -- gameprofilerfiller.popPush("customSpawners"); -+ //gameprofilerfiller.popPush("customSpawners"); // Purpur - if (flag) { - //try (co.aikar.timings.Timing ignored = this.level.timings.miscMobSpawning.startTiming()) { // Paper - timings // Purpur - this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); -@@ -656,7 +656,7 @@ public class ServerChunkCache extends ChunkSource { + try { +- gameprofilerfiller.push("filteringTickingChunks"); ++ //gameprofilerfiller.push("filteringTickingChunks"); // Purpur + this.collectTickingChunks(list); +- gameprofilerfiller.popPush("shuffleChunks"); ++ //gameprofilerfiller.popPush("shuffleChunks"); // Purpur + // Paper start - chunk tick iteration optimisation + this.shuffleRandom.setSeed(this.level.random.nextLong()); + if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled + // Paper end - chunk tick iteration optimisation +- this.tickChunks(gameprofilerfiller, j, list); +- gameprofilerfiller.pop(); ++ this.tickChunks(null, j, list); // Purpur ++ //gameprofilerfiller.pop(); // Purpur + } finally { + list.clear(); } } -- gameprofilerfiller.popPush("broadcast"); -+ //gameprofilerfiller.popPush("broadcast"); // Purpur - // Paper - optimise chunk tick iteration - //this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing // Purpur - // Paper start - optimise chunk tick iteration -@@ -674,8 +674,8 @@ public class ServerChunkCache extends ChunkSource { - // Paper end - optimise chunk tick iteration - //this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing // Purpur - // Paper - optimise chunk tick iteration +- this.broadcastChangedChunks(gameprofilerfiller); - gameprofilerfiller.pop(); -- gameprofilerfiller.pop(); -+ //gameprofilerfiller.pop(); // Purpur ++ this.broadcastChangedChunks(null); // Purpur + //gameprofilerfiller.pop(); // Purpur } } -@@ -847,7 +847,7 @@ public class ServerChunkCache extends ChunkSource { +- private void broadcastChangedChunks(ProfilerFiller profiler) { +- profiler.push("broadcast"); ++ private void broadcastChangedChunks(ProfilerFiller profiler) { // Purpur ++ //profiler.push("broadcast"); // Purpur + Iterator iterator = this.chunkHoldersToBroadcast.iterator(); + + while (iterator.hasNext()) { +@@ -523,7 +523,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + } + + this.chunkHoldersToBroadcast.clear(); +- profiler.pop(); ++ //profiler.pop(); // Purpur + } + + private void collectTickingChunks(List chunks) { +@@ -550,7 +550,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + } + + private void tickChunks(ProfilerFiller profiler, long timeDelta, List chunks) { +- profiler.popPush("naturalSpawnCount"); ++ //profiler.popPush("naturalSpawnCount"); // Purpur + int j = this.distanceManager.getNaturalSpawnChunkCount(); + // Paper start - Optional per player mob spawns + final int naturalSpawnChunkCount = j; +@@ -577,7 +577,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + // Paper end - Optional per player mob spawns + + this.lastSpawnState = spawnercreature_d; +- profiler.popPush("spawnAndTick"); ++ //profiler.popPush("spawnAndTick"); // Purpur + boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit + int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + List list1; +@@ -615,7 +615,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + } + } + +- profiler.popPush("customSpawners"); ++ //profiler.popPush("customSpawners"); // Purpur + if (flag) { + this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); + } +@@ -813,7 +813,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @Override protected void doRunTask(Runnable task) { -- ServerChunkCache.this.level.getProfiler().incrementCounter("runTask"); -+ //ServerChunkCache.this.level.getProfiler().incrementCounter("runTask"); // Purpur +- Profiler.get().incrementCounter("runTask"); ++ //Profiler.get().incrementCounter("runTask"); // Purpur super.doRunTask(task); } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c15357457810240 100644 +index a8650040b69fe92f18606e5029ecd881961b39e7..4c11f0a23ee897691d8a8022baa134ef6f5e3d89 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -830,16 +830,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -724,18 +724,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } public void tick(BooleanSupplier shouldKeepTicking) { -- ProfilerFiller gameprofilerfiller = this.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur this.handlingTick = true; TickRateManager tickratemanager = this.tickRateManager(); @@ -631,15 +669,17 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 - gameprofilerfiller.popPush("weather"); + //gameprofilerfiller.popPush("weather"); // Purpur this.advanceWeatherCycle(); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } -@@ -871,30 +871,30 @@ public class ServerLevel extends Level implements WorldGenLevel { + int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); +@@ -766,30 +766,30 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.tickTime(); } -- gameprofilerfiller.popPush("tickPending"); -+ //gameprofilerfiller.popPush("tickPending"); // Purpur - //this.timings.scheduledBlocks.startTiming(); // Paper // Purpur +- gameprofilerfiller.push("tickPending"); ++ //gameprofilerfiller.push("tickPending"); // Purpur if (!this.isDebug() && flag) { j = this.getGameTime(); - gameprofilerfiller.push("blockTicks"); @@ -651,27 +691,20 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 - gameprofilerfiller.pop(); + //gameprofilerfiller.pop(); // Purpur } - //this.timings.scheduledBlocks.stopTiming(); // Paper // Purpur - gameprofilerfiller.popPush("raid"); + //gameprofilerfiller.popPush("raid"); // Purpur if (flag) { - // this.timings.raids.startTiming(); // Paper - timings // Purpur this.raids.tick(); - // this.timings.raids.stopTiming(); // Paper - timings // Purpur } - gameprofilerfiller.popPush("chunkSource"); + //gameprofilerfiller.popPush("chunkSource"); // Purpur - //this.timings.chunkProviderTick.startTiming(); // Paper - timings // Purpur this.getChunkSource().tick(shouldKeepTicking, true); - //this.timings.chunkProviderTick.stopTiming(); // Paper - timings // Purpur - gameprofilerfiller.popPush("blockEvents"); + //gameprofilerfiller.popPush("blockEvents"); // Purpur if (flag) { - // this.timings.doSounds.startTiming(); // Spigot // Purpur this.runBlockEvents(); -@@ -902,7 +902,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } this.handlingTick = false; @@ -680,13 +713,12 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 boolean flag1 = !paperConfig().unsupportedSettings.disableWorldTickingWhenEmpty || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this if (flag1) { -@@ -910,12 +910,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -797,20 +797,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } if (flag1 || this.emptyTime++ < 300) { - gameprofilerfiller.push("entities"); + //gameprofilerfiller.push("entities"); // Purpur - //this.timings.tickEntities.startTiming(); // Spigot // Purpur if (this.dragonFight != null && flag) { - gameprofilerfiller.push("dragonFight"); + //gameprofilerfiller.push("dragonFight"); // Purpur @@ -696,19 +728,18 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 } org.spigotmc.ActivationRange.activateEntities(this); // Spigot -@@ -925,9 +925,9 @@ public class ServerLevel extends Level implements WorldGenLevel { - if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed - entity.discard(); - } else if (!tickratemanager.isEntityFrozen(entity)) { + this.entityTickList.forEach((entity) -> { + if (!entity.isRemoved()) { + if (!tickratemanager.isEntityFrozen(entity)) { - gameprofilerfiller.push("checkDespawn"); + //gameprofilerfiller.push("checkDespawn"); // Purpur entity.checkDespawn(); - gameprofilerfiller.pop(); + //gameprofilerfiller.pop(); // Purpur - if (true || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { // Paper - now always true if in the ticking list + if (true) { // Paper - rewrite chunk system Entity entity1 = entity.getVehicle(); -@@ -939,22 +939,21 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -822,20 +822,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe entity.stopRiding(); } @@ -721,8 +752,6 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 } } }); - //this.timings.entityTick.stopTiming(); // Spigot // Purpur - //this.timings.tickEntities.stopTiming(); // Spigot // Purpur - gameprofilerfiller.pop(); + //gameprofilerfiller.pop(); // Purpur this.tickBlockEntities(); @@ -730,24 +759,25 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 - gameprofilerfiller.push("entityManagement"); + //gameprofilerfiller.push("entityManagement"); // Purpur - //this.entityManager.tick(); // Paper - rewrite chunk system + // Paper - rewrite chunk system - gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } @Override -@@ -1034,9 +1033,9 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -962,9 +962,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe boolean flag = this.isRaining(); int j = chunkcoordintpair.getMinBlockX(); int k = chunkcoordintpair.getMinBlockZ(); -- ProfilerFiller gameprofilerfiller = this.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - gameprofilerfiller.push("thunder"); + //gameprofilerfiller.push("thunder"); // Purpur - final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change + if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && simpleRandom.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder // Paper - optimise random ticking + BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15)); - if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder -@@ -1075,7 +1074,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1001,7 +1001,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } } @@ -756,55 +786,51 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow for (int l = 0; l < randomTickSpeed; ++l) { -@@ -1088,7 +1087,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1011,12 +1011,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } } // Paper - Option to disable ice and snow - gameprofilerfiller.popPush("tickBlocks"); + //gameprofilerfiller.popPush("tickBlocks"); // Purpur - //timings.chunkTicksBlocks.startTiming(); // Paper // Purpur if (randomTickSpeed > 0) { - // Paper start - optimize random block ticking -@@ -1124,7 +1123,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - // Paper end - optimise random block ticking + this.optimiseRandomTick(chunk, randomTickSpeed); // Paper - optimise random ticking + } - //timings.chunkTicksBlocks.stopTiming(); // Paper // Purpur - gameprofilerfiller.pop(); + //gameprofilerfiller.pop(); // Purpur } @VisibleForTesting -@@ -1471,19 +1470,19 @@ public class ServerLevel extends Level implements WorldGenLevel { - //try { // Purpur - // Paper end - timings +@@ -1355,18 +1355,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // Spigot end + final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity); // Paper - EAR 2 entity.setOldPosAndRot(); -- ProfilerFiller gameprofilerfiller = this.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur ++entity.tickCount; -- this.getProfiler().push(() -> { -+ /*this.getProfiler().push(() -> { // Purpur +- gameprofilerfiller.push(() -> { ++ /*gameprofilerfiller.push(() -> { // Purpur return BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString(); - }); - gameprofilerfiller.incrementCounter("tickNonPassenger"); + });*/ // Purpur + //gameprofilerfiller.incrementCounter("tickNonPassenger"); // Purpur if (isActive) { // Paper - EAR 2 - TimingHistory.activatedEntityTicks++; entity.tick(); entity.postTick(); // CraftBukkit } else { entity.inactiveTick(); } // Paper - EAR 2 -- this.getProfiler().pop(); -+ //this.getProfiler().pop(); // Purpur - //} finally { timer.stopTiming(); } // Paper - timings // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur Iterator iterator = entity.getPassengers().iterator(); -@@ -1512,12 +1511,12 @@ public class ServerLevel extends Level implements WorldGenLevel { - // Paper end + while (iterator.hasNext()) { +@@ -1389,12 +1389,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (passenger instanceof Player || this.entityTickList.contains(passenger)) { passenger.setOldPosAndRot(); ++passenger.tickCount; -- ProfilerFiller gameprofilerfiller = this.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - gameprofilerfiller.push(() -> { + /*gameprofilerfiller.push(() -> { // Purpur @@ -816,8 +842,8 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 // Paper start - EAR 2 if (isActive) { passenger.rideTick(); -@@ -1529,7 +1528,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - vehicle.positionRider(passenger); +@@ -1406,7 +1406,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + vehicle.positionRider(passenger); } // Paper end - EAR 2 - gameprofilerfiller.pop(); @@ -826,77 +852,75 @@ index a84a9218838fb42c49a00c0d5f28e9e486fc7dac..f72af2feb74626abbdfbfd090c153574 while (iterator.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 635e6b46081ec0078b687818310e623cbbf1cc1f..ad9d42e886bc1e2529ca13990626169ab2354898 100644 +index 51229d600ea8a58e5c75bd97a1926f5cdf3704d4..0286b1bd461a5050cb78b9485bac84909ae91150 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1317,7 +1317,7 @@ public class ServerPlayer extends Player { - PortalInfo shapedetectorshape = this.findDimensionEntryPoint(worldserver); +@@ -1669,15 +1669,15 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple + this.unsetRemoved(); + */ + // CraftBukkit end +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - if (shapedetectorshape != null) { -- worldserver1.getProfiler().push("moving"); -+ //worldserver1.getProfiler().push("moving"); // Purpur - worldserver = shapedetectorshape.world; // CraftBukkit - if (worldserver == null) { } else // CraftBukkit - empty to fall through to null to event - if (resourcekey == LevelStem.OVERWORLD && worldserver.getTypeKey() == LevelStem.NETHER) { // CraftBukkit -@@ -1340,8 +1340,8 @@ public class ServerPlayer extends Player { - worldserver = ((CraftWorld) exit.getWorld()).getHandle(); - // CraftBukkit end +- gameprofilerfiller.push("moving"); ++ //gameprofilerfiller.push("moving"); // Purpur + if (worldserver != null && resourcekey == LevelStem.OVERWORLD && worldserver.getTypeKey() == LevelStem.NETHER) { // CraftBukkit - empty to fall through to null to event + this.enteredNetherPosition = this.position(); + } -- worldserver1.getProfiler().pop(); -- worldserver1.getProfiler().push("placing"); -+ //worldserver1.getProfiler().pop(); // Purpur -+ //worldserver1.getProfiler().push("placing"); // Purpur - if (true) { // CraftBukkit +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("placing"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("placing"); // Purpur + // CraftBukkit start this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds - -@@ -1359,7 +1359,7 @@ public class ServerPlayer extends Player { - this.connection.teleport(exit); // CraftBukkit - use internal teleport without event + LevelData worlddata = worldserver.getLevelData(); +@@ -1695,7 +1695,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple + this.connection.internalTeleport(PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); // CraftBukkit - use internal teleport without event this.connection.resetPosition(); - worldserver.addDuringPortalTeleport(this); -- worldserver1.getProfiler().pop(); -+ //worldserver1.getProfiler().pop(); // Purpur + worldserver.addDuringTeleport(this); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur this.triggerDimensionChangeTriggers(worldserver1); + this.stopUsingItem(); this.connection.send(new ClientboundPlayerAbilitiesPacket(this.getAbilities())); - playerlist.sendLevelInfo(this, worldserver); diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 3a15085e0421f46800f779066d235ef21b463289..8368c5ff929df9d32cdb95cc2da0e9f7f3b85d2a 100644 +index 7d276c191b391bca24948ddb36b8b7d0f1f03b03..49cb116fd55e6d5cd36b9773b39191e4ab06b7e0 100644 --- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -265,7 +265,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -274,7 +274,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } protected void keepConnectionAlive() { -- this.server.getProfiler().push("keepAlive"); -+ //this.server.getProfiler().push("keepAlive"); // Purpur +- Profiler.get().push("keepAlive"); ++ //Profiler.get().push("keepAlive"); // Purpur // Paper start - give clients a longer time to respond to pings as per pre 1.12.2 timings // This should effectively place the keepalive handling back to "as it was" before 1.12.2 long currentTime = Util.getMillis(); -@@ -298,7 +298,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -307,7 +307,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } // Paper end - give clients a longer time to respond to pings as per pre 1.12.2 timings -- this.server.getProfiler().pop(); -+ //this.server.getProfiler().pop(); // Purpur +- Profiler.get().pop(); ++ //Profiler.get().pop(); // Purpur } private boolean checkIfClosed(long time) { diff --git a/src/main/java/net/minecraft/server/packs/resources/ResourceManagerReloadListener.java b/src/main/java/net/minecraft/server/packs/resources/ResourceManagerReloadListener.java -index f14113eef226e906c0d21641e74a27471254909d..0c25f3ed0a8a538edc7cadd3476100c9b3631f7a 100644 +index d2d82e4f22bfeac8881b6815e4bef56c254fded9..abc92e09b7bb636612f04ace8232947c8d454e68 100644 --- a/src/main/java/net/minecraft/server/packs/resources/ResourceManagerReloadListener.java +++ b/src/main/java/net/minecraft/server/packs/resources/ResourceManagerReloadListener.java -@@ -16,11 +16,11 @@ public interface ResourceManagerReloadListener extends PreparableReloadListener - Executor applyExecutor +@@ -12,10 +12,10 @@ public interface ResourceManagerReloadListener extends PreparableReloadListener + PreparableReloadListener.PreparationBarrier synchronizer, ResourceManager manager, Executor prepareExecutor, Executor applyExecutor ) { return synchronizer.wait(Unit.INSTANCE).thenRunAsync(() -> { -- applyProfiler.startTick(); -- applyProfiler.push("listener"); -+ //applyProfiler.startTick(); // Purpur -+ //applyProfiler.push("listener"); // Purpur +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("listener"); ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur ++ //profilerFiller.push("listener"); // Purpur this.onResourceManagerReload(manager); -- applyProfiler.pop(); -- applyProfiler.endTick(); -+ //applyProfiler.pop(); // Purpur -+ //applyProfiler.endTick(); // Purpur +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur }, applyExecutor); } @@ -951,10 +975,10 @@ index bce2dac613d29083dd5fbb68739304cc5a6d4d27..600a7036b503f60cc9c95f189f73c2db private ActiveProfiler.PathEntry getCurrentEntry() { diff --git a/src/main/java/net/minecraft/util/profiling/ProfilerFiller.java b/src/main/java/net/minecraft/util/profiling/ProfilerFiller.java -index a715ecf4a8ac91d3e5e5c6269d89e54b2c1cd279..223c3665126c576eddb1a8f7c9f5bc60c6ff9818 100644 +index bc5c8879befe849ce81becf5e3fba6757b01cb70..ce81d6bd87f688a24003f2fbf6d5010ad6273917 100644 --- a/src/main/java/net/minecraft/util/profiling/ProfilerFiller.java +++ b/src/main/java/net/minecraft/util/profiling/ProfilerFiller.java -@@ -6,32 +6,44 @@ import net.minecraft.util.profiling.metrics.MetricCategory; +@@ -6,51 +6,68 @@ import net.minecraft.util.profiling.metrics.MetricCategory; public interface ProfilerFiller { String ROOT = "root"; @@ -979,6 +1003,30 @@ index a715ecf4a8ac91d3e5e5c6269d89e54b2c1cd279..223c3665126c576eddb1a8f7c9f5bc60 + @io.papermc.paper.annotation.DoNotUse // Purpur void popPush(Supplier locationGetter); ++ @io.papermc.paper.annotation.DoNotUse // Purpur + default void addZoneText(String label) { + } + ++ @io.papermc.paper.annotation.DoNotUse // Purpur + default void addZoneValue(long value) { + } + ++ @io.papermc.paper.annotation.DoNotUse // Purpur + default void setZoneColor(int color) { + } + ++ @io.papermc.paper.annotation.DoNotUse // Purpur + default Zone zone(String name) { + this.push(name); + return new Zone(this); + } + ++ @io.papermc.paper.annotation.DoNotUse // Purpur + default Zone zone(Supplier nameSupplier) { + this.push(nameSupplier); + return new Zone(this); + } + + @io.papermc.paper.annotation.DoNotUse // Purpur void markForCharting(MetricCategory type); @@ -1000,371 +1048,405 @@ index a715ecf4a8ac91d3e5e5c6269d89e54b2c1cd279..223c3665126c576eddb1a8f7c9f5bc60 + @io.papermc.paper.annotation.DoNotUse // Purpur void incrementCounter(Supplier markerGetter, int num); - static ProfilerFiller tee(ProfilerFiller a, ProfilerFiller b) { -@@ -41,62 +53,62 @@ public interface ProfilerFiller { - return b == InactiveProfiler.INSTANCE ? a : new ProfilerFiller() { - @Override - public void startTick() { -- a.startTick(); -- b.startTick(); -+ //a.startTick(); // Purpur -+ //b.startTick(); // Purpur - } + static ProfilerFiller combine(ProfilerFiller first, ProfilerFiller second) { +@@ -72,80 +89,80 @@ public interface ProfilerFiller { - @Override - public void endTick() { -- a.endTick(); -- b.endTick(); -+ //a.endTick(); // Purpur -+ //b.endTick(); // Purpur - } - - @Override - public void push(String location) { -- a.push(location); -- b.push(location); -+ //a.push(location); // Purpur -+ //b.push(location); // Purpur - } - - @Override - public void push(Supplier locationGetter) { -- a.push(locationGetter); -- b.push(locationGetter); -+ //a.push(locationGetter); // Purpur -+ //b.push(locationGetter); // Purpur - } - - @Override - public void markForCharting(MetricCategory type) { -- a.markForCharting(type); -- b.markForCharting(type); -+ //a.markForCharting(type); // Purpur -+ //b.markForCharting(type); // Purpur - } - - @Override - public void pop() { -- a.pop(); -- b.pop(); -+ //a.pop(); // Purpur -+ //b.pop(); // Purpur - } - - @Override - public void popPush(String location) { -- a.popPush(location); -- b.popPush(location); -+ //a.popPush(location); // Purpur -+ //b.popPush(location); // Purpur - } - - @Override - public void popPush(Supplier locationGetter) { -- a.popPush(locationGetter); -- b.popPush(locationGetter); -+ //a.popPush(locationGetter); // Purpur -+ //b.popPush(locationGetter); // Purpur - } - - @Override - public void incrementCounter(String marker, int num) { -- a.incrementCounter(marker, num); -- b.incrementCounter(marker, num); -+ //a.incrementCounter(marker, num); // Purpur -+ //b.incrementCounter(marker, num); // Purpur - } - - @Override - public void incrementCounter(Supplier markerGetter, int num) { -- a.incrementCounter(markerGetter, num); -- b.incrementCounter(markerGetter, num); -+ //a.incrementCounter(markerGetter, num); // Purpur -+ //b.incrementCounter(markerGetter, num); // Purpur - } - }; + @Override + public void startTick() { +- this.first.startTick(); +- this.second.startTick(); ++ //this.first.startTick(); // Purpur ++ //this.second.startTick(); // Purpur } + + @Override + public void endTick() { +- this.first.endTick(); +- this.second.endTick(); ++ //this.first.endTick(); // Purpur ++ //this.second.endTick(); // Purpur + } + + @Override + public void push(String location) { +- this.first.push(location); +- this.second.push(location); ++ //this.first.push(location); // Purpur ++ //this.second.push(location); // Purpur + } + + @Override + public void push(Supplier locationGetter) { +- this.first.push(locationGetter); +- this.second.push(locationGetter); ++ //this.first.push(locationGetter); // Purpur ++ //this.second.push(locationGetter); // Purpur + } + + @Override + public void markForCharting(MetricCategory type) { +- this.first.markForCharting(type); +- this.second.markForCharting(type); ++ //this.first.markForCharting(type); // Purpur ++ //this.second.markForCharting(type); // Purpur + } + + @Override + public void pop() { +- this.first.pop(); +- this.second.pop(); ++ //this.first.pop(); // Purpur ++ //this.second.pop(); // Purpur + } + + @Override + public void popPush(String location) { +- this.first.popPush(location); +- this.second.popPush(location); ++ //this.first.popPush(location); // Purpur ++ //this.second.popPush(location); // Purpur + } + + @Override + public void popPush(Supplier locationGetter) { +- this.first.popPush(locationGetter); +- this.second.popPush(locationGetter); ++ //this.first.popPush(locationGetter); // Purpur ++ //this.second.popPush(locationGetter); // Purpur + } + + @Override + public void incrementCounter(String marker, int num) { +- this.first.incrementCounter(marker, num); +- this.second.incrementCounter(marker, num); ++ //this.first.incrementCounter(marker, num); // Purpur ++ //this.second.incrementCounter(marker, num); // Purpur + } + + @Override + public void incrementCounter(Supplier markerGetter, int num) { +- this.first.incrementCounter(markerGetter, num); +- this.second.incrementCounter(markerGetter, num); ++ //this.first.incrementCounter(markerGetter, num); // Purpur ++ //this.second.incrementCounter(markerGetter, num); // Purpur + } + + @Override + public void addZoneText(String label) { +- this.first.addZoneText(label); +- this.second.addZoneText(label); ++ //this.first.addZoneText(label); // Purpur ++ //this.second.addZoneText(label); // Purpur + } + + @Override + public void addZoneValue(long value) { +- this.first.addZoneValue(value); +- this.second.addZoneValue(value); ++ //this.first.addZoneValue(value); // Purpur ++ //this.second.addZoneValue(value); // Purpur + } + + @Override + public void setZoneColor(int color) { +- this.first.setZoneColor(color); +- this.second.setZoneColor(color); ++ //this.first.setZoneColor(color); // Purpur ++ //this.second.setZoneColor(color); // Purpur + } + } + } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 68e8f9913055219486ce19d95dcf9d7c76e08082..2c3ad553272ad651e6ca26917719e6d9fffdef68 100644 +index 520808a1238b28ec42f261b58b2b768cdb1d8277..1e740178898720cffff0a18255ebb9b46265f45f 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -897,7 +897,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -946,9 +946,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // CraftBukkit end public void baseTick() { -- this.level().getProfiler().push("entityBaseTick"); -+ //this.level().getProfiler().push("entityBaseTick"); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("entityBaseTick"); ++ //gameprofilerfiller.push("entityBaseTick"); // Purpur if (firstTick && this instanceof net.minecraft.world.entity.NeutralMob neutralMob) neutralMob.tickInitialPersistentAnger(level); // Paper - Prevent entity loading causing async lookups this.inBlockState = null; if (this.isPassenger() && this.getVehicle().isRemoved()) { -@@ -958,7 +958,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1017,7 +1017,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } } - this.firstTick = false; -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } public void setSharedFlagOnFire(boolean onFire) { -@@ -1175,7 +1175,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1243,9 +1243,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } -- this.level().getProfiler().push("move"); -+ //this.level().getProfiler().push("move"); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("move"); ++ //gameprofilerfiller.push("move"); // Purpur if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) { movement = movement.multiply(this.stuckSpeedMultiplier); this.stuckSpeedMultiplier = Vec3.ZERO; -@@ -1184,7 +1184,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1254,7 +1254,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // Paper start - ignore movement changes while inactive. - if (isTemporarilyActive && !(this instanceof ItemEntity) && movement == getDeltaMovement() && movementType == MoverType.SELF) { + if (isTemporarilyActive && !(this instanceof ItemEntity) && movement == getDeltaMovement() && type == MoverType.SELF) { setDeltaMovement(Vec3.ZERO); -- this.level.getProfiler().pop(); -+ //this.level.getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur return; } // Paper end -@@ -1205,8 +1205,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1275,8 +1275,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.setPos(this.getX() + vec3d1.x, this.getY() + vec3d1.y, this.getZ() + vec3d1.z); } -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("rest"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("rest"); // Purpur +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("rest"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("rest"); // Purpur boolean flag = !Mth.equal(movement.x, vec3d1.x); boolean flag1 = !Mth.equal(movement.z, vec3d1.z); -@@ -1225,7 +1225,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1298,7 +1298,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } - this.checkFallDamage(vec3d1.y, this.onGround(), iblockdata, blockposition); if (this.isRemoved()) { -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } else { if (this.horizontalCollision) { Vec3 vec3d2 = this.getDeltaMovement(); -@@ -1363,7 +1363,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.setRemainingFireTicks(-this.getFireImmuneTicks()); - } +@@ -1347,7 +1347,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + float f = this.getBlockSpeedFactor(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur + this.setDeltaMovement(this.getDeltaMovement().multiply((double) f, 1.0D, (double) f)); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } } // Paper start - detailed watchdog information -@@ -3258,7 +3258,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - ServerLevel worldserver1 = minecraftserver.getLevel(resourcekey); +@@ -3512,9 +3512,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.processPortalCooldown(); + if (this.portalProcess != null) { + if (this.portalProcess.processPortalTeleportation(worldserver, this, this.canUsePortal(false))) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - if (true && !this.isPassenger() && this.portalTime++ >= i) { // CraftBukkit -- this.level().getProfiler().push("portal"); -+ //this.level().getProfiler().push("portal"); // Purpur - this.portalTime = i; - // Paper start - Add EntityPortalReadyEvent - io.papermc.paper.event.entity.EntityPortalReadyEvent event = new io.papermc.paper.event.entity.EntityPortalReadyEvent(this.getBukkitEntity(), worldserver1 == null ? null : worldserver1.getWorld(), org.bukkit.PortalType.NETHER); -@@ -3276,7 +3276,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +- gameprofilerfiller.push("portal"); ++ //gameprofilerfiller.push("portal"); // Purpur + this.setPortalCooldown(); + TeleportTransition teleporttransition = this.portalProcess.getPortalDestination(worldserver, this); + +@@ -3526,7 +3526,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } } - } // Paper - Add EntityPortalReadyEvent - // CraftBukkit end -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - } - this.isInsidePortal = false; -@@ -3736,14 +3736,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + } else if (this.portalProcess.hasExpired()) { + this.portalProcess = null; + } +@@ -4079,12 +4079,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } } - // Paper end - Fix item duplication and teleport issues - if (this.level() instanceof ServerLevel && !this.isRemoved()) { -- this.level().getProfiler().push("changeDimension"); -+ //this.level().getProfiler().push("changeDimension"); // Purpur - // CraftBukkit start - // this.unRide(); - if (worldserver == null) { - return null; - } - // CraftBukkit end -- this.level().getProfiler().push("reposition"); -+ //this.level().getProfiler().push("reposition"); // Purpur - PortalInfo shapedetectorshape = (location == null) ? this.findDimensionEntryPoint(worldserver) : new PortalInfo(new Vec3(location.x(), location.y(), location.z()), Vec3.ZERO, this.yRot, this.xRot, worldserver, null); // CraftBukkit - if (shapedetectorshape == null) { -@@ -3782,7 +3782,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.unRide(); - // CraftBukkit end +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur -- this.level().getProfiler().popPush("reloading"); -+ //this.level().getProfiler().popPush("reloading"); // Purpur - // Paper start - Fix item duplication and teleport issues - if (this instanceof Mob) { - ((Mob) this).dropLeash(true, true); // Paper drop lead -@@ -3809,10 +3809,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - this.removeAfterChangingDimensions(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - ((ServerLevel) this.level()).resetEmptyTime(); - worldserver.resetEmptyTime(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - return entity; - } +- gameprofilerfiller.push("teleportCrossDimension"); ++ //gameprofilerfiller.push("teleportCrossDimension"); // Purpur + entity = this.getType().create(world, EntitySpawnReason.DIMENSION_TRAVEL); + if (entity == null) { +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + return null; } else { + // Paper start - Fix item duplication and teleport issues +@@ -4110,7 +4110,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + + world.resetEmptyTime(); + teleportTarget.postTeleportTransition().onTransition(entity); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + return entity; + } + } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 36022a0ab50655363d26be7dba765e2261baccdf..09cbc472d89d7d8730aedb76ef584b1ff159756b 100644 +index e2a5d66e4b945f69d9f2b538b95aa0b187749d8b..cd2fd85178acdfffc07b72bc0419a73e1d1bef64 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -423,7 +423,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -457,9 +457,9 @@ public abstract class LivingEntity extends Entity implements Attackable { } super.baseTick(); -- this.level().getProfiler().push("livingEntityBaseTick"); -+ //this.level().getProfiler().push("livingEntityBaseTick"); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("livingEntityBaseTick"); ++ //gameprofilerfiller.push("livingEntityBaseTick"); // Purpur if (this.fireImmune() || this.level().isClientSide) { this.clearFire(); } -@@ -526,7 +526,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -567,7 +567,7 @@ public abstract class LivingEntity extends Entity implements Attackable { this.yHeadRotO = this.yHeadRot; this.yRotO = this.getYRot(); this.xRotO = this.getXRot(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } - public boolean canSpawnSoulSpeedParticle() { -@@ -3227,10 +3227,10 @@ public abstract class LivingEntity extends Entity implements Attackable { + @Override +@@ -3382,12 +3382,12 @@ public abstract class LivingEntity extends Entity implements Attackable { } this.run += (f3 - this.run) * 0.3F; -- this.level().getProfiler().push("headTurn"); -+ //this.level().getProfiler().push("headTurn"); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("headTurn"); ++ //gameprofilerfiller.push("headTurn"); // Purpur f2 = this.tickHeadTurn(f1, f2); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("rangeChecks"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("rangeChecks"); // Purpur +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("rangeChecks"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("rangeChecks"); // Purpur // Paper start - stop large pitch and yaw changes from crashing the server this.yRotO += Math.round((this.getYRot() - this.yRotO) / 360.0F) * 360.0F; -@@ -3242,7 +3242,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3399,7 +3399,7 @@ public abstract class LivingEntity extends Entity implements Attackable { this.yHeadRotO += Math.round((this.yHeadRot - this.yHeadRotO) / 360.0F) * 360.0F; // Paper end -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur this.animStep += f2; if (this.isFallFlying()) { ++this.fallFlyTicks; -@@ -3465,19 +3465,19 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3629,21 +3629,21 @@ public abstract class LivingEntity extends Entity implements Attackable { } this.setDeltaMovement(d0, d1, d2); -- this.level().getProfiler().push("ai"); -+ //this.level().getProfiler().push("ai"); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("ai"); ++ //gameprofilerfiller.push("ai"); // Purpur if (this.isImmobile()) { this.jumping = false; this.xxa = 0.0F; this.zza = 0.0F; } else if (this.isEffectiveAi()) { -- this.level().getProfiler().push("newAi"); -+ //this.level().getProfiler().push("newAi"); // Purpur +- gameprofilerfiller.push("newAi"); ++ //gameprofilerfiller.push("newAi"); // Purpur this.serverAiStep(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("jump"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("jump"); // Purpur +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("jump"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("jump"); // Purpur if (this.jumping && this.isAffectedByFluids()) { double d3; -@@ -3504,8 +3504,8 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3670,8 +3670,8 @@ public abstract class LivingEntity extends Entity implements Attackable { this.noJumpDelay = 0; } -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("travel"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("travel"); // Purpur +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("travel"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("travel"); // Purpur this.xxa *= 0.98F; this.zza *= 0.98F; - this.updateFallFlying(); -@@ -3530,8 +3530,8 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.travel(vec3d1); + if (this.isFallFlying()) { +@@ -3704,8 +3704,8 @@ public abstract class LivingEntity extends Entity implements Attackable { } -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("freezing"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("freezing"); // Purpur + this.calculateEntityAnimation(this instanceof FlyingAnimal); +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("freezing"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("freezing"); // Purpur if (!this.level().isClientSide && !this.isDeadOrDying() && !this.freezeLocked) { // Paper - Freeze Tick Lock API int i = this.getTicksFrozen(); -@@ -3548,15 +3548,15 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.hurt(this.damageSources().freeze(), 1.0F); +@@ -3726,15 +3726,15 @@ public abstract class LivingEntity extends Entity implements Attackable { + } } -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("push"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("push"); // Purpur +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("push"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("push"); // Purpur if (this.autoSpinAttackTicks > 0) { --this.autoSpinAttackTicks; this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox()); } this.pushEntities(); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur // Paper start - Add EntityMoveEvent // Purpur start if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index ee98efa69d67cd22eb5722cf68f3b7063e2595c8..56da8a4600688efd1987d82d4fcad1757e33f4f2 100644 +index 7978e307e7bb7f80993c49dcc5ada319a907c648..ff9d23aef4658922692b43a859bd83632fe23612 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -376,13 +376,13 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti +@@ -371,15 +371,15 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab @Override public void baseTick() { super.baseTick(); -- this.level().getProfiler().push("mobBaseTick"); -+ //this.level().getProfiler().push("mobBaseTick"); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("mobBaseTick"); ++ //gameprofilerfiller.push("mobBaseTick"); // Purpur if (this.isAlive() && this.random.nextInt(1000) < this.ambientSoundTime++) { this.resetAmbientSoundTime(); this.playAmbientSound(); } -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur incrementTicksSinceLastInteraction(); // Purpur } -@@ -747,7 +747,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti +@@ -698,9 +698,9 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab @Override public void aiStep() { super.aiStep(); -- this.level().getProfiler().push("looting"); -+ //this.level().getProfiler().push("looting"); // Purpur - if (!this.level().isClientSide && this.canPickUpLoot() && this.isAlive() && !this.dead && (this.level().purpurConfig.entitiesPickUpLootBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { - Vec3i baseblockposition = this.getPickupReach(); - List list = this.level().getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate((double) baseblockposition.getX(), (double) baseblockposition.getY(), (double) baseblockposition.getZ())); -@@ -767,7 +767,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("looting"); ++ //gameprofilerfiller.push("looting"); // Purpur + Level world = this.level(); + + if (world instanceof ServerLevel worldserver) { +@@ -724,7 +724,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab } } -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } protected Vec3i getPickupReach() { -@@ -992,44 +992,44 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti +@@ -946,44 +946,44 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab return; } // Paper end - Allow nerfed mobs to jump and float -- ProfilerFiller gameprofilerfiller = this.level().getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.level().getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - gameprofilerfiller.push("sensing"); + //gameprofilerfiller.push("sensing"); // Purpur @@ -1404,7 +1486,7 @@ index ee98efa69d67cd22eb5722cf68f3b7063e2595c8..56da8a4600688efd1987d82d4fcad175 - gameprofilerfiller.push("mob tick"); + //gameprofilerfiller.pop(); // Purpur + //gameprofilerfiller.push("mob tick"); // Purpur - this.customServerAiStep(); + this.customServerAiStep((ServerLevel) this.level()); - gameprofilerfiller.pop(); - gameprofilerfiller.push("controls"); - gameprofilerfiller.push("move"); @@ -1426,21 +1508,21 @@ index ee98efa69d67cd22eb5722cf68f3b7063e2595c8..56da8a4600688efd1987d82d4fcad175 } diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -index 74d4f653d5c7f1923c59019effd78337402f7025..b4e4670536f6dcea109c029d75d9710cb386f1d0 100644 +index 29ae74339a4831ccef3d01e8054931715ba192ad..74c5914bc51cff128d4b86853316e5e51e02b416 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -@@ -87,8 +87,8 @@ public class GoalSelector { +@@ -82,8 +82,8 @@ public class GoalSelector { } public void tick() { -- ProfilerFiller profilerFiller = this.profiler.get(); +- ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("goalCleanup"); -+ //ProfilerFiller profilerFiller = this.profiler.get(); // Purpur ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur + //profilerFiller.push("goalCleanup"); // Purpur for (WrappedGoal wrappedGoal : this.availableGoals) { if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams -@@ -97,8 +97,8 @@ public class GoalSelector { +@@ -92,8 +92,8 @@ public class GoalSelector { } this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning()); @@ -1451,7 +1533,7 @@ index 74d4f653d5c7f1923c59019effd78337402f7025..b4e4670536f6dcea109c029d75d9710c for (WrappedGoal wrappedGoal2 : this.availableGoals) { // Paper start -@@ -118,13 +118,13 @@ public class GoalSelector { +@@ -113,13 +113,13 @@ public class GoalSelector { } } @@ -1461,14 +1543,14 @@ index 74d4f653d5c7f1923c59019effd78337402f7025..b4e4670536f6dcea109c029d75d9710c } public void tickRunningGoals(boolean tickAll) { -- ProfilerFiller profilerFiller = this.profiler.get(); +- ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("goalTick"); -+ //ProfilerFiller profilerFiller = this.profiler.get(); // Purpur ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur + //profilerFiller.push("goalTick"); // Purpur for (WrappedGoal wrappedGoal : this.availableGoals) { if (wrappedGoal.isRunning() && (tickAll || wrappedGoal.requiresUpdateEveryTick())) { -@@ -132,7 +132,7 @@ public class GoalSelector { +@@ -127,7 +127,7 @@ public class GoalSelector { } } @@ -1478,445 +1560,464 @@ index 74d4f653d5c7f1923c59019effd78337402f7025..b4e4670536f6dcea109c029d75d9710c public Set getAvailableGoals() { diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index 2e9991e6b3c05584002744a2ee2579b1dba218b2..544920a31b649985333f82beafa94a3392f5853e 100644 +index 48c0de870a5bbf647309e69361dfb10ab56c65ab..a5289b6c453c24cb7b8b3a301b72c3adf92c1d13 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -@@ -172,12 +172,12 @@ public abstract class PathNavigation { +@@ -188,13 +188,13 @@ public abstract class PathNavigation { } } // Paper end - EntityPathfindEvent -- this.level.getProfiler().push("pathfind"); -+ //this.level.getProfiler().push("pathfind"); // Purpur +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("pathfind"); ++ //ProfilerFiller profilerFiller = Profiler.get(); ++ //profilerFiller.push("pathfind"); // Purpur BlockPos blockPos = useHeadPos ? this.mob.blockPosition().above() : this.mob.blockPosition(); int i = (int)(followRange + (float)range); PathNavigationRegion pathNavigationRegion = new PathNavigationRegion(this.level, blockPos.offset(-i, -i, -i), blockPos.offset(i, i, i)); Path path = this.pathFinder.findPath(pathNavigationRegion, this.mob, positions, followRange, distance, this.maxVisitedNodesMultiplier); -- this.level.getProfiler().pop(); -+ //this.level.getProfiler().pop(); // Purpur +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur if (path != null && path.getTarget() != null) { this.targetPos = path.getTarget(); this.reachRange = distance; diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java -index 51772f03a3469b11e7166ec6f3a1b9c64a606221..02f2f46ccc48bb4d9bd08555818b0489f60d9f13 100644 +index 116b1e251ffe68bae5c404d0823c2bc7c1afddf6..8f5a5db1a07fa6a95ecfacaab2f9de609202faf4 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java -@@ -26,9 +26,9 @@ public class Sensing { +@@ -28,10 +28,10 @@ public class Sensing { } else if (this.unseen.contains(i)) { return false; } else { -- this.mob.level().getProfiler().push("hasLineOfSight"); -+ //this.mob.level().getProfiler().push("hasLineOfSight"); // Purpur +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("hasLineOfSight"); ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur ++ //profilerFiller.push("hasLineOfSight"); // Purpur boolean bl = this.mob.hasLineOfSight(entity); -- this.mob.level().getProfiler().pop(); -+ //this.mob.level().getProfiler().pop(); // Purpur +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur if (bl) { this.seen.add(i); } else { diff --git a/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java b/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java -index 09502b15c20f401c3b56ecedc4d3b515384d654f..bca7b7192debb3a34a08047010a2438e7b7e2a78 100644 +index 5904b82b87bcdbe41367843885f7c1bd1272d1f1..f60961bd5fdf6d1417e458b92e311c1a0a62463d 100644 --- a/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java +++ b/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java -@@ -252,13 +252,13 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS +@@ -262,15 +262,15 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("allayBrain"); -+ //this.level().getProfiler().push("allayBrain"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("allayBrain"); ++ //gameprofilerfiller.push("allayBrain"); // Purpur //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("allayActivityUpdate"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("allayActivityUpdate"); // Purpur + this.getBrain().tick(world, this); +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("allayActivityUpdate"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("allayActivityUpdate"); // Purpur AllayAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - super.customServerAiStep(); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + super.customServerAiStep(world); } diff --git a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java -index 29412208e329e9fc211b844822a2fc3328a5bc89..f8790ab5b7c1279719271ee57c00f4f2d6ce9714 100644 +index 9ef53608f1608e88de7a7b3e96b43d8d2b4230ae..84516dcfc6cd0fe16c26538ccb86fb5c85b44ffa 100644 --- a/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java +++ b/src/main/java/net/minecraft/world/entity/animal/armadillo/Armadillo.java -@@ -130,12 +130,12 @@ public class Armadillo extends Animal { +@@ -163,14 +163,14 @@ public class Armadillo extends Animal { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("armadilloBrain"); -+ //this.level().getProfiler().push("armadilloBrain"); // Purpur - ((Brain) this.brain).tick((ServerLevel) this.level(), this); // CraftBukkit - decompile error -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("armadilloActivityUpdate"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("armadilloActivityUpdate"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("armadilloBrain"); ++ //gameprofilerfiller.push("armadilloBrain"); // Purpur + ((Brain) this.brain).tick(world, this); // CraftBukkit - decompile error +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("armadilloActivityUpdate"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("armadilloActivityUpdate"); // Purpur ArmadilloAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur if (this.isAlive() && !this.isBaby() && --this.scuteTime <= 0) { - this.playSound(SoundEvents.ARMADILLO_SCUTE_DROP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); this.forceDrops = true; // CraftBukkit + if (this.dropFromGiftLootTable(world, BuiltInLootTables.ARMADILLO_SHED, this::spawnAtLocation)) { diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -index ea1515f189bf3bc4cfef4524fb40f0d826f68cc0..d330f79e860662bc93a1703215e66e6564d181b9 100644 +index 91768d49c3cbef0a135cfd0e60bdb4e84bf109b3..c80d74caa393a31e09f2776cdb3cb950ef99e2ef 100644 --- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java +++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -307,13 +307,13 @@ public class Axolotl extends Animal implements LerpingModel, VariantHolder, B @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("axolotlBrain"); -+ //this.level().getProfiler().push("axolotlBrain"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("axolotlBrain"); ++ //gameprofilerfiller.push("axolotlBrain"); // Purpur //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("axolotlActivityUpdate"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("axolotlActivityUpdate"); // Purpur + this.getBrain().tick(world, this); +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("axolotlActivityUpdate"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("axolotlActivityUpdate"); // Purpur AxolotlAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur if (!this.isNoAi()) { Optional optional = this.getBrain().getMemory(MemoryModuleType.PLAY_DEAD_TICKS); diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -index ed67fcd2b67bfe581863cc6748692c3348f6c883..24a1663cf1cd3f888981a13907811b55bdbf6133 100644 +index dbce71f45c008da883b6d244a06343d83ae25e7e..56d97225a909fd55f0d8aec992d5b6d42687c948 100644 --- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java +++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -@@ -151,14 +151,14 @@ public class Camel extends AbstractHorse implements PlayerRideableJumping, Saddl +@@ -154,16 +154,16 @@ public class Camel extends AbstractHorse { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("camelBrain"); -+ //this.level().getProfiler().push("camelBrain"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("camelBrain"); ++ //gameprofilerfiller.push("camelBrain"); // Purpur Brain behaviorcontroller = (Brain) this.getBrain(); // CraftBukkit - decompile error - behaviorcontroller.tick((ServerLevel) this.level(), this); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("camelActivityUpdate"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("camelActivityUpdate"); // Purpur + behaviorcontroller.tick(world, this); +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("camelActivityUpdate"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("camelActivityUpdate"); // Purpur CamelAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - super.customServerAiStep(); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + super.customServerAiStep(world); } diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -index b0f8115b328eda1e3571051870b5310c5a7e115a..ee8c232ddaa518377bdfa54e83ffc04f7a2f2c9a 100644 +index 49915ec0ee5fb6e7d25b079e0410942d44aa1e33..501a12398c56fe0df4e76a3bbce0f98c6c5aa6cb 100644 --- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -@@ -237,13 +237,13 @@ public class Frog extends Animal implements VariantHolder> { +@@ -240,14 +240,14 @@ public class Frog extends Animal implements VariantHolder> { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("frogBrain"); -+ //this.level().getProfiler().push("frogBrain"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("frogBrain"); ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur ++ //profilerFiller.push("frogBrain"); // Purpur //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel)this.level(), this); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("frogActivityUpdate"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("frogActivityUpdate"); // Purpur + this.getBrain().tick(world, this); +- profilerFiller.pop(); +- profilerFiller.push("frogActivityUpdate"); ++ //profilerFiller.pop(); // Purpur ++ //profilerFiller.push("frogActivityUpdate"); // Purpur FrogAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - super.customServerAiStep(); +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur + super.customServerAiStep(world); } diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -index b98a34357e59168bbb22c967b86a449fc91f47f0..09c4cf772df4644413e40055fedcdf42ee8064fd 100644 +index fb91677fb03b7bc1decdf181b7b15d971ffacdc2..071d14cc6697587ec14f02c69c78df364e7d8a8f 100644 --- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java +++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -@@ -122,13 +122,13 @@ public class Tadpole extends AbstractFish { +@@ -122,15 +122,15 @@ public class Tadpole extends AbstractFish { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("tadpoleBrain"); -+ //this.level().getProfiler().push("tadpoleBrain"); // Purpur - //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("tadpoleActivityUpdate"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("tadpoleActivityUpdate"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); + +- gameprofilerfiller.push("tadpoleBrain"); ++ //gameprofilerfiller.push("tadpoleBrain"); // Purpur + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // // Purpur - TODO: Pufferfish + this.getBrain().tick(world, this); +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("tadpoleActivityUpdate"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("tadpoleActivityUpdate"); // Purpur TadpoleAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - super.customServerAiStep(); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + super.customServerAiStep(world); } diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 79c27b5717fec000ea94138ebc76dbabf5b2eeaf..4e855055abe4d300b6b126e8a9deecaab5827a33 100644 +index 7f196e8a8b5094375c9b13fe6e7311a3450dbb5f..51dcc3893b964e6d20a2b963d3105a2687b3c426 100644 --- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -224,13 +224,13 @@ public class Goat extends Animal { +@@ -226,15 +226,15 @@ public class Goat extends Animal { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("goatBrain"); -+ //this.level().getProfiler().push("goatBrain"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("goatBrain"); ++ //gameprofilerfiller.push("goatBrain"); // Purpur //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); -- this.level().getProfiler().pop(); -- this.level().getProfiler().push("goatActivityUpdate"); -+ //this.level().getProfiler().pop(); // Purpur -+ //this.level().getProfiler().push("goatActivityUpdate"); // Purpur + this.getBrain().tick(world, this); +- gameprofilerfiller.pop(); +- gameprofilerfiller.push("goatActivityUpdate"); ++ //gameprofilerfiller.pop(); // Purpur ++ //gameprofilerfiller.push("goatActivityUpdate"); // Purpur GoatAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - super.customServerAiStep(); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + super.customServerAiStep(world); } diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java -index 0cc5b9e44dd6f1e0afdbb62ef41aa749c0c79b18..21bdcbd51d9f440e0734750b40cefa4c08cdaf5f 100644 +index 464a16df15d8759d66f94ad080d1ea28b3f6474c..3fb4f12095883ea4ec6e0d60e0600b9de6ed7be2 100644 --- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java +++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java -@@ -504,11 +504,11 @@ public class Sniffer extends Animal { +@@ -495,13 +495,13 @@ public class Sniffer extends Animal { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("snifferBrain"); -+ //this.level().getProfiler().push("snifferBrain"); // Purpur - this.getBrain().tick((ServerLevel) this.level(), this); -- this.level().getProfiler().popPush("snifferActivityUpdate"); -+ //this.level().getProfiler().popPush("snifferActivityUpdate"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("snifferBrain"); ++ //gameprofilerfiller.push("snifferBrain"); // Purpur + this.getBrain().tick(world, this); +- gameprofilerfiller.popPush("snifferActivityUpdate"); ++ //gameprofilerfiller.popPush("snifferActivityUpdate"); // Purpur SnifferAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - super.customServerAiStep(); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + super.customServerAiStep(world); } diff --git a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -index 451762b3cd023b8c5828f68e2778aada9c50ab85..f9bb83f35a41e5b076ae438af613a97b8e60c0c3 100644 +index cb20c018c11a0e707c2083cf964bd5303d216edd..f30ad422f19757664228f2064465fbcb22bb54f6 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -@@ -266,10 +266,10 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { +@@ -281,11 +281,11 @@ public class Zoglin extends Monster implements HoglinBase { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("zoglinBrain"); -+ //this.level().getProfiler().push("zoglinBrain"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("zoglinBrain"); ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur ++ //profilerFiller.push("zoglinBrain"); // Purpur if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider - this.getBrain().tick((ServerLevel)this.level(), this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur + this.getBrain().tick(world, this); +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur this.updateActivity(); } diff --git a/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java b/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java -index 796ce24185ab9e80864116f9523c4289fcaad243..82391c84789c27353212d3142c036cc5aedb98f9 100644 +index a16fd9c4679e874ad2d499f3c00c2ddfd780a7a5..0bc771e20a9bab139cd3fc03ff40baabf787b2f7 100644 --- a/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java +++ b/src/main/java/net/minecraft/world/entity/monster/breeze/Breeze.java -@@ -226,11 +226,11 @@ public class Breeze extends Monster { +@@ -235,12 +235,12 @@ public class Breeze extends Monster { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("breezeBrain"); -+ //this.level().getProfiler().push("breezeBrain"); // Purpur - this.getBrain().tick((ServerLevel)this.level(), this); -- this.level().getProfiler().popPush("breezeActivityUpdate"); -+ //this.level().getProfiler().popPush("breezeActivityUpdate"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("breezeBrain"); ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur ++ //profilerFiller.push("breezeBrain"); // Purpur + this.getBrain().tick(world, this); +- profilerFiller.popPush("breezeActivityUpdate"); ++ //profilerFiller.popPush("breezeActivityUpdate"); // Purpur BreezeAi.updateActivity(this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - super.customServerAiStep(); +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur + super.customServerAiStep(world); } diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index a69a4d860cf537322cdf96bfd42e55d3fc684dd1..757d2b7bcb83f5bdcddf85a00e90288f3b82a2d6 100644 +index 7520ab7ec5902f083aefd68895a7d9c47bf4e418..7afde99f81ec222ecbffbdcdad3aa6404e8221e0 100644 --- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -192,10 +192,10 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { +@@ -196,11 +196,11 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("hoglinBrain"); -+ //this.level().getProfiler().push("hoglinBrain"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("hoglinBrain"); ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur ++ //profilerFiller.push("hoglinBrain"); // Purpur //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel)this.level(), this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur + this.getBrain().tick(world, this); +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur HoglinAi.updateActivity(this); if (this.isConverting()) { this.timeInOverworld++; diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index 811b622945ecf67cff1992c3cdd4fcd84f33fb68..1b5977aa14d9a7254e7692bb152cc2808d52107a 100644 +index 7d5ce66c6691b0911ed5afcb1d4186525f09a15e..b53e4a312ea0dbbd16e948e61c3f6b836d46f3b8 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -328,10 +328,10 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento +@@ -339,12 +339,12 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("piglinBrain"); -+ //this.level().getProfiler().push("piglinBrain"); // Purpur - //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("piglinBrain"); ++ //gameprofilerfiller.push("piglinBrain"); // Purpur + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // // Purpur - TODO: Pufferfish + this.getBrain().tick(world, this); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur PiglinAi.updateActivity(this); - super.customServerAiStep(); + super.customServerAiStep(world); } diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -index 71d2501e88a99819ef305fa8715418aad65ec81d..407a0f27719d3944b3a005c664d80246ea1c7cf4 100644 +index bc3b0eb21200eae7e419b2571871b36fc1e07c0f..719179fb232a4f39a2c1642cc0e9593f4dea4bb8 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -@@ -138,10 +138,10 @@ public class PiglinBrute extends AbstractPiglin { +@@ -148,11 +148,11 @@ public class PiglinBrute extends AbstractPiglin { @Override - protected void customServerAiStep() { -- this.level().getProfiler().push("piglinBruteBrain"); -+ //this.level().getProfiler().push("piglinBruteBrain"); // Purpur + protected void customServerAiStep(ServerLevel world) { +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("piglinBruteBrain"); ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur ++ //profilerFiller.push("piglinBruteBrain"); // Purpur if (getRider() == null || this.isControllable()) // Purpur - only use brain if no rider - this.getBrain().tick((ServerLevel)this.level(), this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur + this.getBrain().tick(world, this); +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur PiglinBruteAi.updateActivity(this); PiglinBruteAi.maybePlayActivitySound(this); - super.customServerAiStep(); + super.customServerAiStep(world); diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 9f5325444cc4f64fc88f85794fbad09ddd4f7860..0bb577ec9ba0d23a741ccf067ac35f6be68312ca 100644 +index fcfea2cdd5df9fe505df3f7c866cd8d27ad9b249..692261880d05daa75fc53dde31d0f2b95dc52746 100644 --- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java +++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -@@ -299,9 +299,10 @@ public class Warden extends Monster implements VibrationSystem { - protected void customServerAiStep() { - ServerLevel worldserver = (ServerLevel) this.level(); +@@ -303,9 +303,9 @@ public class Warden extends Monster implements VibrationSystem { + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); -- worldserver.getProfiler().push("wardenBrain"); -+ //worldserver.getProfiler().push("wardenBrain"); // Purpur -+ //if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - TODO: Move to Ridables patch - this.getBrain().tick(worldserver, this); -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur - super.customServerAiStep(); +- gameprofilerfiller.push("wardenBrain"); ++ //gameprofilerfiller.push("wardenBrain"); // Purpur + this.getBrain().tick(world, this); +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur + super.customServerAiStep(world); if ((this.tickCount + this.getId()) % 120 == 0) { - Warden.applyDarknessAround(worldserver, this.position(), this, 20); + Warden.applyDarknessAround(world, this.position(), this, 20); diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index dcf580d852ede8ea01f5d91944a224ec6eca73e4..4be218129188c1be8736940170a861adc10fdb7d 100644 +index c885b214f4d7d91627e98d8779aab8515f205636..b4ffad429ace965f16ebf47119c880b709b27f2e 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -341,7 +341,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -340,9 +340,9 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } - protected void customServerAiStep(boolean inactive) { // Purpur - not final - // Paper end -- this.level().getProfiler().push("villagerBrain"); -+ //this.level().getProfiler().push("villagerBrain"); // Purpur + protected void customServerAiStep(ServerLevel world, boolean inactive) { // Purpur - not final + // Paper end - EAR 2 +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur + +- gameprofilerfiller.push("villagerBrain"); ++ //gameprofilerfiller.push("villagerBrain"); // Purpur // Purpur start if (this.level().purpurConfig.villagerLobotomizeEnabled) { // treat as inactive if lobotomized -@@ -357,7 +357,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - this.getBrain().tick((ServerLevel) this.level(), this); // Paper +@@ -352,7 +352,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } - // Purpur end*/ // Purpur - TODO: Pufferfish -- this.level().getProfiler().pop(); -+ //this.level().getProfiler().pop(); // Purpur + // Purpur end + if (!inactive && (getRider() == null || !this.isControllable())) this.getBrain().tick(world, this); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur if (this.assignProfessionWhenSpawned) { this.assignProfessionWhenSpawned = false; } -diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index dc88014c4d9f172cc54e5d77b488128f9ffbc73d..6379b3b8e633d1a16532b4664e53fa5afa616ab6 100644 ---- a/src/main/java/net/minecraft/world/level/Explosion.java -+++ b/src/main/java/net/minecraft/world/level/Explosion.java -@@ -681,7 +681,7 @@ public class Explosion { - } - - if (flag1) { -- this.level.getProfiler().push("explosion_blocks"); -+ //this.level.getProfiler().push("explosion_blocks"); // Purpur - List> list = new ArrayList(); - - Util.shuffle(this.toBlow, this.level.random); -@@ -759,7 +759,7 @@ public class Explosion { - Block.popResource(this.level, (BlockPos) pair.getSecond(), (ItemStack) pair.getFirst()); - } - -- this.level.getProfiler().pop(); -+ //this.level.getProfiler().pop(); // Purpur - } - - if (this.fire) { diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 4d00d72d66adfb282d354e22703552b333138694..eda2f8cc034cf46293be1be117a60cf8b663c303 100644 +index c2aff2f03451b97f1ec6bd4ee987bb729177320a..7493262c2879af196e5585b15faad69ae42764e3 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -1303,9 +1303,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -270,7 +270,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + + @Override + public final List getEntitiesOfClass(final Class entityClass, final AABB boundingBox, final Predicate predicate) { +- Profiler.get().incrementCounter("getEntities"); ++ //Profiler.get().incrementCounter("getEntities"); // Purpur + final List ret = new java.util.ArrayList<>(); + + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entityClass, null, boundingBox, ret, predicate); +@@ -280,7 +280,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + + @Override + public final List moonrise$getHardCollidingEntities(final Entity entity, final AABB box, final Predicate predicate) { +- Profiler.get().incrementCounter("getEntities"); ++ //Profiler.get().incrementCounter("getEntities"); // Purpur + final List ret = new java.util.ArrayList<>(); + + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getHardCollidingEntities(entity, box, ret, predicate); +@@ -1486,9 +1486,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } protected void tickBlockEntities() { -- ProfilerFiller gameprofilerfiller = this.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = this.getProfiler(); // Purpur +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); // Purpur - gameprofilerfiller.push("blockEntities"); + //gameprofilerfiller.push("blockEntities"); // Purpur - //this.timings.tileEntityPending.startTiming(); // Spigot // Purpur this.tickingBlockEntities = true; if (!this.pendingBlockEntityTickers.isEmpty()) { -@@ -1346,7 +1346,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - //this.timings.tileEntityTick.stopTiming(); // Spigot // Purpur + this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); +@@ -1526,7 +1526,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 + this.tickingBlockEntities = false; - co.aikar.timings.TimingHistory.tileEntityTicks += this.blockEntityTickers.size(); // Paper - gameprofilerfiller.pop(); + //gameprofilerfiller.pop(); // Purpur this.spigotConfig.currentPrimedTnt = 0; // Spigot } -@@ -1561,7 +1561,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1696,7 +1696,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @Override public List getEntities(@Nullable Entity except, AABB box, Predicate predicate) { -- this.getProfiler().incrementCounter("getEntities"); -+ //this.getProfiler().incrementCounter("getEntities"); // Purpur +- Profiler.get().incrementCounter("getEntities"); ++ //Profiler.get().incrementCounter("getEntities"); // Purpur List list = Lists.newArrayList(); - ((ServerLevel)this).getEntityLookup().getEntities(except, box, list, predicate); // Paper - optimise this call - return list; -@@ -1580,7 +1580,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - public void getEntities(EntityTypeTest filter, AABB box, Predicate predicate, List result, int limit) { -- this.getProfiler().incrementCounter("getEntities"); -+ //this.getProfiler().incrementCounter("getEntities"); // Purpur - // Paper start - optimise this call - //TODO use limit - if (filter instanceof net.minecraft.world.entity.EntityType entityTypeTest) { -@@ -1835,6 +1835,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - - public ProfilerFiller getProfiler() { -+ //if (true || gg.pufferfish.pufferfish.PufferfishConfig.disableMethodProfiler) return net.minecraft.util.profiling.InactiveProfiler.INSTANCE; // Pufferfish // Purpur // Purpur - TODO: Pufferfish - return (ProfilerFiller) this.profiler.get(); - } + // Paper start - rewrite chunk system +@@ -1726,7 +1726,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + public void getEntities(final EntityTypeTest entityTypeTest, + final AABB boundingBox, final Predicate predicate, + final List into, final int maxCount) { +- Profiler.get().incrementCounter("getEntities"); ++ //Profiler.get().incrementCounter("getEntities"); // Purpur + if (entityTypeTest instanceof net.minecraft.world.entity.EntityType byType) { + if (maxCount != Integer.MAX_VALUE) { diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 2812505185df691e8f08932aa0bba162a7d9db86..35e94c06361795d032f995e8282f8b35c075dae7 100644 +index 5297798c2be1ba85569c2b92ed221956bf75477a..fa47d14e17d9e7d1b62de7990c875245c3a445a3 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -127,7 +127,7 @@ public final class NaturalSpawner { - } - - public static void spawnForChunk(ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnState info, boolean spawnAnimals, boolean spawnMonsters, boolean rareSpawn) { -- world.getProfiler().push("spawner"); -+ //world.getProfiler().push("spawner"); // Purpur - //world.timings.mobSpawn.startTiming(); // Spigot // Purpur - MobCategory[] aenumcreaturetype = NaturalSpawner.SPAWNING_CATEGORIES; - int i = aenumcreaturetype.length; -@@ -182,7 +182,7 @@ public final class NaturalSpawner { +@@ -211,7 +211,7 @@ public final class NaturalSpawner { + } } - //world.timings.mobSpawn.stopTiming(); // Spigot // Purpur -- world.getProfiler().pop(); -+ //world.getProfiler().pop(); // Purpur +- gameprofilerfiller.pop(); ++ //gameprofilerfiller.pop(); // Purpur } // Paper start - Add mobcaps commands diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index e8d14bf4120dd9861e4ccb8bd6c14e175343c55d..fd637415625fdabcac07e120e9168d09c06141d4 100644 +index 4640baec5bed6c2d53cc0f8ca1d273cc115abe9b..15c83c6f5f56d6a27911d3bbd326cef1c21b1e58 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -443,11 +443,11 @@ public class LevelChunk extends ChunkAccess { - if (LightEngine.hasDifferentLightProperties(this, blockposition, iblockdata1, iblockdata)) { - ProfilerFiller gameprofilerfiller = this.level.getProfiler(); +@@ -407,11 +407,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + if (LightEngine.hasDifferentLightProperties(iblockdata1, iblockdata)) { + ProfilerFiller gameprofilerfiller = Profiler.get(); - gameprofilerfiller.push("updateSkyLightSources"); + //gameprofilerfiller.push("updateSkyLightSources"); // Purpur - // Paper - starlight - remove skyLightSources + // Paper - rewrite chunk system - gameprofilerfiller.popPush("queueCheckLight"); + //gameprofilerfiller.popPush("queueCheckLight"); // Purpur this.level.getChunkSource().getLightEngine().checkBlock(blockposition); @@ -1925,19 +2026,19 @@ index e8d14bf4120dd9861e4ccb8bd6c14e175343c55d..fd637415625fdabcac07e120e9168d09 } boolean flag3 = iblockdata1.hasBlockEntity(); -@@ -1158,9 +1158,9 @@ public class LevelChunk extends ChunkAccess { +@@ -1058,9 +1058,9 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p if (LevelChunk.this.isTicking(blockposition)) { try { -- ProfilerFiller gameprofilerfiller = LevelChunk.this.level.getProfiler(); -+ //ProfilerFiller gameprofilerfiller = LevelChunk.this.level.getProfiler(); +- ProfilerFiller gameprofilerfiller = Profiler.get(); ++ //ProfilerFiller gameprofilerfiller = Profiler.get(); - gameprofilerfiller.push(this::getType); + //gameprofilerfiller.push(this::getType); - //this.blockEntity.tickTimer.startTiming(); // Spigot // Purpur BlockState iblockdata = LevelChunk.this.getBlockState(blockposition); -@@ -1177,7 +1177,7 @@ public class LevelChunk extends ChunkAccess { + if (this.blockEntity.getType().isValid(iblockdata)) { +@@ -1076,7 +1076,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p // Paper end - Remove the Block Entity if it's invalid } @@ -1947,43 +2048,45 @@ index e8d14bf4120dd9861e4ccb8bd6c14e175343c55d..fd637415625fdabcac07e120e9168d09 if (throwable instanceof ThreadDeath) throw throwable; // Paper // Paper start - Prevent block entity and entity crashes diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java -index 18bbb3f8f99849333ff4bc020c8ce758a69312a5..404080976208c30e9e95e5bee47c2a749e709a45 100644 +index cc7d94144e39f7dace7b569b4567def98396e8f9..91abbda59446d462979dddc4b380c6f24d0b4c92 100644 --- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java +++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java -@@ -53,8 +53,8 @@ public class PathFinder { +@@ -58,9 +58,9 @@ public class PathFinder { @Nullable // Paper start - Perf: remove streams and optimize collection - private Path findPath(ProfilerFiller profiler, Node startNode, List> positions, float followRange, int distance, float rangeMultiplier) { -- profiler.push("find_path"); -- profiler.markForCharting(MetricCategory.PATH_FINDING); -+ //profiler.push("find_path"); // Purpur -+ //profiler.markForCharting(MetricCategory.PATH_FINDING); // Purpur + private Path findPath(Node startNode, List> positions, float followRange, int distance, float rangeMultiplier) { +- ProfilerFiller profilerFiller = Profiler.get(); +- profilerFiller.push("find_path"); +- profilerFiller.markForCharting(MetricCategory.PATH_FINDING); ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur ++ //profilerFiller.push("find_path"); // Purpur ++ //profilerFiller.markForCharting(MetricCategory.PATH_FINDING); // Purpur // Set set = positions.keySet(); startNode.g = 0.0F; startNode.h = this.getBestH(startNode, positions); // Paper - optimize collection -@@ -122,7 +122,7 @@ public class PathFinder { +@@ -128,7 +128,7 @@ public class PathFinder { if (best == null || comparator.compare(path, best) < 0) best = path; } -- profiler.pop(); -+ //profiler.pop(); // Purpur +- profilerFiller.pop(); ++ //profilerFiller.pop(); // Purpur return best; // Paper end - Perf: remove streams and optimize collection } diff --git a/src/main/java/net/minecraft/world/ticks/LevelTicks.java b/src/main/java/net/minecraft/world/ticks/LevelTicks.java -index 7a69564572357a7acc043e35b9c113beeb738951..a6d62abd3102770652f914b9d697c6d3c2533cfc 100644 +index 778e6476c86d823dc8efe603a95e589e8b2ea9d9..452fb3442221fd66debfe1e1d6e85ee17951e556 100644 --- a/src/main/java/net/minecraft/world/ticks/LevelTicks.java +++ b/src/main/java/net/minecraft/world/ticks/LevelTicks.java -@@ -81,20 +81,20 @@ public class LevelTicks implements LevelTickAccess { +@@ -79,20 +79,20 @@ public class LevelTicks implements LevelTickAccess { } public void tick(long time, int maxTicks, BiConsumer ticker) { -- ProfilerFiller profilerFiller = this.profiler.get(); +- ProfilerFiller profilerFiller = Profiler.get(); - profilerFiller.push("collect"); - this.collectTicks(time, maxTicks, profilerFiller); - profilerFiller.popPush("run"); - profilerFiller.incrementCounter("ticksToRun", this.toRunThisTick.size()); -+ //ProfilerFiller profilerFiller = this.profiler.get(); // Purpur ++ //ProfilerFiller profilerFiller = Profiler.get(); // Purpur + //profilerFiller.push("collect"); // Purpur + this.collectTicks(time, maxTicks, null); // Purpur + //profilerFiller.popPush("run"); // Purpur diff --git a/patches/api/0002-Build-System-Changes.patch b/patches/api/0002-Build-System-Changes.patch deleted file mode 100644 index 75f91f3eb..000000000 --- a/patches/api/0002-Build-System-Changes.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Sat, 12 Jun 2021 12:35:38 -0400 -Subject: [PATCH] Build System Changes - - -diff --git a/build.gradle.kts b/build.gradle.kts -index 65e67b8726f1e19a6bcb1fe2f448e4ab68df11d1..892e78b1d2d29dc54def03fcb6d85a93ad56d84c 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -121,6 +121,8 @@ tasks.jar { - } - - tasks.withType { -+ (options as StandardJavadocDocletOptions).addStringOption("-add-modules", "jdk.incubator.vector") // Purpur - our javadocs need this for pufferfish's SIMD patch -+ (options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet") // Purpur - silence Paper's bajillion javadoc warnings - val options = options as StandardJavadocDocletOptions - options.overview = "src/main/javadoc/overview.html" - options.use() diff --git a/patches/api/0003-Purpur-client-support.patch b/patches/api/0003-Purpur-client-support.patch deleted file mode 100644 index c5e33fa12..000000000 --- a/patches/api/0003-Purpur-client-support.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Fredthedoggy <45927799+fredthedoggy@users.noreply.github.com> -Date: Thu, 19 Aug 2021 20:04:18 -0400 -Subject: [PATCH] Purpur client support - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 6c327a07bf8a6aa11a2d7dad12b2830acc539484..d972cb242102a3ee7c017299aed64340628c79d8 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -3806,4 +3806,13 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - @Override - Spigot spigot(); - // Spigot end -+ -+ // Purpur start -+ /** -+ * Allows you to get if player uses Purpur Client -+ * -+ * @return True if Player uses Purpur Client -+ */ -+ public boolean usesPurpurClient(); -+ // Purpur end - } diff --git a/patches/api/0004-Default-permissions.patch b/patches/api/0004-Default-permissions.patch deleted file mode 100644 index 66bf74338..000000000 --- a/patches/api/0004-Default-permissions.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 5 Jun 2020 23:32:38 -0500 -Subject: [PATCH] Default permissions - - -diff --git a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java -index 7763d6101ac61900db1e2310966b99584539fd0e..d5a42707d365ffd72532bbb1a59a1ca7145f9918 100644 ---- a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java -+++ b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java -@@ -18,6 +18,7 @@ public final class CommandPermissions { - DefaultPermissions.registerPermission(PREFIX + "plugins", "Allows the user to view the list of plugins running on this server", PermissionDefault.TRUE, commands); - DefaultPermissions.registerPermission(PREFIX + "reload", "Allows the user to reload the server settings", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(PREFIX + "version", "Allows the user to view the version of the server", PermissionDefault.TRUE, commands); -+ DefaultPermissions.registerPermission(PREFIX + "purpur", "Allows the user to use the purpur command", PermissionDefault.OP, commands); // Purpur - - commands.recalculatePermissibles(); - return commands; -diff --git a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java -index e1a4ddf2c07cdd242fa8054a0152522fe4039e85..8e481e3815f5645ee92f0d229e5ff25c8fc9a6c2 100644 ---- a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java -+++ b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java -@@ -89,6 +89,8 @@ public final class DefaultPermissions { - CommandPermissions.registerPermissions(parent); - BroadcastPermissions.registerPermissions(parent); - -+ PurpurPermissions.registerPermissions(); // Purpur -+ - parent.recalculatePermissibles(); - } - } -diff --git a/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java b/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java -new file mode 100644 -index 0000000000000000000000000000000000000000..baec4c87d7ea4d54934ca22fd1eb7b46dd69061b ---- /dev/null -+++ b/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java -@@ -0,0 +1,87 @@ -+package org.bukkit.util.permissions; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.EntityType; -+import org.bukkit.entity.Mob; -+import org.bukkit.permissions.Permission; -+import org.bukkit.permissions.PermissionDefault; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.HashSet; -+import java.util.Set; -+ -+public final class PurpurPermissions { -+ private static final String ROOT = "purpur"; -+ private static final String PREFIX = ROOT + "."; -+ private static final Set mobs = new HashSet<>(); -+ -+ static { -+ for (EntityType mob : EntityType.values()) { -+ Class clazz = mob.getEntityClass(); -+ if (clazz != null && Mob.class.isAssignableFrom(clazz)) { -+ mobs.add(mob.getName()); -+ } -+ } -+ } -+ -+ @NotNull -+ public static Permission registerPermissions() { -+ Permission purpur = DefaultPermissions.registerPermission(ROOT, "Gives the user the ability to use all Purpur utilities and commands", PermissionDefault.FALSE); -+ -+ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.six", "Gives the user six rows of enderchest space", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.five", "Gives the user five rows of enderchest space", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.four", "Gives the user four rows of enderchest space", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.three", "Gives the user three rows of enderchest space", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.two", "Gives the user two rows of enderchest space", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.one", "Gives the user one row of enderchest space", PermissionDefault.FALSE, purpur); -+ -+ DefaultPermissions.registerPermission(PREFIX + "debug.f3n", "Allows the user to use F3+N keybind to swap gamemodes", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "joinfullserver", "Allows the user to join a full server", PermissionDefault.OP, purpur); -+ -+ DefaultPermissions.registerPermission(PREFIX + "drop.spawners", "Allows the user to drop spawner cage when broken with diamond pickaxe with silk touch", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "place.spawners", "Allows the user to place spawner cage in the world", PermissionDefault.FALSE, purpur); -+ -+ DefaultPermissions.registerPermission(PREFIX + "mending_shift_click", "Allows the user to use shift-right-click to mend items", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "inventory_totem", "Uses a totem from anywhere in the user's inventory on death", PermissionDefault.FALSE, purpur); -+ -+ Permission anvil = DefaultPermissions.registerPermission(PREFIX + "anvil", "Allows the user to use all anvil color and format abilities", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "anvil.color", "Allows the user to use color codes in an anvil", PermissionDefault.FALSE, anvil); -+ DefaultPermissions.registerPermission(PREFIX + "anvil.minimessage", "Allows the user to use minimessage tags in an anvil", PermissionDefault.FALSE, anvil); -+ DefaultPermissions.registerPermission(PREFIX + "anvil.remove_italics", "Allows the user to remove italics in an anvil", PermissionDefault.FALSE, anvil); -+ DefaultPermissions.registerPermission(PREFIX + "anvil.format", "Allows the user to use format codes in an anvil", PermissionDefault.FALSE, anvil); -+ anvil.recalculatePermissibles(); -+ -+ Permission book = DefaultPermissions.registerPermission(PREFIX + "book", "Allows the user to use color codes on books", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "book.color.edit", "Allows the user to use color codes on books when editing", PermissionDefault.FALSE, book); -+ DefaultPermissions.registerPermission(PREFIX + "book.color.sign", "Allows the user to use color codes on books when signing", PermissionDefault.FALSE, book); -+ book.recalculatePermissibles(); -+ -+ Permission sign = DefaultPermissions.registerPermission(PREFIX + "sign", "Allows the user to use all sign abilities", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission(PREFIX + "sign.edit", "Allows the user to click signs to open sign editor", PermissionDefault.FALSE, sign); -+ DefaultPermissions.registerPermission(PREFIX + "sign.color", "Allows the user to use color codes on signs", PermissionDefault.FALSE, sign); -+ DefaultPermissions.registerPermission(PREFIX + "sign.style", "Allows the user to use style codes on signs", PermissionDefault.FALSE, sign); -+ DefaultPermissions.registerPermission(PREFIX + "sign.magic", "Allows the user to use magic/obfuscate code on signs", PermissionDefault.FALSE, sign); -+ sign.recalculatePermissibles(); -+ -+ Permission ride = DefaultPermissions.registerPermission("allow.ride", "Allows the user to ride all mobs", PermissionDefault.FALSE, purpur); -+ for (String mob : mobs) { -+ DefaultPermissions.registerPermission("allow.ride." + mob, "Allows the user to ride " + mob, PermissionDefault.FALSE, ride); -+ } -+ ride.recalculatePermissibles(); -+ -+ Permission special = DefaultPermissions.registerPermission("allow.special", "Allows the user to use all mobs special abilities", PermissionDefault.FALSE, purpur); -+ for (String mob : mobs) { -+ DefaultPermissions.registerPermission("allow.special." + mob, "Allows the user to use " + mob + " special ability", PermissionDefault.FALSE, special); -+ } -+ special.recalculatePermissibles(); -+ -+ Permission powered = DefaultPermissions.registerPermission("allow.powered", "Allows the user to toggle all mobs powered state", PermissionDefault.FALSE, purpur); -+ DefaultPermissions.registerPermission("allow.powered.creeper", "Allows the user to toggle creeper powered state", PermissionDefault.FALSE, powered); -+ powered.recalculatePermissibles(); -+ -+ DefaultPermissions.registerPermission(PREFIX + "portal.instant", "Allows the user to bypass portal wait time", PermissionDefault.FALSE, purpur); -+ -+ purpur.recalculatePermissibles(); -+ return purpur; -+ } -+} diff --git a/patches/api/0005-Ridables.patch b/patches/api/0005-Ridables.patch deleted file mode 100644 index fb93dd846..000000000 --- a/patches/api/0005-Ridables.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 4 May 2019 00:57:16 -0500 -Subject: [PATCH] Ridables - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 62e3793903905b94eb1a120345015149abb33713..50344412a04f3008439e337ecf9dd09c7f853bc9 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -1155,4 +1155,35 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - */ - @NotNull String getScoreboardEntryName(); - // Paper end - entity scoreboard name -+ -+ // Purpur start -+ /** -+ * Get the riding player -+ * -+ * @return Riding player -+ */ -+ @Nullable -+ Player getRider(); -+ -+ /** -+ * Check if entity is being ridden -+ * -+ * @return True if being ridden -+ */ -+ boolean hasRider(); -+ -+ /** -+ * Check if entity is ridable -+ * -+ * @return True if ridable -+ */ -+ boolean isRidable(); -+ -+ /** -+ * Check if entity is ridable in water -+ * -+ * @return True if ridable in water -+ */ -+ boolean isRidableInWater(); -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a037df01b07af9ffb98b67aca412c1d34fade03b ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java -@@ -0,0 +1,103 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.Location; -+import org.bukkit.entity.Mob; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Triggered when a ridable mob moves with a rider -+ */ -+public class RidableMoveEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean canceled; -+ private final Player rider; -+ private Location from; -+ private Location to; -+ -+ public RidableMoveEvent(@NotNull Mob entity, @NotNull Player rider, @NotNull Location from, @NotNull Location to) { -+ super(entity); -+ this.rider = rider; -+ this.from = from; -+ this.to = to; -+ } -+ -+ @Override -+ @NotNull -+ public Mob getEntity() { -+ return (Mob) entity; -+ } -+ -+ @NotNull -+ public Player getRider() { -+ return rider; -+ } -+ -+ public boolean isCancelled() { -+ return canceled; -+ } -+ -+ public void setCancelled(boolean cancel) { -+ canceled = cancel; -+ } -+ -+ /** -+ * Gets the location this entity moved from -+ * -+ * @return Location the entity moved from -+ */ -+ @NotNull -+ public Location getFrom() { -+ return from; -+ } -+ -+ /** -+ * Sets the location to mark as where the entity moved from -+ * -+ * @param from New location to mark as the entity's previous location -+ */ -+ public void setFrom(@NotNull Location from) { -+ validateLocation(from); -+ this.from = from; -+ } -+ -+ /** -+ * Gets the location this entity moved to -+ * -+ * @return Location the entity moved to -+ */ -+ @NotNull -+ public Location getTo() { -+ return to; -+ } -+ -+ /** -+ * Sets the location that this entity will move to -+ * -+ * @param to New Location this entity will move to -+ */ -+ public void setTo(@NotNull Location to) { -+ validateLocation(to); -+ this.to = to; -+ } -+ -+ private void validateLocation(@NotNull Location loc) { -+ Preconditions.checkArgument(loc != null, "Cannot use null location!"); -+ Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!"); -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3d3a7d898e3278ce998d713dafbb4b354dad7fc7 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java -@@ -0,0 +1,37 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+public class RidableSpacebarEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ -+ public RidableSpacebarEvent(@NotNull Entity entity) { -+ super(entity); -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ cancelled = cancel; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0006-Allow-inventory-resizing.patch b/patches/api/0006-Allow-inventory-resizing.patch deleted file mode 100644 index 6b3fad2ac..000000000 --- a/patches/api/0006-Allow-inventory-resizing.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 23 Jul 2019 06:50:55 -0500 -Subject: [PATCH] Allow inventory resizing - - -diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java -index 59b375569a75cb1e1f7c610f96078e102ec0d3ed..a3f74891abbdc51dbbddaeb511f2754e0603c904 100644 ---- a/src/main/java/org/bukkit/event/inventory/InventoryType.java -+++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java -@@ -166,7 +166,7 @@ public enum InventoryType { - SMITHING_NEW(4, "Upgrade Gear"), - ; - -- private final int size; -+ private int size; public void setDefaultSize(int size) { this.size = size; } // Purpur - remove final and add setter - private final String title; - private final boolean isCreatable; - diff --git a/patches/api/0007-Llama-API.patch b/patches/api/0007-Llama-API.patch deleted file mode 100644 index cfebb1cee..000000000 --- a/patches/api/0007-Llama-API.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 18 Oct 2019 22:50:05 -0500 -Subject: [PATCH] Llama API - - -diff --git a/src/main/java/org/bukkit/entity/Llama.java b/src/main/java/org/bukkit/entity/Llama.java -index bc84b892cae5fe7019a3ad481e9da79956efa1fe..48eb5b00c460cccde29d327cef1d63fc04d6a829 100644 ---- a/src/main/java/org/bukkit/entity/Llama.java -+++ b/src/main/java/org/bukkit/entity/Llama.java -@@ -119,4 +119,20 @@ public interface Llama extends ChestedHorse, RangedEntity { // Paper - @org.jetbrains.annotations.Nullable - Llama getCaravanTail(); - // Paper end -+ -+ // Purpur start -+ /** -+ * Check if this Llama should attempt to join a caravan -+ * -+ * @return True if Llama is allowed to join a caravan -+ */ -+ boolean shouldJoinCaravan(); -+ -+ /** -+ * Set if this Llama should attempt to join a caravan -+ * -+ * @param shouldJoinCaravan True to allow joining a caravan -+ */ -+ void setShouldJoinCaravan(boolean shouldJoinCaravan); -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8849bb0becb16db907fa648cca2e98ab9d957c75 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java -@@ -0,0 +1,61 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.entity.Llama; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a Llama tries to join a caravan. -+ *

-+ * Cancelling the event will not let the Llama join. To prevent future attempts -+ * at joining a caravan use {@link Llama#setShouldJoinCaravan(boolean)}. -+ */ -+public class LlamaJoinCaravanEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean canceled; -+ private final Llama head; -+ -+ public LlamaJoinCaravanEvent(@NotNull Llama llama, @NotNull Llama head) { -+ super(llama); -+ this.head = head; -+ } -+ -+ @Override -+ @NotNull -+ public Llama getEntity() { -+ return (Llama) entity; -+ } -+ -+ /** -+ * Get the Llama that this Llama is about to follow -+ * -+ * @return Llama about to be followed -+ */ -+ @NotNull -+ public Llama getHead() { -+ return head; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return canceled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ canceled = cancel; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c268c35b541a222d50875c29770c846a8ffcc4f8 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java -@@ -0,0 +1,34 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.entity.Llama; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a Llama leaves a caravan -+ */ -+public class LlamaLeaveCaravanEvent extends EntityEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ public LlamaLeaveCaravanEvent(@NotNull Llama llama) { -+ super(llama); -+ } -+ -+ @Override -+ @NotNull -+ public Llama getEntity() { -+ return (Llama) entity; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0008-AFK-API.patch b/patches/api/0008-AFK-API.patch deleted file mode 100644 index d805660fb..000000000 --- a/patches/api/0008-AFK-API.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 10 Aug 2019 22:19:56 -0500 -Subject: [PATCH] AFK API - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index d972cb242102a3ee7c017299aed64340628c79d8..972cca3e02296f94099f965a4f7662ec63a067ea 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -3814,5 +3814,25 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @return True if Player uses Purpur Client - */ - public boolean usesPurpurClient(); -+ -+ /** -+ * Check if player is AFK -+ * -+ * @return True if AFK -+ */ -+ boolean isAfk(); -+ -+ /** -+ * Set player as AFK -+ * -+ * @param setAfk Whether to set AFK or not -+ */ -+ void setAfk(boolean setAfk); -+ -+ /** -+ * Reset the idle timer back to 0 -+ * @deprecated Use {@link #resetIdleDuration()} instead -+ */ -+ void resetIdleTimer(); - // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java b/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..25e92af7710316ed2afedf846a59dbd672869b51 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java -@@ -0,0 +1,70 @@ -+package org.purpurmc.purpur.event; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class PlayerAFKEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private final boolean setAfk; -+ private boolean shouldKick; -+ private String broadcast; -+ private boolean cancel; -+ -+ public PlayerAFKEvent(@NotNull Player player, boolean setAfk, boolean shouldKick, @Nullable String broadcast, boolean async) { -+ super(player, async); -+ this.setAfk = setAfk; -+ this.shouldKick = shouldKick; -+ this.broadcast = broadcast; -+ } -+ -+ /** -+ * Whether player is going afk or coming back -+ * -+ * @return True if going afk. False is coming back -+ */ -+ public boolean isGoingAfk() { -+ return setAfk; -+ } -+ -+ public boolean shouldKick() { -+ return shouldKick; -+ } -+ -+ public void setShouldKick(boolean shouldKick) { -+ this.shouldKick = shouldKick; -+ } -+ -+ @Nullable -+ public String getBroadcastMsg() { -+ return broadcast; -+ } -+ -+ public void setBroadcastMsg(@Nullable String broadcast) { -+ this.broadcast = broadcast; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0009-Bring-back-server-name.patch b/patches/api/0009-Bring-back-server-name.patch deleted file mode 100644 index 32c20281f..000000000 --- a/patches/api/0009-Bring-back-server-name.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 26 May 2019 15:18:40 -0500 -Subject: [PATCH] Bring back server name - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 5d1b55fdbcbe63f6b42b694d05211a3cc691a09d..54f11593f4acfb89623cf1fad58819e001505fd1 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2910,4 +2910,15 @@ public final class Bukkit { - public static Server.Spigot spigot() { - return server.spigot(); - } -+ -+ // Purpur start -+ /** -+ * Get the name of this server -+ * @return the name of the server -+ */ -+ @NotNull -+ public static String getServerName() { -+ return server.getServerName(); -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index f5c3c1a0c11dd3518981ce3b86dba8ced8578d9c..1299cab5a4a0a017e0a1b792539d9b6fb8ef6c54 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -2552,4 +2552,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - boolean isOwnedByCurrentRegion(@NotNull Entity entity); - // Paper end - Folia region threading API -+ -+ // Purpur start -+ /** -+ * Get the name of this server -+ * @return the name of the server -+ */ -+ @NotNull -+ String getServerName(); -+ // Purpur end - } diff --git a/patches/api/0010-ExecuteCommandEvent.patch b/patches/api/0010-ExecuteCommandEvent.patch deleted file mode 100644 index dd05e0eb9..000000000 --- a/patches/api/0010-ExecuteCommandEvent.patch +++ /dev/null @@ -1,175 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 31 May 2019 00:08:28 -0500 -Subject: [PATCH] ExecuteCommandEvent - - -diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java -index ac9a28922f8a556944a4c3649d74c32c622f0cb0..e842d13febca67ffa1c89fb2c1324d2609fb81fd 100644 ---- a/src/main/java/org/bukkit/command/SimpleCommandMap.java -+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java -@@ -143,6 +143,19 @@ public class SimpleCommandMap implements CommandMap { - return false; - } - -+ // Purpur start -+ String[] parsedArgs = Arrays.copyOfRange(args, 1, args.length); -+ org.purpurmc.purpur.event.ExecuteCommandEvent event = new org.purpurmc.purpur.event.ExecuteCommandEvent(sender, target, sentCommandLabel, parsedArgs); -+ if (!event.callEvent()) { -+ return true; // cancelled -+ } -+ -+ sender = event.getSender(); -+ target = event.getCommand(); -+ sentCommandLabel = event.getLabel(); -+ parsedArgs = event.getArgs(); -+ // Purpur end -+ - // Paper start - Plugins do weird things to workaround normal registration - if (target.timings == null) { - target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target); -@@ -152,7 +165,7 @@ public class SimpleCommandMap implements CommandMap { - try { - try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources - // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) -- target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length)); -+ target.execute(sender, sentCommandLabel, parsedArgs); // Purpur - } // target.timings.stopTiming(); // Spigot // Paper - } catch (CommandException ex) { - server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper -diff --git a/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java b/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bc590c4d49d32f4365a50ceb5785e798702a8179 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java -@@ -0,0 +1,130 @@ -+package org.purpurmc.purpur.event; -+ -+import com.google.common.base.Preconditions; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * This event is called whenever someone runs a command -+ */ -+public class ExecuteCommandEvent extends Event implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancel = false; -+ private CommandSender sender; -+ private Command command; -+ private String label; -+ private String[] args; -+ -+ public ExecuteCommandEvent(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @Nullable String[] args) { -+ this.sender = sender; -+ this.command = command; -+ this.label = label; -+ this.args = args; -+ } -+ -+ /** -+ * Gets the command that the player is attempting to execute. -+ * -+ * @return Command the player is attempting to execute -+ */ -+ @NotNull -+ public Command getCommand() { -+ return command; -+ } -+ -+ /** -+ * Sets the command that the player will execute. -+ * -+ * @param command New command that the player will execute -+ * @throws IllegalArgumentException if command is null or empty -+ */ -+ public void setCommand(@NotNull Command command) throws IllegalArgumentException { -+ Preconditions.checkArgument(command != null, "Command cannot be null"); -+ this.command = command; -+ } -+ -+ /** -+ * Gets the sender that this command will be executed as. -+ * -+ * @return Sender this command will be executed as -+ */ -+ @NotNull -+ public CommandSender getSender() { -+ return sender; -+ } -+ -+ /** -+ * Sets the sender that this command will be executed as. -+ * -+ * @param sender New sender which this event will execute as -+ * @throws IllegalArgumentException if the sender provided is null -+ */ -+ public void setSender(@NotNull final CommandSender sender) throws IllegalArgumentException { -+ Preconditions.checkArgument(sender != null, "Sender cannot be null"); -+ this.sender = sender; -+ } -+ -+ /** -+ * Get the label used to execute this command -+ * -+ * @return Label used to execute this command -+ */ -+ @NotNull -+ public String getLabel() { -+ return label; -+ } -+ -+ /** -+ * Set the label used to execute this command -+ * -+ * @param label Label used -+ */ -+ public void setLabel(@NotNull String label) { -+ this.label = label; -+ } -+ -+ /** -+ * Get the args passed to the command -+ * -+ * @return Args passed to the command -+ */ -+ @NotNull -+ public String[] getArgs() { -+ return args; -+ } -+ -+ /** -+ * Set the args passed to the command -+ * -+ * @param args Args passed to the command -+ */ -+ public void setArgs(@NotNull String[] args) { -+ this.args = args; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0011-Lagging-threshold.patch b/patches/api/0011-Lagging-threshold.patch deleted file mode 100644 index 428bbf5fb..000000000 --- a/patches/api/0011-Lagging-threshold.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 23 Jul 2019 10:07:24 -0500 -Subject: [PATCH] Lagging threshold - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 54f11593f4acfb89623cf1fad58819e001505fd1..215647d7f5cc8487d6a173bc0160fec6db1971eb 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2920,5 +2920,14 @@ public final class Bukkit { - public static String getServerName() { - return server.getServerName(); - } -+ -+ /** -+ * Check if server is lagging according to laggy threshold setting -+ * -+ * @return True if lagging -+ */ -+ public static boolean isLagging() { -+ return server.isLagging(); -+ } - // Purpur end - } -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 1299cab5a4a0a017e0a1b792539d9b6fb8ef6c54..7f9dc209c88a66bd2ee82cc62b948e827c6b1060 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -2560,5 +2560,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - @NotNull - String getServerName(); -+ -+ /** -+ * Check if server is lagging according to laggy threshold setting -+ * -+ * @return True if lagging -+ */ -+ boolean isLagging(); - // Purpur end - } diff --git a/patches/api/0012-PlayerSetSpawnerTypeWithEggEvent.patch b/patches/api/0012-PlayerSetSpawnerTypeWithEggEvent.patch deleted file mode 100644 index fa03a99a9..000000000 --- a/patches/api/0012-PlayerSetSpawnerTypeWithEggEvent.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 5 Jul 2019 18:21:15 -0500 -Subject: [PATCH] PlayerSetSpawnerTypeWithEggEvent - - -diff --git a/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java b/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..519809eab5d926dc7b0a7bad5d446d0defc099dc ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java -@@ -0,0 +1,85 @@ -+package org.purpurmc.purpur.event; -+ -+import org.bukkit.block.Block; -+import org.bukkit.block.CreatureSpawner; -+import org.bukkit.entity.EntityType; -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.jetbrains.annotations.NotNull; -+ -+public class PlayerSetSpawnerTypeWithEggEvent extends PlayerEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Block block; -+ private final CreatureSpawner spawner; -+ private EntityType type; -+ private boolean cancel; -+ -+ public PlayerSetSpawnerTypeWithEggEvent(@NotNull Player player, @NotNull Block block, @NotNull CreatureSpawner spawner, @NotNull EntityType type) { -+ super(player); -+ this.block = block; -+ this.spawner = spawner; -+ this.type = type; -+ } -+ -+ /** -+ * Get the spawner Block in the world -+ * -+ * @return Spawner Block -+ */ -+ @NotNull -+ public Block getBlock() { -+ return block; -+ } -+ -+ /** -+ * Get the spawner state -+ * -+ * @return Spawner state -+ */ -+ @NotNull -+ public CreatureSpawner getSpawner() { -+ return spawner; -+ } -+ -+ /** -+ * Gets the EntityType being set on the spawner -+ * -+ * @return EntityType being set -+ */ -+ @NotNull -+ public EntityType getEntityType() { -+ return type; -+ } -+ -+ /** -+ * Sets the EntityType being set on the spawner -+ * -+ * @param type EntityType to set -+ */ -+ public void setEntityType(@NotNull EntityType type) { -+ this.type = type; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0013-Anvil-API.patch b/patches/api/0013-Anvil-API.patch deleted file mode 100644 index 5ed2626ed..000000000 --- a/patches/api/0013-Anvil-API.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 19 Apr 2020 00:25:09 -0500 -Subject: [PATCH] Anvil API - - -diff --git a/src/main/java/org/bukkit/inventory/AnvilInventory.java b/src/main/java/org/bukkit/inventory/AnvilInventory.java -index c60be4fd24c7fdf65251dd6169e5e1ac3b588d95..569deccd2f1cf21da9b5906433ac493c1f2081be 100644 ---- a/src/main/java/org/bukkit/inventory/AnvilInventory.java -+++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java -@@ -123,4 +123,14 @@ public interface AnvilInventory extends Inventory { - setItem(2, result); - } - // Paper end -+ -+ // Purpur start -+ boolean canBypassCost(); -+ -+ void setBypassCost(boolean bypassCost); -+ -+ boolean canDoUnsafeEnchants(); -+ -+ void setDoUnsafeEnchants(boolean canDoUnsafeEnchants); -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b363c91a29f826910db22f2643decf996a067ab5 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java -@@ -0,0 +1,52 @@ -+package org.purpurmc.purpur.event.inventory; -+ -+import org.bukkit.entity.HumanEntity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.inventory.InventoryEvent; -+import org.bukkit.inventory.AnvilInventory; -+import org.bukkit.inventory.InventoryView; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player takes the result item out of an anvil -+ */ -+public class AnvilTakeResultEvent extends InventoryEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Player player; -+ private final ItemStack result; -+ -+ public AnvilTakeResultEvent(@NotNull HumanEntity player, @NotNull InventoryView view, @NotNull ItemStack result) { -+ super(view); -+ this.player = (Player) player; -+ this.result = result; -+ } -+ -+ @NotNull -+ public Player getPlayer() { -+ return player; -+ } -+ -+ @NotNull -+ public ItemStack getResult() { -+ return result; -+ } -+ -+ @NotNull -+ @Override -+ public AnvilInventory getInventory() { -+ return (AnvilInventory) super.getInventory(); -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fd6a5a3589d436c2aaf988fd305899695799d3bb ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java -@@ -0,0 +1,35 @@ -+package org.purpurmc.purpur.event.inventory; -+ -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.inventory.InventoryEvent; -+import org.bukkit.inventory.AnvilInventory; -+import org.bukkit.inventory.InventoryView; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when anvil slots change, triggering the result slot to be updated -+ */ -+public class AnvilUpdateResultEvent extends InventoryEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ public AnvilUpdateResultEvent(@NotNull InventoryView view) { -+ super(view); -+ } -+ -+ @NotNull -+ @Override -+ public AnvilInventory getInventory() { -+ return (AnvilInventory) super.getInventory(); -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0018-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch b/patches/api/0018-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch deleted file mode 100644 index e6dd23224..000000000 --- a/patches/api/0018-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 2 Oct 2020 17:43:24 -0500 -Subject: [PATCH] Add predicate to recipe's ExactChoice ingredient - - -diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java -index db8bcc66bdc4bedfffb4705db6338eda4c0ad29a..feda3ddfaaf37b6ee218a0e0b1fbc199899bd364 100644 ---- a/src/main/java/org/bukkit/inventory/RecipeChoice.java -+++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java -@@ -10,6 +10,7 @@ import java.util.function.Predicate; - import org.bukkit.Material; - import org.bukkit.Tag; - import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; // Purpur - - /** - * Represents a potential item match within a recipe. All choices within a -@@ -150,6 +151,7 @@ public interface RecipeChoice extends Predicate, Cloneable { - public static class ExactChoice implements RecipeChoice { - - private List choices; -+ private Predicate predicate; // Purpur - - public ExactChoice(@NotNull ItemStack stack) { - this(Arrays.asList(stack)); -@@ -194,6 +196,7 @@ public interface RecipeChoice extends Predicate, Cloneable { - - @Override - public boolean test(@NotNull ItemStack t) { -+ if (predicate != null) return predicate.test(t); // Purpur - for (ItemStack match : choices) { - if (t.isSimilar(match)) { - return true; -@@ -203,6 +206,17 @@ public interface RecipeChoice extends Predicate, Cloneable { - return false; - } - -+ // Purpur start -+ @Nullable -+ public Predicate getPredicate() { -+ return predicate; -+ } -+ -+ public void setPredicate(@Nullable Predicate predicate) { -+ this.predicate = predicate; -+ } -+ // Purpur end -+ - @Override - public int hashCode() { - int hash = 7; diff --git a/patches/api/0019-Rabid-Wolf-API.patch b/patches/api/0019-Rabid-Wolf-API.patch deleted file mode 100644 index fa9743084..000000000 --- a/patches/api/0019-Rabid-Wolf-API.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 8 Dec 2020 17:15:15 -0500 -Subject: [PATCH] Rabid Wolf API - - -diff --git a/src/main/java/org/bukkit/entity/Wolf.java b/src/main/java/org/bukkit/entity/Wolf.java -index 4b84c04675775e2a606630b00de8afe51665cebc..ccbaf40a3131f477b4be2264401ad893725c1162 100644 ---- a/src/main/java/org/bukkit/entity/Wolf.java -+++ b/src/main/java/org/bukkit/entity/Wolf.java -@@ -112,4 +112,20 @@ public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.Collar - return variant; - } - } -+ -+ // Purpur start -+ /** -+ * Checks if this wolf is rabid -+ * -+ * @return whether the wolf is rabid -+ */ -+ public boolean isRabid(); -+ -+ /** -+ * Sets this wolf to be rabid or not -+ * -+ * @param rabid whether the wolf should be rabid -+ */ -+ public void setRabid(boolean rabid); -+ // Purpur end - } diff --git a/patches/api/0020-PlayerBookTooLargeEvent.patch b/patches/api/0020-PlayerBookTooLargeEvent.patch deleted file mode 100644 index 937bb73c4..000000000 --- a/patches/api/0020-PlayerBookTooLargeEvent.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 23 Dec 2020 00:43:27 -0600 -Subject: [PATCH] PlayerBookTooLargeEvent - - -diff --git a/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java b/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c88394336bc9ab0f66a2af24d393f4a176a234d5 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java -@@ -0,0 +1,65 @@ -+package org.purpurmc.purpur.event.player; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.player.PlayerEvent; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player tries to bypass book limitations -+ */ -+public class PlayerBookTooLargeEvent extends PlayerEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ private final ItemStack book; -+ private boolean kickPlayer = true; -+ -+ /** -+ * @param player The player -+ * @param book The book -+ */ -+ public PlayerBookTooLargeEvent(@NotNull Player player, @NotNull ItemStack book) { -+ super(player, !Bukkit.isPrimaryThread()); -+ this.book = book; -+ } -+ -+ /** -+ * Get the book containing the wanted edits -+ * -+ * @return The book -+ */ -+ @NotNull -+ public ItemStack getBook() { -+ return book; -+ } -+ -+ /** -+ * Whether server should kick the player or not -+ * -+ * @return True to kick player -+ */ -+ public boolean shouldKickPlayer() { -+ return kickPlayer; -+ } -+ -+ /** -+ * Whether server should kick the player or not -+ * -+ * @param kickPlayer True to kick player -+ */ -+ public void setShouldKickPlayer(boolean kickPlayer) { -+ this.kickPlayer = kickPlayer; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0021-Full-netherite-armor-grants-fire-resistance.patch b/patches/api/0021-Full-netherite-armor-grants-fire-resistance.patch deleted file mode 100644 index 5082cfcd3..000000000 --- a/patches/api/0021-Full-netherite-armor-grants-fire-resistance.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 24 Dec 2020 11:00:04 -0600 -Subject: [PATCH] Full netherite armor grants fire resistance - - -diff --git a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java -index c9f395064656dd0126410eb3c6e197baa450c063..13156a12e5df50cdc1e465dc0bd9d94108275629 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java -@@ -217,6 +217,12 @@ public class EntityPotionEffectEvent extends EntityEvent implements Cancellable - * When all effects are removed due to a bucket of milk. - */ - MILK, -+ // Purpur start -+ /** -+ * When a player wears full netherite armor -+ */ -+ NETHERITE_ARMOR, -+ // Purpur end - /** - * When a player gets bad omen after killing a patrol captain. - */ diff --git a/patches/api/0022-Add-EntityTeleportHinderedEvent.patch b/patches/api/0022-Add-EntityTeleportHinderedEvent.patch deleted file mode 100644 index a172c1de1..000000000 --- a/patches/api/0022-Add-EntityTeleportHinderedEvent.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 9 Jan 2021 15:26:04 +0100 -Subject: [PATCH] Add EntityTeleportHinderedEvent - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c66eb163877e872f234d86dc244cab7efeb818cd ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java -@@ -0,0 +1,117 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.entity.Entity; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Fired when an entity is hindered from teleporting. -+ */ -+public class EntityTeleportHinderedEvent extends EntityEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @NotNull -+ private final Reason reason; -+ -+ @Nullable -+ private final TeleportCause teleportCause; -+ -+ private boolean retry = false; -+ -+ public EntityTeleportHinderedEvent(@NotNull Entity what, @NotNull Reason reason, -+ @Nullable TeleportCause teleportCause) { -+ super(what); -+ this.reason = reason; -+ this.teleportCause = teleportCause; -+ } -+ -+ /** -+ * @return why the teleport was hindered. -+ */ -+ @NotNull -+ public Reason getReason() { -+ return reason; -+ } -+ -+ /** -+ * @return why the teleport occurred if cause was given, otherwise {@code null}. -+ */ -+ @Nullable -+ public TeleportCause getTeleportCause() { -+ return teleportCause; -+ } -+ -+ /** -+ * Whether the teleport should be retried. -+ *

-+ * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack -+ * overflow. Do not retry more than necessary. -+ *

-+ * -+ * @return whether the teleport should be retried. -+ */ -+ public boolean shouldRetry() { -+ return retry; -+ } -+ -+ /** -+ * Sets whether the teleport should be retried. -+ *

-+ * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack -+ * overflow. Do not retry more than necessary. -+ *

-+ * -+ * @param retry whether the teleport should be retried. -+ */ -+ public void setShouldRetry(boolean retry) { -+ this.retry = retry; -+ } -+ -+ /** -+ * Calls the event and tests if should retry. -+ * -+ * @return whether the teleport should be retried. -+ */ -+ @Override -+ public boolean callEvent() { -+ super.callEvent(); -+ return shouldRetry(); -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ /** -+ * Reason for hindrance in teleports. -+ */ -+ public enum Reason { -+ /** -+ * The teleported entity is a passenger of another entity. -+ */ -+ IS_PASSENGER, -+ -+ /** -+ * The teleported entity has passengers. -+ */ -+ IS_VEHICLE, -+ -+ /** -+ * The teleport event was cancelled. -+ *

-+ * This is only caused by players teleporting. -+ *

-+ */ -+ EVENT_CANCELLED, -+ } -+} diff --git a/patches/api/0024-API-for-any-mob-to-burn-daylight.patch b/patches/api/0024-API-for-any-mob-to-burn-daylight.patch deleted file mode 100644 index eb412045f..000000000 --- a/patches/api/0024-API-for-any-mob-to-burn-daylight.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Tue, 25 May 2021 16:30:30 -0400 -Subject: [PATCH] API for any mob to burn daylight - -Co-authored by: Encode42 - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 50344412a04f3008439e337ecf9dd09c7f853bc9..f482467ae784b134da97eb38afb7f12585520297 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -1185,5 +1185,12 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - * @return True if ridable in water - */ - boolean isRidableInWater(); -+ -+ /** -+ * Checks if the entity is in daylight -+ * -+ * @return True if in daylight -+ */ -+ boolean isInDaylight(); - // Purpur end - } -diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java -index aba9952b2256b058eb413ce93f3305c861a200db..61a046584acf48693489ff551a0dd4c4b16af9ff 100644 ---- a/src/main/java/org/bukkit/entity/LivingEntity.java -+++ b/src/main/java/org/bukkit/entity/LivingEntity.java -@@ -1455,5 +1455,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource - * @param slot Equipment slot to play break animation for - */ - void broadcastItemBreak(@NotNull org.bukkit.inventory.EquipmentSlot slot); -+ -+ /** -+ * If this mob will burn in the sunlight -+ * -+ * @return True if mob will burn in sunlight -+ */ -+ boolean shouldBurnInDay(); -+ -+ /** -+ * Set if this mob should burn in the sunlight -+ * -+ * @param shouldBurnInDay True to burn in sunlight -+ */ -+ void setShouldBurnInDay(boolean shouldBurnInDay); - // Purpur end - } diff --git a/patches/api/0026-Fix-default-permission-system.patch b/patches/api/0026-Fix-default-permission-system.patch deleted file mode 100644 index 754c4e1e3..000000000 --- a/patches/api/0026-Fix-default-permission-system.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 30 Jun 2021 17:44:27 -0500 -Subject: [PATCH] Fix default permission system - - -diff --git a/src/main/java/org/bukkit/permissions/PermissibleBase.java b/src/main/java/org/bukkit/permissions/PermissibleBase.java -index cd3296fea01648592d2af89b3d80135acb6d0958..45797a6fbae1d8edc4211cb30def24ad4f59bd49 100644 ---- a/src/main/java/org/bukkit/permissions/PermissibleBase.java -+++ b/src/main/java/org/bukkit/permissions/PermissibleBase.java -@@ -168,7 +168,7 @@ public class PermissibleBase implements Permissible { - - for (Permission perm : defaults) { - String name = perm.getName().toLowerCase(java.util.Locale.ENGLISH); -- permissions.put(name, new PermissionAttachmentInfo(parent, name, null, true)); -+ permissions.put(name, new PermissionAttachmentInfo(parent, name, null, perm.getDefault().getValue(isOp()))); // Purpur - Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent); - calculateChildPermissions(perm.getChildren(), false, null); - } -@@ -196,7 +196,7 @@ public class PermissibleBase implements Permissible { - String name = entry.getKey(); - - Permission perm = Bukkit.getServer().getPluginManager().getPermission(name); -- boolean value = entry.getValue() ^ invert; -+ boolean value = (entry.getValue() == null && perm != null ? perm.getDefault().getValue(isOp()) : entry.getValue()) ^ invert; // Purpur - String lname = name.toLowerCase(java.util.Locale.ENGLISH); - - permissions.put(lname, new PermissionAttachmentInfo(parent, lname, attachment, value)); -diff --git a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java -index 8e481e3815f5645ee92f0d229e5ff25c8fc9a6c2..10627d2a11251a8cb01bbc3f6242d66f3505a16e 100644 ---- a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java -+++ b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java -@@ -31,7 +31,7 @@ public final class DefaultPermissions { - - if (withLegacy) { - Permission legacy = new Permission(LEGACY_PREFIX + result.getName(), result.getDescription(), PermissionDefault.FALSE); -- legacy.getChildren().put(result.getName(), true); -+ legacy.getChildren().put(result.getName(), null); // Purpur - registerPermission(perm, false); - } - -@@ -40,7 +40,7 @@ public final class DefaultPermissions { - - @NotNull - public static Permission registerPermission(@NotNull Permission perm, @NotNull Permission parent) { -- parent.getChildren().put(perm.getName(), true); -+ parent.getChildren().put(perm.getName(), null); // Purpur - return registerPermission(perm); - } - -@@ -53,7 +53,7 @@ public final class DefaultPermissions { - @NotNull - public static Permission registerPermission(@NotNull String name, @Nullable String desc, @NotNull Permission parent) { - Permission perm = registerPermission(name, desc); -- parent.getChildren().put(perm.getName(), true); -+ parent.getChildren().put(perm.getName(), null); // Purpur - return perm; - } - -@@ -66,7 +66,7 @@ public final class DefaultPermissions { - @NotNull - public static Permission registerPermission(@NotNull String name, @Nullable String desc, @Nullable PermissionDefault def, @NotNull Permission parent) { - Permission perm = registerPermission(name, desc, def); -- parent.getChildren().put(perm.getName(), true); -+ parent.getChildren().put(perm.getName(), null); // Purpur - return perm; - } - -@@ -79,7 +79,7 @@ public final class DefaultPermissions { - @NotNull - public static Permission registerPermission(@NotNull String name, @Nullable String desc, @Nullable PermissionDefault def, @Nullable Map children, @NotNull Permission parent) { - Permission perm = registerPermission(name, desc, def, children); -- parent.getChildren().put(perm.getName(), true); -+ parent.getChildren().put(perm.getName(), null); // Purpur - return perm; - } - diff --git a/patches/api/0027-Summoner-API.patch b/patches/api/0027-Summoner-API.patch deleted file mode 100644 index bc94bd07e..000000000 --- a/patches/api/0027-Summoner-API.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Jul 2021 18:45:01 -0500 -Subject: [PATCH] Summoner API - - -diff --git a/src/main/java/org/bukkit/entity/IronGolem.java b/src/main/java/org/bukkit/entity/IronGolem.java -index 655e37cb3a09610a3f3df805d6dcad17d722da62..09fd716c8fc9ea34a1cbf87bcbe22df035422a51 100644 ---- a/src/main/java/org/bukkit/entity/IronGolem.java -+++ b/src/main/java/org/bukkit/entity/IronGolem.java -@@ -19,4 +19,20 @@ public interface IronGolem extends Golem { - * player created, false if you want it to be a natural village golem. - */ - public void setPlayerCreated(boolean playerCreated); -+ -+ // Purpur start -+ /** -+ * Get the player that summoned this iron golem -+ * -+ * @return UUID of summoner -+ */ -+ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner(); -+ -+ /** -+ * Set the player that summoned this iron golem -+ * -+ * @param summoner UUID of summoner -+ */ -+ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner); -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/entity/Snowman.java b/src/main/java/org/bukkit/entity/Snowman.java -index 7fbfdb07585c7b28acea1f0c1f58ada0cc744441..21fcca092e2e31baa5ece0de9e44e3fade8c7123 100644 ---- a/src/main/java/org/bukkit/entity/Snowman.java -+++ b/src/main/java/org/bukkit/entity/Snowman.java -@@ -23,4 +23,20 @@ public interface Snowman extends Golem, RangedEntity, io.papermc.paper.entity.Sh - * @param derpMode True to remove the pumpkin, false to add a pumpkin - */ - void setDerp(boolean derpMode); -+ -+ // Purpur start -+ /** -+ * Get the player that summoned this snowman -+ * -+ * @return UUID of summoner -+ */ -+ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner(); -+ -+ /** -+ * Set the player that summoned this snowman -+ * -+ * @param summoner UUID of summoner -+ */ -+ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner); -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/entity/Wither.java b/src/main/java/org/bukkit/entity/Wither.java -index 14543c2238b45c526dd9aebea2aa5c22f5df54dc..5312daf33405704c74e2c9e109754285ea6cf734 100644 ---- a/src/main/java/org/bukkit/entity/Wither.java -+++ b/src/main/java/org/bukkit/entity/Wither.java -@@ -107,4 +107,20 @@ public interface Wither extends Monster, Boss, com.destroystokyo.paper.entity.Ra - */ - void enterInvulnerabilityPhase(); - // Paper end -+ -+ // Purpur start -+ /** -+ * Get the player that summoned this wither -+ * -+ * @return UUID of summoner -+ */ -+ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner(); -+ -+ /** -+ * Set the player that summoned this wither -+ * -+ * @param summoner UUID of summoner -+ */ -+ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner); -+ // Purpur end - } diff --git a/patches/api/0028-Clean-up-version-command-output.patch b/patches/api/0028-Clean-up-version-command-output.patch deleted file mode 100644 index 1bd0a28dd..000000000 --- a/patches/api/0028-Clean-up-version-command-output.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 15 Jul 2021 23:43:04 -0500 -Subject: [PATCH] Clean up version command output - - -diff --git a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java -index a736d7bcdc5861a01b66ba36158db1c716339346..22fc165fd9c95f0f3ae1be7a0857e48cc50fad5b 100644 ---- a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java -+++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java -@@ -26,6 +26,12 @@ public interface VersionFetcher { - @NotNull - Component getVersionMessage(@NotNull String serverVersion); - -+ // Purpur start -+ default int distance() { -+ return 0; -+ } -+ // Purpur end -+ - class DummyVersionFetcher implements VersionFetcher { - - @Override -diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java -index fd5d9881abfd930bb883120f018f76dc78b62b14..d3dadad49df09e85c724c93e8cc88da2c985e9b4 100644 ---- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java -+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java -@@ -214,7 +214,7 @@ public class VersionCommand extends BukkitCommand { - String version = Bukkit.getVersion(); - // Paper start - if (version.startsWith("null")) { // running from ide? -- setVersionMessage(Component.text("Unknown version, custom build?", NamedTextColor.YELLOW)); -+ setVersionMessage(Component.text("* Unknown version, custom build?", NamedTextColor.RED)); // Purpur - return; - } - setVersionMessage(getVersionFetcher().getVersionMessage(version)); -@@ -255,9 +255,11 @@ public class VersionCommand extends BukkitCommand { - // Paper start - private void setVersionMessage(final @NotNull Component msg) { - lastCheck = System.currentTimeMillis(); -- final Component message = Component.textOfChildren( -- Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE), -- Component.newline(), -+ // Purpur start -+ int distance = getVersionFetcher().distance(); -+ final Component message = Component.join(net.kyori.adventure.text.JoinConfiguration.separator(Component.newline()), -+ ChatColor.parseMM("Current: %s%s*", distance == 0 ? "" : distance > 0 ? "" : "", Bukkit.getVersion()), -+ // Purpur end - msg - ); - this.versionMessage = Component.text() diff --git a/patches/api/0030-Added-the-ability-to-add-combustible-items.patch b/patches/api/0030-Added-the-ability-to-add-combustible-items.patch deleted file mode 100644 index 597454cba..000000000 --- a/patches/api/0030-Added-the-ability-to-add-combustible-items.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Mon, 9 Aug 2021 13:22:03 +0200 -Subject: [PATCH] Added the ability to add combustible items - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 215647d7f5cc8487d6a173bc0160fec6db1971eb..7bc4e5e9947ab646707a5c0b39c70c0cc6606bd8 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2929,5 +2929,24 @@ public final class Bukkit { - public static boolean isLagging() { - return server.isLagging(); - } -+ -+ /** -+ * Add an Item as fuel for furnaces -+ * -+ * @param material The material that will be the fuel -+ * @param burnTime The time (in ticks) this item will burn for -+ */ -+ public static void addFuel(@NotNull Material material, int burnTime) { -+ server.addFuel(material, burnTime); -+ } -+ -+ /** -+ * Remove an item as fuel for furnaces -+ * -+ * @param material The material that will no longer be a fuel -+ */ -+ public static void removeFuel(@NotNull Material material) { -+ server.removeFuel(material); -+ } - // Purpur end - } -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 7f9dc209c88a66bd2ee82cc62b948e827c6b1060..fa926319ff033768d78508491e072efec1dcbc9f 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -2567,5 +2567,20 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @return True if lagging - */ - boolean isLagging(); -+ -+ /** -+ * Add an Item as fuel for furnaces -+ * -+ * @param material The material that will be the fuel -+ * @param burnTime The time (in ticks) this item will burn for -+ */ -+ public void addFuel(@NotNull Material material, int burnTime); -+ -+ /** -+ * Remove an item as fuel for furnaces -+ * -+ * @param material The material that will no longer be a fuel -+ */ -+ public void removeFuel(@NotNull Material material); - // Purpur end - } diff --git a/patches/api/0031-Grindstone-API.patch b/patches/api/0031-Grindstone-API.patch deleted file mode 100644 index 5a699b1c1..000000000 --- a/patches/api/0031-Grindstone-API.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 27 Dec 2021 08:10:50 -0600 -Subject: [PATCH] Grindstone API - - -diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..eebb5d124456b8209d1b8e8cc4cb772dd3714f04 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java -@@ -0,0 +1,72 @@ -+package org.purpurmc.purpur.event.inventory; -+ -+import org.bukkit.entity.HumanEntity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.inventory.InventoryEvent; -+import org.bukkit.inventory.GrindstoneInventory; -+import org.bukkit.inventory.InventoryView; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a player takes the result item out of a Grindstone -+ */ -+public class GrindstoneTakeResultEvent extends InventoryEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Player player; -+ private final ItemStack result; -+ private int experienceAmount; -+ -+ public GrindstoneTakeResultEvent(@NotNull HumanEntity player, @NotNull InventoryView view, @NotNull ItemStack result, int experienceAmount) { -+ super(view); -+ this.player = (Player) player; -+ this.result = result; -+ this.experienceAmount = experienceAmount; -+ } -+ -+ @NotNull -+ public Player getPlayer() { -+ return player; -+ } -+ -+ @NotNull -+ public ItemStack getResult() { -+ return result; -+ } -+ -+ @NotNull -+ @Override -+ public GrindstoneInventory getInventory() { -+ return (GrindstoneInventory) super.getInventory(); -+ } -+ -+ /** -+ * Get the amount of experience this transaction will give -+ * -+ * @return Amount of experience to give -+ */ -+ public int getExperienceAmount() { -+ return this.experienceAmount; -+ } -+ -+ /** -+ * Set the amount of experience this transaction will give -+ * -+ * @param experienceAmount Amount of experience to give -+ */ -+ public void setExperienceAmount(int experienceAmount) { -+ this.experienceAmount = experienceAmount; -+ } -+ -+ @NotNull -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0032-Shears-can-have-looting-enchantment.patch b/patches/api/0032-Shears-can-have-looting-enchantment.patch deleted file mode 100644 index 53f2a3f93..000000000 --- a/patches/api/0032-Shears-can-have-looting-enchantment.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 3 Jan 2022 02:00:50 -0600 -Subject: [PATCH] Shears can have looting enchantment - - -diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java -index 5831ffe24eed01311c71989dcb1830dbc395607b..45f5493eebfecf56b7c0ef4659c078dfc62c0612 100644 ---- a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java -+++ b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java -@@ -238,6 +238,16 @@ public enum EnchantmentTarget { - public boolean includes(@NotNull Material item) { - return item.equals(Material.BOW) || item.equals(Material.CROSSBOW); - } -+ }, -+ -+ /** -+ * Allow the Enchantment to be placed on shears. -+ */ -+ WEAPON_AND_SHEARS { -+ @Override -+ public boolean includes(@NotNull Material item) { -+ return WEAPON.includes(item) || item.equals(Material.SHEARS); -+ } - // Purpur end - }; - diff --git a/patches/api/0033-Lobotomize-stuck-villagers.patch b/patches/api/0033-Lobotomize-stuck-villagers.patch deleted file mode 100644 index 03b9bf50d..000000000 --- a/patches/api/0033-Lobotomize-stuck-villagers.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 24 Jan 2022 20:42:22 -0600 -Subject: [PATCH] Lobotomize stuck villagers - - -diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java -index 3bc24457d143449e6a338d79becf7c39b9f81054..4a5edf4e72e81b22c1abb2ade244f7f4292e993c 100644 ---- a/src/main/java/org/bukkit/entity/Villager.java -+++ b/src/main/java/org/bukkit/entity/Villager.java -@@ -328,4 +328,14 @@ public interface Villager extends AbstractVillager { - */ - public void clearReputations(); - // Paper end -+ -+ // Purpur start -+ -+ /** -+ * Check if villager is currently lobotomized -+ * -+ * @return True if lobotomized -+ */ -+ boolean isLobotomized(); -+ // Purpur end - } diff --git a/patches/api/0034-Add-local-difficulty-api.patch b/patches/api/0034-Add-local-difficulty-api.patch deleted file mode 100644 index 46e1e1486..000000000 --- a/patches/api/0034-Add-local-difficulty-api.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 9 Jul 2022 00:57:26 -0500 -Subject: [PATCH] Add local difficulty api - - -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 97f97ea5c6aa513c439f86a9c82821e0f7d9cd1e..099516b90c504205b894b387542221e8c0c98b40 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -4249,6 +4249,16 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - @Nullable - public DragonBattle getEnderDragonBattle(); - -+ // Purpur start -+ /** -+ * Gets the local difficulty (based on inhabited time) at a location -+ * -+ * @param location Location to check -+ * @return The local difficulty -+ */ -+ public float getLocalDifficultyAt(@NotNull Location location); -+ // Purpur end -+ - /** - * Get all {@link FeatureFlag} enabled in this world. - * diff --git a/patches/api/0035-Remove-Timings.patch b/patches/api/0035-Remove-Timings.patch deleted file mode 100644 index 75f6b7465..000000000 --- a/patches/api/0035-Remove-Timings.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 1 Jul 2022 04:03:26 -0500 -Subject: [PATCH] Remove Timings - - -diff --git a/src/main/java/co/aikar/timings/TimedEventExecutor.java b/src/main/java/co/aikar/timings/TimedEventExecutor.java -index 8f29c1561ba5916cb5634392edd8bd2a5a294a51..6fbc64e0f214d0c8e5afcbe385e414a4e1fe1c72 100644 ---- a/src/main/java/co/aikar/timings/TimedEventExecutor.java -+++ b/src/main/java/co/aikar/timings/TimedEventExecutor.java -@@ -77,9 +77,9 @@ public class TimedEventExecutor implements EventExecutor { - executor.execute(listener, event); - return; - } -- try (Timing ignored = timings.startTiming()){ -+ //try (Timing ignored = timings.startTiming()){ // Purpur - executor.execute(listener, event); -- } -+ //} // Purpur - } - - @Override -diff --git a/src/main/java/co/aikar/timings/Timing.java b/src/main/java/co/aikar/timings/Timing.java -index 7514fad26f955329f8bf17ff17db75f0c8301ee5..1d866e980abc542bdfee1ce082cd9cdd7761e9f7 100644 ---- a/src/main/java/co/aikar/timings/Timing.java -+++ b/src/main/java/co/aikar/timings/Timing.java -@@ -39,6 +39,7 @@ public interface Timing extends AutoCloseable { - * @return Timing - */ - @NotNull -+ @io.papermc.paper.annotation.DoNotUse // Purpur - Timing startTiming(); - - /** -@@ -46,6 +47,7 @@ public interface Timing extends AutoCloseable { - * - * Will automatically be called when this Timing is used with try-with-resources - */ -+ @io.papermc.paper.annotation.DoNotUse // Purpur - void stopTiming(); - - /** -@@ -56,6 +58,7 @@ public interface Timing extends AutoCloseable { - * @return Timing - */ - @NotNull -+ @io.papermc.paper.annotation.DoNotUse // Purpur - Timing startTimingIfSync(); - - /** -@@ -65,12 +68,14 @@ public interface Timing extends AutoCloseable { - * - * But only if we are on the primary thread. - */ -+ @io.papermc.paper.annotation.DoNotUse // Purpur - void stopTimingIfSync(); - - /** - * @deprecated Doesn't do anything - Removed - */ - @Deprecated -+ @io.papermc.paper.annotation.DoNotUse // Purpur - void abort(); - - /** -@@ -82,5 +87,6 @@ public interface Timing extends AutoCloseable { - TimingHandler getTimingHandler(); - - @Override -+ @io.papermc.paper.annotation.DoNotUse // Purpur - void close(); - } -diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java -index 9812d668ad945aba486fbf6d5bf83c4292cb5d03..752d54830aa8baa1450bf72da03ae55ed30293c2 100644 ---- a/src/main/java/co/aikar/timings/Timings.java -+++ b/src/main/java/co/aikar/timings/Timings.java -@@ -124,7 +124,7 @@ public final class Timings { - @NotNull - public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) { - Timing timing = of(plugin, name, groupHandler); -- timing.startTiming(); -+ //timing.startTiming(); // Purpur - return timing; - } - -@@ -145,9 +145,11 @@ public final class Timings { - * @param enabled Should timings be reported - */ - public static void setTimingsEnabled(boolean enabled) { -- timingsEnabled = enabled; -- warnAboutDeprecationOnEnable(); -- reset(); -+ // Purpur start - we don't do that here... -+ timingsEnabled = false; -+ //warnAboutDeprecationOnEnable(); -+ //reset(); -+ // Purpur end - } - - private static void warnAboutDeprecationOnEnable() { -diff --git a/src/main/java/co/aikar/timings/TimingsCommand.java b/src/main/java/co/aikar/timings/TimingsCommand.java -index e801e79fa57c44b2e5d359647c920f88064826f1..1abfcee0f6d632f4cd8d74b4994a90c9ea9d254c 100644 ---- a/src/main/java/co/aikar/timings/TimingsCommand.java -+++ b/src/main/java/co/aikar/timings/TimingsCommand.java -@@ -45,7 +45,7 @@ public class TimingsCommand extends BukkitCommand { - public TimingsCommand(@NotNull String name) { - super(name); - this.description = "Manages Spigot Timings data to see performance of the server."; -- this.usageMessage = "/timings "; -+ this.usageMessage = "/timings";// "; // Purpur - this.setPermission("bukkit.command.timings"); - } - -@@ -54,8 +54,12 @@ public class TimingsCommand extends BukkitCommand { - if (!testPermission(sender)) { - return true; - } -- if (false) { -- sender.sendMessage(Timings.deprecationMessage()); -+ if (true) { -+ net.kyori.adventure.text.minimessage.MiniMessage mm = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage(); -+ sender.sendMessage(mm.deserialize("Purpur has removed timings to save your performance. Please use /spark instead")); -+ sender.sendMessage(mm.deserialize("For more information, view its documentation at")); -+ sender.sendMessage(mm.deserialize("https://spark.lucko.me/docs/Command-Usage")); -+ return true; - } - if (args.length < 1) { - sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED)); -@@ -115,7 +119,7 @@ public class TimingsCommand extends BukkitCommand { - Preconditions.checkNotNull(args, "Arguments cannot be null"); - Preconditions.checkNotNull(alias, "Alias cannot be null"); - -- if (args.length == 1) { -+ if (false && args.length == 1) { // Purpur - return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS, - new ArrayList(TIMINGS_SUBCOMMANDS.size())); - } -diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java -index e842d13febca67ffa1c89fb2c1324d2609fb81fd..5349f16136d9348c374a7dfe5b89a71dfcb0e66d 100644 ---- a/src/main/java/org/bukkit/command/SimpleCommandMap.java -+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java -@@ -163,10 +163,10 @@ public class SimpleCommandMap implements CommandMap { - // Paper end - - try { -- try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources -+ //try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources // Purpur - // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) - target.execute(sender, sentCommandLabel, parsedArgs); // Purpur -- } // target.timings.stopTiming(); // Spigot // Paper -+ //} // target.timings.stopTiming(); // Spigot // Paper // Purpur - } catch (CommandException ex) { - server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper - //target.timings.stopTiming(); // Spigot // Paper -diff --git a/src/main/java/org/spigotmc/CustomTimingsHandler.java b/src/main/java/org/spigotmc/CustomTimingsHandler.java -index 12946bd55fcf7c40d39081779a7fa30049ee6165..9c2d605c50cbf9aefa56ec209df9f6cea1392e89 100644 ---- a/src/main/java/org/spigotmc/CustomTimingsHandler.java -+++ b/src/main/java/org/spigotmc/CustomTimingsHandler.java -@@ -61,7 +61,7 @@ public final class CustomTimingsHandler { - handler = timing; - } - -- public void startTiming() { handler.startTiming(); } -- public void stopTiming() { handler.stopTiming(); } -+ public void startTiming() { /*handler.startTiming();*/ } // Purpur -+ public void stopTiming() { /*handler.stopTiming();*/ } // Purpur - - } diff --git a/patches/api/0036-Add-Bee-API.patch b/patches/api/0036-Add-Bee-API.patch deleted file mode 100644 index 6efae8520..000000000 --- a/patches/api/0036-Add-Bee-API.patch +++ /dev/null @@ -1,179 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SageSphinx63920 -Date: Mon, 25 Jul 2022 19:33:49 +0200 -Subject: [PATCH] Add Bee API - - -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..833f46d1941f377765132fc528c45567ee0290d2 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java -@@ -0,0 +1,48 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.Bee; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a bee targets a flower -+ */ -+public class BeeFoundFlowerEvent extends EntityEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Location location; -+ -+ public BeeFoundFlowerEvent(@NotNull Bee bee, @Nullable Location location) { -+ super(bee); -+ this.location = location; -+ } -+ -+ @Override -+ @NotNull -+ public Bee getEntity() { -+ return (Bee) super.getEntity(); -+ } -+ -+ /** -+ * Returns the location of the flower that the bee targets -+ * -+ * @return The location of the flower -+ */ -+ @Nullable -+ public Location getLocation() { -+ return location; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ae0bb654745724889c67fae9072ae90ea3778ba4 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java -@@ -0,0 +1,47 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.Bee; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a bee starts pollinating -+ */ -+public class BeeStartedPollinatingEvent extends EntityEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Location location; -+ -+ public BeeStartedPollinatingEvent(@NotNull Bee bee, @NotNull Location location) { -+ super(bee); -+ this.location = location; -+ } -+ -+ @Override -+ @NotNull -+ public Bee getEntity() { -+ return (Bee) super.getEntity(); -+ } -+ -+ /** -+ * Returns the location of the flower that the bee pollinates -+ * -+ * @return The location of the flower -+ */ -+ @NotNull -+ public Location getLocation() { -+ return this.location; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ff3c9f075be2f624af8b0ce5fffc5ea69a41f32e ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java -@@ -0,0 +1,60 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.entity.Bee; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Called when a bee stops pollinating -+ */ -+public class BeeStopPollinatingEvent extends EntityEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Location location; -+ private final boolean success; -+ -+ public BeeStopPollinatingEvent(@NotNull Bee bee, @Nullable Location location, boolean success) { -+ super(bee); -+ this.location = location; -+ this.success = success; -+ } -+ -+ @Override -+ @NotNull -+ public Bee getEntity() { -+ return (Bee) super.getEntity(); -+ } -+ -+ /** -+ * Returns the location of the flower that the bee stopped pollinating -+ * -+ * @return The location of the flower -+ */ -+ @Nullable -+ public Location getLocation() { -+ return location; -+ } -+ -+ /** -+ * Returns whether the bee successfully pollinated the flower -+ * -+ * @return True if the pollination was successful -+ */ -+ public boolean wasSuccessful() { -+ return success; -+ } -+ -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0037-Debug-Marker-API.patch b/patches/api/0037-Debug-Marker-API.patch deleted file mode 100644 index 8541e74ea..000000000 --- a/patches/api/0037-Debug-Marker-API.patch +++ /dev/null @@ -1,341 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: YouHaveTrouble -Date: Sat, 23 Jul 2022 14:40:17 +0200 -Subject: [PATCH] Debug Marker API - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 7bc4e5e9947ab646707a5c0b39c70c0cc6606bd8..70ef8f63ab79e102cb4326c21cc344488f4fbdd3 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2948,5 +2948,89 @@ public final class Bukkit { - public static void removeFuel(@NotNull Material material) { - server.removeFuel(material); - } -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ */ -+ public static void sendBlockHighlight(@NotNull Location location, int duration) { -+ server.sendBlockHighlight(location, duration); -+ } -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client -+ */ -+ public static void sendBlockHighlight(@NotNull Location location, int duration, int argb) { -+ server.sendBlockHighlight(location, duration, argb); -+ } -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ */ -+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text) { -+ server.sendBlockHighlight(location, duration, text); -+ } -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client -+ */ -+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb) { -+ server.sendBlockHighlight(location, duration, text, argb); -+ } -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client -+ * @param transparency Transparency of the highlight -+ * @throws IllegalArgumentException If transparency is outside 0-255 range -+ */ -+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency) { -+ server.sendBlockHighlight(location, duration, color, transparency); -+ } -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client -+ * @param transparency Transparency of the highlight -+ * @throws IllegalArgumentException If transparency is outside 0-255 range -+ */ -+ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency) { -+ server.sendBlockHighlight(location, duration, text, color, transparency); -+ } -+ -+ /** -+ * Clears all debug block highlights for all players on the server. -+ */ -+ public static void clearBlockHighlights() { -+ server.clearBlockHighlights(); -+ } - // Purpur end - } -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index fa926319ff033768d78508491e072efec1dcbc9f..320422ff95773efa01e8205edcc5c6c9a84d5ecd 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -2582,5 +2582,75 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - * @param material The material that will no longer be a fuel - */ - public void removeFuel(@NotNull Material material); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, int argb); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client -+ * @param transparency Transparency of the highlight -+ * @throws IllegalArgumentException If transparency is outside 0-255 range -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on the server. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client -+ * @param transparency Transparency of the highlight -+ * @throws IllegalArgumentException If transparency is outside 0-255 range -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency); -+ -+ /** -+ * Clears all debug block highlights for all players on the server. -+ */ -+ void clearBlockHighlights(); - // Purpur end - } -diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 099516b90c504205b894b387542221e8c0c98b40..83a5b68c785a88594e6e3824ed282844086f7f1a 100644 ---- a/src/main/java/org/bukkit/World.java -+++ b/src/main/java/org/bukkit/World.java -@@ -4257,6 +4257,76 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient - * @return The local difficulty - */ - public float getLocalDifficultyAt(@NotNull Location location); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on this world. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on this world. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, int argb); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on this world. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on this world. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on this world. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client -+ * @param transparency Transparency of the highlight -+ * @throws IllegalArgumentException If transparency is outside 0-255 range -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to all players on this world. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client -+ * @param transparency Transparency of the highlight -+ * @throws IllegalArgumentException If transparency is outside 0-255 range -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency); -+ -+ /** -+ * Clears all debug block highlights for all players on this world. -+ */ -+ void clearBlockHighlights(); - // Purpur end - - /** -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 972cca3e02296f94099f965a4f7662ec63a067ea..ec49be86fa9b2612ae2853f06f503bffa3a1271d 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -3834,5 +3834,75 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @deprecated Use {@link #resetIdleDuration()} instead - */ - void resetIdleTimer(); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to this player. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to this player. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, int argb); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to this player. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to this player. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to this player. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client -+ * @param transparency Transparency of the highlight -+ * @throws IllegalArgumentException If transparency is outside 0-255 range -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency); -+ -+ /** -+ * Creates debug block highlight on specified block location and show it to this player. -+ *

-+ * Clients may be inconsistent in displaying it. -+ * @param location Location to highlight -+ * @param duration Duration for highlight to show in milliseconds -+ * @param text Text to show above the highlight -+ * @param color Color of the highlight. Will be ignored on some versions of vanilla client -+ * @param transparency Transparency of the highlight -+ * @throws IllegalArgumentException If transparency is outside 0-255 range -+ */ -+ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency); -+ -+ /** -+ * Clears all debug block highlights -+ */ -+ void clearBlockHighlights(); - // Purpur end - } diff --git a/patches/api/0038-Add-death-screen-API.patch b/patches/api/0038-Add-death-screen-API.patch deleted file mode 100644 index 68f89598e..000000000 --- a/patches/api/0038-Add-death-screen-API.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Fri, 23 Sep 2022 18:35:28 -0700 -Subject: [PATCH] Add death screen API - - -diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index ec49be86fa9b2612ae2853f06f503bffa3a1271d..d057743b8f6a463434c1f76398c7a98614b19d47 100644 ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -3904,5 +3904,25 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * Clears all debug block highlights - */ - void clearBlockHighlights(); -+ -+ /** -+ * Sends a player the death screen with a specified death message. -+ * -+ * @param message The death message to show the player -+ */ -+ void sendDeathScreen(@NotNull net.kyori.adventure.text.Component message); -+ -+ /** -+ * Sends a player the death screen with a specified death message, -+ * along with the entity that caused the death. -+ * -+ * @param message The death message to show the player -+ * @param killer The entity that killed the player -+ * @deprecated Use {@link #sendDeathScreen(net.kyori.adventure.text.Component)} instead, as 1.20 removed the killer ID from the packet. -+ */ -+ @Deprecated(since = "1.20") -+ default void sendDeathScreen(@NotNull net.kyori.adventure.text.Component message, @Nullable Entity killer) { -+ sendDeathScreen(message); -+ } - // Purpur end - } diff --git a/patches/api/0039-Language-API.patch b/patches/api/0039-Language-API.patch deleted file mode 100644 index 1fbe2ebee..000000000 --- a/patches/api/0039-Language-API.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Sat, 1 Oct 2022 17:08:23 -0700 -Subject: [PATCH] Language API - - -diff --git a/src/main/java/org/purpurmc/purpur/language/Language.java b/src/main/java/org/purpurmc/purpur/language/Language.java -new file mode 100644 -index 0000000000000000000000000000000000000000..38483d908ed830e97883733bee2370f87060f4c7 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/language/Language.java -@@ -0,0 +1,60 @@ -+package org.purpurmc.purpur.language; -+ -+import net.kyori.adventure.translation.Translatable; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Represents a language that can translate translation keys -+ */ -+public abstract class Language { -+ private static Language language; -+ -+ /** -+ * Returns the default language of the server -+ */ -+ @NotNull -+ public static Language getLanguage() { -+ return language; -+ } -+ -+ public static void setLanguage(@NotNull Language language) { -+ if (Language.language != null) { -+ throw new UnsupportedOperationException("Cannot redefine singleton Language"); -+ } -+ Language.language = language; -+ } -+ -+ /** -+ * Checks if a certain translation key is translatable with this language -+ * @param key The translation key -+ * @return Whether this language can translate the key -+ */ -+ abstract public boolean has(@NotNull String key); -+ -+ /** -+ * Checks if a certain translation key is translatable with this language -+ * @param key The translation key -+ * @return Whether this language can translate the key -+ */ -+ public boolean has(@NotNull Translatable key) { -+ return has(key.translationKey()); -+ } -+ -+ /** -+ * Translates a translation key to this language -+ * @param key The translation key -+ * @return The translated key, or the translation key if it couldn't be translated -+ */ -+ @NotNull -+ abstract public String getOrDefault(@NotNull String key); -+ -+ /** -+ * Translates a translation key to this language -+ * @param key The translation key -+ * @return The translated key, or the translation key if it couldn't be translated -+ */ -+ @NotNull -+ public String getOrDefault(@NotNull Translatable key) { -+ return getOrDefault(key.translationKey()); -+ } -+} diff --git a/patches/api/0040-Add-log-suppression-for-LibraryLoader.patch b/patches/api/0040-Add-log-suppression-for-LibraryLoader.patch deleted file mode 100644 index d1a85cb9d..000000000 --- a/patches/api/0040-Add-log-suppression-for-LibraryLoader.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Krakenied -Date: Fri, 14 Oct 2022 23:11:27 +0200 -Subject: [PATCH] Add log suppression for LibraryLoader - - -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index eaefbb00e9993d54906cc8cf35cf753c0d6c7707..f1e58639213be0c43cd2ff090b625e7d0a67e8be 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -55,6 +55,7 @@ public final class JavaPluginLoader implements PluginLoader { - private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")}; - private final List loaders = new CopyOnWriteArrayList(); - private final LibraryLoader libraryLoader; -+ public static boolean SuppressLibraryLoaderLogger = false; // Purpur - - /** - * This class was not meant to be constructed explicitly -diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -index 8e1b6be2462aaa692efa1f72986921a6dc357196..b6e18b12fd4d61ce92203582906d24b4d14e6cc5 100644 ---- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java -@@ -68,6 +68,7 @@ public class LibraryLoader - @Override - public void transferStarted(@NotNull TransferEvent event) throws TransferCancelledException - { -+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - logger.log( Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName() ); - } - } ); -@@ -88,6 +89,7 @@ public class LibraryLoader - { - return null; - } -+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - logger.log( Level.INFO, "[{0}] Loading {1} libraries... please wait", new Object[] - { - java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), desc.getLibraries().size() // Paper - use configured log prefix -@@ -135,6 +137,7 @@ public class LibraryLoader - } - - jarFiles.add( url ); -+ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - logger.log( Level.INFO, "[{0}] Loaded library {1}", new Object[] - { - java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), file // Paper - use configured log prefix diff --git a/patches/api/0041-Fire-Immunity-API.patch b/patches/api/0041-Fire-Immunity-API.patch deleted file mode 100644 index d84da08f3..000000000 --- a/patches/api/0041-Fire-Immunity-API.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Racci <90304606+DaRacci@users.noreply.github.com> -Date: Fri, 4 Feb 2022 16:09:47 +1100 -Subject: [PATCH] Fire Immunity API - - -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index f482467ae784b134da97eb38afb7f12585520297..07b8c0dd049ff783fd2e408be634642479bf8b1e 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -1192,5 +1192,18 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - * @return True if in daylight - */ - boolean isInDaylight(); -+ -+ /** -+ * Checks if the entity is fire immune -+ * -+ * @return True if fire immune -+ */ -+ boolean isImmuneToFire(); -+ -+ /** -+ * Sets if the entity is fire immune -+ * Set this to null to restore the entity type default -+ */ -+ void setImmuneToFire(@Nullable Boolean fireImmune); - // Purpur end - } diff --git a/patches/api/0042-Added-goat-ram-event.patch b/patches/api/0042-Added-goat-ram-event.patch deleted file mode 100644 index 7665c860d..000000000 --- a/patches/api/0042-Added-goat-ram-event.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SageSphinx63920 -Date: Sat, 29 Oct 2022 00:06:05 +0200 -Subject: [PATCH] Added goat ram event - - -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f62c14f3d4999e9112c1c73642aa337d97b94b5a ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java -@@ -0,0 +1,59 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.entity.Goat; -+import org.bukkit.entity.LivingEntity; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityEvent; -+import org.jetbrains.annotations.NotNull; -+ -+/** -+ * Called when a goat rams an entity -+ */ -+public class GoatRamEntityEvent extends EntityEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private final LivingEntity rammedEntity; -+ private boolean cancelled; -+ -+ public GoatRamEntityEvent(@NotNull Goat goat, @NotNull LivingEntity rammedEntity) { -+ super(goat); -+ this.rammedEntity = rammedEntity; -+ } -+ -+ /** -+ * Returns the entity that was rammed by the goat -+ * -+ * @return The rammed entity -+ */ -+ @NotNull -+ public LivingEntity getRammedEntity() { -+ return this.rammedEntity; -+ } -+ -+ @Override -+ @NotNull -+ public Goat getEntity() { -+ return (Goat) super.getEntity(); -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+} diff --git a/patches/api/0043-Add-PreExplodeEvents.patch b/patches/api/0043-Add-PreExplodeEvents.patch deleted file mode 100644 index db26aac79..000000000 --- a/patches/api/0043-Add-PreExplodeEvents.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SageSphinx63920 -Date: Mon, 26 Dec 2022 23:40:13 +0100 -Subject: [PATCH] Add PreExplodeEvents - - -diff --git a/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java b/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8ea97ddceedb7c719e8a50a0dd8f3f0919ca1647 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java -@@ -0,0 +1,53 @@ -+package org.purpurmc.purpur.event; -+ -+import org.bukkit.block.Block; -+import org.bukkit.block.BlockState; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.block.BlockExplodeEvent; -+import org.jetbrains.annotations.NotNull; -+import java.util.Collections; -+ -+/** -+ * Called before a block's explosion is processed -+ */ -+public class PreBlockExplodeEvent extends BlockExplodeEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private final float yield; -+ -+ public PreBlockExplodeEvent(@NotNull final Block what, final float yield, @NotNull BlockState explodedBlockState) { -+ super(what, explodedBlockState, Collections.emptyList(), yield); -+ this.yield = yield; -+ this.cancelled = false; -+ } -+ -+ /** -+ * Returns the percentage of blocks to drop from this explosion -+ * -+ * @return The yield. -+ */ -+ public float getYield() { -+ return yield; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java b/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2d4f68228861492baaea0bcc604dfef623b337ba ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java -@@ -0,0 +1,64 @@ -+package org.purpurmc.purpur.event.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.entity.EntityExplodeEvent; -+import org.jetbrains.annotations.NotNull; -+import java.util.Collections; -+ -+/** -+ * Called before an entity's explosion is processed -+ */ -+public class PreEntityExplodeEvent extends EntityExplodeEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ private boolean cancelled; -+ private final float yield; -+ private final Location location; -+ -+ public PreEntityExplodeEvent(@NotNull org.bukkit.entity.Entity what, @NotNull final Location location, final float yield) { -+ super(what, location, Collections.emptyList(), yield); -+ this.cancelled = false; -+ this.yield = yield; -+ this.location = location; -+ } -+ -+ /** -+ * Returns the percentage of blocks to drop from this explosion -+ * -+ * @return The yield. -+ */ -+ public float getYield() { -+ return yield; -+ } -+ -+ /** -+ * Returns the location where the explosion happened. -+ * -+ * @return The location of the explosion -+ */ -+ @NotNull -+ public Location getLocation() { -+ return location; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return this.cancelled; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancelled = cancel; -+ } -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/api/0044-Stored-Bee-API.patch b/patches/api/0044-Stored-Bee-API.patch deleted file mode 100644 index e155a6a0f..000000000 --- a/patches/api/0044-Stored-Bee-API.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: EOT3000 -Date: Sat, 10 Jun 2023 20:27:14 -0400 -Subject: [PATCH] Stored Bee API - - -diff --git a/src/main/java/org/bukkit/block/EntityBlockStorage.java b/src/main/java/org/bukkit/block/EntityBlockStorage.java -index 739911cda33b373f99df627a3a378b37d7d461aa..51e78c22cd021722b963fe31d1d9175d141add1a 100644 ---- a/src/main/java/org/bukkit/block/EntityBlockStorage.java -+++ b/src/main/java/org/bukkit/block/EntityBlockStorage.java -@@ -47,6 +47,24 @@ public interface EntityBlockStorage extends TileState { - @NotNull - List releaseEntities(); - -+ // Purpur start -+ /** -+ * Releases a stored entity, and returns the entity in the world. -+ * -+ * @param entity Entity to release -+ * @return The entity which was released, or null if the stored entity is not in the hive -+ */ -+ @org.jetbrains.annotations.Nullable -+ T releaseEntity(@NotNull org.purpurmc.purpur.entity.StoredEntity entity); -+ -+ /** -+ * Gets all the entities currently stored in the block. -+ * -+ * @return List of all entities which are stored in the block -+ */ -+ @NotNull -+ List> getEntities(); -+ //Purpur end - /** - * Add an entity to the block. - * -diff --git a/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java b/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java -new file mode 100644 -index 0000000000000000000000000000000000000000..29540d55532197d2381a52ea9222b5785d224ef8 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java -@@ -0,0 +1,52 @@ -+package org.purpurmc.purpur.entity; -+ -+import org.bukkit.Nameable; -+import org.bukkit.block.EntityBlockStorage; -+import org.bukkit.entity.Entity; -+import org.bukkit.entity.EntityType; -+import org.bukkit.persistence.PersistentDataHolder; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Represents an entity stored in a block -+ * -+ * @see org.bukkit.block.EntityBlockStorage -+ */ -+public interface StoredEntity extends PersistentDataHolder, Nameable { -+ /** -+ * Checks if this entity has been released yet -+ * -+ * @return if this entity has been released -+ */ -+ boolean hasBeenReleased(); -+ -+ /** -+ * Releases the entity from its stored block -+ * -+ * @return the released entity, or null if unsuccessful (including if this entity has already been released) -+ */ -+ @Nullable -+ T release(); -+ -+ /** -+ * Returns the block in which this entity is stored -+ * -+ * @return the EntityBlockStorage in which this entity is stored, or null if it has been released -+ */ -+ @Nullable -+ EntityBlockStorage getBlockStorage(); -+ -+ /** -+ * Gets the entity type of this stored entity -+ * -+ * @return the type of entity this stored entity represents -+ */ -+ @NotNull -+ EntityType getType(); -+ -+ /** -+ * Writes data to the block entity snapshot. {@link EntityBlockStorage#update()} must be run in order to update the block in game. -+ */ -+ void update(); -+} diff --git a/patches/api/0045-Explorer-Map-API.patch b/patches/api/0045-Explorer-Map-API.patch deleted file mode 100644 index 91241d8f1..000000000 --- a/patches/api/0045-Explorer-Map-API.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 5 Jul 2023 12:48:08 -0500 -Subject: [PATCH] Explorer Map API - - -diff --git a/src/main/java/org/bukkit/map/MapRenderer.java b/src/main/java/org/bukkit/map/MapRenderer.java -index cb7040876a99a5a7e49b81684ef0f3b79584c376..22d8f31b1b8a5dbb5ab3275068642937c097abfe 100644 ---- a/src/main/java/org/bukkit/map/MapRenderer.java -+++ b/src/main/java/org/bukkit/map/MapRenderer.java -@@ -54,4 +54,12 @@ public abstract class MapRenderer { - */ - public abstract void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player); - -+ // Purpur - start -+ /** -+ * Check if this is an explorer (aka treasure) map. -+ * -+ * @return True if explorer map -+ */ -+ public abstract boolean isExplorerMap(); -+ // Purpur - end - } diff --git a/patches/api/0046-Stonecutter-damage.patch b/patches/api/0046-Stonecutter-damage.patch deleted file mode 100644 index 8d0888381..000000000 --- a/patches/api/0046-Stonecutter-damage.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Sun, 11 Feb 2024 23:07:47 -0800 -Subject: [PATCH] Stonecutter damage - - -diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java -index 446b3ffd5caca5344be1c250475679834cd0d4a2..3da8d3d8925cd7a111c0c357bceecfd3a801c8eb 100644 ---- a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java -+++ b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java -@@ -303,7 +303,8 @@ public class EntityDamageEvent extends EntityEvent implements Cancellable { - WORLD_BORDER, - /** - * Damage caused when an entity contacts a block such as a Cactus, -- * Dripstone (Stalagmite) or Berry Bush. -+ * Dripstone (Stalagmite) or Berry Bush. (Stonecutters too if you -+ * have the Stonecutter damage Purpur feature enabled) - *

- * Damage: variable - */ diff --git a/patches/generated-api/0001-Ridables.patch b/patches/generated-api/0001-Ridables.patch deleted file mode 100644 index 4a9d76ce8..000000000 --- a/patches/generated-api/0001-Ridables.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 4 May 2019 00:57:16 -0500 -Subject: [PATCH] Ridables - - -diff --git a/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -index 069f2668f5229b0368b796e65eef1648fba0a097..50dc058cd8ecade74be30c75907d07f349c4df87 100644 ---- a/com/destroystokyo/paper/entity/ai/VanillaGoal.java -+++ b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -@@ -442,6 +442,12 @@ public interface VanillaGoal extends Goal { - - GoalKey ZOMBIE_ATTACK_TURTLE_EGG = create("zombie_attack_turtle_egg", Zombie.class); - -+ // Purpur start -+ GoalKey MOB_HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider")); -+ GoalKey HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider")); -+ GoalKey LLAMA_HAS_RIDER = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_has_rider")); -+ // Purpur end -+ - /** - * Removed in 1.20.2 - */ diff --git a/patches/generated-api/0002-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch b/patches/generated-api/0002-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch deleted file mode 100644 index ddfb8fbce..000000000 --- a/patches/generated-api/0002-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 28 Jun 2020 21:50:55 -0500 -Subject: [PATCH] Phantoms attracted to crystals and crystals shoot phantoms - - -diff --git a/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -index 50dc058cd8ecade74be30c75907d07f349c4df87..b3a1325786fffb1a585b3911c75c03d184e8a848 100644 ---- a/com/destroystokyo/paper/entity/ai/VanillaGoal.java -+++ b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -@@ -446,6 +446,8 @@ public interface VanillaGoal extends Goal { - GoalKey MOB_HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider")); - GoalKey HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider")); - GoalKey LLAMA_HAS_RIDER = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_has_rider")); -+ GoalKey FIND_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal")); -+ GoalKey ORBIT_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal")); - // Purpur end - - /** diff --git a/patches/generated-api/0003-Add-option-to-disable-zombie-aggressiveness-towards-.patch b/patches/generated-api/0003-Add-option-to-disable-zombie-aggressiveness-towards-.patch deleted file mode 100644 index fef774bc6..000000000 --- a/patches/generated-api/0003-Add-option-to-disable-zombie-aggressiveness-towards-.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: nitricspace -Date: Wed, 23 Sep 2020 22:14:38 +0100 -Subject: [PATCH] Add option to disable zombie aggressiveness towards villagers - when lagging - - -diff --git a/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -index b3a1325786fffb1a585b3911c75c03d184e8a848..31c4d5da936f88e68c67c6e464b94563a47a0f34 100644 ---- a/com/destroystokyo/paper/entity/ai/VanillaGoal.java -+++ b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -@@ -448,6 +448,8 @@ public interface VanillaGoal extends Goal { - GoalKey LLAMA_HAS_RIDER = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_has_rider")); - GoalKey FIND_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal")); - GoalKey ORBIT_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal")); -+ GoalKey DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); -+ GoalKey ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager")); - // Purpur end - - /** diff --git a/patches/generated-api/0004-Rabid-Wolf-API.patch b/patches/generated-api/0004-Rabid-Wolf-API.patch deleted file mode 100644 index 82e3b3a72..000000000 --- a/patches/generated-api/0004-Rabid-Wolf-API.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 8 Dec 2020 17:15:15 -0500 -Subject: [PATCH] Rabid Wolf API - - -diff --git a/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -index 31c4d5da936f88e68c67c6e464b94563a47a0f34..a41aa6c187d60373630eb803cb69d58b85eacc98 100644 ---- a/com/destroystokyo/paper/entity/ai/VanillaGoal.java -+++ b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -@@ -450,6 +450,7 @@ public interface VanillaGoal extends Goal { - GoalKey ORBIT_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal")); - GoalKey DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); - GoalKey ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager")); -+ GoalKey AVOID_RABID_WOLF = GoalKey.of(Wolf.class, NamespacedKey.minecraft("avoid_rabid_wolf")); - // Purpur end - - /** diff --git a/patches/generated-api/0005-Iron-golem-poppy-calms-anger.patch b/patches/generated-api/0005-Iron-golem-poppy-calms-anger.patch deleted file mode 100644 index d85e4e893..000000000 --- a/patches/generated-api/0005-Iron-golem-poppy-calms-anger.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 13 May 2021 21:38:01 -0500 -Subject: [PATCH] Iron golem poppy calms anger - - -diff --git a/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -index a41aa6c187d60373630eb803cb69d58b85eacc98..9b991201a2f6cc9feccccf7f4e7bcded64117764 100644 ---- a/com/destroystokyo/paper/entity/ai/VanillaGoal.java -+++ b/com/destroystokyo/paper/entity/ai/VanillaGoal.java -@@ -451,6 +451,7 @@ public interface VanillaGoal extends Goal { - GoalKey DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); - GoalKey ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager")); - GoalKey AVOID_RABID_WOLF = GoalKey.of(Wolf.class, NamespacedKey.minecraft("avoid_rabid_wolf")); -+ GoalKey RECEIVE_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("receive_flower")); - // Purpur end - - /** diff --git a/patches/server/0002-Purpur-config-files.patch b/patches/server/0002-Purpur-config-files.patch deleted file mode 100644 index d0887d441..000000000 --- a/patches/server/0002-Purpur-config-files.patch +++ /dev/null @@ -1,529 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 9 May 2019 18:09:43 -0500 -Subject: [PATCH] Purpur config files - - -diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index 4b002e8b75d117b726b0de274a76d3596fce015b..8cde30544e14f8fc2dac32966ae3c21f8cf3a551 100644 ---- a/src/main/java/com/destroystokyo/paper/Metrics.java -+++ b/src/main/java/com/destroystokyo/paper/Metrics.java -@@ -593,7 +593,7 @@ public class Metrics { - boolean logFailedRequests = config.getBoolean("logFailedRequests", false); - // Only start Metrics, if it's enabled in the config - if (config.getBoolean("enabled", true)) { -- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger()); -+ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Pufferfish // Purpur - - metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { - String minecraftVersion = Bukkit.getVersion(); -@@ -602,16 +602,8 @@ public class Metrics { - })); - - metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size())); -- metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline")); -- final String paperVersion; -- final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion(); -- if (implVersion != null) { -- final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1); -- paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); -- } else { -- paperVersion = "unknown"; -- } -- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion)); -+ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur -+ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() != null) ? org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() : "unknown")); // Purpur - - metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { - Map> map = new HashMap<>(); -diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index e6c7f62ed379a78645933670299e4fcda8540ed1..edb94e5601acc38994dac20a167b145de778d426 100644 ---- a/src/main/java/net/minecraft/commands/CommandSourceStack.java -+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java -@@ -331,6 +331,30 @@ public class CommandSourceStack implements ExecutionCommandSource io.papermc.paper.adventure.PaperAdventure.asVanilla(message), broadcastToOps); -+ } -+ // Purpur end -+ - public void sendSuccess(Supplier feedbackSupplier, boolean broadcastToOps) { - boolean flag1 = this.source.acceptsSuccess() && !this.silent; - boolean flag2 = broadcastToOps && this.source.shouldInformAdmins() && !this.silent; -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index eb4fc900164d1fb3a78653ae8bc42ea30323f5b7..6d47aa73788eef78aa6714384db879b4e907de9b 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -232,6 +232,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - thread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized - io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command - com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics -+ // Purpur start -+ try { -+ org.purpurmc.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings")); -+ } catch (Exception e) { -+ DedicatedServer.LOGGER.error("Unable to load server configuration", e); -+ return false; -+ } -+ org.purpurmc.purpur.PurpurConfig.registerCommands(); -+ // Purpur end - com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now - io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // Paper - init PaperBrigadierProvider - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index b4ef3ad2c17168085372f1fe46809f02d9dfe74a..04f7f6743aabdca54892b2b155386f86032cf807 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -170,6 +170,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // Paper end - add paper world config - - public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray -+ public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - public final co.aikar.timings.WorldTimingsHandler timings; // Paper - public static BlockPos lastPhysicsProblem; // Spigot - private org.spigotmc.TickLimiter entityLimiter; -@@ -216,6 +217,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config; Async-Anti-Xray: Pass executor - this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot - this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config -+ this.purpurConfig = new org.purpurmc.purpur.PurpurWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), env); // Purpur - this.generator = gen; - this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 467ef4ffd6ee13b247ac9e453b006ec3d89362c9..d97f33d654086c892f01e47a59be7e37f6e03ae7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1054,6 +1054,7 @@ public final class CraftServer implements Server { - - org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot - this.console.paperConfigurations.reloadConfigs(this.console); -+ org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur - for (ServerLevel world : this.console.getAllLevels()) { - // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty - world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) -@@ -1069,6 +1070,7 @@ public final class CraftServer implements Server { - } - } - world.spigotConfig.init(); // Spigot -+ world.purpurConfig.init(); // Purpur - } - - Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper -@@ -1084,6 +1086,7 @@ public final class CraftServer implements Server { - this.reloadData(); - org.spigotmc.SpigotConfig.registerCommands(); // Spigot - io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper -+ org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur - this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); - this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); - -@@ -3048,6 +3051,18 @@ public final class CraftServer implements Server { - return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); - } - -+ // Purpur start -+ @Override -+ public YamlConfiguration getPurpurConfig() { -+ return org.purpurmc.purpur.PurpurConfig.config; -+ } -+ -+ @Override -+ public java.util.Properties getServerProperties() { -+ return getProperties().properties; -+ } -+ // Purpur end -+ - @Override - public void restart() { - org.spigotmc.RestartCommand.restart(); -diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index c988afa496d25314451435eedd64079a0d87cef0..45a33086e1bb8a70e0fa01090731d27a0474da41 100644 ---- a/src/main/java/org/bukkit/craftbukkit/Main.java -+++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -175,6 +175,14 @@ public class Main { - .describedAs("Jar file"); - // Paper end - -+ // Purpur Start -+ acceptsAll(asList("purpur", "purpur-settings"), "File for purpur settings") -+ .withRequiredArg() -+ .ofType(File.class) -+ .defaultsTo(new File("purpur.yml")) -+ .describedAs("Yml file"); -+ // Purpur end -+ - // Paper start - acceptsAll(asList("server-name"), "Name of the server") - .withRequiredArg() -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4f015144be0a7a448c6c2b0765232c02ad405d09 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -0,0 +1,175 @@ -+package org.purpurmc.purpur; -+ -+import com.google.common.base.Throwables; -+import com.google.common.collect.ImmutableMap; -+import com.mojang.datafixers.util.Pair; -+import net.kyori.adventure.bossbar.BossBar; -+import net.kyori.adventure.text.minimessage.MiniMessage; -+import net.minecraft.core.registries.BuiltInRegistries; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.world.effect.MobEffect; -+import net.minecraft.world.effect.MobEffectInstance; -+import net.minecraft.world.entity.EntityDimensions; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.food.FoodProperties; -+import net.minecraft.world.food.Foods; -+import net.minecraft.world.item.enchantment.Enchantment; -+import net.minecraft.world.level.block.Block; -+import net.minecraft.world.level.block.Blocks; -+import org.bukkit.Bukkit; -+import org.bukkit.command.Command; -+import org.bukkit.configuration.ConfigurationSection; -+import org.bukkit.configuration.InvalidConfigurationException; -+import org.bukkit.configuration.file.YamlConfiguration; -+import org.purpurmc.purpur.command.PurpurCommand; -+import org.purpurmc.purpur.task.TPSBarTask; -+ -+import java.io.File; -+import java.io.IOException; -+import java.lang.reflect.InvocationTargetException; -+import java.lang.reflect.Method; -+import java.lang.reflect.Modifier; -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.HashSet; -+import java.util.List; -+import java.util.Map; -+import java.util.Set; -+import java.util.logging.Level; -+ -+@SuppressWarnings("unused") -+public class PurpurConfig { -+ private static final String HEADER = "This is the main configuration file for Purpur.\n" -+ + "As you can see, there's tons to configure. Some options may impact gameplay, so use\n" -+ + "with caution, and make sure you know what each option does before configuring.\n" -+ + "\n" -+ + "If you need help with the configuration or have any questions related to Purpur,\n" -+ + "join us in our Discord guild.\n" -+ + "\n" -+ + "Website: https://purpurmc.org \n" -+ + "Docs: https://purpurmc.org/docs \n"; -+ private static File CONFIG_FILE; -+ public static YamlConfiguration config; -+ -+ private static Map commands; -+ -+ public static int version; -+ static boolean verbose; -+ -+ public static void init(File configFile) { -+ CONFIG_FILE = configFile; -+ config = new YamlConfiguration(); -+ try { -+ config.load(CONFIG_FILE); -+ } catch (IOException ignore) { -+ } catch (InvalidConfigurationException ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Could not load purpur.yml, please correct your syntax errors", ex); -+ throw Throwables.propagate(ex); -+ } -+ config.options().header(HEADER); -+ config.options().copyDefaults(true); -+ verbose = getBoolean("verbose", false); -+ -+ commands = new HashMap<>(); -+ commands.put("purpur", new PurpurCommand("purpur")); -+ -+ version = getInt("config-version", 35); -+ set("config-version", 35); -+ -+ readConfig(PurpurConfig.class, null); -+ -+ Blocks.rebuildCache(); -+ } -+ -+ protected static void log(String s) { -+ if (verbose) { -+ log(Level.INFO, s); -+ } -+ } -+ -+ protected static void log(Level level, String s) { -+ Bukkit.getLogger().log(level, s); -+ } -+ -+ public static void registerCommands() { -+ for (Map.Entry entry : commands.entrySet()) { -+ MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Purpur", entry.getValue()); -+ } -+ } -+ -+ static void readConfig(Class clazz, Object instance) { -+ for (Method method : clazz.getDeclaredMethods()) { -+ if (Modifier.isPrivate(method.getModifiers())) { -+ if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { -+ try { -+ method.setAccessible(true); -+ method.invoke(instance); -+ } catch (InvocationTargetException ex) { -+ throw Throwables.propagate(ex.getCause()); -+ } catch (Exception ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex); -+ } -+ } -+ } -+ } -+ -+ try { -+ config.save(CONFIG_FILE); -+ } catch (IOException ex) { -+ Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex); -+ } -+ } -+ -+ private static void set(String path, Object val) { -+ config.addDefault(path, val); -+ config.set(path, val); -+ } -+ -+ private static String getString(String path, String def) { -+ config.addDefault(path, def); -+ return config.getString(path, config.getString(path)); -+ } -+ -+ private static boolean getBoolean(String path, boolean def) { -+ config.addDefault(path, def); -+ return config.getBoolean(path, config.getBoolean(path)); -+ } -+ -+ private static double getDouble(String path, double def) { -+ config.addDefault(path, def); -+ return config.getDouble(path, config.getDouble(path)); -+ } -+ -+ private static int getInt(String path, int def) { -+ config.addDefault(path, def); -+ return config.getInt(path, config.getInt(path)); -+ } -+ -+ private static List getList(String path, T def) { -+ config.addDefault(path, def); -+ return config.getList(path, config.getList(path)); -+ } -+ -+ static Map getMap(String path, Map def) { -+ if (def != null && config.getConfigurationSection(path) == null) { -+ config.addDefault(path, def); -+ return def; -+ } -+ return toMap(config.getConfigurationSection(path)); -+ } -+ -+ private static Map toMap(ConfigurationSection section) { -+ ImmutableMap.Builder builder = ImmutableMap.builder(); -+ if (section != null) { -+ for (String key : section.getKeys(false)) { -+ Object obj = section.get(key); -+ if (obj != null) { -+ builder.put(key, obj instanceof ConfigurationSection val ? toMap(val) : obj); -+ } -+ } -+ } -+ return builder.build(); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5f0732c2b8f85185b6dfc1db3119c22e8be7f5da ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -0,0 +1,92 @@ -+package org.purpurmc.purpur; -+ -+import net.minecraft.core.registries.BuiltInRegistries; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.util.Mth; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.item.DyeColor; -+import net.minecraft.world.item.Item; -+import net.minecraft.world.item.Items; -+import net.minecraft.world.level.block.Block; -+import net.minecraft.world.level.block.Blocks; -+import net.minecraft.world.level.block.state.properties.Tilt; -+import org.purpurmc.purpur.tool.Flattenable; -+import org.purpurmc.purpur.tool.Strippable; -+import org.purpurmc.purpur.tool.Tillable; -+import org.purpurmc.purpur.tool.Waxable; -+import org.purpurmc.purpur.tool.Weatherable; -+import org.apache.commons.lang.BooleanUtils; -+import org.bukkit.ChatColor; -+import org.bukkit.World; -+import org.bukkit.configuration.ConfigurationSection; -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+import java.util.function.Predicate; -+import java.util.logging.Level; -+import static org.purpurmc.purpur.PurpurConfig.log; -+ -+@SuppressWarnings("unused") -+public class PurpurWorldConfig { -+ -+ private final String worldName; -+ private final World.Environment environment; -+ -+ public PurpurWorldConfig(String worldName, World.Environment environment) { -+ this.worldName = worldName; -+ this.environment = environment; -+ init(); -+ } -+ -+ public void init() { -+ log("-------- World Settings For [" + worldName + "] --------"); -+ PurpurConfig.readConfig(PurpurWorldConfig.class, this); -+ } -+ -+ private void set(String path, Object val) { -+ PurpurConfig.config.addDefault("world-settings.default." + path, val); -+ PurpurConfig.config.set("world-settings.default." + path, val); -+ if (PurpurConfig.config.get("world-settings." + worldName + "." + path) != null) { -+ PurpurConfig.config.addDefault("world-settings." + worldName + "." + path, val); -+ PurpurConfig.config.set("world-settings." + worldName + "." + path, val); -+ } -+ } -+ -+ private ConfigurationSection getConfigurationSection(String path) { -+ ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + "." + path); -+ return section != null ? section : PurpurConfig.config.getConfigurationSection("world-settings.default." + path); -+ } -+ -+ private String getString(String path, String def) { -+ PurpurConfig.config.addDefault("world-settings.default." + path, def); -+ return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); -+ } -+ -+ private boolean getBoolean(String path, boolean def) { -+ PurpurConfig.config.addDefault("world-settings.default." + path, def); -+ return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path)); -+ } -+ -+ private double getDouble(String path, double def) { -+ PurpurConfig.config.addDefault("world-settings.default." + path, def); -+ return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path)); -+ } -+ -+ private int getInt(String path, int def) { -+ PurpurConfig.config.addDefault("world-settings.default." + path, def); -+ return PurpurConfig.config.getInt("world-settings." + worldName + "." + path, PurpurConfig.config.getInt("world-settings.default." + path)); -+ } -+ -+ private List getList(String path, T def) { -+ PurpurConfig.config.addDefault("world-settings.default." + path, def); -+ return PurpurConfig.config.getList("world-settings." + worldName + "." + path, PurpurConfig.config.getList("world-settings.default." + path)); -+ } -+ -+ private Map getMap(String path, Map def) { -+ final Map fallback = PurpurConfig.getMap("world-settings.default." + path, def); -+ final Map value = PurpurConfig.getMap("world-settings." + worldName + "." + path, null); -+ return value.isEmpty() ? fallback : value; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java b/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..afdf04f8b22ad0b7c0b41675e44687b49c2f86d6 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java -@@ -0,0 +1,65 @@ -+package org.purpurmc.purpur.command; -+ -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ServerLevel; -+import org.purpurmc.purpur.PurpurConfig; -+import org.bukkit.ChatColor; -+import org.bukkit.Location; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+ -+import java.io.File; -+import java.util.Collections; -+import java.util.List; -+import java.util.stream.Collectors; -+import java.util.stream.Stream; -+ -+public class PurpurCommand extends Command { -+ public PurpurCommand(String name) { -+ super(name); -+ this.description = "Purpur related commands"; -+ this.usageMessage = "/purpur [reload | version]"; -+ this.setPermission("bukkit.command.purpur"); -+ } -+ -+ @Override -+ public List tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { -+ if (args.length == 1) { -+ return Stream.of("reload", "version") -+ .filter(arg -> arg.startsWith(args[0].toLowerCase())) -+ .collect(Collectors.toList()); -+ } -+ return Collections.emptyList(); -+ } -+ -+ @Override -+ public boolean execute(CommandSender sender, String commandLabel, String[] args) { -+ if (!testPermission(sender)) return true; -+ -+ if (args.length != 1) { -+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); -+ return false; -+ } -+ -+ if (args[0].equalsIgnoreCase("reload")) { -+ Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues."); -+ Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server."); -+ -+ MinecraftServer console = MinecraftServer.getServer(); -+ PurpurConfig.init((File) console.options.valueOf("purpur-settings")); -+ for (ServerLevel level : console.getAllLevels()) { -+ level.purpurConfig.init(); -+ } -+ console.server.reloadCount++; -+ -+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Purpur config reload complete."); -+ } else if (args[0].equalsIgnoreCase("version")) { -+ Command verCmd = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version"); -+ if (verCmd != null) { -+ return verCmd.execute(sender, commandLabel, new String[0]); -+ } -+ } -+ -+ return true; -+ } -+} diff --git a/patches/server/0003-Purpur-client-support.patch b/patches/server/0003-Purpur-client-support.patch deleted file mode 100644 index c6be6a65a..000000000 --- a/patches/server/0003-Purpur-client-support.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 30 Jul 2021 14:31:25 -0500 -Subject: [PATCH] Purpur client support - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 8437316888c6056060a2780652147590b6fe7443..8b07eb1c428bc70b8ee07ea2209f1898d6034809 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -298,6 +298,7 @@ public class ServerPlayer extends Player { - public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent - public @Nullable String clientBrandName = null; // Paper - Brand support - public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event -+ public boolean purpurClient = false; // Purpur - - // Paper start - replace player chunk loader - private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); -diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 8ac5d8ccf731100a1be690cb2ed1be82cadba8ed..4228fd441f8350d43bd545e31c920304f07968bc 100644 ---- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -78,6 +78,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks - private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit - protected static final ResourceLocation MINECRAFT_BRAND = new ResourceLocation("brand"); // Paper - Brand support -+ protected static final ResourceLocation PURPUR_CLIENT = new ResourceLocation("purpur", "client"); // Purpur - - public ServerCommonPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { // CraftBukkit - this.server = minecraftserver; -@@ -170,6 +171,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t register custom payload", ex); - this.disconnect("Invalid payload REGISTER!", org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause - } -+ // Purpur start -+ } else if (identifier.equals(PURPUR_CLIENT)) { -+ try { -+ player.purpurClient = true; -+ } catch (Exception ignore) { -+ } -+ // Purpur end - } else if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER)) { - try { - String channels = payload.toString(com.google.common.base.Charsets.UTF_8); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 5f896948d158651cd9837364759dbfbcce6b7d21..7f78db4e0331d0f4801807ed1242642ee940d0f8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3522,4 +3522,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - public void setSendViewDistance(final int viewDistance) { - this.getHandle().setSendViewDistance(viewDistance); - } -+ -+ // Purpur start -+ @Override -+ public boolean usesPurpurClient() { -+ return getHandle().purpurClient; -+ } -+ // Purpur end - } diff --git a/patches/server/0004-Fix-decompile-errors.patch b/patches/server/0004-Fix-decompile-errors.patch deleted file mode 100644 index f16d294f4..000000000 --- a/patches/server/0004-Fix-decompile-errors.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 12 Jun 2022 06:20:21 -0500 -Subject: [PATCH] Fix decompile errors - - -diff --git a/src/main/java/net/minecraft/commands/execution/tasks/BuildContexts.java b/src/main/java/net/minecraft/commands/execution/tasks/BuildContexts.java -index b0d26b0eadb2a43924629424a6c13198aace8f69..9f5c3ec2eae9b30bdb8dbcb328d7f701cb7aeb9d 100644 ---- a/src/main/java/net/minecraft/commands/execution/tasks/BuildContexts.java -+++ b/src/main/java/net/minecraft/commands/execution/tasks/BuildContexts.java -@@ -52,7 +52,7 @@ public class BuildContexts> { - } - - RedirectModifier redirectModifier = commandContext.getRedirectModifier(); -- if (redirectModifier instanceof CustomModifierExecutor customModifierExecutor) { -+ if (redirectModifier instanceof CustomModifierExecutor customModifierExecutor) { // Purpur - decompile error - customModifierExecutor.apply(baseSource, list, contextChain, chainModifiers, ExecutionControl.create(context, frame)); - return; - } -@@ -92,11 +92,11 @@ public class BuildContexts> { - - if (list.isEmpty()) { - if (chainModifiers.isReturn()) { -- context.queueNext(new CommandQueueEntry<>(frame, FallthroughTask.instance())); -+ context.queueNext(new CommandQueueEntry<>(frame, (EntryAction) FallthroughTask.instance())); // Purpur - decompile error - } - } else { - CommandContext commandContext2 = contextChain.getTopContext(); -- if (commandContext2.getCommand() instanceof CustomCommandExecutor customCommandExecutor) { -+ if (commandContext2.getCommand() instanceof CustomCommandExecutor customCommandExecutor) { // Purpur - decompile error - ExecutionControl executionControl = ExecutionControl.create(context, frame); - - for (T executionCommandSource2 : list) { -diff --git a/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java b/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java -index 7b118a92a6eb779f800ae8f5d8f6e3c861fc4f6a..057a038e8dcacd7496a0b2373de2c20255a5c297 100644 ---- a/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java -+++ b/src/main/java/net/minecraft/commands/synchronization/ArgumentTypeInfos.java -@@ -119,10 +119,10 @@ public class ArgumentTypeInfos { - register(registry, "dimension", DimensionArgument.class, SingletonArgumentInfo.contextFree(DimensionArgument::dimension)); - register(registry, "gamemode", GameModeArgument.class, SingletonArgumentInfo.contextFree(GameModeArgument::gameMode)); - register(registry, "time", TimeArgument.class, new TimeArgument.Info()); -- register(registry, "resource_or_tag", fixClassType(ResourceOrTagArgument.class), new ResourceOrTagArgument.Info()); -- register(registry, "resource_or_tag_key", fixClassType(ResourceOrTagKeyArgument.class), new ResourceOrTagKeyArgument.Info()); -- register(registry, "resource", fixClassType(ResourceArgument.class), new ResourceArgument.Info()); -- register(registry, "resource_key", fixClassType(ResourceKeyArgument.class), new ResourceKeyArgument.Info()); -+ register(registry, "resource_or_tag", fixClassType(ResourceOrTagArgument.class), new ResourceOrTagArgument.Info<>()); // Purpur - decompile error -+ register(registry, "resource_or_tag_key", fixClassType(ResourceOrTagKeyArgument.class), new ResourceOrTagKeyArgument.Info<>()); // Purpur - decompile error -+ register(registry, "resource", fixClassType(ResourceArgument.class), new ResourceArgument.Info<>()); // Purpur - decompile error -+ register(registry, "resource_key", fixClassType(ResourceKeyArgument.class), new ResourceKeyArgument.Info<>()); // Purpur - decompile error - register(registry, "template_mirror", TemplateMirrorArgument.class, SingletonArgumentInfo.contextFree(TemplateMirrorArgument::templateMirror)); - register(registry, "template_rotation", TemplateRotationArgument.class, SingletonArgumentInfo.contextFree(TemplateRotationArgument::templateRotation)); - register(registry, "heightmap", HeightmapTypeArgument.class, SingletonArgumentInfo.contextFree(HeightmapTypeArgument::heightmap)); diff --git a/patches/server/0005-Component-related-conveniences.patch b/patches/server/0005-Component-related-conveniences.patch deleted file mode 100644 index 934ea5bc3..000000000 --- a/patches/server/0005-Component-related-conveniences.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 29 Jun 2021 21:37:40 -0500 -Subject: [PATCH] Component related conveniences - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 8b07eb1c428bc70b8ee07ea2209f1898d6034809..0b9c85adaf5c7b5dcb23ab74a4fd02e6c0798851 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1978,6 +1978,26 @@ public class ServerPlayer extends Player { - this.lastSentExp = -1; // CraftBukkit - Added to reset - } - -+ // Purpur start -+ public void sendActionBarMessage(@Nullable String message) { -+ if (message != null && !message.isEmpty()) { -+ sendActionBarMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message)); -+ } -+ } -+ -+ public void sendActionBarMessage(@Nullable net.kyori.adventure.text.Component message) { -+ if (message != null) { -+ sendActionBarMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message)); -+ } -+ } -+ -+ public void sendActionBarMessage(@Nullable Component message) { -+ if (message != null) { -+ displayClientMessage(message, true); -+ } -+ } -+ // Purpur end -+ - @Override - public void displayClientMessage(Component message, boolean overlay) { - this.sendSystemMessage(message, overlay); -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index a2142930b4d4b05987c90496fb9d733d99040aa0..2d6b6795703431939005aa09d1ed590c3f755163 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1063,6 +1063,20 @@ public abstract class PlayerList { - } - // CraftBukkit end - -+ // Purpur Start -+ public void broadcastMiniMessage(@Nullable String message, boolean overlay) { -+ if (message != null && !message.isEmpty()) { -+ this.broadcastMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message), overlay); -+ } -+ } -+ -+ public void broadcastMessage(@Nullable net.kyori.adventure.text.Component message, boolean overlay) { -+ if (message != null) { -+ this.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), overlay); -+ } -+ } -+ // Purpur end -+ - public void broadcastAll(Packet packet, ResourceKey dimension) { - Iterator iterator = this.players.iterator(); - -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -index 160dc3216e8f5db5f9b3cce5e2d655f2b35b208a..43b9a7e8ed9043c4d3f8295258a27209ddb4474b 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -@@ -177,6 +177,15 @@ public class DamageSource { - } - } - -+ // Purpur start -+ public Component getLocalizedDeathMessage(String str, LivingEntity entity) { -+ net.kyori.adventure.text.Component name = io.papermc.paper.adventure.PaperAdventure.asAdventure(entity.getDisplayName()); -+ net.kyori.adventure.text.minimessage.tag.resolver.TagResolver template = net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("player", name); -+ net.kyori.adventure.text.Component component = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(str, template); -+ return io.papermc.paper.adventure.PaperAdventure.asVanilla(component); -+ } -+ // Purpur end -+ - public String getMsgId() { - return this.type().msgId(); - } -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 2bc85351e6e52f90da5fdb29d8d042a06132d742..6c7f80723d67baf0ca036e0a12c3007144352edf 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4190,6 +4190,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return SlotAccess.NULL; - } - -+ // Purpur Start -+ public void sendMiniMessage(@Nullable String message) { -+ if (message != null && !message.isEmpty()) { -+ this.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message)); -+ } -+ } -+ -+ public void sendMessage(@Nullable net.kyori.adventure.text.Component message) { -+ if (message != null) { -+ this.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message)); -+ } -+ } -+ // Purpur end -+ - @Override - public void sendSystemMessage(Component message) {} - diff --git a/patches/server/0006-Ridables.patch b/patches/server/0006-Ridables.patch deleted file mode 100644 index ab339717c..000000000 --- a/patches/server/0006-Ridables.patch +++ /dev/null @@ -1,6546 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 5 Jul 2020 22:19:49 -0500 -Subject: [PATCH] Ridables - - -diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java -index 665e88b2dedf9d5bb50914d5f3d377f2d19f40b0..f70a80b496bd1498778e82fc221c3b1b39308b75 100644 ---- a/src/main/java/net/minecraft/core/BlockPos.java -+++ b/src/main/java/net/minecraft/core/BlockPos.java -@@ -61,6 +61,12 @@ public class BlockPos extends Vec3i { - private static final int X_OFFSET = 38; - // Paper end - Optimize Bit Operations by inlining - -+ // Purpur start -+ public BlockPos(net.minecraft.world.entity.Entity entity) { -+ super(entity.getBlockX(), entity.getBlockY(), entity.getBlockZ()); -+ } -+ // Purpur end -+ - public BlockPos(int x, int y, int z) { - super(x, y, z); - } -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 57e6aaa63c1308baa5e2863b82b7521d5f4a4f31..73b77367039eb6a4445d1ef2d66fb3410e91f4b8 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1762,6 +1762,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - Add EntityMoveEvent - net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers - worldserver.updateLagCompensationTick(); // Paper - lag compensation -+ worldserver.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - - this.profiler.push(() -> { - String s = String.valueOf(worldserver); -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 0981d440d0dbfe4df668d1f3f1b5706a93bc4434..fc791a66d299905798c2c1ca542467e4c7933caf 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -229,6 +229,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent - public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent - private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current) -+ public boolean hasRidableMoveEvent = false; // Purpur - - public LevelChunk getChunkIfLoaded(int x, int z) { - return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 0b9c85adaf5c7b5dcb23ab74a4fd02e6c0798851..2820333cbcd2cb972c4408cb0d9cc1be37a844cf 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -814,6 +814,15 @@ public class ServerPlayer extends Player { - this.trackEnteredOrExitedLavaOnVehicle(); - this.updatePlayerAttributes(); - this.advancements.flushDirty(this); -+ -+ // Purpur start -+ if (this.level().purpurConfig.useNightVisionWhenRiding && this.getVehicle() != null && this.getVehicle().getRider() == this && this.level().getGameTime() % 100 == 0) { // 5 seconds -+ MobEffectInstance nightVision = this.getEffect(MobEffects.NIGHT_VISION); -+ if (nightVision == null || nightVision.getDuration() <= 300) { // 15 seconds -+ this.addEffect(new MobEffectInstance(MobEffects.NIGHT_VISION, 400, 0)); // 20 seconds -+ } -+ } -+ // Purpur end - } - - private void updatePlayerAttributes() { -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 5e9202bc7fc649764568b55d66ba0d684118c00c..1377d7abfe024b8ac977aa1a071b401836c3c048 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2789,6 +2789,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); - -+ player.processClick(enumhand); // Purpur -+ - // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a - if ((entity instanceof Bucketable && entity instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) { - entity.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it. -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 6c7f80723d67baf0ca036e0a12c3007144352edf..9c99a3df80c5f0a0d81e1f6a6516d088438a0b1e 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -381,7 +381,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - private final Set tags; - private final double[] pistonDeltas; - private long pistonDeltasGameTime; -- private EntityDimensions dimensions; -+ protected EntityDimensions dimensions; // Purpur - private -> protected - private float eyeHeight; - public boolean isInPowderSnow; - public boolean wasInPowderSnow; -@@ -3080,6 +3080,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.passengers = ImmutableList.copyOf(list); - } - -+ // Purpur start -+ if (isRidable() && this.passengers.get(0) == passenger && passenger instanceof Player player) { -+ onMount(player); -+ this.rider = player; -+ } -+ // Purpur end -+ - this.gameEvent(GameEvent.ENTITY_MOUNT, passenger); - } - } -@@ -3119,6 +3126,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return false; - } - // CraftBukkit end -+ -+ // Purpur start -+ if (this.rider != null && this.passengers.get(0) == this.rider) { -+ onDismount(this.rider); -+ this.rider = null; -+ } -+ // Purpur end -+ - if (this.passengers.size() == 1 && this.passengers.get(0) == entity) { - this.passengers = ImmutableList.of(); - } else { -@@ -5009,4 +5024,44 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return ((net.minecraft.server.level.ServerChunkCache) level.getChunkSource()).isPositionTicking(this); - } - // Paper end - Expose entity id counter -+ // Purpur start -+ @Nullable -+ private Player rider = null; -+ -+ @Nullable -+ public Player getRider() { -+ return rider; -+ } -+ -+ public boolean isRidable() { -+ return false; -+ } -+ -+ public boolean isControllable() { -+ return true; -+ } -+ -+ public void onMount(Player rider) { -+ if (this instanceof Mob) { -+ ((Mob) this).setTarget(null, null, false); -+ ((Mob) this).getNavigation().stop(); -+ } -+ rider.setJumping(false); // fixes jump on mount -+ } -+ -+ public void onDismount(Player player) { -+ } -+ -+ public boolean onSpacebar() { -+ return false; -+ } -+ -+ public boolean onClick(InteractionHand hand) { -+ return false; -+ } -+ -+ public boolean processClick(InteractionHand hand) { -+ return false; -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/entity/GlowSquid.java b/src/main/java/net/minecraft/world/entity/GlowSquid.java -index 09fdea983772612ef3fff6b2da3cf469a34e4ec0..aa76a24421cdb3908a3544d92eb3d1e3c2ebedc4 100644 ---- a/src/main/java/net/minecraft/world/entity/GlowSquid.java -+++ b/src/main/java/net/minecraft/world/entity/GlowSquid.java -@@ -23,6 +23,19 @@ public class GlowSquid extends Squid { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.glowSquidRidable; -+ } -+ -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.glowSquidControllable; -+ } -+ // Purpur end -+ - @Override - protected ParticleOptions getInkParticle() { - return ParticleTypes.GLOW_SQUID_INK; -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 6e043457a29a890bcefd27fc5bb07c1a7e4e30f7..72bd60f691a639a0e7b6b5a98e5a3816305cfdaf 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -229,9 +229,9 @@ public abstract class LivingEntity extends Entity implements Attackable { - protected int deathScore; - public float lastHurt; - public boolean jumping; -- public float xxa; -- public float yya; -- public float zza; -+ public float xxa; public float getStrafeMot() { return xxa; } public void setStrafeMot(float strafe) { xxa = strafe; } // Purpur - OBFHELPER -+ public float yya; public float getVerticalMot() { return yya; } public void setVerticalMot(float vertical) { yya = vertical; } // Purpur - OBFHELPER -+ public float zza; public float getForwardMot() { return zza; } public void setForwardMot(float forward) { zza = forward; } // Purpur - OBFHELPER - protected int lerpSteps; - protected double lerpX; - protected double lerpY; -@@ -300,7 +300,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.useItem = ItemStack.EMPTY; - this.lastClimbablePos = Optional.empty(); - this.appliedScale = 1.0F; -- this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type)); -+ this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type), this); // Purpur - this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit - // CraftBukkit - setHealth(getMaxHealth()) inlined and simplified to skip the instanceof check for EntityPlayer, as getBukkitEntity() is not initialized in constructor - this.entityData.set(LivingEntity.DATA_HEALTH_ID, (float) this.getAttribute(Attributes.MAX_HEALTH).getValue()); -@@ -350,6 +350,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - public static AttributeSupplier.Builder createLivingAttributes() { - return AttributeSupplier.builder().add(Attributes.MAX_HEALTH).add(Attributes.KNOCKBACK_RESISTANCE).add(Attributes.MOVEMENT_SPEED).add(Attributes.ARMOR).add(Attributes.ARMOR_TOUGHNESS).add(Attributes.MAX_ABSORPTION).add(Attributes.STEP_HEIGHT).add(Attributes.SCALE).add(Attributes.GRAVITY).add(Attributes.SAFE_FALL_DISTANCE).add(Attributes.FALL_DAMAGE_MULTIPLIER).add(Attributes.JUMP_STRENGTH); - } -+ public boolean shouldSendAttribute(Attribute attribute) { return true; } // Purpur - - @Override - protected void checkFallDamage(double heightDifference, boolean onGround, BlockState state, BlockPos landedPosition) { -@@ -2781,7 +2782,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - protected long lastJumpTime = 0L; // Paper - Prevent excessive velocity through repeated crits -- protected void jumpFromGround() { -+ public void jumpFromGround() { // Purpur - protected -> public - float f = this.getJumpPower(); - - if (f > 1.0E-5F) { -@@ -3494,8 +3495,10 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.pushEntities(); - this.level().getProfiler().pop(); - // Paper start - Add EntityMoveEvent -- if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) { -- if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { -+ // Purpur start -+ if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { -+ if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) { -+ // Purpur end - Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO); - Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); - io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone()); -@@ -3505,6 +3508,21 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch()); - } - } -+ // Purpur start -+ if (getRider() != null) { -+ getRider().resetLastActionTime(); -+ if (((ServerLevel) level()).hasRidableMoveEvent && this instanceof Mob) { -+ Location from = new Location(level().getWorld(), xo, yo, zo, this.yRotO, this.xRotO); -+ Location to = new Location(level().getWorld(), getX(), getY(), getZ(), this.getYRot(), this.getXRot()); -+ org.purpurmc.purpur.event.entity.RidableMoveEvent event = new org.purpurmc.purpur.event.entity.RidableMoveEvent((org.bukkit.entity.Mob) getBukkitLivingEntity(), (Player) getRider().getBukkitEntity(), from, to.clone()); -+ if (!event.callEvent()) { -+ absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch()); -+ } else if (!to.equals(event.getTo())) { -+ absMoveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); -+ } -+ } -+ } -+ // Purpur end - } - // Paper end - Add EntityMoveEvent - if (!this.level().isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index e89f9c3e887601d8461eb967ae0bf582b672f631..26b03594b6ccd69ca35156472e27543d11ba2077 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -165,8 +165,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - this.restrictRadius = -1.0F; - this.goalSelector = new GoalSelector(world.getProfilerSupplier()); - this.targetSelector = new GoalSelector(world.getProfilerSupplier()); -- this.lookControl = new LookControl(this); -- this.moveControl = new MoveControl(this); -+ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this); // Purpur -+ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this); // Purpur - this.jumpControl = new JumpControl(this); - this.bodyRotationControl = this.createBodyControl(); - this.navigation = this.createNavigation(world); -@@ -1525,7 +1525,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - protected void onOffspringSpawnedFromEgg(Player player, Mob child) {} - - protected InteractionResult mobInteract(Player player, InteractionHand hand) { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } - - public boolean isWithinRestriction() { -@@ -1902,4 +1902,56 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - - return itemmonsteregg == null ? null : new ItemStack(itemmonsteregg); - } -+ -+ // Purpur start -+ public double getMaxY() { -+ return level().getHeight(); -+ } -+ -+ public InteractionResult tryRide(Player player, InteractionHand hand) { -+ return tryRide(player, hand, InteractionResult.PASS); -+ } -+ -+ public InteractionResult tryRide(Player player, InteractionHand hand, InteractionResult result) { -+ if (!isRidable()) { -+ return result; -+ } -+ if (hand != InteractionHand.MAIN_HAND) { -+ return InteractionResult.PASS; -+ } -+ if (player.isShiftKeyDown()) { -+ return InteractionResult.PASS; -+ } -+ if (!player.getItemInHand(hand).isEmpty()) { -+ return InteractionResult.PASS; -+ } -+ if (!passengers.isEmpty() || player.isPassenger()) { -+ return InteractionResult.PASS; -+ } -+ if (this instanceof TamableAnimal tamable) { -+ if (tamable.isTame() && !tamable.isOwnedBy(player)) { -+ return InteractionResult.PASS; -+ } -+ if (!tamable.isTame() && !level().purpurConfig.untamedTamablesAreRidable) { -+ return InteractionResult.PASS; -+ } -+ } -+ if (this instanceof AgeableMob ageable) { -+ if (ageable.isBaby() && !level().purpurConfig.babiesAreRidable) { -+ return InteractionResult.PASS; -+ } -+ } -+ if (!player.getBukkitEntity().hasPermission("allow.ride." + net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getKey(getType()).getPath())) { -+ player.sendMiniMessage(org.purpurmc.purpur.PurpurConfig.cannotRideMob); -+ return InteractionResult.PASS; -+ } -+ player.setYRot(this.getYRot()); -+ player.setXRot(this.getXRot()); -+ if (player.startRiding(this)) { -+ return InteractionResult.SUCCESS; -+ } else { -+ return InteractionResult.PASS; -+ } -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -index 9ef8f014af332da129bfcd3370da983ec035ecc6..c51b429822d56761f69c49ecd4addfab7b90bad8 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -@@ -22,13 +22,20 @@ public class AttributeMap { - private final Map, AttributeInstance> attributes = new Object2ObjectOpenHashMap<>(); - private final Set dirtyAttributes = new ObjectOpenHashSet<>(); - private final AttributeSupplier supplier; -+ private final net.minecraft.world.entity.LivingEntity entity; // Purpur - - public AttributeMap(AttributeSupplier defaultAttributes) { -+ // Purpur start -+ this(defaultAttributes, null); -+ } -+ public AttributeMap(AttributeSupplier defaultAttributes, net.minecraft.world.entity.LivingEntity entity) { -+ this.entity = entity; -+ // Purpur end - this.supplier = defaultAttributes; - } - - private void onAttributeModified(AttributeInstance instance) { -- if (instance.getAttribute().value().isClientSyncable()) { -+ if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - this.dirtyAttributes.add(instance); - } - } -@@ -38,7 +45,7 @@ public class AttributeMap { - } - - public Collection getSyncableAttributes() { -- return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().value().isClientSyncable()).collect(Collectors.toList()); -+ return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(attribute.getAttribute().value()))).collect(Collectors.toList()); // Purpur - } - - @Nullable -diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java -index 10a1434313b11dae8210484583c6bf3b627416f7..35af18f371b3beaf81fcdca79fefe85e0a862b50 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java -+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java -@@ -129,7 +129,7 @@ public class DefaultAttributes { - .put(EntityType.OCELOT, Ocelot.createAttributes().build()) - .put(EntityType.PANDA, Panda.createAttributes().build()) - .put(EntityType.PARROT, Parrot.createAttributes().build()) -- .put(EntityType.PHANTOM, Monster.createMonsterAttributes().build()) -+ .put(EntityType.PHANTOM, net.minecraft.world.entity.monster.Phantom.createAttributes().build()) // Purpur - .put(EntityType.PIG, Pig.createAttributes().build()) - .put(EntityType.PIGLIN, Piglin.createAttributes().build()) - .put(EntityType.PIGLIN_BRUTE, PiglinBrute.createAttributes().build()) -diff --git a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java -index c8fd5696de7c3623cdb4f498190a5c2708cf843e..e403d9dfeeaa3dcf53be790d761e7e922419efb0 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java -+++ b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java -@@ -29,6 +29,20 @@ public class MoveControl implements Control { - this.mob = entity; - } - -+ // Purpur start -+ public void setSpeedModifier(double speed) { -+ this.speedModifier = speed; -+ } -+ -+ public void setForward(float forward) { -+ this.strafeForwards = forward; -+ } -+ -+ public void setStrafe(float strafe) { -+ this.strafeRight = strafe; -+ } -+ // Purpur end -+ - public boolean hasWanted() { - return this.operation == MoveControl.Operation.MOVE_TO; - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java b/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java -index fbfc2f2515ad709b2c1212aef9521e795547d66b..e77bd11af62682d5eca41f6c9e1aed30eb6879ce 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java -+++ b/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java -@@ -3,7 +3,7 @@ package net.minecraft.world.entity.ai.control; - import net.minecraft.util.Mth; - import net.minecraft.world.entity.Mob; - --public class SmoothSwimmingLookControl extends LookControl { -+public class SmoothSwimmingLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - private final int maxYRotFromCenter; - private static final int HEAD_TILT_X = 10; - private static final int HEAD_TILT_Y = 20; -@@ -14,7 +14,7 @@ public class SmoothSwimmingLookControl extends LookControl { - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (this.lookAtCooldown > 0) { - this.lookAtCooldown--; - this.getYRotD().ifPresent(yaw -> this.mob.yHeadRot = this.rotateTowards(this.mob.yHeadRot, yaw + 20.0F, this.yMaxRotSpeed)); -diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index dc27ddf5131e7398a5390a5187261d4c7fb6ccaa..c4a09778ca6bf5c15b588234bcadec3496017e3d 100644 ---- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java -+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -44,12 +44,59 @@ public class Bat extends AmbientCreature { - - public Bat(EntityType type, Level world) { - super(type, world); -+ this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.075F); // Purpur - if (!world.isClientSide) { - this.setResting(true); - } - - } - -+ // Purpur start -+ @Override -+ public boolean shouldSendAttribute(net.minecraft.world.entity.ai.attributes.Attribute attribute) { return attribute != Attributes.FLYING_SPEED.value(); } // Fixes log spam on clients -+ -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.batRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.batRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.batControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.batMaxY; -+ } -+ -+ @Override -+ public void onMount(Player rider) { -+ super.onMount(rider); -+ if (isResting()) { -+ setResting(false); -+ level().levelEvent(null, 1025, new BlockPos(this).above(), 0); -+ } -+ } -+ -+ @Override -+ public void travel(Vec3 vec3) { -+ super.travel(vec3); -+ if (getRider() != null && this.isControllable() && !onGround) { -+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; -+ setSpeed(speed); -+ Vec3 mot = getDeltaMovement(); -+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed)); -+ setDeltaMovement(mot.scale(0.9D)); -+ } -+ } -+ // Purpur end -+ - @Override - public boolean isFlapping() { - return !this.isResting() && (float) this.tickCount % 10.0F == 0.0F; -@@ -99,7 +146,7 @@ public class Bat extends AmbientCreature { - protected void pushEntities() {} - - public static AttributeSupplier.Builder createAttributes() { -- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D); -+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - } - - public boolean isResting() { -@@ -132,6 +179,14 @@ public class Bat extends AmbientCreature { - - @Override - protected void customServerAiStep() { -+ // Purpur start -+ if (getRider() != null && this.isControllable()) { -+ Vec3 mot = getDeltaMovement(); -+ setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); -+ return; -+ } -+ // Purpur end -+ - super.customServerAiStep(); - BlockPos blockposition = this.blockPosition(); - BlockPos blockposition1 = blockposition.above(); -diff --git a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java -index 3231eaa6af2ddfe4095ff2d650f580ebd4d43aea..e8cb124d232f7316cc8c35dd8bd12f79bbcda7d6 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java -+++ b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java -@@ -87,6 +87,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { - @Override - protected void registerGoals() { - super.registerGoals(); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(0, new PanicGoal(this, 1.25)); - this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6, 1.4, EntitySelector.NO_SPECTATORS::test)); - this.goalSelector.addGoal(4, new AbstractFish.FishSwimGoal(this)); -@@ -100,7 +101,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { - @Override - public void travel(Vec3 movementInput) { - if (this.isEffectiveAi() && this.isInWater()) { -- this.moveRelative(0.01F, movementInput); -+ this.moveRelative(getRider() != null ? getSpeed() : 0.01F, movementInput); // Purpur - this.move(MoverType.SELF, this.getDeltaMovement()); - this.setDeltaMovement(this.getDeltaMovement().scale(0.9)); - if (this.getTarget() == null) { -@@ -161,7 +162,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { - protected void playStepSound(BlockPos pos, BlockState state) { - } - -- static class FishMoveControl extends MoveControl { -+ static class FishMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur - private final AbstractFish fish; - - FishMoveControl(AbstractFish owner) { -@@ -169,14 +170,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { - this.fish = owner; - } - -+ // Purpur start - @Override -- public void tick() { -+ public void purpurTick(Player rider) { -+ super.purpurTick(rider); -+ fish.setDeltaMovement(fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); -+ } -+ // Purpur end -+ -+ @Override -+ public void vanillaTick() { // Purpur - if (this.fish.isEyeInFluid(FluidTags.WATER)) { - this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0, 0.005, 0.0)); - } - - if (this.operation == MoveControl.Operation.MOVE_TO && !this.fish.getNavigation().isDone()) { -- float f = (float)(this.speedModifier * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); -+ float f = (float)(this.getSpeedModifier() * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - this.fish.setSpeed(Mth.lerp(0.125F, this.fish.getSpeed(), f)); - double d = this.wantedX - this.fish.getX(); - double e = this.wantedY - this.fish.getY(); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 0dfb8109fd8c022b079da00f6a0e3fc85b57bf7a..4b84cf76d052112e00cd13c330182abfbe618820 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -143,6 +143,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - public Bee(EntityType type, Level world) { - super(type, world); - this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60); -+ final org.purpurmc.purpur.controller.FlyingMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.25F, 1.0F, false); // Purpur - // Paper start - Fix MC-167279 - class BeeFlyingMoveControl extends FlyingMoveControl { - public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) { -@@ -151,11 +152,24 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - - @Override - public void tick() { -+ // Purpur start -+ if (mob.getRider() != null && mob.isControllable()) { -+ flyingController.purpurTick(mob.getRider()); -+ return; -+ } -+ // Purpur end - if (this.mob.getY() <= Bee.this.level().getMinBuildHeight()) { - this.mob.setNoGravity(false); - } - super.tick(); - } -+ -+ // Purpur start -+ @Override -+ public boolean hasWanted() { -+ return mob.getRider() != null || !mob.isControllable() || super.hasWanted(); -+ } -+ // Purpur end - } - this.moveControl = new BeeFlyingMoveControl(this, 20, true); - // Paper end - Fix MC-167279 -@@ -167,6 +181,40 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - this.setPathfindingMalus(PathType.FENCE, -1.0F); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.beeRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.beeRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.beeControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.beeMaxY; -+ } -+ -+ @Override -+ public void travel(Vec3 vec3) { -+ super.travel(vec3); -+ if (getRider() != null && this.isControllable() && !onGround) { -+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; -+ setSpeed(speed); -+ Vec3 mot = getDeltaMovement(); -+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed)); -+ setDeltaMovement(mot.scale(0.9D)); -+ } -+ } -+ // Purpur end -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -@@ -181,6 +229,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.399999976158142D, true)); - this.goalSelector.addGoal(1, new Bee.BeeEnterHiveGoal()); - this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); -@@ -198,6 +247,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - this.goalSelector.addGoal(7, new Bee.BeeGrowCropGoal()); - this.goalSelector.addGoal(8, new Bee.BeeWanderGoal()); - this.goalSelector.addGoal(9, new FloatGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new Bee.BeeHurtByOtherGoal(this)).setAlertOthers(new Class[0])); - this.targetSelector.addGoal(2, new Bee.BeeBecomeAngryTargetGoal(this)); - this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); -@@ -872,16 +922,16 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - } - } - -- private class BeeLookControl extends LookControl { -+ private class BeeLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - - BeeLookControl(final Mob entity) { - super(entity); - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (!Bee.this.isAngry()) { -- super.tick(); -+ super.vanillaTick(); // Purpur - } - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 07559b9629d4ecb40b511256f400a781e39820e0..3826c794ddde6b915e233e2d0395557e3ea867e0 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -104,6 +104,31 @@ public class Cat extends TamableAnimal implements VariantHolder(this, Rabbit.class, false, (Predicate) null)); - this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR)); - } -@@ -377,6 +404,7 @@ public class Cat extends TamableAnimal implements VariantHolder { -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cod.java b/src/main/java/net/minecraft/world/entity/animal/Cod.java -index 824e5e4fe7619ae46061c3c978c9a044db8c84ab..e2a98b45e56a368de19bb65e304370a5998c7cb9 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cod.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cod.java -@@ -13,6 +13,18 @@ public class Cod extends AbstractSchoolingFish { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.codRidable; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.codControllable; -+ } -+ // Purpur end -+ - @Override - public ItemStack getBucketItemStack() { - return new ItemStack(Items.COD_BUCKET); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java -index 5a7b1be351834a6b8889b1380cede1be025cb302..41b6c79c31414378d433500a35e434e546738e42 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java -@@ -44,9 +44,27 @@ public class Cow extends Animal { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.cowRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.cowRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.cowControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new PanicGoal(this, 2.0D)); - this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, (itemstack) -> { -@@ -94,6 +112,7 @@ public class Cow extends Animal { - - @Override - public InteractionResult mobInteract(Player player, InteractionHand hand) { -+ if (getRider() != null) return InteractionResult.PASS; // Purpur - ItemStack itemstack = player.getItemInHand(hand); - - if (itemstack.is(Items.BUCKET) && !this.isBaby()) { -@@ -101,7 +120,7 @@ public class Cow extends Animal { - PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, hand); - - if (event.isCancelled()) { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } - // CraftBukkit end - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -index 1b1cb0e4d54e52ebe794199e386c54c5d84b3719..3af2017a4b860992a6db88edec3624fcb9884ae1 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -@@ -81,14 +81,82 @@ public class Dolphin extends WaterAnimal { - public static final Predicate ALLOWED_ITEMS = (entityitem) -> { - return !entityitem.hasPickUpDelay() && entityitem.isAlive() && entityitem.isInWater(); - }; -+ private int spitCooldown; // Purpur - - public Dolphin(EntityType type, Level world) { - super(type, world); -- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); -+ // Purpur start -+ class DolphinMoveControl extends SmoothSwimmingMoveControl { -+ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterMoveControllerWASD; -+ private final Dolphin dolphin; -+ -+ public DolphinMoveControl(Dolphin dolphin, int pitchChange, int yawChange, float speedInWater, float speedInAir, boolean buoyant) { -+ super(dolphin, pitchChange, yawChange, speedInWater, speedInAir, buoyant); -+ this.dolphin = dolphin; -+ this.waterMoveControllerWASD = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(dolphin); -+ } -+ -+ @Override -+ public void tick() { -+ if (dolphin.getRider() != null && dolphin.isControllable()) { -+ purpurTick(dolphin.getRider()); -+ } else { -+ super.tick(); -+ } -+ } -+ -+ public void purpurTick(Player rider) { -+ if (dolphin.getAirSupply() < 150) { -+ // if drowning override player WASD controls to find air -+ super.tick(); -+ } else { -+ waterMoveControllerWASD.purpurTick(rider); -+ dolphin.setDeltaMovement(dolphin.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); -+ } -+ } -+ }; -+ this.moveControl = new DolphinMoveControl(this, 85, 10, 0.02F, 0.1F, true); -+ // Purpur end - this.lookControl = new SmoothSwimmingLookControl(this, 10); - this.setCanPickUpLoot(true); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.dolphinRidable; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.dolphinControllable; -+ } -+ -+ @Override -+ public boolean onSpacebar() { -+ if (spitCooldown == 0 && getRider() != null) { -+ spitCooldown = level().purpurConfig.dolphinSpitCooldown; -+ -+ org.bukkit.craftbukkit.entity.CraftPlayer player = (org.bukkit.craftbukkit.entity.CraftPlayer) getRider().getBukkitEntity(); -+ if (!player.hasPermission("allow.special.dolphin")) { -+ return false; -+ } -+ -+ org.bukkit.Location loc = player.getEyeLocation(); -+ loc.setPitch(loc.getPitch() - 10); -+ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(10).add(loc.toVector()); -+ -+ org.purpurmc.purpur.entity.DolphinSpit spit = new org.purpurmc.purpur.entity.DolphinSpit(level(), this); -+ spit.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), level().purpurConfig.dolphinSpitSpeed, 5.0F); -+ -+ level().addFreshEntity(spit); -+ playSound(SoundEvents.DOLPHIN_ATTACK, 1.0F, 1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F); -+ return true; -+ } -+ return false; -+ } -+ // Purpur end -+ - @Nullable - @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { -@@ -158,6 +226,7 @@ public class Dolphin extends WaterAnimal { - protected void registerGoals() { - this.goalSelector.addGoal(0, new BreathAirGoal(this)); - this.goalSelector.addGoal(0, new TryFindWaterGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this)); - this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0D)); - this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0D, 10)); -@@ -168,6 +237,7 @@ public class Dolphin extends WaterAnimal { - this.goalSelector.addGoal(8, new Dolphin.PlayWithItemsGoal()); - this.goalSelector.addGoal(8, new FollowBoatGoal(this)); - this.goalSelector.addGoal(9, new AvoidEntityGoal<>(this, Guardian.class, 8.0F, 1.0D, 1.0D)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Guardian.class})).setAlertOthers()); - } - -@@ -214,7 +284,7 @@ public class Dolphin extends WaterAnimal { - - @Override - protected boolean canRide(Entity entity) { -- return true; -+ return boardingCooldown <= 0; // Purpur - make dolphin honor ride cooldown like all other non-boss mobs; - } - - @Override -@@ -249,6 +319,11 @@ public class Dolphin extends WaterAnimal { - @Override - public void tick() { - super.tick(); -+ // Purpur start -+ if (spitCooldown > 0) { -+ spitCooldown--; -+ } -+ // Purpur end - if (this.isNoAi()) { - this.setAirSupply(this.getMaxAirSupply()); - } else { -diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java -index e705449496b1a06270ecbc13f4dce5357479845b..935dff4d167d8b6ef4b7cdc95bf000a2ce761f92 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Fox.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java -@@ -145,6 +145,44 @@ public class Fox extends Animal implements VariantHolder { - this.setCanPickUpLoot(true); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.foxRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.foxRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.foxControllable; -+ } -+ -+ @Override -+ public float getJumpPower() { -+ return getRider() != null && this.isControllable() ? 0.5F : super.getJumpPower(); -+ } -+ -+ @Override -+ public void onMount(Player rider) { -+ super.onMount(rider); -+ setCanPickUpLoot(false); -+ clearStates(); -+ setIsPouncing(false); -+ spitOutItem(getItemBySlot(EquipmentSlot.MAINHAND)); -+ setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); -+ } -+ -+ @Override -+ public void onDismount(Player rider) { -+ super.onDismount(rider); -+ setCanPickUpLoot(true); -+ } -+ // Purpur end -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -@@ -164,6 +202,7 @@ public class Fox extends Animal implements VariantHolder { - return entityliving instanceof AbstractSchoolingFish; - }); - this.goalSelector.addGoal(0, new Fox.FoxFloatGoal()); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(0, new ClimbOnTopOfPowderSnowGoal(this, this.level())); - this.goalSelector.addGoal(1, new Fox.FaceplantGoal()); - this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2D)); -@@ -190,6 +229,7 @@ public class Fox extends Animal implements VariantHolder { - this.goalSelector.addGoal(11, new Fox.FoxSearchForItemsGoal()); - this.goalSelector.addGoal(12, new Fox.FoxLookAtPlayerGoal(this, Player.class, 24.0F)); - this.goalSelector.addGoal(13, new Fox.PerchAndSearchGoal()); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(3, new Fox.DefendTrustedTargetGoal(LivingEntity.class, false, false, (entityliving) -> { - return Fox.TRUSTED_TARGET_SELECTOR.test(entityliving) && !this.trusts(entityliving.getUUID()); - })); -@@ -769,16 +809,16 @@ public class Fox extends Animal implements VariantHolder { - return new Vec3(0.0D, (double) (0.55F * this.getEyeHeight()), (double) (this.getBbWidth() * 0.4F)); - } - -- public class FoxLookControl extends LookControl { -+ public class FoxLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - - public FoxLookControl() { - super(Fox.this); - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (!Fox.this.isSleeping()) { -- super.tick(); -+ super.vanillaTick(); // Purpur - } - - } -@@ -789,16 +829,16 @@ public class Fox extends Animal implements VariantHolder { - } - } - -- private class FoxMoveControl extends MoveControl { -+ private class FoxMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - - public FoxMoveControl() { - super(Fox.this); - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (Fox.this.canMove()) { -- super.tick(); -+ super.vanillaTick(); // Purpur - } - - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -index 932fae98c551052cadba4c6fc6e575fc30a25d58..4cc9138201b08aff8bb47720c6fe1e3447f03967 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -@@ -61,8 +61,27 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.ironGolemRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ironGolemRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.ironGolemControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { -+ if (level().purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0D, true)); - this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9D, 32.0F)); - this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6D, false)); -@@ -70,6 +89,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - this.goalSelector.addGoal(5, new OfferFlowerGoal(this)); - this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); - this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new DefendVillageTargetGoal(this)); - this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); -@@ -265,13 +285,13 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - ItemStack itemstack = player.getItemInHand(hand); - - if (!itemstack.is(Items.IRON_INGOT)) { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } else { - float f = this.getHealth(); - - this.heal(25.0F); - if (this.getHealth() == f) { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } else { - float f1 = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F; - -diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index 0c21959f57ae88fcd0a4d6dc911c1ce347c96528..11944ee34fc7e3e5551b9e18a563164f96898a54 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -64,6 +64,23 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder optional = this.getEffectsFromItemStack(itemstack); - - if (optional.isEmpty()) { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } - - itemstack.consume(1, player); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java -index 2c7491edbb60e7ec6a208ea7292cd28a3f8f9e31..2b074f68c1be2ff591543685bbb4e7ea1c7784f8 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java -@@ -66,6 +66,23 @@ public class Ocelot extends Animal { - this.reassessTrustingGoals(); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.ocelotRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ocelotRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.ocelotControllable; -+ } -+ // Purpur end -+ - public boolean isTrusting() { - return (Boolean) this.entityData.get(Ocelot.DATA_TRUSTING); - } -@@ -99,12 +116,14 @@ public class Ocelot extends Animal { - return itemstack.is(ItemTags.OCELOT_FOOD); - }, true); - this.goalSelector.addGoal(1, new FloatGoal(this)); -+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(3, this.temptGoal); - this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3F)); - this.goalSelector.addGoal(8, new OcelotAttackGoal(this)); - this.goalSelector.addGoal(9, new BreedGoal(this, 0.8D)); - this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8D, 1.0000001E-5F)); - this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0F)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Chicken.class, false)); - this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR)); - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java -index db60b91c2b26ca8cdb66e05deab7742ffe212767..5f9b7ae2ed4acff0fa7cfee07a29a28b5c0d67f8 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Panda.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java -@@ -120,6 +120,32 @@ public class Panda extends Animal { - - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.pandaRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pandaRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.pandaControllable; -+ } -+ -+ @Override -+ public void onMount(Player rider) { -+ super.onMount(rider); -+ setForwardMot(0.0F); -+ sit(false); -+ eat(false); -+ setOnBack(false); -+ } -+ // Purpur end -+ - @Override - public boolean canTakeItem(ItemStack stack) { - EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(stack); -@@ -281,6 +307,7 @@ public class Panda extends Animal { - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(2, new Panda.PandaPanicGoal(this, 2.0D)); - this.goalSelector.addGoal(2, new Panda.PandaBreedGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new Panda.PandaAttackGoal(this, 1.2000000476837158D, true)); -@@ -298,6 +325,7 @@ public class Panda extends Animal { - this.goalSelector.addGoal(12, new Panda.PandaRollGoal(this)); - this.goalSelector.addGoal(13, new FollowParentGoal(this, 1.25D)); - this.goalSelector.addGoal(14, new WaterAvoidingRandomStrollGoal(this, 1.0D)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new Panda.PandaHurtByTargetGoal(this, new Class[0])).setAlertOthers(new Class[0])); - } - -@@ -655,7 +683,7 @@ public class Panda extends Animal { - ItemStack itemstack = player.getItemInHand(hand); - - if (this.isScared()) { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } else if (this.isOnBack()) { - this.setOnBack(false); - return InteractionResult.sidedSuccess(this.level().isClientSide); -@@ -673,7 +701,7 @@ public class Panda extends Animal { - this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying - } else { - if (this.level().isClientSide || this.isSitting() || this.isInWater()) { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } - - this.tryToSit(); -@@ -692,7 +720,7 @@ public class Panda extends Animal { - - return InteractionResult.SUCCESS; - } else { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } - } - -@@ -737,7 +765,7 @@ public class Panda extends Animal { - return this.isBaby() ? Panda.BABY_DIMENSIONS : super.getDefaultDimensions(pose); - } - -- private static class PandaMoveControl extends MoveControl { -+ private static class PandaMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - - private final Panda panda; - -@@ -747,9 +775,9 @@ public class Panda extends Animal { - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (this.panda.canPerformAction()) { -- super.tick(); -+ super.vanillaTick(); // Purpur - } - } - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Parrot.java b/src/main/java/net/minecraft/world/entity/animal/Parrot.java -index 5ca96541abbb754f4d9fbe01f37ebaf19c532bbb..12200cca54304d567a1880527a49f3e26ad08c7b 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Parrot.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Parrot.java -@@ -124,12 +124,68 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder type, Level world) { - super(type, world); -- this.moveControl = new FlyingMoveControl(this, 10, false); -+ // Purpur start -+ final org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); -+ class ParrotMoveControl extends FlyingMoveControl { -+ public ParrotMoveControl(Mob entity, int maxPitchChange, boolean noGravity) { -+ super(entity, maxPitchChange, noGravity); -+ } -+ -+ @Override -+ public void tick() { -+ if (mob.getRider() != null && mob.isControllable()) { -+ flyingController.purpurTick(mob.getRider()); -+ } else { -+ super.tick(); -+ } -+ } -+ -+ @Override -+ public boolean hasWanted() { -+ return mob.getRider() != null && mob.isControllable() ? getForwardMot() != 0 || getStrafeMot() != 0 : super.hasWanted(); -+ } -+ } -+ this.moveControl = new ParrotMoveControl(this, 10, false); -+ // Purpur end - this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F); - this.setPathfindingMalus(PathType.DAMAGE_FIRE, -1.0F); - this.setPathfindingMalus(PathType.COCOA, -1.0F); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.parrotRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.parrotRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.parrotControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.parrotMaxY; -+ } -+ -+ @Override -+ public void travel(Vec3 vec3) { -+ super.travel(vec3); -+ if (getRider() != null && this.isControllable() && !onGround) { -+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; -+ setSpeed(speed); -+ Vec3 mot = getDeltaMovement(); -+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed)); -+ setDeltaMovement(mot.scale(0.9D)); -+ } -+ } -+ // Purpur end -+ - @Nullable - @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { -@@ -148,8 +204,10 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder { -diff --git a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -index c87a57e8ceac32a6c8a603aa24f8cb053610e47c..d97314380b69ea2ad83b86c0f1bcaaccd4a1644f 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -+++ b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -@@ -59,11 +59,40 @@ public class PolarBear extends Animal implements NeutralMob { - private int remainingPersistentAngerTime; - @Nullable - private UUID persistentAngerTarget; -+ private int standTimer = 0; // Purpur - - public PolarBear(EntityType type, Level world) { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.polarBearRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.polarBearRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.polarBearControllable; -+ } -+ -+ @Override -+ public boolean onSpacebar() { -+ if (!isStanding()) { -+ if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0) { -+ setStanding(true); -+ playSound(SoundEvents.POLAR_BEAR_WARNING, 1.0F, 1.0F); -+ } -+ } -+ return false; -+ } -+ // Purpur end -+ - @Nullable - @Override - public AgeableMob getBreedOffspring(ServerLevel world, AgeableMob entity) { -@@ -79,12 +108,14 @@ public class PolarBear extends Animal implements NeutralMob { - protected void registerGoals() { - super.registerGoals(); - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal()); - this.goalSelector.addGoal(1, new PolarBear.PolarBearPanicGoal()); - this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25)); - this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); - this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new PolarBear.PolarBearHurtByTargetGoal()); - this.targetSelector.addGoal(2, new PolarBear.PolarBearAttackPlayersGoal()); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); -@@ -201,6 +232,12 @@ public class PolarBear extends Animal implements NeutralMob { - if (!this.level().isClientSide) { - this.updatePersistentAnger((ServerLevel)this.level(), true); - } -+ -+ // Purpur start -+ if (isStanding() && --standTimer <= 0) { -+ setStanding(false); -+ } -+ // Purpur end - } - - @Override -@@ -230,6 +267,7 @@ public class PolarBear extends Animal implements NeutralMob { - - public void setStanding(boolean warning) { - this.entityData.set(DATA_STANDING_ID, warning); -+ standTimer = warning ? 20 : -1; // Purpur - } - - public float getStandingAnimationScale(float tickDelta) { -diff --git a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java -index 3f0fad476fe573c3ba946a9436d1b3f7c5260ee2..d75016647c513841358d08e5931821ecf8c21c2a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java -@@ -51,6 +51,18 @@ public class Pufferfish extends AbstractFish { - this.refreshDimensions(); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.pufferfishRidable; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.pufferfishControllable; -+ } -+ // Purpur end -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -index b58300e114e2e27ac68d7a9489bc52b127c9bc17..ba408a4195e03b484f143fbe66d5d3b13ebb8f11 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -@@ -86,6 +86,7 @@ public class Rabbit extends Animal implements VariantHolder { - private boolean wasOnGround; - private int jumpDelayTicks; - public int moreCarrotTicks; -+ private boolean actualJump; // Purpur - - public Rabbit(EntityType type, Level world) { - super(type, world); -@@ -93,9 +94,55 @@ public class Rabbit extends Animal implements VariantHolder { - this.moveControl = new Rabbit.RabbitMoveControl(this); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.rabbitRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.rabbitRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.rabbitControllable; -+ } -+ -+ @Override -+ public boolean onSpacebar() { -+ if (onGround) { -+ actualJump = true; -+ jumpFromGround(); -+ actualJump = false; -+ } -+ return true; -+ } -+ -+ private void handleJumping() { -+ if (onGround) { -+ RabbitJumpControl jumpController = (RabbitJumpControl) jumpControl; -+ if (!wasOnGround) { -+ setJumping(false); -+ jumpController.setCanJump(false); -+ } -+ if (!jumpController.wantJump()) { -+ if (moveControl.hasWanted()) { -+ startJumping(); -+ } -+ } else if (!jumpController.canJump()) { -+ jumpController.setCanJump(true); -+ } -+ } -+ wasOnGround = onGround; -+ } -+ // Purpur end -+ - @Override - public void registerGoals() { - this.goalSelector.addGoal(1, new FloatGoal(this)); -+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level())); - this.goalSelector.addGoal(1, new Rabbit.RabbitPanicGoal(this, 2.2D)); - this.goalSelector.addGoal(2, new BreedGoal(this, 0.8D)); -@@ -112,6 +159,14 @@ public class Rabbit extends Animal implements VariantHolder { - - @Override - protected float getJumpPower() { -+ // Purpur start -+ if (getRider() != null && this.isControllable()) { -+ if (getForwardMot() < 0) { -+ setSpeed(getForwardMot() * 2F); -+ } -+ return actualJump ? 0.5F : 0.3F; -+ } -+ // Purpur end - float f = 0.3F; - - if (this.horizontalCollision || this.moveControl.hasWanted() && this.moveControl.getWantedY() > this.getY() + 0.5D) { -@@ -136,7 +191,7 @@ public class Rabbit extends Animal implements VariantHolder { - } - - @Override -- protected void jumpFromGround() { -+ public void jumpFromGround() { // Purpur - protected -> public - super.jumpFromGround(); - double d0 = this.moveControl.getSpeedModifier(); - -@@ -186,6 +241,13 @@ public class Rabbit extends Animal implements VariantHolder { - - @Override - public void customServerAiStep() { -+ // Purpur start -+ if (getRider() != null && this.isControllable()) { -+ handleJumping(); -+ return; -+ } -+ // Purpur end -+ - if (this.jumpDelayTicks > 0) { - --this.jumpDelayTicks; - } -@@ -466,7 +528,7 @@ public class Rabbit extends Animal implements VariantHolder { - } - } - -- private static class RabbitMoveControl extends MoveControl { -+ private static class RabbitMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - - private final Rabbit rabbit; - private double nextJumpSpeed; -@@ -477,14 +539,14 @@ public class Rabbit extends Animal implements VariantHolder { - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (this.rabbit.onGround() && !this.rabbit.jumping && !((Rabbit.RabbitJumpControl) this.rabbit.jumpControl).wantJump()) { - this.rabbit.setSpeedModifier(0.0D); - } else if (this.hasWanted()) { - this.rabbit.setSpeedModifier(this.nextJumpSpeed); - } - -- super.tick(); -+ super.vanillaTick(); // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/Salmon.java b/src/main/java/net/minecraft/world/entity/animal/Salmon.java -index 0af79daa357f53a8871e293b57e16c099e5d3f64..87c442fb198cad8671ad1419e589a5a67c4fdca8 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Salmon.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Salmon.java -@@ -13,6 +13,18 @@ public class Salmon extends AbstractSchoolingFish { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.salmonRidable; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.salmonControllable; -+ } -+ // Purpur end -+ - @Override - public int getMaxSchoolSize() { - return 5; -diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -index 3ce86f952a18cae7fda1903916903b31a63a40b4..7c1da46554aefde8e5e2b33a3644c9cbd771d7bc 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -117,10 +117,28 @@ public class Sheep extends Animal implements Shearable { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.sheepRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.sheepRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.sheepControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.eatBlockGoal = new EatBlockGoal(this); - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D)); - this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new TemptGoal(this, 1.1D, (itemstack) -> { -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index 5c2ed3c39c8eb850f3be1e2ea5b5a7ea266e16d1..d51b486afb83bf3e12046ed5e61e73eec5bd7c7c 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -52,12 +52,31 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.snowGolemRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.snowGolemRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.snowGolemControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new RangedAttackGoal(this, 1.25D, 20, 10.0F)); - this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F)); - this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F)); - this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entityliving) -> { - return entityliving instanceof Enemy; - })); -@@ -105,6 +124,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - return; - } - -+ if (getRider() != null && this.isControllable() && !level().purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden - BlockState iblockdata = Blocks.SNOW.defaultBlockState(); - - for (int i = 0; i < 4; ++i) { -@@ -151,7 +171,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); - if (event != null) { - if (event.isCancelled()) { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } - drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); - } -@@ -165,7 +185,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - - return InteractionResult.sidedSuccess(this.level().isClientSide); - } else { -- return InteractionResult.PASS; -+ return tryRide(player, hand); // Purpur - } - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index 43b4ea96c5c4a6234e5b83d41db9b85c1fe27b8f..37402f7df48f04a6df2211e079519ed95d3735bc 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Squid.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -46,9 +46,32 @@ public class Squid extends WaterAnimal { - this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.squidRidable; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.squidControllable; -+ } -+ -+ protected void rotateVectorAroundY(org.bukkit.util.Vector vector, double degrees) { -+ double rad = Math.toRadians(degrees); -+ double cos = Math.cos(rad); -+ double sine = Math.sin(rad); -+ double x = vector.getX(); -+ double z = vector.getZ(); -+ vector.setX(cos * x - sine * z); -+ vector.setZ(sine * x + cos * z); -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new Squid.SquidFleeGoal()); - } - -@@ -290,6 +313,37 @@ public class Squid extends WaterAnimal { - - @Override - public void tick() { -+ // Purpur start -+ Player rider = squid.getRider(); -+ if (rider != null && squid.isControllable()) { -+ if (rider.jumping) { -+ squid.onSpacebar(); -+ } -+ float forward = rider.getForwardMot(); -+ float strafe = rider.getStrafeMot(); -+ float speed = (float) squid.getAttributeValue(Attributes.MOVEMENT_SPEED) * 10F; -+ if (forward < 0.0F) { -+ speed *= -0.5; -+ } -+ org.bukkit.util.Vector dir = rider.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(speed / 20.0F); -+ if (strafe != 0.0F) { -+ if (forward == 0.0F) { -+ dir.setY(0); -+ rotateVectorAroundY(dir, strafe > 0.0F ? -90 : 90); -+ } else if (forward < 0.0F) { -+ rotateVectorAroundY(dir, strafe > 0.0F ? 45 : -45); -+ } else { -+ rotateVectorAroundY(dir, strafe > 0.0F ? -45 : 45); -+ } -+ } -+ if (forward != 0.0F || strafe != 0.0F) { -+ squid.setMovementVector((float) dir.getX(), (float) dir.getY(), (float) dir.getZ()); -+ } else { -+ squid.setMovementVector(0.0F, 0.0F, 0.0F); -+ } -+ return; -+ } -+ // Purpur end - int i = this.squid.getNoActionTime(); - if (i > 100) { - this.squid.setMovementVector(0.0F, 0.0F, 0.0F); -diff --git a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -index 3d03ffe2e12eca82dfa2f414471d12bb362d4552..18dcb67d246b63637d8c948b6c3f48c58d71c339 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -+++ b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -@@ -67,6 +67,18 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.tropicalFishRidable; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.tropicalFishControllable; -+ } -+ // Purpur end -+ - public static String getPredefinedName(int variant) { - return "entity.minecraft.tropical_fish.predefined." + variant; - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index 30b87b5cb18c25cdd04eab64cfbe5acd6c1b6d84..4742d90ca38c1d8034b0cfcf7f336e225fade197 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -87,6 +87,23 @@ public class Turtle extends Animal { - this.moveControl = new Turtle.TurtleMoveControl(this); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.turtleRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.turtleRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.turtleControllable; -+ } -+ // Purpur end -+ - public void setHomePos(BlockPos pos) { - this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos... - } -@@ -189,6 +206,7 @@ public class Turtle extends Animal { - - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(0, new Turtle.TurtlePanicGoal(this, 1.2D)); - this.goalSelector.addGoal(1, new Turtle.TurtleBreedGoal(this, 1.0D)); - this.goalSelector.addGoal(1, new Turtle.TurtleLayEggGoal(this, 1.0D)); -@@ -342,13 +360,15 @@ public class Turtle extends Animal { - return this.isBaby() ? Turtle.BABY_DIMENSIONS : super.getDefaultDimensions(pose); - } - -- private static class TurtleMoveControl extends MoveControl { -+ private static class TurtleMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - - private final Turtle turtle; -+ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur - - TurtleMoveControl(Turtle turtle) { - super(turtle); - this.turtle = turtle; -+ waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(turtle, 0.25D); // Purpur - } - - private void updateSpeed() { -@@ -368,7 +388,7 @@ public class Turtle extends Animal { - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - this.updateSpeed(); - if (this.operation == MoveControl.Operation.MOVE_TO && !this.turtle.getNavigation().isDone()) { - double d0 = this.wantedX - this.turtle.getX(); -@@ -384,7 +404,7 @@ public class Turtle extends Animal { - - this.turtle.setYRot(this.rotlerp(this.turtle.getYRot(), f, 90.0F)); - this.turtle.yBodyRot = this.turtle.getYRot(); -- float f1 = (float) (this.speedModifier * this.turtle.getAttributeValue(Attributes.MOVEMENT_SPEED)); -+ float f1 = (float) (this.getSpeedModifier() * this.turtle.getAttributeValue(Attributes.MOVEMENT_SPEED)); - - this.turtle.setSpeed(Mth.lerp(0.125F, this.turtle.getSpeed(), f1)); - this.turtle.setDeltaMovement(this.turtle.getDeltaMovement().add(0.0D, (double) this.turtle.getSpeed() * d1 * 0.1D, 0.0D)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -index cebbb7341f86b13dcbfc3a41cbe264e9d4b68d60..92cc8a9b033052d5f510792d916c60cb2b90f07c 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -@@ -124,9 +124,32 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder(this, Llama.class, 24.0F, 1.5D, 1.5D)); -@@ -138,6 +161,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder type, Level world) { - super(type, world); -- this.moveControl = new FlyingMoveControl(this, 20, true); -+ // Purpur start -+ this.purpurController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.1F, 0.5F); -+ this.moveControl = new FlyingMoveControl(this, 20, true) { -+ @Override -+ public void tick() { -+ if (mob.getRider() != null && mob.isControllable()) { -+ purpurController.purpurTick(mob.getRider()); -+ } else { -+ super.tick(); -+ } -+ } -+ }; -+ // Purpur end - this.setCanPickUpLoot(this.canPickUpLoot()); - this.vibrationUser = new Allay.VibrationUser(); - this.vibrationData = new VibrationSystem.Data(); -@@ -117,6 +130,28 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS - } - // CraftBukkit end - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.allayRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.allayRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.allayControllable; -+ } -+ -+ @Override -+ protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -+ } -+ // Purpur end -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(Allay.MEMORY_TYPES, Allay.SENSOR_TYPES); -@@ -218,6 +253,7 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("allayBrain"); -+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("allayActivityUpdate"); -diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -index a8cc6ddbf45370fe632e5c5fb7ceef3d299e62a4..045ac081120f65987251d04d1522a5b7197e1d88 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -+++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -96,6 +96,23 @@ public class Axolotl extends Animal implements LerpingModel, VariantHolder getModelRotationValues() { - return this.modelRotationValues; -@@ -271,6 +288,7 @@ public class Axolotl extends Animal implements LerpingModel, VariantHolder> { - public final AnimationState croakAnimationState = new AnimationState(); - public final AnimationState tongueAnimationState = new AnimationState(); - public final AnimationState swimIdleAnimationState = new AnimationState(); -+ private org.purpurmc.purpur.controller.MoveControllerWASD purpurLandController; // Purpur -+ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurWaterController; // Purpur - - public Frog(EntityType type, Level world) { - super(type, world); -@@ -110,7 +112,55 @@ public class Frog extends Animal implements VariantHolder> { - this.setPathfindingMalus(PathType.WATER, 4.0F); - this.setPathfindingMalus(PathType.TRAPDOOR, -1.0F); - this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); -+ // Purpur start -+ this.purpurLandController = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.2F); -+ this.purpurWaterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F); -+ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) { -+ @Override -+ public void tick() { -+ net.minecraft.world.entity.player.Player rider = mob.getRider(); -+ if (rider != null && mob.isControllable()) { -+ if (mob.isInWater()) { -+ purpurWaterController.purpurTick(rider); -+ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, -0.005D, 0.0D)); -+ } else { -+ purpurLandController.purpurTick(rider); -+ } -+ } else { -+ super.tick(); -+ } -+ } -+ }; -+ // Purpur end -+ } -+ -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.frogRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.frogRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.frogControllable; -+ } -+ -+ @Override -+ protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -+ } -+ -+ @Override -+ public float getJumpPower() { -+ return (getRider() != null && isControllable()) ? level().purpurConfig.frogRidableJumpHeight * this.getBlockJumpFactor() : super.getJumpPower(); - } -+ // Purpur end - - @Override - protected Brain.Provider brainProvider() { -@@ -184,6 +234,7 @@ public class Frog extends Animal implements VariantHolder> { - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("frogBrain"); -+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("frogActivityUpdate"); -@@ -371,7 +422,7 @@ public class Frog extends Animal implements VariantHolder> { - return world.getBlockState(pos.below()).is(BlockTags.FROGS_SPAWNABLE_ON) && isBrightEnoughToSpawn(world, pos); - } - -- class FrogLookControl extends LookControl { -+ class FrogLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - FrogLookControl(final Mob entity) { - super(entity); - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -index 290d41136f5ec7671bc4990dfe50da0a770c124d..b98a34357e59168bbb22c967b86a449fc91f47f0 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -@@ -51,13 +51,50 @@ public class Tadpole extends AbstractFish { - protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.HURT_BY, SensorType.FROG_TEMPTATIONS); - protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.LOOK_TARGET, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.NEAREST_VISIBLE_ADULT, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.BREED_TARGET, MemoryModuleType.IS_PANICKING); - public boolean ageLocked; // Paper -+ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurController; // Purpur - - public Tadpole(EntityType type, Level world) { - super(type, world); -- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); -+ // Purpur start -+ this.purpurController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F); -+ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) { -+ @Override -+ public void tick() { -+ Player rider = mob.getRider(); -+ if (rider != null && mob.isControllable()) { -+ purpurController.purpurTick(rider); -+ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, 0.002D, 0.0D)); -+ } else { -+ super.tick(); -+ } -+ } -+ }; -+ // Purpur end - this.lookControl = new SmoothSwimmingLookControl(this, 10); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.tadpoleRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.tadpoleRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.tadpoleControllable; -+ } -+ -+ @Override -+ protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -+ } -+ // Purpur end -+ - @Override - protected PathNavigation createNavigation(Level world) { - return new WaterBoundPathNavigation(this, world); -@@ -86,6 +123,7 @@ public class Tadpole extends AbstractFish { - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("tadpoleBrain"); -+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("tadpoleActivityUpdate"); -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 02e49c7ae5e120302b6479cf3e3934b9217eebf0..9cd8220a1e5e43c141ad27df4969e66ef3746ecd 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -91,6 +91,23 @@ public class Goat extends Animal { - return InstrumentItem.create(Items.GOAT_HORN, (Holder) holderset.getRandomElement(randomsource).get()); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.goatRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.goatRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.goatControllable; -+ } -+ // Purpur end -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(Goat.MEMORY_TYPES, Goat.SENSOR_TYPES); -@@ -193,6 +210,7 @@ public class Goat extends Animal { - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("goatBrain"); -+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("goatActivityUpdate"); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -index 9357cf0179d19fbdfe76413e909a99b924c85780..12a137665f93d992094e86327a496057890d1018 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -@@ -217,11 +217,21 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - - protected AbstractHorse(EntityType type, Level world) { - super(type, world); -+ this.moveControl = new net.minecraft.world.entity.ai.control.MoveControl(this); // Purpur - use vanilla controller -+ this.lookControl = new net.minecraft.world.entity.ai.control.LookControl(this); // Purpur - use vanilla controller - this.createInventory(); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return false; // vanilla handles -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - this.goalSelector.addGoal(1, new PanicGoal(this, 1.2D)); - this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D)); - this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D, AbstractHorse.class)); -@@ -232,6 +242,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - if (this.canPerformRearing()) { - this.goalSelector.addGoal(9, new RandomStandGoal(this)); - } -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - - this.addBehaviourGoals(); - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -index ff02169ba14f5264cea8beaf1779e2890c5d74b8..1febe8e173886d501e40331c12261701bd36b0f6 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -@@ -15,6 +15,13 @@ public class Donkey extends AbstractChestedHorse { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.donkeyRidableInWater; -+ } -+ // Purpur end -+ - @Override - protected SoundEvent getAmbientSound() { - return SoundEvents.DONKEY_AMBIENT; -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -index 6e299770fca78699f7e1988db4cdef37b99d74c1..816c698a81a77f217a606468aa157bdaed779479 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -@@ -44,6 +44,13 @@ public class Horse extends AbstractHorse implements VariantHolder { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.horseRidableInWater; -+ } -+ // Purpur end -+ - @Override - protected void randomizeAttributes(RandomSource random) { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)generateMaxHealth(random::nextInt)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 1dd4290287725898ace29e46b439b55df8fdd1af..3943ca63aaeecfb98c34ceef9b0c40e71de4e832 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -@@ -78,7 +78,51 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, Level world) { - super(type, world); -+ // Purpur start -+ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this) { -+ @Override -+ public void tick() { -+ if (entity.getRider() != null && entity.isControllable() && isSaddled()) { -+ purpurTick(entity.getRider()); -+ } else { -+ vanillaTick(); -+ } -+ } -+ }; -+ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) { -+ @Override -+ public void tick() { -+ if (entity.getRider() != null && entity.isControllable() && isSaddled()) { -+ purpurTick(entity.getRider()); -+ } else { -+ vanillaTick(); -+ } -+ } -+ }; -+ // Purpur end -+ } -+ -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.llamaRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.llamaRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.llamaControllable; -+ } -+ -+ @Override -+ public boolean isSaddled() { -+ return super.isSaddled() || (isTamed() && getSwag() != null); - } -+ // Purpur end - - public boolean isTraderLlama() { - return false; -@@ -120,6 +164,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder public - super.jumpFromGround(); - double d0 = this.moveControl.getSpeedModifier(); - -diff --git a/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java b/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java -index 6725013c608e9321ce0d088059672af4412cf6db..1c8ac6b9603a6e282c5bbe8cdcc61046c9efe41e 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java -+++ b/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java -@@ -25,6 +25,13 @@ public class EnderDragonPart extends Entity { - this.name = name; - } - -+ // Purpur start -+ @Override -+ public net.minecraft.world.InteractionResult interact(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) { -+ return parentMob.isAlive() ? parentMob.tryRide(player, hand) : net.minecraft.world.InteractionResult.PASS; -+ } -+ // Purpur end -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - } -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -index 6f14607a88761171a72e274b3c9b476b20a272f1..170038f2bfdfd01003b6661672a9f8ed266343e2 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -@@ -106,6 +106,7 @@ public class EnderDragon extends Mob implements Enemy { - @Nullable - private BlockPos podium; - // Paper end - Allow changing the EnderDragon podium -+ private boolean hadRider; // Purpur - - public EnderDragon(EntityType entitytypes, Level world) { - super(EntityType.ENDER_DRAGON, world); -@@ -128,6 +129,37 @@ public class EnderDragon extends Mob implements Enemy { - this.noCulling = true; - this.phaseManager = new EnderDragonPhaseManager(this); - this.explosionSource = new Explosion(world, this, null, null, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, Explosion.BlockInteraction.DESTROY, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, SoundEvents.GENERIC_EXPLODE); // CraftBukkit -+ -+ // Purpur start -+ this.moveControl = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this) { -+ @Override -+ public void vanillaTick() { -+ // dragon doesn't use the controller. do nothing -+ } -+ }; -+ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) { -+ @Override -+ public void vanillaTick() { -+ // dragon doesn't use the controller. do nothing -+ } -+ -+ @Override -+ public void purpurTick(Player rider) { -+ setYawPitch(rider.getYRot() - 180F, rider.xRotO * 0.5F); -+ } -+ }; -+ // Purpur end -+ } -+ -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.enderDragonRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.enderDragonRidableInWater; - } - - public void setDragonFight(EndDragonFight fight) { -@@ -142,6 +174,17 @@ public class EnderDragon extends Mob implements Enemy { - return this.fightOrigin; - } - -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.enderDragonControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.enderDragonMaxY; -+ } -+ // Purpur end -+ - public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D); - } -@@ -203,6 +246,37 @@ public class EnderDragon extends Mob implements Enemy { - - @Override - public void aiStep() { -+ // Purpur start -+ boolean hasRider = getRider() != null && this.isControllable(); -+ if (hasRider) { -+ if (!hadRider) { -+ hadRider = true; -+ noPhysics = false; -+ this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(4.0F, 2.0F); -+ } -+ -+ // dragon doesn't use controllers, so must tick manually -+ moveControl.tick(); -+ lookControl.tick(); -+ -+ moveRelative((float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F, new Vec3(-getStrafeMot(), getVerticalMot(), -getForwardMot())); -+ Vec3 mot = getDeltaMovement(); -+ setDeltaMovement(mot); -+ move(MoverType.PLAYER, mot); -+ -+ mot = mot.multiply(0.9F, 0.9F, 0.9F); -+ setDeltaMovement(mot); -+ -+ // control wing flap speed on client -+ phaseManager.setPhase(mot.x() * mot.x() + mot.z() * mot.z() < 0.005F ? EnderDragonPhase.HOVERING : EnderDragonPhase.HOLDING_PATTERN); -+ } else if (hadRider) { -+ hadRider = false; -+ noPhysics = true; -+ this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(16.0F, 8.0F); -+ phaseManager.setPhase(EnderDragonPhase.HOLDING_PATTERN); // HoldingPattern -+ } -+ // Purpur end -+ - this.processFlappingMovement(); - if (this.level().isClientSide) { - this.setHealth(this.getHealth()); -@@ -229,6 +303,8 @@ public class EnderDragon extends Mob implements Enemy { - float f; - - if (this.isDeadOrDying()) { -+ if (hasRider) ejectPassengers(); // Purpur -+ - float f1 = (this.random.nextFloat() - 0.5F) * 8.0F; - - f = (this.random.nextFloat() - 0.5F) * 4.0F; -@@ -241,9 +317,9 @@ public class EnderDragon extends Mob implements Enemy { - - f = 0.2F / ((float) vec3d.horizontalDistance() * 10.0F + 1.0F); - f *= (float) Math.pow(2.0D, vec3d.y); -- if (this.phaseManager.getCurrentPhase().isSitting()) { -+ if (!hasRider && this.phaseManager.getCurrentPhase().isSitting()) { // Purpur - this.flapTime += 0.1F; -- } else if (this.inWall) { -+ } else if (!hasRider && this.inWall) { // Purpur - this.flapTime += f * 0.5F; - } else { - this.flapTime += f; -@@ -277,7 +353,7 @@ public class EnderDragon extends Mob implements Enemy { - } - - this.phaseManager.getCurrentPhase().doClientTick(); -- } else { -+ } else if (!hasRider) { // Purpur - DragonPhaseInstance idragoncontroller = this.phaseManager.getCurrentPhase(); - - idragoncontroller.doServerTick(); -@@ -346,7 +422,7 @@ public class EnderDragon extends Mob implements Enemy { - this.tickPart(this.body, (double) (f11 * 0.5F), 0.0D, (double) (-f12 * 0.5F)); - this.tickPart(this.wing1, (double) (f12 * 4.5F), 2.0D, (double) (f11 * 4.5F)); - this.tickPart(this.wing2, (double) (f12 * -4.5F), 2.0D, (double) (f11 * -4.5F)); -- if (!this.level().isClientSide && this.hurtTime == 0) { -+ if (!hasRider && !this.level().isClientSide && this.hurtTime == 0) { // Purpur - this.knockBack(this.level().getEntities((Entity) this, this.wing1.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); - this.knockBack(this.level().getEntities((Entity) this, this.wing2.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); - this.hurt(this.level().getEntities((Entity) this, this.head.getBoundingBox().inflate(1.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); -@@ -390,7 +466,7 @@ public class EnderDragon extends Mob implements Enemy { - } - - if (!this.level().isClientSide) { -- this.inWall = this.checkWalls(this.head.getBoundingBox()) | this.checkWalls(this.neck.getBoundingBox()) | this.checkWalls(this.body.getBoundingBox()); -+ this.inWall = !hasRider && this.checkWalls(this.head.getBoundingBox()) | this.checkWalls(this.neck.getBoundingBox()) | this.checkWalls(this.body.getBoundingBox()); // Purpur - if (this.dragonFight != null) { - this.dragonFight.updateDragon(this); - } -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 7ddca52f7fe3f289b4b867e134326b1ead1a2aee..14f9ded1b44d05d69f1a9394fdacab5b145e4c45 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -88,16 +88,30 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - return !entityliving.getType().is(EntityTypeTags.WITHER_FRIENDS) && entityliving.attackable(); - }; - private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0D).selector(WitherBoss.LIVING_ENTITY_SELECTOR); -+ private int shootCooldown = 0; // Purpur - // Paper start - private boolean canPortal = false; - - public void setCanTravelThroughPortals(boolean canPortal) { this.canPortal = canPortal; } - // Paper end -+ private org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD purpurController; // Purpur - - public WitherBoss(EntityType type, Level world) { - super(type, world); - this.bossEvent = (ServerBossEvent) (new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS)).setDarkenScreen(true); -- this.moveControl = new FlyingMoveControl(this, 10, false); -+ // Purpur start -+ this.purpurController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.1F); -+ this.moveControl = new FlyingMoveControl(this, 10, false) { -+ @Override -+ public void tick() { -+ if (mob.getRider() != null && mob.isControllable()) { -+ purpurController.purpurTick(mob.getRider()); -+ } else { -+ super.tick(); -+ } -+ } -+ }; -+ // Purpur end - this.setHealth(this.getMaxHealth()); - this.xpReward = 50; - } -@@ -112,13 +126,113 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - return navigationflying; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.witherRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.witherControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.witherMaxY; -+ } -+ -+ @Override -+ public void travel(Vec3 vec3) { -+ super.travel(vec3); -+ if (getRider() != null && this.isControllable() && !onGround) { -+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 5F; -+ setSpeed(speed); -+ Vec3 mot = getDeltaMovement(); -+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.5, speed)); -+ setDeltaMovement(mot.scale(0.9D)); -+ } -+ } -+ -+ @Override -+ public void onMount(Player rider) { -+ super.onMount(rider); -+ this.entityData.set(DATA_TARGETS.get(0), 0); -+ this.entityData.set(DATA_TARGETS.get(1), 0); -+ this.entityData.set(DATA_TARGETS.get(2), 0); -+ getNavigation().stop(); -+ shootCooldown = 20; -+ } -+ -+ @Override -+ public boolean onClick(net.minecraft.world.InteractionHand hand) { -+ return shoot(getRider(), hand == net.minecraft.world.InteractionHand.MAIN_HAND ? new int[]{1} : new int[]{2}); -+ } -+ -+ public boolean shoot(@Nullable Player rider, int[] heads) { -+ if (shootCooldown > 0) { -+ return false; -+ } -+ -+ shootCooldown = 20; -+ if (rider == null) { -+ return false; -+ } -+ -+ org.bukkit.craftbukkit.entity.CraftHumanEntity player = rider.getBukkitEntity(); -+ if (!player.hasPermission("allow.special.wither")) { -+ return false; -+ } -+ -+ net.minecraft.world.phys.HitResult rayTrace = getRayTrace(120, net.minecraft.world.level.ClipContext.Fluid.NONE); -+ if (rayTrace == null) { -+ return false; -+ } -+ -+ Vec3 loc; -+ if (rayTrace.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK) { -+ BlockPos pos = ((net.minecraft.world.phys.BlockHitResult) rayTrace).getBlockPos(); -+ loc = new Vec3(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D); -+ } else if (rayTrace.getType() == net.minecraft.world.phys.HitResult.Type.ENTITY) { -+ Entity target = ((net.minecraft.world.phys.EntityHitResult) rayTrace).getEntity(); -+ loc = new Vec3(target.getX(), target.getY() + (target.getEyeHeight() / 2), target.getZ()); -+ } else { -+ org.bukkit.block.Block block = player.getTargetBlock(null, 120); -+ loc = new Vec3(block.getX() + 0.5D, block.getY() + 0.5D, block.getZ() + 0.5D); -+ } -+ -+ for (int head : heads) { -+ shoot(head, loc.x(), loc.y(), loc.z(), rider); -+ } -+ -+ return true; // handled -+ } -+ -+ public void shoot(int head, double x, double y, double z, Player rider) { -+ level().levelEvent(null, 1024, blockPosition(), 0); -+ double headX = getHeadX(head); -+ double headY = getHeadY(head); -+ double headZ = getHeadZ(head); -+ WitherSkull skull = new WitherSkull(level(), this, x - headX, y - headY, z - headZ); -+ skull.setPosRaw(headX, headY, headZ); -+ level().addFreshEntity(skull); -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(0, new WitherBoss.WitherDoNothingGoal()); - this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0D, 40, 20.0F)); - this.goalSelector.addGoal(5, new WaterAvoidingRandomFlyingGoal(this, 1.0D)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 0, false, false, WitherBoss.LIVING_ENTITY_SELECTOR)); - } -@@ -263,6 +377,16 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - - @Override - protected void customServerAiStep() { -+ // Purpur start -+ if (getRider() != null && this.isControllable()) { -+ Vec3 mot = getDeltaMovement(); -+ setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); -+ } -+ if (shootCooldown > 0) { -+ shootCooldown--; -+ } -+ // Purpur end -+ - int i; - - if (this.getInvulnerableTicks() > 0) { -@@ -580,11 +704,11 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - } - - public int getAlternativeTarget(int headIndex) { -- return (Integer) this.entityData.get((EntityDataAccessor) WitherBoss.DATA_TARGETS.get(headIndex)); -+ return getRider() != null && this.isControllable() ? 0 : this.entityData.get(WitherBoss.DATA_TARGETS.get(headIndex)); // Purpur - } - - public void setAlternativeTarget(int headIndex, int id) { -- this.entityData.set((EntityDataAccessor) WitherBoss.DATA_TARGETS.get(headIndex), id); -+ if (getRider() == null || !this.isControllable()) this.entityData.set(WitherBoss.DATA_TARGETS.get(headIndex), id); // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -index 0c5fe46d2da113beff3e220843593d616e37d4ca..8f71739a4b23bc53994f1cbff8500b6bad288a42 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -69,12 +69,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(2, new RestrictSunGoal(this)); - this.goalSelector.addGoal(3, new FleeSunGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Wolf.class, 6.0F, 1.0D, 1.2D)); - this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Blaze.java b/src/main/java/net/minecraft/world/entity/monster/Blaze.java -index aee2fa184bc5723dfd3d54f460a173982d874c8b..0e1aa9a00284ce43436b1290f9ebe243c4d09fdc 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Blaze.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Blaze.java -@@ -32,6 +32,7 @@ public class Blaze extends Monster { - - public Blaze(EntityType type, Level world) { - super(type, world); -+ this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur - this.setPathfindingMalus(PathType.WATER, -1.0F); - this.setPathfindingMalus(PathType.LAVA, 8.0F); - this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); -@@ -39,19 +40,55 @@ public class Blaze extends Monster { - this.xpReward = 10; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.blazeRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.blazeRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.blazeControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.blazeMaxY; -+ } -+ -+ @Override -+ public void travel(Vec3 vec3) { -+ super.travel(vec3); -+ if (getRider() != null && this.isControllable() && !onGround) { -+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); -+ setSpeed(speed); -+ Vec3 mot = getDeltaMovement(); -+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed)); -+ setDeltaMovement(mot.scale(0.9D)); -+ } -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(4, new Blaze.BlazeAttackGoal(this)); - this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0)); - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 0.0F)); - this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers()); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); - } - - public static AttributeSupplier.Builder createAttributes() { -- return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0); -+ return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - } - - @Override -@@ -116,6 +153,13 @@ public class Blaze extends Monster { - - @Override - protected void customServerAiStep() { -+ // Purpur start -+ if (getRider() != null && this.isControllable()) { -+ Vec3 mot = getDeltaMovement(); -+ setDeltaMovement(mot.x(), getVerticalMot() > 0 ? 0.07D : -0.07D, mot.z()); -+ return; -+ } -+ // Purpur end - this.nextHeightOffsetChangeTick--; - if (this.nextHeightOffsetChangeTick <= 0) { - this.nextHeightOffsetChangeTick = 100; -diff --git a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java -index 87e4b300ac248f6c13d9b4a8f24fd78b24b565b4..504996c8309fcd11de1dd166dee12d7e7db8db56 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java -@@ -26,6 +26,23 @@ public class CaveSpider extends Spider { - return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0D); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.caveSpiderRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.caveSpiderRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.caveSpiderControllable; -+ } -+ // Purpur end -+ - @Override - public boolean doHurtTarget(Entity target) { - if (super.doHurtTarget(target)) { -diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index cbcb2bfa8f91099e5c374f590f48885390bdf7a7..6e812033323b1d1ace9023d57f0405e0d546c337 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -61,21 +61,98 @@ public class Creeper extends Monster implements PowerableMob { - public int explosionRadius = 3; - private int droppedSkulls; - private Player entityIgniter; // CraftBukkit -+ // Purpur start -+ private int spacebarCharge = 0; -+ private int prevSpacebarCharge = 0; -+ private int powerToggleDelay = 0; -+ // Purpur end - - public Creeper(EntityType type, Level world) { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.creeperRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.creeperRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.creeperControllable; -+ } -+ -+ @Override -+ protected void customServerAiStep() { -+ if (powerToggleDelay > 0) { -+ powerToggleDelay--; -+ } -+ if (getRider() != null && this.isControllable()) { -+ if (getRider().getForwardMot() != 0 || getRider().getStrafeMot() != 0) { -+ spacebarCharge = 0; -+ setIgnited(false); -+ setSwellDir(-1); -+ } -+ if (spacebarCharge == prevSpacebarCharge) { -+ spacebarCharge = 0; -+ } -+ prevSpacebarCharge = spacebarCharge; -+ } -+ super.customServerAiStep(); -+ } -+ -+ @Override -+ public void onMount(Player rider) { -+ super.onMount(rider); -+ setIgnited(false); -+ setSwellDir(-1); -+ } -+ -+ @Override -+ public boolean onSpacebar() { -+ if (powerToggleDelay > 0) { -+ return true; // just toggled power, do not jump or ignite -+ } -+ spacebarCharge++; -+ if (spacebarCharge > maxSwell - 2) { -+ spacebarCharge = 0; -+ if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.powered.creeper")) { -+ powerToggleDelay = 20; -+ setPowered(!isPowered()); -+ setIgnited(false); -+ setSwellDir(-1); -+ return true; -+ } -+ } -+ if (!isIgnited()) { -+ if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0 && -+ getRider().getBukkitEntity().hasPermission("allow.special.creeper")) { -+ setIgnited(true); -+ setSwellDir(1); -+ return true; -+ } -+ } -+ return getForwardMot() == 0 && getStrafeMot() == 0; // do not jump if standing still -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(1, new FloatGoal(this)); - this.goalSelector.addGoal(2, new SwellGoal(this)); -+ this.goalSelector.addGoal(3, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Ocelot.class, 6.0F, 1.0D, 1.2D)); - this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Cat.class, 6.0F, 1.0D, 1.2D)); - this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, false)); - this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8D)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true)); - this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); - } -@@ -323,6 +400,7 @@ public class Creeper extends Monster implements PowerableMob { - com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited); - if (event.callEvent()) { - this.entityData.set(Creeper.DATA_IS_IGNITED, event.isIgnited()); -+ if (!event.isIgnited()) setSwellDir(-1); // Purpur - } - } - // Paper end - CreeperIgniteEvent -diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -index cff1b5e0e3fd32d82157d5f13d83d4abdfad7378..2b93338db154e6c0c3c8814adabaab761f08af08 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -@@ -71,6 +71,23 @@ public class Drowned extends Zombie implements RangedAttackMob { - return Zombie.createAttributes().add(Attributes.STEP_HEIGHT, 1.0D); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.drownedRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.drownedRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.drownedControllable; -+ } -+ // Purpur end -+ - @Override - protected void addBehaviourGoals() { - this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0D)); -@@ -262,8 +279,7 @@ public class Drowned extends Zombie implements RangedAttackMob { - this.searchingForLand = targetingUnderwater; - } - -- private static class DrownedMoveControl extends MoveControl { -- -+ private static class DrownedMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - private final Drowned drowned; - - public DrownedMoveControl(Drowned drowned) { -@@ -272,7 +288,7 @@ public class Drowned extends Zombie implements RangedAttackMob { - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - LivingEntity entityliving = this.drowned.getTarget(); - - if (this.drowned.wantsToSwim() && this.drowned.isInWater()) { -@@ -295,7 +311,7 @@ public class Drowned extends Zombie implements RangedAttackMob { - - this.drowned.setYRot(this.rotlerp(this.drowned.getYRot(), f, 90.0F)); - this.drowned.yBodyRot = this.drowned.getYRot(); -- float f1 = (float) (this.speedModifier * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); -+ float f1 = (float) (this.getSpeedModifier() * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - float f2 = Mth.lerp(0.125F, this.drowned.getSpeed(), f1); - - this.drowned.setSpeed(f2); -@@ -305,7 +321,7 @@ public class Drowned extends Zombie implements RangedAttackMob { - this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(0.0D, -0.008D, 0.0D)); - } - -- super.tick(); -+ super.vanillaTick(); // Purpur - } - - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -index fd995b1f29c47884e9db2cb92f1dd615d62ae032..430899602940aa04c21d45ae94bcc506352389cf 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -@@ -33,6 +33,18 @@ public class ElderGuardian extends Guardian { - - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.elderGuardianRidable; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.elderGuardianControllable; -+ } -+ // Purpur end -+ - public static AttributeSupplier.Builder createAttributes() { - return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.ATTACK_DAMAGE, 8.0D).add(Attributes.MAX_HEALTH, 80.0D); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index 260202fab3ac300552c557b44dcf251f083c6a78..0c1e3b00bdc1e6b033e6e9e37400a475cee2500e 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -93,9 +93,27 @@ public class EnderMan extends Monster implements NeutralMob { - this.setPathfindingMalus(PathType.WATER, -1.0F); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.endermanRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.endermanRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.endermanControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new EnderMan.EndermanFreezeWhenLookedAt(this)); - this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false)); - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D, 0.0F)); -@@ -103,6 +121,7 @@ public class EnderMan extends Monster implements NeutralMob { - this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); - this.goalSelector.addGoal(10, new EnderMan.EndermanLeaveBlockGoal(this)); - this.goalSelector.addGoal(11, new EnderMan.EndermanTakeBlockGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt)); - this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, true, false)); -@@ -279,7 +298,7 @@ public class EnderMan extends Monster implements NeutralMob { - - @Override - protected void customServerAiStep() { -- if (this.level().isDay() && this.tickCount >= this.targetChangeTime + 600) { -+ if ((getRider() == null || !this.isControllable()) && this.level().isDay() && this.tickCount >= this.targetChangeTime + 600) { // Purpur - no random teleporting - float f = this.getLightLevelDependentMagicValue(); - - if (f > 0.5F && this.level().canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper - EndermanEscapeEvent -@@ -394,6 +413,7 @@ public class EnderMan extends Monster implements NeutralMob { - public boolean hurt(DamageSource source, float amount) { - if (this.isInvulnerableTo(source)) { - return false; -+ } else if (getRider() != null && this.isControllable()) { return super.hurt(source, amount); // Purpur - no teleporting on damage - } else { - boolean flag = source.getDirectEntity() instanceof ThrownPotion; - boolean flag1; -diff --git a/src/main/java/net/minecraft/world/entity/monster/Endermite.java b/src/main/java/net/minecraft/world/entity/monster/Endermite.java -index 9c78905762d9a484878fa9cf03a2ca3850e7e613..ee88933c7baba3bc82c6dc9d52291d5f9fc0f25d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Endermite.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Endermite.java -@@ -38,14 +38,33 @@ public class Endermite extends Monster { - this.xpReward = 3; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.endermiteRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.endermiteRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.endermiteControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(1, new FloatGoal(this)); -+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level())); - this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false)); - this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 1.0D)); - this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers()); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Evoker.java b/src/main/java/net/minecraft/world/entity/monster/Evoker.java -index 38e866571c35ebc4843a8d4fa39691902a5fcc91..0d1931398f1f6bad941ff133a0d872ffabb00bd3 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Evoker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Evoker.java -@@ -52,10 +52,28 @@ public class Evoker extends SpellcasterIllager { - this.xpReward = 10; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.evokerRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.evokerRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.evokerControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - super.registerGoals(); - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new Evoker.EvokerCastingSpellGoal()); - this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6D, 1.0D)); - this.goalSelector.addGoal(4, new Evoker.EvokerSummonSpellGoal()); -@@ -64,6 +82,7 @@ public class Evoker extends SpellcasterIllager { - this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); - this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); - this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers()); - this.targetSelector.addGoal(2, (new NearestAttackableTargetGoal<>(this, Player.class, true)).setUnseenMemoryTicks(300)); - this.targetSelector.addGoal(3, (new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)).setUnseenMemoryTicks(300)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ghast.java b/src/main/java/net/minecraft/world/entity/monster/Ghast.java -index 373a4f036157017b0d95e8f1849780582235a549..862ad83b536fd0b5eb38ac0f2940cc46aed1fba2 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ghast.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ghast.java -@@ -43,11 +43,47 @@ public class Ghast extends FlyingMob implements Enemy { - this.moveControl = new Ghast.GhastMoveControl(this); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.ghastRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ghastRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.ghastControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.ghastMaxY; -+ } -+ -+ @Override -+ public void travel(Vec3 vec3) { -+ super.travel(vec3); -+ if (getRider() != null && this.isControllable() && !onGround) { -+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); -+ setSpeed(speed); -+ Vec3 mot = getDeltaMovement(); -+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed)); -+ setDeltaMovement(mot.scale(0.9D)); -+ } -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(5, new Ghast.RandomFloatAroundGoal(this)); - this.goalSelector.addGoal(7, new Ghast.GhastLookGoal(this)); - this.goalSelector.addGoal(7, new Ghast.GhastShootFireballGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving) -> { - return Math.abs(entityliving.getY() - this.getY()) <= 4.0D; - })); -@@ -102,7 +138,7 @@ public class Ghast extends FlyingMob implements Enemy { - } - - public static AttributeSupplier.Builder createAttributes() { -- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FOLLOW_RANGE, 100.0D); -+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FOLLOW_RANGE, 100.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - } - - @Override -@@ -154,7 +190,7 @@ public class Ghast extends FlyingMob implements Enemy { - - } - -- private static class GhastMoveControl extends MoveControl { -+ private static class GhastMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - - private final Ghast ghast; - private int floatDuration; -@@ -165,7 +201,7 @@ public class Ghast extends FlyingMob implements Enemy { - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (this.operation == MoveControl.Operation.MOVE_TO) { - if (this.floatDuration-- <= 0) { - this.floatDuration += this.ghast.getRandom().nextInt(5) + 2; -diff --git a/src/main/java/net/minecraft/world/entity/monster/Giant.java b/src/main/java/net/minecraft/world/entity/monster/Giant.java -index 118521ae54254b0a73bb7cba7b2871c9c26f89fc..868e8383a890d76b4cfeac8b77b06e8f58d0a6dc 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Giant.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Giant.java -@@ -12,6 +12,29 @@ public class Giant extends Monster { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.giantRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.giantRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.giantControllable; -+ } -+ -+ @Override -+ protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); -+ } -+ // Purpur end -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Guardian.java b/src/main/java/net/minecraft/world/entity/monster/Guardian.java -index 6c2e2fd5826a5f8070502e20d1d140c3d70bd0d3..9a1b1a1b0b6d59d599a2ab87f047121f47cf2bec 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Guardian.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Guardian.java -@@ -66,15 +66,36 @@ public class Guardian extends Monster { - this.xpReward = 10; - this.setPathfindingMalus(PathType.WATER, 0.0F); - this.moveControl = new Guardian.GuardianMoveControl(this); -+ // Purpur start -+ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) { -+ @Override -+ public void setYawPitch(float yaw, float pitch) { -+ super.setYawPitch(yaw, pitch * 0.35F); -+ } -+ }; -+ // Purpur end - this.clientSideTailAnimation = this.random.nextFloat(); - this.clientSideTailAnimationO = this.clientSideTailAnimation; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.guardianRidable; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.guardianControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - MoveTowardsRestrictionGoal pathfindergoalmovetowardsrestriction = new MoveTowardsRestrictionGoal(this, 1.0D); - - this.randomStrollGoal = new RandomStrollGoal(this, 1.0D, 80); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(4, this.guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field - this.goalSelector.addGoal(5, pathfindergoalmovetowardsrestriction); - this.goalSelector.addGoal(7, this.randomStrollGoal); -@@ -83,6 +104,7 @@ public class Guardian extends Monster { - this.goalSelector.addGoal(9, new RandomLookAroundGoal(this)); - this.randomStrollGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); - pathfindergoalmovetowardsrestriction.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 10, true, false, new Guardian.GuardianAttackSelector(this))); - } - -@@ -333,7 +355,7 @@ public class Guardian extends Monster { - @Override - public void travel(Vec3 movementInput) { - if (this.isControlledByLocalInstance() && this.isInWater()) { -- this.moveRelative(0.1F, movementInput); -+ this.moveRelative(getRider() != null && this.isControllable() ? getSpeed() : 0.1F, movementInput); // Purpur - this.move(MoverType.SELF, this.getDeltaMovement()); - this.setDeltaMovement(this.getDeltaMovement().scale(0.9D)); - if (!this.isMoving() && this.getTarget() == null) { -@@ -345,7 +367,7 @@ public class Guardian extends Monster { - - } - -- private static class GuardianMoveControl extends MoveControl { -+ private static class GuardianMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur - - private final Guardian guardian; - -@@ -354,8 +376,17 @@ public class Guardian extends Monster { - this.guardian = guardian; - } - -+ // Purpur start - @Override -- public void tick() { -+ public void purpurTick(Player rider) { -+ super.purpurTick(rider); -+ guardian.setDeltaMovement(guardian.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); -+ guardian.setMoving(guardian.getForwardMot() > 0.0F); // control tail speed -+ } -+ // Purpur end -+ -+ @Override -+ public void vanillaTick() { // Purpur - if (this.operation == MoveControl.Operation.MOVE_TO && !this.guardian.getNavigation().isDone()) { - Vec3 vec3d = new Vec3(this.wantedX - this.guardian.getX(), this.wantedY - this.guardian.getY(), this.wantedZ - this.guardian.getZ()); - double d0 = vec3d.length(); -@@ -366,7 +397,7 @@ public class Guardian extends Monster { - - this.guardian.setYRot(this.rotlerp(this.guardian.getYRot(), f, 90.0F)); - this.guardian.yBodyRot = this.guardian.getYRot(); -- float f1 = (float) (this.speedModifier * this.guardian.getAttributeValue(Attributes.MOVEMENT_SPEED)); -+ float f1 = (float) (this.getSpeedModifier() * this.guardian.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - float f2 = Mth.lerp(0.125F, this.guardian.getSpeed(), f1); - - this.guardian.setSpeed(f2); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Husk.java b/src/main/java/net/minecraft/world/entity/monster/Husk.java -index c34c8483a026f61fe20935697d321d7ef5d8dfbc..20ea3187626a667815245974df88189f7d6ffc76 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Husk.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Husk.java -@@ -22,6 +22,23 @@ public class Husk extends Zombie { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.huskRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.huskRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.huskControllable; -+ } -+ // Purpur end -+ - public static boolean checkHuskSpawnRules(EntityType type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - return checkMonsterSpawnRules(type, world, spawnReason, pos, random) && (MobSpawnType.isSpawner(spawnReason) || world.canSeeSky(pos)); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -index a7964208c952cb4e34916ae6523850fc3921b07e..bef63bb69ea81298a1021eadd6c260943e18eba7 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -@@ -56,10 +56,28 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { - - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.illusionerRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.illusionerRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.illusionerControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - super.registerGoals(); - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new SpellcasterIllager.SpellcasterCastingSpellGoal()); - this.goalSelector.addGoal(4, new Illusioner.IllusionerMirrorSpellGoal()); - this.goalSelector.addGoal(5, new Illusioner.IllusionerBlindnessSpellGoal()); -@@ -67,6 +85,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { - this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); - this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); - this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers()); - this.targetSelector.addGoal(2, (new NearestAttackableTargetGoal<>(this, Player.class, true)).setUnseenMemoryTicks(300)); - this.targetSelector.addGoal(3, (new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)).setUnseenMemoryTicks(300)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -index 7be2393dc3cb79556d9767b09f43be0f81308a12..6a03a5f1c209d248207b6835ba1d7c0f59dec557 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -+++ b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -@@ -24,6 +24,28 @@ public class MagmaCube extends Slime { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.magmaCubeRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.magmaCubeRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.magmaCubeControllable; -+ } -+ -+ @Override -+ public float getJumpPower() { -+ return 0.42F * this.getBlockJumpFactor(); // from EntityLiving -+ } -+ // Purpur end -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); - } -@@ -64,11 +86,12 @@ public class MagmaCube extends Slime { - } - - @Override -- protected void jumpFromGround() { -+ public void jumpFromGround() { // Purpur - protected -> public - Vec3 vec3 = this.getDeltaMovement(); - float f = (float)this.getSize() * 0.1F; - this.setDeltaMovement(vec3.x, (double)(this.getJumpPower() + f), vec3.z); - this.hasImpulse = true; -+ this.actualJump = false; // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index 68f8945292753535a3b73acb9f48c1594f0789a4..03c873b830f45d848af076ac7921fc4d019f69c8 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -59,6 +59,64 @@ public class Phantom extends FlyingMob implements Enemy { - this.lookControl = new Phantom.PhantomLookControl(this, this); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.phantomRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.phantomRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.phantomControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.phantomMaxY; -+ } -+ -+ @Override -+ public void travel(Vec3 vec3) { -+ super.travel(vec3); -+ if (getRider() != null && this.isControllable() && !onGround) { -+ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); -+ setSpeed(speed); -+ Vec3 mot = getDeltaMovement(); -+ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed)); -+ setDeltaMovement(mot.scale(0.9D)); -+ } -+ } -+ -+ public static net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder createAttributes() { -+ return Monster.createMonsterAttributes().add(Attributes.FLYING_SPEED, 3.0D); -+ } -+ -+ @Override -+ public boolean onSpacebar() { -+ if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.special.phantom")) { -+ shoot(); -+ } -+ return false; -+ } -+ -+ public boolean shoot() { -+ org.bukkit.Location loc = ((org.bukkit.entity.LivingEntity) getBukkitEntity()).getEyeLocation(); -+ loc.setPitch(-loc.getPitch()); -+ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(100).add(loc.toVector()); -+ -+ org.purpurmc.purpur.entity.PhantomFlames flames = new org.purpurmc.purpur.entity.PhantomFlames(level(), this); -+ flames.canGrief = level().purpurConfig.phantomAllowGriefing; -+ flames.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), 1.0F, 5.0F); -+ level().addFreshEntity(flames); -+ return true; -+ } -+ // Purpur end -+ - @Override - public boolean isFlapping() { - return (this.getUniqueFlapTickOffset() + this.tickCount) % Phantom.TICKS_PER_FLAP == 0; -@@ -71,9 +129,11 @@ public class Phantom extends FlyingMob implements Enemy { - - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new Phantom.PhantomAttackStrategyGoal()); - this.goalSelector.addGoal(2, new Phantom.PhantomSweepAttackGoal()); - this.goalSelector.addGoal(3, new Phantom.PhantomCircleAroundAnchorGoal()); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal()); - } - -@@ -139,6 +199,7 @@ public class Phantom extends FlyingMob implements Enemy { - @Override - public void aiStep() { - if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API -+ if (getRider() == null || !this.isControllable()) // Purpur - this.igniteForSeconds(8); - } - -@@ -254,7 +315,7 @@ public class Phantom extends FlyingMob implements Enemy { - private AttackPhase() {} - } - -- private class PhantomMoveControl extends MoveControl { -+ private class PhantomMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - - private float speed = 0.1F; - -@@ -262,8 +323,19 @@ public class Phantom extends FlyingMob implements Enemy { - super(entity); - } - -+ // Purpur start -+ public void purpurTick(Player rider) { -+ if (!Phantom.this.onGround) { -+ // phantom is always in motion when flying -+ // TODO - FIX THIS -+ // rider.setForward(1.0F); -+ } -+ super.purpurTick(rider); -+ } -+ // Purpur end -+ - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (Phantom.this.horizontalCollision) { - Phantom.this.setYRot(Phantom.this.getYRot() + 180.0F); - this.speed = 0.1F; -@@ -309,14 +381,20 @@ public class Phantom extends FlyingMob implements Enemy { - } - } - -- private class PhantomLookControl extends LookControl { -+ private class PhantomLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - - public PhantomLookControl(final Phantom entity, final Mob phantom) { - super(phantom); - } - -+ // Purpur start -+ public void purpurTick(Player rider) { -+ setYawPitch(rider.getYRot(), -rider.xRotO * 0.75F); -+ } -+ // Purpur end -+ - @Override -- public void tick() {} -+ public void vanillaTick() {} // Purpur - } - - private class PhantomBodyRotationControl extends BodyRotationControl { -diff --git a/src/main/java/net/minecraft/world/entity/monster/Pillager.java b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -index ac411202c0029052a962b51b015da191b124de5f..6bfe582390dcb6111dcaf8325bd2773b9f5fd6a9 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Pillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -@@ -58,15 +58,34 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.pillagerRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pillagerRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.pillagerControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - super.registerGoals(); - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F)); // Paper - decomp fix - this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0D, 8.0F)); - this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); - this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0F, 1.0F)); - this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 15.0F)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers()); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index 2d7b7c949faaaaae94c0043132a4a822f55df104..1248a48c0146258d14efcaa805a82ce1a79c623d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -68,14 +68,39 @@ public class Ravager extends Raider { - this.setPathfindingMalus(PathType.LEAVES, 0.0F); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.ravagerRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ravagerRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.ravagerControllable; -+ } -+ -+ @Override -+ public void onMount(Player rider) { -+ super.onMount(rider); -+ getNavigation().stop(); -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - super.registerGoals(); - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, true)); - this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4D)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); - this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(2, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers()); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true)); - this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true, (entityliving) -> { -@@ -128,7 +153,7 @@ public class Ravager extends Raider { - @Override - public void aiStep() { - super.aiStep(); -- if (this.isAlive()) { -+ if (this.isAlive() && (getRider() == null || !this.isControllable())) { // Purpur - if (this.isImmobile()) { - this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.0D); - } else { -diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index 5215fa54666979ef4da074ddfdb082e7274f2957..78433d0b7624019018012c55e8dd6fec029f8cd1 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -97,12 +97,31 @@ public class Shulker extends AbstractGolem implements VariantHolder(this, Player.class, true)); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -index 5642bddc8268d70e5bb5446b65be1d8ce34feb9b..2f4f38fe7b7640b6658884b826d7f7a335370bd3 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -@@ -26,6 +26,23 @@ public class Skeleton extends AbstractSkeleton { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.skeletonRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.skeletonRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.skeletonControllable; -+ } -+ // Purpur end -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java -index f223e78eb1204bbf5f2de38a7ce5b663800f7dc4..2c73e80d916529cb0433846a2e57bc845bf7f3d4 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Slime.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java -@@ -61,6 +61,7 @@ public class Slime extends Mob implements Enemy { - public float squish; - public float oSquish; - private boolean wasOnGround; -+ protected boolean actualJump; // Purpur - - public Slime(EntityType type, Level world) { - super(type, world); -@@ -68,12 +69,48 @@ public class Slime extends Mob implements Enemy { - this.moveControl = new Slime.SlimeMoveControl(this); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.slimeRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.slimeRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.slimeControllable; -+ } -+ -+ @Override -+ public float getJumpPower() { -+ float height = super.getJumpPower(); -+ return getRider() != null && this.isControllable() && actualJump ? height * 1.5F : height; -+ } -+ -+ @Override -+ public boolean onSpacebar() { -+ if (onGround && getRider() != null && this.isControllable()) { -+ actualJump = true; -+ if (getRider().getForwardMot() == 0 || getRider().getStrafeMot() == 0) { -+ jumpFromGround(); // jump() here if not moving -+ } -+ } -+ return true; // do not jump() in wasd controller, let vanilla controller handle -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new Slime.SlimeFloatGoal(this)); - this.goalSelector.addGoal(2, new Slime.SlimeAttackGoal(this)); - this.goalSelector.addGoal(3, new Slime.SlimeRandomDirectionGoal(this)); - this.goalSelector.addGoal(5, new Slime.SlimeKeepOnJumpingGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving) -> { - return Math.abs(entityliving.getY() - this.getY()) <= 4.0D; - })); -@@ -382,11 +419,12 @@ public class Slime extends Mob implements Enemy { - } - - @Override -- protected void jumpFromGround() { -+ public void jumpFromGround() { // Purpur - protected -> public - Vec3 vec3d = this.getDeltaMovement(); - - this.setDeltaMovement(vec3d.x, (double) this.getJumpPower(), vec3d.z); - this.hasImpulse = true; -+ this.actualJump = false; // Purpur - } - - @Nullable -@@ -420,7 +458,7 @@ public class Slime extends Mob implements Enemy { - return super.getDefaultDimensions(pose).scale((float) this.getSize()); - } - -- private static class SlimeMoveControl extends MoveControl { -+ private static class SlimeMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - - private float yRot; - private int jumpDelay; -@@ -439,21 +477,33 @@ public class Slime extends Mob implements Enemy { - } - - public void setWantedMovement(double speed) { -- this.speedModifier = speed; -+ this.setSpeedModifier(speed); // Purpur - this.operation = MoveControl.Operation.MOVE_TO; - } - - @Override - public void tick() { -+ // Purpur start -+ if (slime.getRider() != null && slime.isControllable()) { -+ purpurTick(slime.getRider()); -+ if (slime.getForwardMot() != 0 || slime.getStrafeMot() != 0) { -+ if (jumpDelay > 10) { -+ jumpDelay = 6; -+ } -+ } else { -+ jumpDelay = 20; -+ } -+ } else { -+ // Purpur end - this.mob.setYRot(this.rotlerp(this.mob.getYRot(), this.yRot, 90.0F)); - this.mob.yHeadRot = this.mob.getYRot(); - this.mob.yBodyRot = this.mob.getYRot(); -- if (this.operation != MoveControl.Operation.MOVE_TO) { -+ } if ((slime.getRider() == null || !slime.isControllable()) && this.operation != MoveControl.Operation.MOVE_TO) { // Purpur - this.mob.setZza(0.0F); - } else { - this.operation = MoveControl.Operation.WAIT; - if (this.mob.onGround()) { -- this.mob.setSpeed((float) (this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); -+ this.mob.setSpeed((float) (this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (slime.getRider() != null && slime.isControllable() && (slime.getRider().getForwardMot() != 0 || slime.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur - if (this.jumpDelay-- <= 0) { - this.jumpDelay = this.slime.getJumpDelay(); - if (this.isAggressive) { -@@ -470,7 +520,7 @@ public class Slime extends Mob implements Enemy { - this.mob.setSpeed(0.0F); - } - } else { -- this.mob.setSpeed((float) (this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); -+ this.mob.setSpeed((float) (this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (slime.getRider() != null && slime.isControllable() && (slime.getRider().getForwardMot() != 0 || slime.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur - } - - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java -index fa0316e9d2a4cf213982994dc8bf310299cca984..87f63373ccef3de9ce77a92933ff332be4fd6305 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Spider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java -@@ -51,9 +51,27 @@ public class Spider extends Monster { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.spiderRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.spiderRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.spiderControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(1, new FloatGoal(this)); -+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Armadillo.class, 6.0F, 1.0D, 1.2D, (entityliving) -> { - return !((Armadillo) entityliving).isScared(); - })); -@@ -62,6 +80,7 @@ public class Spider extends Monster { - this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8D)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); - this.targetSelector.addGoal(2, new Spider.SpiderTargetGoal<>(this, Player.class)); - this.targetSelector.addGoal(3, new Spider.SpiderTargetGoal<>(this, IronGolem.class)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Stray.java b/src/main/java/net/minecraft/world/entity/monster/Stray.java -index 207a649d737adff440bd3f7cba15b0dbca338a35..44006bcb7d70661a6990e3fc4375dd6da34517e0 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Stray.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Stray.java -@@ -21,6 +21,23 @@ public class Stray extends AbstractSkeleton { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.strayRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.strayRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.strayControllable; -+ } -+ // Purpur end -+ - public static boolean checkStraySpawnRules(EntityType type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - BlockPos blockPos = pos; - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java -index fe85900a610afd0b237d8b5a164181c03afbdfc7..7e5ad9d52db7a39be60e0b2f24e13e8ed82785e1 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Strider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java -@@ -97,6 +97,23 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.striderRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.striderRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.striderControllable; -+ } -+ // Purpur end -+ - public static boolean checkStriderSpawnRules(EntityType type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); - -@@ -158,6 +175,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - @Override - protected void registerGoals() { - this.goalSelector.addGoal(1, new PanicGoal(this, 1.65D)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.temptGoal = new TemptGoal(this, 1.4D, (itemstack) -> { - return itemstack.is(ItemTags.STRIDER_TEMPT_ITEMS); -@@ -468,7 +486,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - if (!enuminteractionresult.consumesAction()) { - ItemStack itemstack = player.getItemInHand(hand); - -- return itemstack.is(Items.SADDLE) ? itemstack.interactLivingEntity(player, this, hand) : InteractionResult.PASS; -+ return itemstack.is(Items.SADDLE) ? itemstack.interactLivingEntity(player, this, hand) : tryRide(player, hand); // Purpur - } else { - if (flag && !this.isSilent()) { - this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.STRIDER_EAT, this.getSoundSource(), 1.0F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java -index fd3b37dde54623ba38186efb2a64d364c86b81d2..98c9d7080595a5d9ffa3d65a153780b68aec0e47 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vex.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java -@@ -60,6 +60,50 @@ public class Vex extends Monster implements TraceableEntity { - this.xpReward = 3; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.vexRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vexRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.vexControllable; -+ } -+ -+ @Override -+ public double getMaxY() { -+ return level().purpurConfig.vexMaxY; -+ } -+ -+ @Override -+ public void travel(Vec3 vec3) { -+ super.travel(vec3); -+ if (getRider() != null && this.isControllable()) { -+ float speed; -+ if (onGround) { -+ speed = (float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F; -+ } else { -+ speed = (float) getAttributeValue(Attributes.FLYING_SPEED); -+ } -+ setSpeed(speed); -+ Vec3 mot = getDeltaMovement(); -+ move(MoverType.SELF, mot.multiply(speed, 1.0, speed)); -+ setDeltaMovement(mot.scale(0.9D)); -+ } -+ } -+ -+ @Override -+ public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { -+ return false; // no fall damage please -+ } -+ // Purpur end -+ - @Override - public boolean isFlapping() { - return this.tickCount % Vex.TICKS_PER_FLAP == 0; -@@ -73,7 +117,7 @@ public class Vex extends Monster implements TraceableEntity { - - @Override - public void tick() { -- this.noPhysics = true; -+ this.noPhysics = getRider() == null || !this.isControllable(); // Purpur - super.tick(); - this.noPhysics = false; - this.setNoGravity(true); -@@ -88,17 +132,19 @@ public class Vex extends Monster implements TraceableEntity { - protected void registerGoals() { - super.registerGoals(); - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(4, new Vex.VexChargeAttackGoal()); - this.goalSelector.addGoal(8, new Vex.VexRandomMoveGoal()); - this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); - this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers()); - this.targetSelector.addGoal(2, new Vex.VexCopyOwnerTargetGoal(this)); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true)); - } - - public static AttributeSupplier.Builder createAttributes() { -- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0D).add(Attributes.ATTACK_DAMAGE, 4.0D); -+ return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0D).add(Attributes.ATTACK_DAMAGE, 4.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur; - } - - @Override -@@ -230,14 +276,14 @@ public class Vex extends Monster implements TraceableEntity { - this.setDropChance(EquipmentSlot.MAINHAND, 0.0F); - } - -- private class VexMoveControl extends MoveControl { -+ private class VexMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - - public VexMoveControl(final Vex entityvex) { - super(entityvex); - } - - @Override -- public void tick() { -+ public void vanillaTick() { // Purpur - if (this.operation == MoveControl.Operation.MOVE_TO) { - Vec3 vec3d = new Vec3(this.wantedX - Vex.this.getX(), this.wantedY - Vex.this.getY(), this.wantedZ - Vex.this.getZ()); - double d0 = vec3d.length(); -@@ -246,7 +292,7 @@ public class Vex extends Monster implements TraceableEntity { - this.operation = MoveControl.Operation.WAIT; - Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().scale(0.5D)); - } else { -- Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3d.scale(this.speedModifier * 0.05D / d0))); -+ Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3d.scale(this.getSpeedModifier() * 0.05D / d0))); // Purpur - if (Vex.this.getTarget() == null) { - Vec3 vec3d1 = Vex.this.getDeltaMovement(); - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -index b3da310d6fd1d533da805c38c2f449cf06d01492..c6d12c939cd3fbd9facf88cdc0c7c51744089484 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -@@ -50,14 +50,33 @@ public class Vindicator extends AbstractIllager { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.vindicatorRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vindicatorRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.vindicatorControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - super.registerGoals(); - this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new Vindicator.VindicatorBreakDoorGoal(this)); - this.goalSelector.addGoal(2, new AbstractIllager.RaiderOpenDoorGoal(this)); - this.goalSelector.addGoal(3, new Raider.HoldGroundAttackGoal(this, 10.0F)); - this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, false)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java -index 5803c1d36b769f0186baa0665976749765b4cb61..b5f44495f0a384c8a7d8d96e3a0f16999fba86fe 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Witch.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java -@@ -55,6 +55,23 @@ public class Witch extends Raider implements RangedAttackMob { - super(type, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.witchRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witchRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.witchControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - super.registerGoals(); -@@ -63,10 +80,12 @@ public class Witch extends Raider implements RangedAttackMob { - }); - this.attackPlayersGoal = new NearestAttackableWitchTargetGoal<>(this, Player.class, 10, true, false, (Predicate) null); - this.goalSelector.addGoal(1, new FloatGoal(this)); -+ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0D, 60, 10.0F)); - this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(3, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[]{Raider.class})); - this.targetSelector.addGoal(2, this.healRaidersGoal); - this.targetSelector.addGoal(3, this.attackPlayersGoal); -diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -index 3f1191795e58f31b7e2fe34ef2774df13b9a789f..355ed17da77256c84d8ba7d4d99b5c73d729a48d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -@@ -32,6 +32,23 @@ public class WitherSkeleton extends AbstractSkeleton { - this.setPathfindingMalus(PathType.LAVA, 8.0F); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.witherSkeletonRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherSkeletonRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.witherSkeletonControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -index cfdb2b793f11544ec5e2d1e726134089994b2b0f..2cb65bc3e2a2f990f4036f4f0418d9cd5226381e 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -@@ -80,6 +80,23 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { - this.xpReward = 5; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.zoglinRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zoglinRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.zoglinControllable; -+ } -+ // Purpur end -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); -@@ -235,6 +252,7 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("zoglinBrain"); -+ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider - this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); - this.updateActivity(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index e42dfc62bb179be1ab01b0096c05c6549d38abbc..7c78b243164a517818565845b1a6c7d40c8839d8 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -104,11 +104,30 @@ public class Zombie extends Monster { - this(EntityType.ZOMBIE, world); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.zombieRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.zombieControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper - Add zombie targets turtle egg config - this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.addBehaviourGoals(); - } - -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index f38acc96f71298e40ce9433e7759fd223ca55e48..cc3d9f47ef6d1efa589c8bed5c51ed9e61d7c07d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -80,6 +80,23 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - }); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.zombieVillagerRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieVillagerRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.zombieVillagerControllable; -+ } -+ // Purpur end -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -index a6def4133f06c41be287e9942643e80a7b8e8218..2ff0ce04ce210b77c555f59967182ed4dd3fe9aa 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -62,6 +62,23 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - this.setPathfindingMalus(PathType.LAVA, 8.0F); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.zombifiedPiglinRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombifiedPiglinRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.zombifiedPiglinControllable; -+ } -+ // Purpur end -+ - @Override - public void setPersistentAngerTarget(@Nullable UUID angryAt) { - this.persistentAngerTarget = angryAt; -diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index c583d883118ded5e1884c757427dc5e73c10dd27..6e86e0597af66bad8f2e97661b588e950b2679ba 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -90,6 +90,23 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - this.xpReward = 5; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.hoglinRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.hoglinRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.hoglinControllable; -+ } -+ // Purpur end -+ - @Override - public boolean canBeLeashed(Player player) { - return !this.isLeashed(); -@@ -156,6 +173,7 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("hoglinBrain"); -+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); - HoglinAi.updateActivity(this); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index a8ab486c7e11ec137da48174af6f1030dfd48056..6632cab4ed43bbfd10b4d8f3b2c447a35eba735e 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -94,6 +94,23 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - this.xpReward = 5; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.piglinRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.piglinRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.piglinControllable; -+ } -+ // Purpur end -+ - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); -@@ -297,6 +314,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("piglinBrain"); -+ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider // Purpur - TODO: Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - PiglinAi.updateActivity(this); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -index fcadd7f28ccb81bbb36e97d8b8d8a8ba3f3d6a16..17e2457bc83e7ee4402c10ee7d2ef5aa36901565 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -@@ -62,6 +62,23 @@ public class PiglinBrute extends AbstractPiglin { - this.xpReward = 20; - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.piglinBruteRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.piglinBruteRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.piglinBruteControllable; -+ } -+ // Purpur end -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 50.0).add(Attributes.MOVEMENT_SPEED, 0.35F).add(Attributes.ATTACK_DAMAGE, 7.0); - } -@@ -107,6 +124,7 @@ public class PiglinBrute extends AbstractPiglin { - @Override - protected void customServerAiStep() { - this.level().getProfiler().push("piglinBruteBrain"); -+ if (getRider() == null || this.isControllable()) // Purpur - only use brain if no rider - this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); - PiglinBruteAi.updateActivity(this); -diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index ddd60be52dce5773c80934be5aa5705db239e3dd..9f5325444cc4f64fc88f85794fbad09ddd4f7860 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -+++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -@@ -123,8 +123,32 @@ public class Warden extends Monster implements VibrationSystem { - this.setPathfindingMalus(PathType.LAVA, 8.0F); - this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); - this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); -+ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.5F); // Purpur - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.wardenRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wardenRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.wardenControllable; -+ } -+ -+ @Override -+ protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -+ } -+ // Purpur end -+ - @Override - public Packet getAddEntityPacket() { - return new ClientboundAddEntityPacket(this, this.hasPose(Pose.EMERGING) ? 1 : 0); -@@ -392,17 +416,14 @@ public class Warden extends Monster implements VibrationSystem { - - @Contract("null->false") - public boolean canTargetEntity(@Nullable Entity entity) { -- boolean flag; -- -+ if (getRider() != null && isControllable()) return false; // Purpur - if (entity instanceof LivingEntity entityliving) { - if (this.level() == entity.level() && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity) && !this.isAlliedTo(entity) && entityliving.getType() != EntityType.ARMOR_STAND && entityliving.getType() != EntityType.WARDEN && !entityliving.isInvulnerable() && !entityliving.isDeadOrDying() && this.level().getWorldBorder().isWithinBounds(entityliving.getBoundingBox())) { -- flag = true; -- return flag; -+ return true; // Purpur - wtf - } - } - -- flag = false; -- return flag; -+ return false; // Purpur - wtf - } - - public static void applyDarknessAround(ServerLevel world, Vec3 pos, @Nullable Entity entity, int range) { -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index a7930f9875aa4aca997caaead46ecdc21e5e11d7..980f48b546f0da5696c110357ea42352a48fbd42 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -156,6 +156,28 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - this.setVillagerData(this.getVillagerData().setType(type).setProfession(VillagerProfession.NONE)); - } - -+ // Purpur start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.villagerRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.villagerRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.villagerControllable; -+ } -+ -+ @Override -+ protected void registerGoals() { -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); -+ } -+ // Purpur end -+ - @Override - public Brain getBrain() { - return (Brain) super.getBrain(); // CraftBukkit - decompile error -@@ -256,6 +278,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - // Paper end - this.level().getProfiler().push("villagerBrain"); - if (!inactive) this.getBrain().tick((ServerLevel) this.level(), this); // Paper -+ /*// Purpur start // Purpur - TODO: Pufferfish -+ if (!inactive && (getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider -+ this.getBrain().tick((ServerLevel) this.level(), this); // Paper -+ } -+ // Purpur end*/ // Purpur - TODO: Pufferfish - this.level().getProfiler().pop(); - if (this.assignProfessionWhenSpawned) { - this.assignProfessionWhenSpawned = false; -@@ -312,7 +339,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - if (!itemstack.is(Items.VILLAGER_SPAWN_EGG) && this.isAlive() && !this.isTrading() && !this.isSleeping()) { - if (this.isBaby()) { - this.setUnhappy(); -- return InteractionResult.sidedSuccess(this.level().isClientSide); -+ return tryRide(player, hand, InteractionResult.sidedSuccess(this.level().isClientSide)); // Purpur - } else { - boolean flag = this.getOffers().isEmpty(); - -@@ -325,8 +352,9 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - } - - if (flag) { -- return InteractionResult.sidedSuccess(this.level().isClientSide); -+ return tryRide(player, hand, InteractionResult.sidedSuccess(this.level().isClientSide)); // Purpur - } else { -+ if (level().purpurConfig.villagerRidable && itemstack.isEmpty()) return tryRide(player, hand); // Purpur - if (!this.level().isClientSide && !this.offers.isEmpty()) { - this.startTrading(player); - } -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index 0854e9b7ee2e6b23b6c1ee6a324a5a253c9d4679..6bdf3d1e3652a661282d61f1dc2bfc2712339953 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -71,6 +71,23 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - //this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader // Paper - move back to MobSpawnerTrader - Vanilla behavior is that only traders spawned by it have this value set. - } - -+ // Purpur - start -+ @Override -+ public boolean isRidable() { -+ return level().purpurConfig.wanderingTraderRidable; -+ } -+ -+ @Override -+ public boolean dismountsUnderwater() { -+ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wanderingTraderRidableInWater; -+ } -+ -+ @Override -+ public boolean isControllable() { -+ return level().purpurConfig.wanderingTraderControllable; -+ } -+ // Purpur end -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); -@@ -118,8 +135,9 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - } - - if (this.getOffers().isEmpty()) { -- return InteractionResult.sidedSuccess(this.level().isClientSide); -+ return tryRide(player, hand, InteractionResult.sidedSuccess(this.level().isClientSide)); // Purpur - } else { -+ if (level().purpurConfig.wanderingTraderRidable && itemstack.isEmpty()) return tryRide(player, hand); // Purpur - if (!this.level().isClientSide) { - this.setTradingPlayer(player); - this.openTradingScreen(player, this.getDisplayName(), 1); -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 093d1388ff90ad59110a37536b6639f939549068..66753bffa1e21ac5d5aaab4bc6cccb833774ddf5 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -206,6 +206,19 @@ public abstract class Player extends LivingEntity { - } - // CraftBukkit end - -+ // Purpur start -+ public abstract void resetLastActionTime(); -+ -+ @Override -+ public boolean processClick(InteractionHand hand) { -+ Entity vehicle = getRootVehicle(); -+ if (vehicle != null && vehicle.getRider() == this) { -+ return vehicle.onClick(hand); -+ } -+ return false; -+ } -+ // Purpur end -+ - public Player(Level world, BlockPos pos, float yaw, GameProfile gameProfile) { - super(EntityType.PLAYER, world); - this.lastItemInMainHand = ItemStack.EMPTY; -diff --git a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java -index ffd01d24cbfc90e2a8807757e61b2cf20a944354..a419820d5001079ed839e67c757bc8fa591a20b3 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java -@@ -30,6 +30,12 @@ public class LlamaSpit extends Projectile { - this.setPos(owner.getX() - (double) (owner.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(owner.yBodyRot * 0.017453292F), owner.getEyeY() - 0.10000000149011612D, owner.getZ() + (double) (owner.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(owner.yBodyRot * 0.017453292F)); - } - -+ // Purpur start -+ public void super_tick() { -+ super.tick(); -+ } -+ // Purpur end -+ - @Override - protected double getDefaultGravity() { - return 0.06D; -diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -index 55b4b5ad5f084c9a271a716d076672478d6486ba..4117260538e47c978ea31c76f439d43369ebedfb 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -@@ -111,6 +111,14 @@ public class WitherSkull extends AbstractHurtingProjectile { - - } - -+ // Purpur start -+ @Override -+ public boolean canHitEntity(Entity target) { -+ // do not hit rider -+ return target != this.getRider() && super.canHitEntity(target); -+ } -+ // Purpur end -+ - @Override - public boolean hurt(DamageSource source, float amount) { - return false; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index a2d336ceb52b63db5c03432ee7bc94dc6a742b82..a6268b3df9691278606501284b5504da718703c2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -1280,4 +1280,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return this.getHandle().getScoreboardName(); - } - // Paper end - entity scoreboard name -+ -+ // Purpur start -+ @Override -+ public org.bukkit.entity.Player getRider() { -+ net.minecraft.world.entity.player.Player rider = getHandle().getRider(); -+ return rider != null ? (org.bukkit.entity.Player) rider.getBukkitEntity() : null; -+ } -+ -+ @Override -+ public boolean hasRider() { -+ return getHandle().getRider() != null; -+ } -+ -+ @Override -+ public boolean isRidable() { -+ return getHandle().isRidable(); -+ } -+ -+ @Override -+ public boolean isRidableInWater() { -+ return !getHandle().dismountsUnderwater(); -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 547ab158cd0cbf51da06ea97740cfce34bca651b..a49193a023bbd9b65bcd3652dc9c241720500755 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -592,6 +592,15 @@ public class CraftEventFactory { - // Paper end - craftServer.getPluginManager().callEvent(event); - -+ // Purpur start -+ if (who != null) { -+ switch (action) { -+ case LEFT_CLICK_BLOCK, LEFT_CLICK_AIR -> who.processClick(InteractionHand.MAIN_HAND); -+ case RIGHT_CLICK_BLOCK, RIGHT_CLICK_AIR -> who.processClick(InteractionHand.OFF_HAND); -+ } -+ } -+ // Purpur end -+ - return event; - } - -@@ -1179,6 +1188,7 @@ public class CraftEventFactory { - EntityDamageEvent event; - if (damager != null) { - event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions, critical); -+ damager.processClick(InteractionHand.MAIN_HAND); // Purpur - } else { - event = new EntityDamageEvent(damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions); - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 19161d9736b626811423deefedd045abe60360cc..9287376ae1374e355857108d722f1be2fd7276d9 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -172,4 +172,9 @@ public class PurpurConfig { - } - return builder.build(); - } -+ -+ public static String cannotRideMob = "You cannot mount that mob"; -+ private static void messages() { -+ cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); -+ } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 5f0732c2b8f85185b6dfc1db3119c22e8be7f5da..3eae97d610d8f61528b87039723ef4ce2dc75c91 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -89,4 +89,726 @@ public class PurpurWorldConfig { - final Map value = PurpurConfig.getMap("world-settings." + worldName + "." + path, null); - return value.isEmpty() ? fallback : value; - } -+ -+ public boolean babiesAreRidable = true; -+ public boolean untamedTamablesAreRidable = true; -+ public boolean useNightVisionWhenRiding = false; -+ public boolean useDismountsUnderwaterTag = true; -+ private void ridableSettings() { -+ babiesAreRidable = getBoolean("ridable-settings.babies-are-ridable", babiesAreRidable); -+ untamedTamablesAreRidable = getBoolean("ridable-settings.untamed-tamables-are-ridable", untamedTamablesAreRidable); -+ useNightVisionWhenRiding = getBoolean("ridable-settings.use-night-vision", useNightVisionWhenRiding); -+ useDismountsUnderwaterTag = getBoolean("ridable-settings.use-dismounts-underwater-tag", useDismountsUnderwaterTag); -+ } -+ -+ public boolean allayRidable = false; -+ public boolean allayRidableInWater = true; -+ public boolean allayControllable = true; -+ private void allaySettings() { -+ allayRidable = getBoolean("mobs.allay.ridable", allayRidable); -+ allayRidableInWater = getBoolean("mobs.allay.ridable-in-water", allayRidableInWater); -+ allayControllable = getBoolean("mobs.allay.controllable", allayControllable); -+ } -+ -+ public boolean axolotlRidable = false; -+ public boolean axolotlControllable = true; -+ private void axolotlSettings() { -+ axolotlRidable = getBoolean("mobs.axolotl.ridable", axolotlRidable); -+ axolotlControllable = getBoolean("mobs.axolotl.controllable", axolotlControllable); -+ } -+ -+ public boolean batRidable = false; -+ public boolean batRidableInWater = true; -+ public boolean batControllable = true; -+ public double batMaxY = 320D; -+ private void batSettings() { -+ batRidable = getBoolean("mobs.bat.ridable", batRidable); -+ batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater); -+ batControllable = getBoolean("mobs.bat.controllable", batControllable); -+ batMaxY = getDouble("mobs.bat.ridable-max-y", batMaxY); -+ } -+ -+ public boolean beeRidable = false; -+ public boolean beeRidableInWater = true; -+ public boolean beeControllable = true; -+ public double beeMaxY = 320D; -+ private void beeSettings() { -+ beeRidable = getBoolean("mobs.bee.ridable", beeRidable); -+ beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); -+ beeControllable = getBoolean("mobs.bee.controllable", beeControllable); -+ beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY); -+ } -+ -+ public boolean blazeRidable = false; -+ public boolean blazeRidableInWater = true; -+ public boolean blazeControllable = true; -+ public double blazeMaxY = 320D; -+ private void blazeSettings() { -+ blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); -+ blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); -+ blazeControllable = getBoolean("mobs.blaze.controllable", blazeControllable); -+ blazeMaxY = getDouble("mobs.blaze.ridable-max-y", blazeMaxY); -+ } -+ -+ public boolean camelRidableInWater = false; -+ private void camelSettings() { -+ camelRidableInWater = getBoolean("mobs.camel.ridable-in-water", camelRidableInWater); -+ } -+ -+ public boolean catRidable = false; -+ public boolean catRidableInWater = true; -+ public boolean catControllable = true; -+ private void catSettings() { -+ catRidable = getBoolean("mobs.cat.ridable", catRidable); -+ catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); -+ catControllable = getBoolean("mobs.cat.controllable", catControllable); -+ } -+ -+ public boolean caveSpiderRidable = false; -+ public boolean caveSpiderRidableInWater = true; -+ public boolean caveSpiderControllable = true; -+ private void caveSpiderSettings() { -+ caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable); -+ caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater); -+ caveSpiderControllable = getBoolean("mobs.cave_spider.controllable", caveSpiderControllable); -+ } -+ -+ public boolean chickenRidable = false; -+ public boolean chickenRidableInWater = false; -+ public boolean chickenControllable = true; -+ private void chickenSettings() { -+ chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); -+ chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); -+ chickenControllable = getBoolean("mobs.chicken.controllable", chickenControllable); -+ } -+ -+ public boolean codRidable = false; -+ public boolean codControllable = true; -+ private void codSettings() { -+ codRidable = getBoolean("mobs.cod.ridable", codRidable); -+ codControllable = getBoolean("mobs.cod.controllable", codControllable); -+ } -+ -+ public boolean cowRidable = false; -+ public boolean cowRidableInWater = true; -+ public boolean cowControllable = true; -+ private void cowSettings() { -+ cowRidable = getBoolean("mobs.cow.ridable", cowRidable); -+ cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); -+ cowControllable = getBoolean("mobs.cow.controllable", cowControllable); -+ } -+ -+ public boolean creeperRidable = false; -+ public boolean creeperRidableInWater = true; -+ public boolean creeperControllable = true; -+ private void creeperSettings() { -+ creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); -+ creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -+ creeperControllable = getBoolean("mobs.creeper.controllable", creeperControllable); -+ } -+ -+ public boolean dolphinRidable = false; -+ public boolean dolphinControllable = true; -+ public int dolphinSpitCooldown = 20; -+ public float dolphinSpitSpeed = 1.0F; -+ public float dolphinSpitDamage = 2.0F; -+ private void dolphinSettings() { -+ dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); -+ dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable); -+ dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown); -+ dolphinSpitSpeed = (float) getDouble("mobs.dolphin.spit.speed", dolphinSpitSpeed); -+ dolphinSpitDamage = (float) getDouble("mobs.dolphin.spit.damage", dolphinSpitDamage); -+ } -+ -+ public boolean donkeyRidableInWater = false; -+ private void donkeySettings() { -+ donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); -+ } -+ -+ public boolean drownedRidable = false; -+ public boolean drownedRidableInWater = true; -+ public boolean drownedControllable = true; -+ private void drownedSettings() { -+ drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); -+ drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); -+ drownedControllable = getBoolean("mobs.drowned.controllable", drownedControllable); -+ } -+ -+ public boolean elderGuardianRidable = false; -+ public boolean elderGuardianControllable = true; -+ private void elderGuardianSettings() { -+ elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable); -+ elderGuardianControllable = getBoolean("mobs.elder_guardian.controllable", elderGuardianControllable); -+ } -+ -+ public boolean enderDragonRidable = false; -+ public boolean enderDragonRidableInWater = true; -+ public boolean enderDragonControllable = true; -+ public double enderDragonMaxY = 320D; -+ private void enderDragonSettings() { -+ enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); -+ enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); -+ enderDragonControllable = getBoolean("mobs.ender_dragon.controllable", enderDragonControllable); -+ enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY); -+ } -+ -+ public boolean endermanRidable = false; -+ public boolean endermanRidableInWater = true; -+ public boolean endermanControllable = true; -+ private void endermanSettings() { -+ endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); -+ endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -+ endermanControllable = getBoolean("mobs.enderman.controllable", endermanControllable); -+ } -+ -+ public boolean endermiteRidable = false; -+ public boolean endermiteRidableInWater = true; -+ public boolean endermiteControllable = true; -+ private void endermiteSettings() { -+ endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable); -+ endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater); -+ endermiteControllable = getBoolean("mobs.endermite.controllable", endermiteControllable); -+ } -+ -+ public boolean evokerRidable = false; -+ public boolean evokerRidableInWater = true; -+ public boolean evokerControllable = true; -+ private void evokerSettings() { -+ evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); -+ evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); -+ evokerControllable = getBoolean("mobs.evoker.controllable", evokerControllable); -+ } -+ -+ public boolean foxRidable = false; -+ public boolean foxRidableInWater = true; -+ public boolean foxControllable = true; -+ private void foxSettings() { -+ foxRidable = getBoolean("mobs.fox.ridable", foxRidable); -+ foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); -+ foxControllable = getBoolean("mobs.fox.controllable", foxControllable); -+ } -+ -+ public boolean frogRidable = false; -+ public boolean frogRidableInWater = true; -+ public boolean frogControllable = true; -+ public float frogRidableJumpHeight = 0.65F; -+ private void frogSettings() { -+ frogRidable = getBoolean("mobs.frog.ridable", frogRidable); -+ frogRidableInWater = getBoolean("mobs.frog.ridable-in-water", frogRidableInWater); -+ frogControllable = getBoolean("mobs.frog.controllable", frogControllable); -+ frogRidableJumpHeight = (float) getDouble("mobs.frog.ridable-jump-height", frogRidableJumpHeight); -+ } -+ -+ public boolean ghastRidable = false; -+ public boolean ghastRidableInWater = true; -+ public boolean ghastControllable = true; -+ public double ghastMaxY = 320D; -+ private void ghastSettings() { -+ ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); -+ ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater); -+ ghastControllable = getBoolean("mobs.ghast.controllable", ghastControllable); -+ ghastMaxY = getDouble("mobs.ghast.ridable-max-y", ghastMaxY); -+ } -+ -+ public boolean giantRidable = false; -+ public boolean giantRidableInWater = true; -+ public boolean giantControllable = true; -+ private void giantSettings() { -+ giantRidable = getBoolean("mobs.giant.ridable", giantRidable); -+ giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater); -+ giantControllable = getBoolean("mobs.giant.controllable", giantControllable); -+ } -+ -+ public boolean glowSquidRidable = false; -+ public boolean glowSquidControllable = true; -+ private void glowSquidSettings() { -+ glowSquidRidable = getBoolean("mobs.glow_squid.ridable", glowSquidRidable); -+ glowSquidControllable = getBoolean("mobs.glow_squid.controllable", glowSquidControllable); -+ } -+ -+ public boolean goatRidable = false; -+ public boolean goatRidableInWater = true; -+ public boolean goatControllable = true; -+ private void goatSettings() { -+ goatRidable = getBoolean("mobs.goat.ridable", goatRidable); -+ goatRidableInWater = getBoolean("mobs.goat.ridable-in-water", goatRidableInWater); -+ goatControllable = getBoolean("mobs.goat.controllable", goatControllable); -+ } -+ -+ public boolean guardianRidable = false; -+ public boolean guardianControllable = true; -+ private void guardianSettings() { -+ guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable); -+ guardianControllable = getBoolean("mobs.guardian.controllable", guardianControllable); -+ } -+ -+ public boolean hoglinRidable = false; -+ public boolean hoglinRidableInWater = true; -+ public boolean hoglinControllable = true; -+ private void hoglinSettings() { -+ hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); -+ hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); -+ hoglinControllable = getBoolean("mobs.hoglin.controllable", hoglinControllable); -+ } -+ -+ public boolean horseRidableInWater = false; -+ private void horseSettings() { -+ horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); -+ } -+ -+ public boolean huskRidable = false; -+ public boolean huskRidableInWater = true; -+ public boolean huskControllable = true; -+ private void huskSettings() { -+ huskRidable = getBoolean("mobs.husk.ridable", huskRidable); -+ huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); -+ huskControllable = getBoolean("mobs.husk.controllable", huskControllable); -+ } -+ -+ public boolean illusionerRidable = false; -+ public boolean illusionerRidableInWater = true; -+ public boolean illusionerControllable = true; -+ private void illusionerSettings() { -+ illusionerRidable = getBoolean("mobs.illusioner.ridable", illusionerRidable); -+ illusionerRidableInWater = getBoolean("mobs.illusioner.ridable-in-water", illusionerRidableInWater); -+ illusionerControllable = getBoolean("mobs.illusioner.controllable", illusionerControllable); -+ } -+ -+ public boolean ironGolemRidable = false; -+ public boolean ironGolemRidableInWater = true; -+ public boolean ironGolemControllable = true; -+ public boolean ironGolemCanSwim = false; -+ private void ironGolemSettings() { -+ ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); -+ ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); -+ ironGolemControllable = getBoolean("mobs.iron_golem.controllable", ironGolemControllable); -+ ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); -+ } -+ -+ public boolean llamaRidable = false; -+ public boolean llamaRidableInWater = false; -+ public boolean llamaControllable = true; -+ private void llamaSettings() { -+ llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); -+ llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); -+ llamaControllable = getBoolean("mobs.llama.controllable", llamaControllable); -+ } -+ -+ public boolean magmaCubeRidable = false; -+ public boolean magmaCubeRidableInWater = true; -+ public boolean magmaCubeControllable = true; -+ private void magmaCubeSettings() { -+ magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable); -+ magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater); -+ magmaCubeControllable = getBoolean("mobs.magma_cube.controllable", magmaCubeControllable); -+ } -+ -+ public boolean mooshroomRidable = false; -+ public boolean mooshroomRidableInWater = true; -+ public boolean mooshroomControllable = true; -+ private void mooshroomSettings() { -+ mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); -+ mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); -+ mooshroomControllable = getBoolean("mobs.mooshroom.controllable", mooshroomControllable); -+ } -+ -+ public boolean muleRidableInWater = false; -+ private void muleSettings() { -+ muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); -+ } -+ -+ public boolean ocelotRidable = false; -+ public boolean ocelotRidableInWater = true; -+ public boolean ocelotControllable = true; -+ private void ocelotSettings() { -+ ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); -+ ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); -+ ocelotControllable = getBoolean("mobs.ocelot.controllable", ocelotControllable); -+ } -+ -+ public boolean pandaRidable = false; -+ public boolean pandaRidableInWater = true; -+ public boolean pandaControllable = true; -+ private void pandaSettings() { -+ pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); -+ pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); -+ pandaControllable = getBoolean("mobs.panda.controllable", pandaControllable); -+ } -+ -+ public boolean parrotRidable = false; -+ public boolean parrotRidableInWater = true; -+ public boolean parrotControllable = true; -+ public double parrotMaxY = 320D; -+ private void parrotSettings() { -+ parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); -+ parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); -+ parrotControllable = getBoolean("mobs.parrot.controllable", parrotControllable); -+ parrotMaxY = getDouble("mobs.parrot.ridable-max-y", parrotMaxY); -+ } -+ -+ public boolean phantomRidable = false; -+ public boolean phantomRidableInWater = true; -+ public boolean phantomControllable = true; -+ public double phantomMaxY = 320D; -+ public float phantomFlameDamage = 1.0F; -+ public int phantomFlameFireTime = 8; -+ public boolean phantomAllowGriefing = false; -+ private void phantomSettings() { -+ phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); -+ phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -+ phantomControllable = getBoolean("mobs.phantom.controllable", phantomControllable); -+ phantomMaxY = getDouble("mobs.phantom.ridable-max-y", phantomMaxY); -+ phantomFlameDamage = (float) getDouble("mobs.phantom.flames.damage", phantomFlameDamage); -+ phantomFlameFireTime = getInt("mobs.phantom.flames.fire-time", phantomFlameFireTime); -+ phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing); -+ } -+ -+ public boolean pigRidable = false; -+ public boolean pigRidableInWater = false; -+ public boolean pigControllable = true; -+ private void pigSettings() { -+ pigRidable = getBoolean("mobs.pig.ridable", pigRidable); -+ pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); -+ pigControllable = getBoolean("mobs.pig.controllable", pigControllable); -+ } -+ -+ public boolean piglinRidable = false; -+ public boolean piglinRidableInWater = true; -+ public boolean piglinControllable = true; -+ private void piglinSettings() { -+ piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); -+ piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); -+ piglinControllable = getBoolean("mobs.piglin.controllable", piglinControllable); -+ } -+ -+ public boolean piglinBruteRidable = false; -+ public boolean piglinBruteRidableInWater = true; -+ public boolean piglinBruteControllable = true; -+ private void piglinBruteSettings() { -+ piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable); -+ piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater); -+ piglinBruteControllable = getBoolean("mobs.piglin_brute.controllable", piglinBruteControllable); -+ } -+ -+ public boolean pillagerRidable = false; -+ public boolean pillagerRidableInWater = true; -+ public boolean pillagerControllable = true; -+ private void pillagerSettings() { -+ pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); -+ pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); -+ pillagerControllable = getBoolean("mobs.pillager.controllable", pillagerControllable); -+ } -+ -+ public boolean polarBearRidable = false; -+ public boolean polarBearRidableInWater = true; -+ public boolean polarBearControllable = true; -+ private void polarBearSettings() { -+ polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); -+ polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); -+ polarBearControllable = getBoolean("mobs.polar_bear.controllable", polarBearControllable); -+ } -+ -+ public boolean pufferfishRidable = false; -+ public boolean pufferfishControllable = true; -+ private void pufferfishSettings() { -+ pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable); -+ pufferfishControllable = getBoolean("mobs.pufferfish.controllable", pufferfishControllable); -+ } -+ -+ public boolean rabbitRidable = false; -+ public boolean rabbitRidableInWater = true; -+ public boolean rabbitControllable = true; -+ private void rabbitSettings() { -+ rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); -+ rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); -+ rabbitControllable = getBoolean("mobs.rabbit.controllable", rabbitControllable); -+ } -+ -+ public boolean ravagerRidable = false; -+ public boolean ravagerRidableInWater = false; -+ public boolean ravagerControllable = true; -+ private void ravagerSettings() { -+ ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); -+ ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); -+ ravagerControllable = getBoolean("mobs.ravager.controllable", ravagerControllable); -+ } -+ -+ public boolean salmonRidable = false; -+ public boolean salmonControllable = true; -+ private void salmonSettings() { -+ salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable); -+ salmonControllable = getBoolean("mobs.salmon.controllable", salmonControllable); -+ } -+ -+ public boolean sheepRidable = false; -+ public boolean sheepRidableInWater = true; -+ public boolean sheepControllable = true; -+ private void sheepSettings() { -+ sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); -+ sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); -+ sheepControllable = getBoolean("mobs.sheep.controllable", sheepControllable); -+ } -+ -+ public boolean shulkerRidable = false; -+ public boolean shulkerRidableInWater = true; -+ public boolean shulkerControllable = true; -+ private void shulkerSettings() { -+ shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); -+ shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); -+ shulkerControllable = getBoolean("mobs.shulker.controllable", shulkerControllable); -+ } -+ -+ public boolean silverfishRidable = false; -+ public boolean silverfishRidableInWater = true; -+ public boolean silverfishControllable = true; -+ private void silverfishSettings() { -+ silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); -+ silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); -+ silverfishControllable = getBoolean("mobs.silverfish.controllable", silverfishControllable); -+ } -+ -+ public boolean skeletonRidable = false; -+ public boolean skeletonRidableInWater = true; -+ public boolean skeletonControllable = true; -+ private void skeletonSettings() { -+ skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); -+ skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); -+ skeletonControllable = getBoolean("mobs.skeleton.controllable", skeletonControllable); -+ } -+ -+ public boolean skeletonHorseRidable = false; -+ public boolean skeletonHorseRidableInWater = true; -+ public boolean skeletonHorseCanSwim = false; -+ private void skeletonHorseSettings() { -+ skeletonHorseRidable = getBoolean("mobs.skeleton_horse.ridable", skeletonHorseRidable); -+ skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater); -+ skeletonHorseCanSwim = getBoolean("mobs.skeleton_horse.can-swim", skeletonHorseCanSwim); -+ } -+ -+ public boolean slimeRidable = false; -+ public boolean slimeRidableInWater = true; -+ public boolean slimeControllable = true; -+ private void slimeSettings() { -+ slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable); -+ slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater); -+ slimeControllable = getBoolean("mobs.slime.controllable", slimeControllable); -+ } -+ -+ public boolean snowGolemRidable = false; -+ public boolean snowGolemRidableInWater = true; -+ public boolean snowGolemControllable = true; -+ public boolean snowGolemLeaveTrailWhenRidden = false; -+ private void snowGolemSettings() { -+ snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); -+ snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); -+ snowGolemControllable = getBoolean("mobs.snow_golem.controllable", snowGolemControllable); -+ snowGolemLeaveTrailWhenRidden = getBoolean("mobs.snow_golem.leave-trail-when-ridden", snowGolemLeaveTrailWhenRidden); -+ } -+ -+ public boolean snifferRidable = false; -+ public boolean snifferRidableInWater = true; -+ public boolean snifferControllable = true; -+ private void snifferSettings() { -+ snifferRidable = getBoolean("mobs.sniffer.ridable", snifferRidable); -+ snifferRidableInWater = getBoolean("mobs.sniffer.ridable-in-water", snifferRidableInWater); -+ snifferControllable = getBoolean("mobs.sniffer.controllable", snifferControllable); -+ } -+ -+ public boolean squidRidable = false; -+ public boolean squidControllable = true; -+ private void squidSettings() { -+ squidRidable = getBoolean("mobs.squid.ridable", squidRidable); -+ squidControllable = getBoolean("mobs.squid.controllable", squidControllable); -+ } -+ -+ public boolean spiderRidable = false; -+ public boolean spiderRidableInWater = false; -+ public boolean spiderControllable = true; -+ private void spiderSettings() { -+ spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable); -+ spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater); -+ spiderControllable = getBoolean("mobs.spider.controllable", spiderControllable); -+ } -+ -+ public boolean strayRidable = false; -+ public boolean strayRidableInWater = true; -+ public boolean strayControllable = true; -+ private void straySettings() { -+ strayRidable = getBoolean("mobs.stray.ridable", strayRidable); -+ strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater); -+ strayControllable = getBoolean("mobs.stray.controllable", strayControllable); -+ } -+ -+ public boolean striderRidable = false; -+ public boolean striderRidableInWater = false; -+ public boolean striderControllable = true; -+ private void striderSettings() { -+ striderRidable = getBoolean("mobs.strider.ridable", striderRidable); -+ striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); -+ striderControllable = getBoolean("mobs.strider.controllable", striderControllable); -+ } -+ -+ public boolean tadpoleRidable = false; -+ public boolean tadpoleRidableInWater = true; -+ public boolean tadpoleControllable = true; -+ private void tadpoleSettings() { -+ tadpoleRidable = getBoolean("mobs.tadpole.ridable", tadpoleRidable); -+ tadpoleRidableInWater = getBoolean("mobs.tadpole.ridable-in-water", tadpoleRidableInWater); -+ tadpoleControllable = getBoolean("mobs.tadpole.controllable", tadpoleControllable); -+ } -+ -+ public boolean traderLlamaRidable = false; -+ public boolean traderLlamaRidableInWater = false; -+ public boolean traderLlamaControllable = true; -+ private void traderLlamaSettings() { -+ traderLlamaRidable = getBoolean("mobs.trader_llama.ridable", traderLlamaRidable); -+ traderLlamaRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", traderLlamaRidableInWater); -+ traderLlamaControllable = getBoolean("mobs.trader_llama.controllable", traderLlamaControllable); -+ } -+ -+ public boolean tropicalFishRidable = false; -+ public boolean tropicalFishControllable = true; -+ private void tropicalFishSettings() { -+ tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable); -+ tropicalFishControllable = getBoolean("mobs.tropical_fish.controllable", tropicalFishControllable); -+ } -+ -+ public boolean turtleRidable = false; -+ public boolean turtleRidableInWater = true; -+ public boolean turtleControllable = true; -+ private void turtleSettings() { -+ turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); -+ turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); -+ turtleControllable = getBoolean("mobs.turtle.controllable", turtleControllable); -+ } -+ -+ public boolean vexRidable = false; -+ public boolean vexRidableInWater = true; -+ public boolean vexControllable = true; -+ public double vexMaxY = 320D; -+ private void vexSettings() { -+ vexRidable = getBoolean("mobs.vex.ridable", vexRidable); -+ vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater); -+ vexControllable = getBoolean("mobs.vex.controllable", vexControllable); -+ vexMaxY = getDouble("mobs.vex.ridable-max-y", vexMaxY); -+ } -+ -+ public boolean villagerRidable = false; -+ public boolean villagerRidableInWater = true; -+ public boolean villagerControllable = true; -+ private void villagerSettings() { -+ villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); -+ villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -+ villagerControllable = getBoolean("mobs.villager.controllable", villagerControllable); -+ } -+ -+ public boolean vindicatorRidable = false; -+ public boolean vindicatorRidableInWater = true; -+ public boolean vindicatorControllable = true; -+ private void vindicatorSettings() { -+ vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); -+ vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); -+ vindicatorControllable = getBoolean("mobs.vindicator.controllable", vindicatorControllable); -+ } -+ -+ public boolean wanderingTraderRidable = false; -+ public boolean wanderingTraderRidableInWater = true; -+ public boolean wanderingTraderControllable = true; -+ private void wanderingTraderSettings() { -+ wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); -+ wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); -+ wanderingTraderControllable = getBoolean("mobs.wandering_trader.controllable", wanderingTraderControllable); -+ } -+ -+ public boolean wardenRidable = false; -+ public boolean wardenRidableInWater = true; -+ public boolean wardenControllable = true; -+ private void wardenSettings() { -+ wardenRidable = getBoolean("mobs.warden.ridable", wardenRidable); -+ wardenRidableInWater = getBoolean("mobs.warden.ridable-in-water", wardenRidableInWater); -+ wardenControllable = getBoolean("mobs.warden.controllable", wardenControllable); -+ } -+ -+ public boolean witchRidable = false; -+ public boolean witchRidableInWater = true; -+ public boolean witchControllable = true; -+ private void witchSettings() { -+ witchRidable = getBoolean("mobs.witch.ridable", witchRidable); -+ witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater); -+ witchControllable = getBoolean("mobs.witch.controllable", witchControllable); -+ } -+ -+ public boolean witherRidable = false; -+ public boolean witherRidableInWater = true; -+ public boolean witherControllable = true; -+ public double witherMaxY = 320D; -+ private void witherSettings() { -+ witherRidable = getBoolean("mobs.wither.ridable", witherRidable); -+ witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); -+ witherControllable = getBoolean("mobs.wither.controllable", witherControllable); -+ witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); -+ } -+ -+ public boolean witherSkeletonRidable = false; -+ public boolean witherSkeletonRidableInWater = true; -+ public boolean witherSkeletonControllable = true; -+ private void witherSkeletonSettings() { -+ witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable); -+ witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater); -+ witherSkeletonControllable = getBoolean("mobs.wither_skeleton.controllable", witherSkeletonControllable); -+ } -+ -+ public boolean wolfRidable = false; -+ public boolean wolfRidableInWater = true; -+ public boolean wolfControllable = true; -+ private void wolfSettings() { -+ wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); -+ wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); -+ wolfControllable = getBoolean("mobs.wolf.controllable", wolfControllable); -+ } -+ -+ public boolean zoglinRidable = false; -+ public boolean zoglinRidableInWater = true; -+ public boolean zoglinControllable = true; -+ private void zoglinSettings() { -+ zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable); -+ zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater); -+ zoglinControllable = getBoolean("mobs.zoglin.controllable", zoglinControllable); -+ } -+ -+ public boolean zombieRidable = false; -+ public boolean zombieRidableInWater = true; -+ public boolean zombieControllable = true; -+ private void zombieSettings() { -+ zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); -+ zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); -+ zombieControllable = getBoolean("mobs.zombie.controllable", zombieControllable); -+ } -+ -+ public boolean zombieHorseRidable = false; -+ public boolean zombieHorseRidableInWater = false; -+ public boolean zombieHorseCanSwim = false; -+ private void zombieHorseSettings() { -+ zombieHorseRidable = getBoolean("mobs.zombie_horse.ridable", zombieHorseRidable); -+ zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); -+ zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim); -+ } -+ -+ public boolean zombieVillagerRidable = false; -+ public boolean zombieVillagerRidableInWater = true; -+ public boolean zombieVillagerControllable = true; -+ private void zombieVillagerSettings() { -+ zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); -+ zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); -+ zombieVillagerControllable = getBoolean("mobs.zombie_villager.controllable", zombieVillagerControllable); -+ } -+ -+ public boolean zombifiedPiglinRidable = false; -+ public boolean zombifiedPiglinRidableInWater = true; -+ public boolean zombifiedPiglinControllable = true; -+ private void zombifiedPiglinSettings() { -+ zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); -+ zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); -+ zombifiedPiglinControllable = getBoolean("mobs.zombified_piglin.controllable", zombifiedPiglinControllable); -+ } - } -diff --git a/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ed494e0ad278813a0eb261101447b84cca3ad7aa ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java -@@ -0,0 +1,71 @@ -+package org.purpurmc.purpur.controller; -+ -+import net.minecraft.world.entity.Mob; -+import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.entity.player.Player; -+ -+public class FlyingMoveControllerWASD extends MoveControllerWASD { -+ protected final float groundSpeedModifier; -+ protected final float flyingSpeedModifier; -+ protected int tooHighCooldown = 0; -+ protected boolean setNoGravityFlag; -+ -+ public FlyingMoveControllerWASD(Mob entity) { -+ this(entity, 1.0F); -+ } -+ -+ public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier) { -+ this(entity, groundSpeedModifier, 1.0F, true); -+ } -+ -+ public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier, float flyingSpeedModifier) { -+ this(entity, groundSpeedModifier, flyingSpeedModifier, true); -+ } -+ -+ public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier, float flyingSpeedModifier, boolean setNoGravityFlag) { -+ super(entity); -+ this.groundSpeedModifier = groundSpeedModifier; -+ this.flyingSpeedModifier = flyingSpeedModifier; -+ this.setNoGravityFlag = setNoGravityFlag; -+ } -+ -+ @Override -+ public void purpurTick(Player rider) { -+ float forward = Math.max(0.0F, rider.getForwardMot()); -+ float vertical = forward == 0.0F ? 0.0F : -(rider.xRotO / 45.0F); -+ float strafe = rider.getStrafeMot(); -+ -+ if (rider.jumping && spacebarEvent(entity)) { -+ entity.onSpacebar(); -+ } -+ -+ if (entity.getY() >= entity.getMaxY() || --tooHighCooldown > 0) { -+ if (tooHighCooldown <= 0) { -+ tooHighCooldown = 20; -+ } -+ entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, -0.05D, 0.0D)); -+ vertical = 0.0F; -+ } -+ -+ setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED)); -+ float speed = (float) getSpeedModifier(); -+ -+ if (entity.onGround) { -+ speed *= groundSpeedModifier; // TODO = fix this! -+ } else { -+ speed *= flyingSpeedModifier; -+ } -+ -+ if (setNoGravityFlag) { -+ entity.setNoGravity(forward > 0); -+ } -+ -+ entity.setSpeed(speed); -+ entity.setVerticalMot(vertical); -+ entity.setStrafeMot(strafe); -+ entity.setForwardMot(forward); -+ -+ setForward(entity.getForwardMot()); -+ setStrafe(entity.getStrafeMot()); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9383c07fa53141127106a1f289366a040960d52e ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java -@@ -0,0 +1,63 @@ -+package org.purpurmc.purpur.controller; -+ -+import net.minecraft.world.entity.Mob; -+import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.entity.player.Player; -+import net.minecraft.world.phys.Vec3; -+ -+public class FlyingWithSpacebarMoveControllerWASD extends FlyingMoveControllerWASD { -+ public FlyingWithSpacebarMoveControllerWASD(Mob entity) { -+ super(entity); -+ } -+ -+ public FlyingWithSpacebarMoveControllerWASD(Mob entity, float groundSpeedModifier) { -+ super(entity, groundSpeedModifier); -+ } -+ -+ @Override -+ public void purpurTick(Player rider) { -+ float forward = rider.getForwardMot(); -+ float strafe = rider.getStrafeMot() * 0.5F; -+ float vertical = 0; -+ -+ if (forward < 0.0F) { -+ forward *= 0.5F; -+ strafe *= 0.5F; -+ } -+ -+ float speed = (float) entity.getAttributeValue(Attributes.MOVEMENT_SPEED); -+ -+ if (entity.onGround) { -+ speed *= groundSpeedModifier; -+ } -+ -+ if (rider.jumping && spacebarEvent(entity) && !entity.onSpacebar()) { -+ entity.setNoGravity(true); -+ vertical = 1.0F; -+ } else { -+ entity.setNoGravity(false); -+ } -+ -+ if (entity.getY() >= entity.getMaxY() || --tooHighCooldown > 0) { -+ if (tooHighCooldown <= 0) { -+ tooHighCooldown = 20; -+ } -+ entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, -0.2D, 0.0D)); -+ vertical = 0.0F; -+ } -+ -+ setSpeedModifier(speed); -+ entity.setSpeed((float) getSpeedModifier()); -+ entity.setVerticalMot(vertical); -+ entity.setStrafeMot(strafe); -+ entity.setForwardMot(forward); -+ -+ setForward(entity.getForwardMot()); -+ setStrafe(entity.getStrafeMot()); -+ -+ Vec3 mot = entity.getDeltaMovement(); -+ if (mot.y > 0.2D) { -+ entity.setDeltaMovement(mot.x, 0.2D, mot.z); -+ } -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b8c25c96e95dd5ec3ad9fa4c41bd6c08e144832d ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java -@@ -0,0 +1,76 @@ -+package org.purpurmc.purpur.controller; -+ -+ -+import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket; -+import net.minecraft.util.Mth; -+import net.minecraft.world.entity.Mob; -+import net.minecraft.world.entity.ai.control.LookControl; -+import net.minecraft.world.entity.player.Player; -+ -+public class LookControllerWASD extends LookControl { -+ protected final Mob entity; -+ private float yOffset = 0; -+ private float xOffset = 0; -+ -+ public LookControllerWASD(Mob entity) { -+ super(entity); -+ this.entity = entity; -+ } -+ -+ // tick -+ @Override -+ public void tick() { -+ if (entity.getRider() != null && entity.isControllable()) { -+ purpurTick(entity.getRider()); -+ } else { -+ vanillaTick(); -+ } -+ } -+ -+ protected void purpurTick(Player rider) { -+ setYawPitch(rider.getYRot(), rider.getXRot()); -+ } -+ -+ public void vanillaTick() { -+ super.tick(); -+ } -+ -+ public void setYawPitch(float yRot, float xRot) { -+ entity.setXRot(normalizePitch(xRot + xOffset)); -+ entity.setYRot(normalizeYaw(yRot + yOffset)); -+ entity.setYHeadRot(entity.getYRot()); -+ entity.xRotO = entity.getXRot(); -+ entity.yRotO = entity.getYRot(); -+ -+ entity.tracker.broadcast(new ClientboundMoveEntityPacket -+ .PosRot(entity.getId(), -+ (short) 0, (short) 0, (short) 0, -+ (byte) Mth.floor(entity.getYRot() * 256.0F / 360.0F), -+ (byte) Mth.floor(entity.getXRot() * 256.0F / 360.0F), -+ entity.onGround)); -+ } -+ -+ public void setOffsets(float yaw, float pitch) { -+ yOffset = yaw; -+ xOffset = pitch; -+ } -+ -+ public float normalizeYaw(float yaw) { -+ yaw %= 360.0f; -+ if (yaw >= 180.0f) { -+ yaw -= 360.0f; -+ } else if (yaw < -180.0f) { -+ yaw += 360.0f; -+ } -+ return yaw; -+ } -+ -+ public float normalizePitch(float pitch) { -+ if (pitch > 90.0f) { -+ pitch = 90.0f; -+ } else if (pitch < -90.0f) { -+ pitch = -90.0f; -+ } -+ return pitch; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java -new file mode 100644 -index 0000000000000000000000000000000000000000..21fd6ea2a482758a3016e3bc2cdebe2d89267481 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java -@@ -0,0 +1,89 @@ -+package org.purpurmc.purpur.controller; -+ -+import net.minecraft.world.entity.Mob; -+import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.entity.ai.control.MoveControl; -+import net.minecraft.world.entity.player.Player; -+import org.purpurmc.purpur.event.entity.RidableSpacebarEvent; -+ -+public class MoveControllerWASD extends MoveControl { -+ protected final Mob entity; -+ private final double speedModifier; -+ -+ public MoveControllerWASD(Mob entity) { -+ this(entity, 1.0D); -+ } -+ -+ public MoveControllerWASD(Mob entity, double speedModifier) { -+ super(entity); -+ this.entity = entity; -+ this.speedModifier = speedModifier; -+ } -+ -+ @Override -+ public boolean hasWanted() { -+ return entity.getRider() != null ? strafeForwards != 0 || strafeRight != 0 : super.hasWanted(); -+ } -+ -+ @Override -+ public void tick() { -+ if (entity.getRider() != null && entity.isControllable()) { -+ purpurTick(entity.getRider()); -+ } else { -+ vanillaTick(); -+ } -+ } -+ -+ public void vanillaTick() { -+ super.tick(); -+ } -+ -+ public void purpurTick(Player rider) { -+ float forward = rider.getForwardMot() * 0.5F; -+ float strafe = rider.getStrafeMot() * 0.25F; -+ -+ if (forward <= 0.0F) { -+ forward *= 0.5F; -+ } -+ -+ float yawOffset = 0; -+ if (strafe != 0) { -+ if (forward == 0) { -+ yawOffset += strafe > 0 ? -90 : 90; -+ forward = Math.abs(strafe * 2); -+ } else { -+ yawOffset += strafe > 0 ? -30 : 30; -+ strafe /= 2; -+ if (forward < 0) { -+ yawOffset += strafe > 0 ? -110 : 110; -+ forward *= -1; -+ } -+ } -+ } else if (forward < 0) { -+ yawOffset -= 180; -+ forward *= -1; -+ } -+ -+ ((LookControllerWASD) entity.getLookControl()).setOffsets(yawOffset, 0); -+ -+ if (rider.jumping && spacebarEvent(entity) && !entity.onSpacebar() && entity.onGround) { -+ entity.jumpFromGround(); -+ } -+ -+ setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED) * speedModifier); -+ -+ entity.setSpeed((float) getSpeedModifier()); -+ entity.setForwardMot(forward); -+ -+ setForward(entity.getForwardMot()); -+ setStrafe(entity.getStrafeMot()); -+ } -+ -+ public static boolean spacebarEvent(Mob entity) { -+ if (RidableSpacebarEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ return new RidableSpacebarEvent(entity.getBukkitEntity()).callEvent(); -+ } else { -+ return true; -+ } -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java b/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ba2a37dad43e238e54632975abea8ee6fafaa9e0 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java -@@ -0,0 +1,50 @@ -+package org.purpurmc.purpur.controller; -+ -+import net.minecraft.world.entity.Mob; -+import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.entity.player.Player; -+ -+public class WaterMoveControllerWASD extends MoveControllerWASD { -+ private final double speedModifier; -+ -+ public WaterMoveControllerWASD(Mob entity) { -+ this(entity, 1.0D); -+ } -+ -+ public WaterMoveControllerWASD(Mob entity, double speedModifier) { -+ super(entity); -+ this.speedModifier = speedModifier; -+ } -+ -+ @Override -+ public void purpurTick(Player rider) { -+ float forward = rider.getForwardMot(); -+ float strafe = rider.getStrafeMot() * 0.5F; // strafe slower by default -+ float vertical = -(rider.xRotO / 90); -+ -+ if (forward == 0.0F) { -+ // strafe slower if not moving forward -+ strafe *= 0.5F; -+ // do not move vertically if not moving forward -+ vertical = 0.0F; -+ } else if (forward < 0.0F) { -+ // water animals can't swim backwards -+ forward = 0.0F; -+ vertical = 0.0F; -+ } -+ -+ if (rider.jumping && spacebarEvent(entity)) { -+ entity.onSpacebar(); -+ } -+ -+ setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED) * speedModifier); -+ entity.setSpeed((float) getSpeedModifier() * 0.1F); -+ -+ entity.setForwardMot(forward * (float) speedModifier); -+ entity.setStrafeMot(strafe * (float) speedModifier); -+ entity.setVerticalMot(vertical * (float) speedModifier); -+ -+ setForward(entity.getForwardMot()); -+ setStrafe(entity.getStrafeMot()); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java b/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java -new file mode 100644 -index 0000000000000000000000000000000000000000..89c476c740b4efb4f44c1dcd384b908626d96780 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java -@@ -0,0 +1,100 @@ -+package org.purpurmc.purpur.entity; -+ -+import net.minecraft.core.particles.ParticleTypes; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.util.Mth; -+import net.minecraft.world.damagesource.DamageSource; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.entity.LivingEntity; -+import net.minecraft.world.entity.animal.Dolphin; -+import net.minecraft.world.entity.projectile.LlamaSpit; -+import net.minecraft.world.entity.projectile.ProjectileUtil; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.phys.BlockHitResult; -+import net.minecraft.world.phys.EntityHitResult; -+import net.minecraft.world.phys.HitResult; -+import net.minecraft.world.phys.Vec3; -+import org.bukkit.event.entity.EntityRemoveEvent; -+ -+public class DolphinSpit extends LlamaSpit { -+ public LivingEntity dolphin; -+ public int ticksLived; -+ -+ public DolphinSpit(EntityType type, Level world) { -+ super(type, world); -+ } -+ -+ public DolphinSpit(Level world, Dolphin dolphin) { -+ this(EntityType.LLAMA_SPIT, world); -+ setOwner(dolphin.getRider() != null ? dolphin.getRider() : dolphin); -+ this.dolphin = dolphin; -+ this.setPos( -+ dolphin.getX() - (double) (dolphin.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(dolphin.yBodyRot * 0.017453292F), -+ dolphin.getEyeY() - 0.10000000149011612D, -+ dolphin.getZ() + (double) (dolphin.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(dolphin.yBodyRot * 0.017453292F)); -+ } -+ -+ public void tick() { -+ super_tick(); -+ -+ Vec3 mot = this.getDeltaMovement(); -+ HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); -+ -+ this.preHitTargetOrDeflectSelf(hitResult); -+ -+ double x = this.getX() + mot.x; -+ double y = this.getY() + mot.y; -+ double z = this.getZ() + mot.z; -+ -+ this.updateRotation(); -+ -+ Vec3 motDouble = mot.scale(2.0); -+ for (int i = 0; i < 5; i++) { -+ ((ServerLevel) level()).sendParticles(null, ParticleTypes.BUBBLE, -+ getX() + random.nextFloat() / 2 - 0.25F, -+ getY() + random.nextFloat() / 2 - 0.25F, -+ getZ() + random.nextFloat() / 2 - 0.25F, -+ 0, motDouble.x(), motDouble.y(), motDouble.z(), 0.1D, true); -+ } -+ -+ if (++ticksLived > 20) { -+ this.discard(EntityRemoveEvent.Cause.DISCARD); -+ } else { -+ this.setDeltaMovement(mot.scale(0.99D)); -+ if (!this.isNoGravity()) { -+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.06D, 0.0D)); -+ } -+ -+ this.setPos(x, y, z); -+ } -+ } -+ -+ @Override -+ public void shoot(double x, double y, double z, float speed, float inaccuracy) { -+ setDeltaMovement(new Vec3(x, y, z).normalize().add( -+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, -+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, -+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) -+ .scale(speed)); -+ } -+ -+ @Override -+ protected void onHitEntity(EntityHitResult entityHitResult) { -+ Entity shooter = this.getOwner(); -+ if (shooter instanceof LivingEntity) { -+ entityHitResult.getEntity().hurt(entityHitResult.getEntity().damageSources().mobProjectile(this, (LivingEntity) shooter), level().purpurConfig.dolphinSpitDamage); -+ } -+ } -+ -+ @Override -+ protected void onHitBlock(BlockHitResult blockHitResult) { -+ if (this.hitCancelled) { -+ return; -+ } -+ BlockState state = this.level().getBlockState(blockHitResult.getBlockPos()); -+ state.onProjectileHit(this.level(), state, blockHitResult, this); -+ this.discard(EntityRemoveEvent.Cause.DISCARD); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java b/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c0b7e0eeffdf31b88662232b07944bf3e6fa2148 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java -@@ -0,0 +1,114 @@ -+package org.purpurmc.purpur.entity; -+ -+import net.minecraft.core.particles.ParticleTypes; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.util.Mth; -+import net.minecraft.world.damagesource.DamageSource; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.entity.LivingEntity; -+import net.minecraft.world.entity.decoration.ArmorStand; -+import net.minecraft.world.entity.monster.Phantom; -+import net.minecraft.world.entity.projectile.LlamaSpit; -+import net.minecraft.world.entity.projectile.ProjectileUtil; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.state.BlockBehaviour; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.phys.BlockHitResult; -+import net.minecraft.world.phys.EntityHitResult; -+import net.minecraft.world.phys.HitResult; -+import net.minecraft.world.phys.Vec3; -+ -+public class PhantomFlames extends LlamaSpit { -+ public Phantom phantom; -+ public int ticksLived; -+ public boolean canGrief = false; -+ -+ public PhantomFlames(EntityType type, Level world) { -+ super(type, world); -+ } -+ -+ public PhantomFlames(Level world, Phantom phantom) { -+ this(EntityType.LLAMA_SPIT, world); -+ setOwner(phantom.getRider() != null ? phantom.getRider() : phantom); -+ this.phantom = phantom; -+ this.setPos( -+ phantom.getX() - (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(phantom.yBodyRot * 0.017453292F), -+ phantom.getEyeY() - 0.10000000149011612D, -+ phantom.getZ() + (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(phantom.yBodyRot * 0.017453292F)); -+ } -+ -+ public void tick() { -+ super_tick(); -+ -+ Vec3 mot = this.getDeltaMovement(); -+ HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); -+ -+ this.preHitTargetOrDeflectSelf(hitResult); -+ -+ double x = this.getX() + mot.x; -+ double y = this.getY() + mot.y; -+ double z = this.getZ() + mot.z; -+ -+ this.updateRotation(); -+ -+ Vec3 motDouble = mot.scale(2.0); -+ for (int i = 0; i < 5; i++) { -+ ((ServerLevel) level()).sendParticles(null, ParticleTypes.FLAME, -+ getX() + random.nextFloat() / 2 - 0.25F, -+ getY() + random.nextFloat() / 2 - 0.25F, -+ getZ() + random.nextFloat() / 2 - 0.25F, -+ 0, motDouble.x(), motDouble.y(), motDouble.z(), 0.1D, true); -+ } -+ -+ if (++ticksLived > 20) { -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ } else if (this.level().getBlockStates(this.getBoundingBox()).noneMatch(BlockBehaviour.BlockStateBase::isAir)) { -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ } else if (this.isInWaterOrBubble()) { -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ } else { -+ this.setDeltaMovement(mot.scale(0.99D)); -+ if (!this.isNoGravity()) { -+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.06D, 0.0D)); -+ } -+ -+ this.setPos(x, y, z); -+ } -+ } -+ -+ @Override -+ public void shoot(double x, double y, double z, float speed, float inaccuracy) { -+ setDeltaMovement(new Vec3(x, y, z).normalize().add( -+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, -+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, -+ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) -+ .scale(speed)); -+ } -+ -+ @Override -+ protected void onHitEntity(EntityHitResult entityHitResult) { -+ Entity shooter = this.getOwner(); -+ if (shooter instanceof LivingEntity) { -+ Entity target = entityHitResult.getEntity(); -+ if (canGrief || (target instanceof LivingEntity && !(target instanceof ArmorStand))) { -+ boolean hurt = target.hurt(target.damageSources().mobProjectile(this, (LivingEntity) shooter), level().purpurConfig.phantomFlameDamage); -+ if (hurt && level().purpurConfig.phantomFlameFireTime > 0) { -+ target.igniteForSeconds(level().purpurConfig.phantomFlameFireTime); -+ } -+ } -+ } -+ } -+ -+ @Override -+ protected void onHitBlock(BlockHitResult blockHitResult) { -+ if (this.hitCancelled) { -+ return; -+ } -+ if (this.canGrief) { -+ BlockState state = this.level().getBlockState(blockHitResult.getBlockPos()); -+ state.onProjectileHit(this.level(), state, blockHitResult, this); -+ } -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java b/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8babdaddd8b33278aea0369dbbeeb445abe45016 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java -@@ -0,0 +1,20 @@ -+package org.purpurmc.purpur.entity.ai; -+ -+import net.minecraft.world.entity.Mob; -+import net.minecraft.world.entity.ai.goal.Goal; -+ -+import java.util.EnumSet; -+ -+public class HasRider extends Goal { -+ public final Mob entity; -+ -+ public HasRider(Mob entity) { -+ this.entity = entity; -+ setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK, Flag.TARGET, Flag.UNKNOWN_BEHAVIOR)); -+ } -+ -+ @Override -+ public boolean canUse() { -+ return entity.getRider() != null && entity.isControllable(); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java b/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java -new file mode 100644 -index 0000000000000000000000000000000000000000..432f4f3d82af2f19820890b68d33189a9f2c69f9 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java -@@ -0,0 +1,17 @@ -+package org.purpurmc.purpur.entity.ai; -+ -+import net.minecraft.world.entity.animal.horse.AbstractHorse; -+ -+public class HorseHasRider extends HasRider { -+ public final AbstractHorse horse; -+ -+ public HorseHasRider(AbstractHorse entity) { -+ super(entity); -+ this.horse = entity; -+ } -+ -+ @Override -+ public boolean canUse() { -+ return super.canUse() && horse.isSaddled(); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java b/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java -new file mode 100644 -index 0000000000000000000000000000000000000000..18a95e043cbffa65eeaaf65ff7695e5dc939820c ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java -@@ -0,0 +1,17 @@ -+package org.purpurmc.purpur.entity.ai; -+ -+import net.minecraft.world.entity.animal.horse.Llama; -+ -+public class LlamaHasRider extends HasRider { -+ public final Llama llama; -+ -+ public LlamaHasRider(Llama entity) { -+ super(entity); -+ this.llama = entity; -+ } -+ -+ @Override -+ public boolean canUse() { -+ return super.canUse() && llama.isSaddled() && llama.isControllable(); -+ } -+} diff --git a/patches/server/0007-Configurable-entity-base-attributes.patch b/patches/server/0007-Configurable-entity-base-attributes.patch deleted file mode 100644 index 47c653034..000000000 --- a/patches/server/0007-Configurable-entity-base-attributes.patch +++ /dev/null @@ -1,2851 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 10 Dec 2020 16:44:54 -0600 -Subject: [PATCH] Configurable entity base attributes - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 9c99a3df80c5f0a0d81e1f6a6516d088438a0b1e..e49dda27dd609ebf377f679c4f60c13a5f610c8e 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -163,7 +163,7 @@ import org.bukkit.plugin.PluginManager; - // CraftBukkit end - - public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder { -- -+ public static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur - // CraftBukkit start - private static final int CURRENT_LEVEL = 2; - public boolean preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; keep initial motion on first setPositionRotation -diff --git a/src/main/java/net/minecraft/world/entity/GlowSquid.java b/src/main/java/net/minecraft/world/entity/GlowSquid.java -index aa76a24421cdb3908a3544d92eb3d1e3c2ebedc4..8211c152e6f4232e82e452b08047e4579465d770 100644 ---- a/src/main/java/net/minecraft/world/entity/GlowSquid.java -+++ b/src/main/java/net/minecraft/world/entity/GlowSquid.java -@@ -36,6 +36,11 @@ public class GlowSquid extends Squid { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.glowSquidMaxHealth); -+ } -+ - @Override - protected ParticleOptions getInkParticle() { - return ParticleTypes.GLOW_SQUID_INK; -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 72bd60f691a639a0e7b6b5a98e5a3816305cfdaf..a3ee2af337acef86a15b12c9e6d8cd8452980a87 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -301,6 +301,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.lastClimbablePos = Optional.empty(); - this.appliedScale = 1.0F; - this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type), this); // Purpur -+ this.initAttributes(); // Purpur - this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit - // CraftBukkit - setHealth(getMaxHealth()) inlined and simplified to skip the instanceof check for EntityPlayer, as getBukkitEntity() is not initialized in constructor - this.entityData.set(LivingEntity.DATA_HEALTH_ID, (float) this.getAttribute(Attributes.MAX_HEALTH).getValue()); -@@ -315,6 +316,8 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.brain = this.makeBrain(new Dynamic(dynamicopsnbt, (Tag) dynamicopsnbt.createMap((Map) ImmutableMap.of(dynamicopsnbt.createString("memories"), (Tag) dynamicopsnbt.emptyMap())))); - } - -+ protected void initAttributes() {}// Purpur -+ - public Brain getBrain() { - return this.brain; - } -diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index f8a649b0fee040bbf53084ca7094583ab4ffd900..cea588d68c7e23ad8831bc611f1030d63354d91c 100644 ---- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java -+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -265,6 +265,18 @@ public class Bat extends AmbientCreature { - } - } - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.batMaxHealth); -+ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.batFollowRange); -+ this.getAttribute(Attributes.KNOCKBACK_RESISTANCE).setBaseValue(this.level().purpurConfig.batKnockbackResistance); -+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.batMovementSpeed); -+ this.getAttribute(Attributes.FLYING_SPEED).setBaseValue(this.level().purpurConfig.batFlyingSpeed); -+ this.getAttribute(Attributes.ARMOR).setBaseValue(this.level().purpurConfig.batArmor); -+ this.getAttribute(Attributes.ARMOR_TOUGHNESS).setBaseValue(this.level().purpurConfig.batArmorToughness); -+ this.getAttribute(Attributes.ATTACK_KNOCKBACK).setBaseValue(this.level().purpurConfig.batAttackKnockback); -+ } -+ - @Override - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 4b84cf76d052112e00cd13c330182abfbe618820..ae4b53f4cdd78368deb7d510be4936ffefce4d9c 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -467,6 +467,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - } - } - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.beeMaxHealth); -+ } -+ - @Override - public int getRemainingPersistentAngerTime() { - return (Integer) this.entityData.get(Bee.DATA_REMAINING_ANGER_TIME); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 3826c794ddde6b915e233e2d0395557e3ea867e0..7930e9735abf8357df737798e80b08295c2e06ec 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -129,6 +129,13 @@ public class Cat extends TamableAnimal implements VariantHolder { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.foxMaxHealth); -+ } -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -index 4cc9138201b08aff8bb47720c6fe1e3447f03967..2919d055e2136a956aa038bd0bf4c1a2ff5afa2f 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -@@ -76,6 +76,11 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - public boolean isControllable() { - return level().purpurConfig.ironGolemControllable; - } -+ -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ironGolemMaxHealth); -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index 11944ee34fc7e3e5551b9e18a563164f96898a54..b47dddb2fc6058a90665ccbd362088d9a2e837b5 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -81,6 +81,11 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder { - } - wasOnGround = onGround; - } -+ -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.rabbitMaxHealth); -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/Salmon.java b/src/main/java/net/minecraft/world/entity/animal/Salmon.java -index 87c442fb198cad8671ad1419e589a5a67c4fdca8..742805994f29a18af444912b10af631d2c60cacf 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Salmon.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Salmon.java -@@ -25,6 +25,11 @@ public class Salmon extends AbstractSchoolingFish { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.salmonMaxHealth); -+ } -+ - @Override - public int getMaxSchoolSize() { - return 5; -diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -index 7c1da46554aefde8e5e2b33a3644c9cbd771d7bc..b68886cc72d3055e7745fe4a955192bbad90dc13 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -134,6 +134,11 @@ public class Sheep extends Animal implements Shearable { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.sheepMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - this.eatBlockGoal = new EatBlockGoal(this); -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index d51b486afb83bf3e12046ed5e61e73eec5bd7c7c..a54893d51cc1ce204e59a6ffe8b84228775af4da 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -69,6 +69,11 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.snowGolemMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index 37402f7df48f04a6df2211e079519ed95d3735bc..e38416189d9dc72f0b5951a1f6430dbc4578c422 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Squid.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -68,6 +68,11 @@ public class Squid extends WaterAnimal { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.squidMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -index 18dcb67d246b63637d8c948b6c3f48c58d71c339..327b1805d9d4069212a8772ff189c9ab24ae1183 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -+++ b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -@@ -79,6 +79,11 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.tropicalFishMaxHealth); -+ } -+ - public static String getPredefinedName(int variant) { - return "entity.minecraft.tropical_fish.predefined." + variant; - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index 4742d90ca38c1d8034b0cfcf7f336e225fade197..b8dcf3d632c79585ec7e9f50fa040fa9fac5d7c5 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -104,6 +104,11 @@ public class Turtle extends Animal { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.turtleMaxHealth); -+ } -+ - public void setHomePos(BlockPos pos) { - this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos... - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -index 731909acd1e18dcfbd25becb0ddff30fb2a6a0f5..8aaac4e86ec6d9c40999f6198cda7d367ece54e3 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -@@ -146,6 +146,11 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder getModelRotationValues() { - return this.modelRotationValues; -diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -index 4477f201ff02a5e0758af5431b7d9b7c5e11d642..07a5599a9370ba167e985006d74caa3c80288e28 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -+++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -@@ -316,6 +316,23 @@ public class Camel extends AbstractHorse implements PlayerRideableJumping, Saddl - return this.dashCooldown; - } - -+ // Purpur start -+ @Override -+ public float generateMaxHealth(net.minecraft.util.RandomSource random) { -+ return (float) generateMaxHealth(this.level().purpurConfig.camelMaxHealthMin, this.level().purpurConfig.camelMaxHealthMax); -+ } -+ -+ @Override -+ public double generateJumpStrength(net.minecraft.util.RandomSource random) { -+ return generateJumpStrength(this.level().purpurConfig.camelJumpStrengthMin, this.level().purpurConfig.camelJumpStrengthMax); -+ } -+ -+ @Override -+ public double generateSpeed(net.minecraft.util.RandomSource random) { -+ return generateSpeed(this.level().purpurConfig.camelMovementSpeedMin, this.level().purpurConfig.camelMovementSpeedMax); -+ } -+ // Purpur end -+ - @Override - protected SoundEvent getAmbientSound() { - return SoundEvents.CAMEL_AMBIENT; -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -index 12a137665f93d992094e86327a496057890d1018..59829fb7342696d29aa709d392f89bf263257fd3 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -@@ -229,6 +229,44 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.generateMaxHealth(random)); -+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.generateSpeed(random)); -+ this.getAttribute(Attributes.JUMP_STRENGTH).setBaseValue(this.generateJumpStrength(random)); -+ } -+ -+ protected double generateMaxHealth(double min, double max) { -+ if (min == max) return min; -+ int diff = Mth.floor(max - min); -+ double base = max - diff; -+ int first = Mth.floor((double) diff / 2); -+ int rest = diff - first; -+ return base + random.nextInt(first + 1) + random.nextInt(rest + 1); -+ } -+ -+ protected double generateJumpStrength(double min, double max) { -+ if (min == max) return min; -+ return min + (max - min) * this.random.nextDouble(); -+ } -+ -+ protected double generateSpeed(double min, double max) { -+ if (min == max) return min; -+ return min + (max - min) * this.random.nextDouble(); -+ } -+ -+ protected float generateMaxHealth(RandomSource random) { -+ return 15.0F + (float) random.nextInt(8) + (float) random.nextInt(9); -+ } -+ -+ protected double generateJumpStrength(RandomSource random) { -+ return 0.4000000059604645D + random.nextDouble() * 0.2D + random.nextDouble() * 0.2D + random.nextDouble() * 0.2D; -+ } -+ -+ protected double generateSpeed(RandomSource random) { -+ return (0.44999998807907104D + random.nextDouble() * 0.3D + random.nextDouble() * 0.3D + random.nextDouble() * 0.3D) * 0.25D; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur -@@ -1260,7 +1298,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - entityData = new AgeableMob.AgeableMobGroupData(0.2F); - } - -- this.randomizeAttributes(world.getRandom()); -+ // this.randomizeAttributes(world.getRandom()); // Purpur - replaced by initAttributes() - return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData); - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -index 1febe8e173886d501e40331c12261701bd36b0f6..b47a72ffb8b947cea5d4bc6ee37b824c4161be31 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -@@ -22,6 +22,21 @@ public class Donkey extends AbstractChestedHorse { - } - // Purpur end - -+ @Override -+ public float generateMaxHealth(net.minecraft.util.RandomSource random) { -+ return (float) generateMaxHealth(this.level().purpurConfig.donkeyMaxHealthMin, this.level().purpurConfig.donkeyMaxHealthMax); -+ } -+ -+ @Override -+ public double generateJumpStrength(net.minecraft.util.RandomSource random) { -+ return generateJumpStrength(this.level().purpurConfig.donkeyJumpStrengthMin, this.level().purpurConfig.donkeyJumpStrengthMax); -+ } -+ -+ @Override -+ public double generateSpeed(net.minecraft.util.RandomSource random) { -+ return generateSpeed(this.level().purpurConfig.donkeyMovementSpeedMin, this.level().purpurConfig.donkeyMovementSpeedMax); -+ } -+ - @Override - protected SoundEvent getAmbientSound() { - return SoundEvents.DONKEY_AMBIENT; -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -index 816c698a81a77f217a606468aa157bdaed779479..9ad0d3972d1970b11687da174a83e3a0a4180c0e 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -@@ -51,6 +51,21 @@ public class Horse extends AbstractHorse implements VariantHolder { - } - // Purpur end - -+ @Override -+ public float generateMaxHealth(RandomSource random) { -+ return (float) generateMaxHealth(this.level().purpurConfig.horseMaxHealthMin, this.level().purpurConfig.horseMaxHealthMax); -+ } -+ -+ @Override -+ public double generateJumpStrength(RandomSource random) { -+ return generateJumpStrength(this.level().purpurConfig.horseJumpStrengthMin, this.level().purpurConfig.horseJumpStrengthMax); -+ } -+ -+ @Override -+ public double generateSpeed(RandomSource random) { -+ return generateSpeed(this.level().purpurConfig.horseMovementSpeedMin, this.level().purpurConfig.horseMovementSpeedMax); -+ } -+ - @Override - protected void randomizeAttributes(RandomSource random) { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)generateMaxHealth(random::nextInt)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 3943ca63aaeecfb98c34ceef9b0c40e71de4e832..697895661826e4a1ecbdfd2c3a195b9d0ee7e00a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -@@ -124,6 +124,21 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - return checkMonsterSpawnRules(type, world, spawnReason, pos, random) && (MobSpawnType.isSpawner(spawnReason) || world.canSeeSky(pos)); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -index bef63bb69ea81298a1021eadd6c260943e18eba7..c680e1efb73a6387aad6ecdab94f690c12451a32 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -@@ -73,6 +73,13 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { - } - // Purpur end - -+ @Override -+ protected void initAttributes() { -+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.illusionerMovementSpeed); -+ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.illusionerFollowRange); -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.illusionerMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -index 6a03a5f1c209d248207b6835ba1d7c0f59dec557..61cd97bc17802d3ab30999fc1f2b91e8b00652b2 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -+++ b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -@@ -46,6 +46,26 @@ public class MagmaCube extends Slime { - } - // Purpur end - -+ @Override -+ protected String getMaxHealthEquation() { -+ return level().purpurConfig.magmaCubeMaxHealth; -+ } -+ -+ @Override -+ protected String getAttackDamageEquation() { -+ return level().purpurConfig.magmaCubeAttackDamage; -+ } -+ -+ @Override -+ protected java.util.Map getMaxHealthCache() { -+ return level().purpurConfig.magmaCubeMaxHealthCache; -+ } -+ -+ @Override -+ protected java.util.Map getAttackDamageCache() { -+ return level().purpurConfig.magmaCubeAttackDamageCache; -+ } -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index 03c873b830f45d848af076ac7921fc4d019f69c8..01e8eaecec61e664838b5d7f18a9c3e730f00ddf 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -149,7 +149,10 @@ public class Phantom extends FlyingMob implements Enemy { - - private void updatePhantomSizeInfo() { - this.refreshDimensions(); -- this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue((double) (6 + this.getPhantomSize())); -+ // Purpur start -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(getFromCache(() -> this.level().purpurConfig.phantomMaxHealth, () -> this.level().purpurConfig.phantomMaxHealthCache, () -> 20.0D)); -+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(getFromCache(() -> this.level().purpurConfig.phantomAttackDamage, () -> this.level().purpurConfig.phantomAttackDamageCache, () -> (double) 6 + this.getPhantomSize())); -+ // Purpur end - } - - public int getPhantomSize() { -@@ -174,6 +177,21 @@ public class Phantom extends FlyingMob implements Enemy { - return true; - } - -+ private double getFromCache(java.util.function.Supplier equation, java.util.function.Supplier> cache, java.util.function.Supplier defaultValue) { -+ int size = getPhantomSize(); -+ Double value = cache.get().get(size); -+ if (value == null) { -+ try { -+ value = ((Number) scriptEngine.eval("let size = " + size + "; " + equation.get())).doubleValue(); -+ } catch (javax.script.ScriptException e) { -+ e.printStackTrace(); -+ value = defaultValue.get(); -+ } -+ cache.get().put(size, value); -+ } -+ return value; -+ } -+ - @Override - public void tick() { - super.tick(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Pillager.java b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -index 6bfe582390dcb6111dcaf8325bd2773b9f5fd6a9..8c06e648df453fdd4eea0aa4843fada9b6375f81 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Pillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -@@ -75,6 +75,11 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pillagerMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index 1248a48c0146258d14efcaa805a82ce1a79c623d..32d547a4430a8f524a7fc0bd1aa063bbebfaeb7f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -91,6 +91,11 @@ public class Ravager extends Raider { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ravagerMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index 78433d0b7624019018012c55e8dd6fec029f8cd1..1793c5f4e33fbab9d64d81bb1767b0e9b248106f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -114,6 +114,11 @@ public class Shulker extends AbstractGolem implements VariantHolder getMaxHealthCache() { -+ return level().purpurConfig.slimeMaxHealthCache; -+ } -+ -+ protected java.util.Map getAttackDamageCache() { -+ return level().purpurConfig.slimeAttackDamageCache; -+ } -+ -+ protected double getFromCache(java.util.function.Supplier equation, java.util.function.Supplier> cache, java.util.function.Supplier defaultValue) { -+ int size = getSize(); -+ Double value = cache.get().get(size); -+ if (value == null) { -+ try { -+ value = ((Number) scriptEngine.eval("let size = " + size + "; " + equation.get())).doubleValue(); -+ } catch (javax.script.ScriptException e) { -+ e.printStackTrace(); -+ value = defaultValue.get(); -+ } -+ cache.get().put(size, value); -+ } -+ return value; -+ } - // Purpur end - - @Override -@@ -135,9 +166,9 @@ public class Slime extends Mob implements Enemy { - this.entityData.set(Slime.ID_SIZE, j); - this.reapplyPosition(); - this.refreshDimensions(); -- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double) (j * j)); -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(getFromCache(this::getMaxHealthEquation, this::getMaxHealthCache, () -> (double) size * size)); // Purpur - this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue((double) (0.2F + 0.1F * (float) j)); -- this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue((double) j); -+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(getFromCache(this::getAttackDamageEquation, this::getAttackDamageCache, () -> (double) j)); // Purpur - if (heal) { - this.setHealth(this.getMaxHealth()); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java -index 87f63373ccef3de9ce77a92933ff332be4fd6305..92276f6c015e60783f23f433466f50c918057f61 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Spider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java -@@ -68,6 +68,11 @@ public class Spider extends Monster { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.spiderMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(1, new FloatGoal(this)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Stray.java b/src/main/java/net/minecraft/world/entity/monster/Stray.java -index 44006bcb7d70661a6990e3fc4375dd6da34517e0..e1327ea96fe394b1c27dbe88c49596256e4e61d3 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Stray.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Stray.java -@@ -38,6 +38,11 @@ public class Stray extends AbstractSkeleton { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.strayMaxHealth); -+ } -+ - public static boolean checkStraySpawnRules(EntityType type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - BlockPos blockPos = pos; - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java -index 7e5ad9d52db7a39be60e0b2f24e13e8ed82785e1..4abbeaf9f88511f37bd14c17dbd9a107648a5534 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Strider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java -@@ -114,6 +114,11 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.striderMaxHealth); -+ } -+ - public static boolean checkStriderSpawnRules(EntityType type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java -index 98c9d7080595a5d9ffa3d65a153780b68aec0e47..ca6c688b31240863dfc5095c7b6187583cf2f6ce 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vex.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java -@@ -102,6 +102,11 @@ public class Vex extends Monster implements TraceableEntity { - public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { - return false; // no fall damage please - } -+ -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vexMaxHealth); -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -index c6d12c939cd3fbd9facf88cdc0c7c51744089484..e270da29fdab5060b6a936bba67c433a78c54b5b 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -@@ -67,6 +67,11 @@ public class Vindicator extends AbstractIllager { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vindicatorMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java -index b5f44495f0a384c8a7d8d96e3a0f16999fba86fe..d99c52b4f0326421f90162d4894044394b3c49c4 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Witch.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java -@@ -72,6 +72,11 @@ public class Witch extends Raider implements RangedAttackMob { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witchMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -index 355ed17da77256c84d8ba7d4d99b5c73d729a48d..9fd9b95cbec010dafec261b5923938c5b39cd1e6 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -@@ -49,6 +49,11 @@ public class WitherSkeleton extends AbstractSkeleton { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witherSkeletonMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -index 2cb65bc3e2a2f990f4036f4f0418d9cd5226381e..698076b0e958aadf9736d7753df64a73dd3c17cd 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -@@ -97,6 +97,11 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zoglinMaxHealth); -+ } -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index 7c78b243164a517818565845b1a6c7d40c8839d8..9af1c4b794ddaf8640076f172cf0317acad6bcb2 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -121,6 +121,11 @@ public class Zombie extends Monster { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -@@ -596,7 +601,7 @@ public class Zombie extends Monster { - } - - protected void randomizeReinforcementsChance() { -- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * 0.10000000149011612D); -+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieSpawnReinforcements); // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index cc3d9f47ef6d1efa589c8bed5c51ed9e61d7c07d..8e7f0f2069c3382f3a7b08b80f829398e62377f7 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -97,6 +97,16 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieVillagerMaxHealth); -+ } -+ -+ @Override -+ protected void randomizeReinforcementsChance() { -+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieVillagerSpawnReinforcements); -+ } -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -index 2ff0ce04ce210b77c555f59967182ed4dd3fe9aa..138f3f6a9b0754d54e5f8000962bb52b224f677d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -79,6 +79,11 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombifiedPiglinMaxHealth); -+ } -+ - @Override - public void setPersistentAngerTarget(@Nullable UUID angryAt) { - this.persistentAngerTarget = angryAt; -@@ -261,7 +266,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - - @Override - protected void randomizeReinforcementsChance() { -- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(0.0D); -+ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombifiedPiglinSpawnReinforcements); // Purpur - } - - @Nullable -diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index 6e86e0597af66bad8f2e97661b588e950b2679ba..3bfc073fb142e3446044a42c33be6c30587cc3c4 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -107,6 +107,11 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.hoglinMaxHealth); -+ } -+ - @Override - public boolean canBeLeashed(Player player) { - return !this.isLeashed(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index 6632cab4ed43bbfd10b4d8f3b2c447a35eba735e..06e0f737615c90bd733a89a731156598ccfe447f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -111,6 +111,11 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinMaxHealth); -+ } -+ - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -index 17e2457bc83e7ee4402c10ee7d2ef5aa36901565..362f3fddd8090799278f4b4e58c5af5de00315f2 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -@@ -79,6 +79,11 @@ public class PiglinBrute extends AbstractPiglin { - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinBruteMaxHealth); -+ } -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 50.0).add(Attributes.MOVEMENT_SPEED, 0.35F).add(Attributes.ATTACK_DAMAGE, 7.0); - } -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 980f48b546f0da5696c110357ea42352a48fbd42..ff86c7d4878e43fc9d375b9b60213a2271b92cff 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -178,6 +178,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.villagerMaxHealth); -+ } -+ - @Override - public Brain getBrain() { - return (Brain) super.getBrain(); // CraftBukkit - decompile error -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index 6bdf3d1e3652a661282d61f1dc2bfc2712339953..ac3cca0db4478841f91d966bd49ca4e5b5e91229 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -88,6 +88,11 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - } - // Purpur end - -+ @Override -+ public void initAttributes() { -+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.wanderingTraderMaxHealth); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3eae97d610d8f61528b87039723ef4ce2dc75c91..e248395ad5f5f012aeefecf367d54f90cade0996 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -112,99 +112,190 @@ public class PurpurWorldConfig { - - public boolean axolotlRidable = false; - public boolean axolotlControllable = true; -+ public double axolotlMaxHealth = 14.0D; - private void axolotlSettings() { - axolotlRidable = getBoolean("mobs.axolotl.ridable", axolotlRidable); - axolotlControllable = getBoolean("mobs.axolotl.controllable", axolotlControllable); -+ axolotlMaxHealth = getDouble("mobs.axolotl.attributes.max_health", axolotlMaxHealth); - } - - public boolean batRidable = false; - public boolean batRidableInWater = true; - public boolean batControllable = true; - public double batMaxY = 320D; -+ public double batMaxHealth = 6.0D; -+ public double batFollowRange = 16.0D; -+ public double batKnockbackResistance = 0.0D; -+ public double batMovementSpeed = 0.6D; -+ public double batFlyingSpeed = 0.6D; -+ public double batArmor = 0.0D; -+ public double batArmorToughness = 0.0D; -+ public double batAttackKnockback = 0.0D; - private void batSettings() { - batRidable = getBoolean("mobs.bat.ridable", batRidable); - batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater); - batControllable = getBoolean("mobs.bat.controllable", batControllable); - batMaxY = getDouble("mobs.bat.ridable-max-y", batMaxY); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.bat.attributes.max-health", batMaxHealth); -+ set("mobs.bat.attributes.max-health", null); -+ set("mobs.bat.attributes.max_health", oldValue); -+ } -+ batMaxHealth = getDouble("mobs.bat.attributes.max_health", batMaxHealth); -+ batFollowRange = getDouble("mobs.bat.attributes.follow_range", batFollowRange); -+ batKnockbackResistance = getDouble("mobs.bat.attributes.knockback_resistance", batKnockbackResistance); -+ batMovementSpeed = getDouble("mobs.bat.attributes.movement_speed", batMovementSpeed); -+ batFlyingSpeed = getDouble("mobs.bat.attributes.flying_speed", batFlyingSpeed); -+ batArmor = getDouble("mobs.bat.attributes.armor", batArmor); -+ batArmorToughness = getDouble("mobs.bat.attributes.armor_toughness", batArmorToughness); -+ batAttackKnockback = getDouble("mobs.bat.attributes.attack_knockback", batAttackKnockback); - } - - public boolean beeRidable = false; - public boolean beeRidableInWater = true; - public boolean beeControllable = true; - public double beeMaxY = 320D; -+ public double beeMaxHealth = 10.0D; - private void beeSettings() { - beeRidable = getBoolean("mobs.bee.ridable", beeRidable); - beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); - beeControllable = getBoolean("mobs.bee.controllable", beeControllable); - beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.bee.attributes.max-health", beeMaxHealth); -+ set("mobs.bee.attributes.max-health", null); -+ set("mobs.bee.attributes.max_health", oldValue); -+ } -+ beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth); - } - - public boolean blazeRidable = false; - public boolean blazeRidableInWater = true; - public boolean blazeControllable = true; - public double blazeMaxY = 320D; -+ public double blazeMaxHealth = 20.0D; - private void blazeSettings() { - blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); - blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); - blazeControllable = getBoolean("mobs.blaze.controllable", blazeControllable); - blazeMaxY = getDouble("mobs.blaze.ridable-max-y", blazeMaxY); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.blaze.attributes.max-health", blazeMaxHealth); -+ set("mobs.blaze.attributes.max-health", null); -+ set("mobs.blaze.attributes.max_health", oldValue); -+ } -+ blazeMaxHealth = getDouble("mobs.blaze.attributes.max_health", blazeMaxHealth); - } - - public boolean camelRidableInWater = false; -+ public double camelMaxHealthMin = 32.0D; -+ public double camelMaxHealthMax = 32.0D; -+ public double camelJumpStrengthMin = 0.42D; -+ public double camelJumpStrengthMax = 0.42D; -+ public double camelMovementSpeedMin = 0.09D; -+ public double camelMovementSpeedMax = 0.09D; - private void camelSettings() { - camelRidableInWater = getBoolean("mobs.camel.ridable-in-water", camelRidableInWater); -+ camelMaxHealthMin = getDouble("mobs.camel.attributes.max_health.min", camelMaxHealthMin); -+ camelMaxHealthMax = getDouble("mobs.camel.attributes.max_health.max", camelMaxHealthMax); -+ camelJumpStrengthMin = getDouble("mobs.camel.attributes.jump_strength.min", camelJumpStrengthMin); -+ camelJumpStrengthMax = getDouble("mobs.camel.attributes.jump_strength.max", camelJumpStrengthMax); -+ camelMovementSpeedMin = getDouble("mobs.camel.attributes.movement_speed.min", camelMovementSpeedMin); -+ camelMovementSpeedMax = getDouble("mobs.camel.attributes.movement_speed.max", camelMovementSpeedMax); - } - - public boolean catRidable = false; - public boolean catRidableInWater = true; - public boolean catControllable = true; -+ public double catMaxHealth = 10.0D; - private void catSettings() { - catRidable = getBoolean("mobs.cat.ridable", catRidable); - catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); - catControllable = getBoolean("mobs.cat.controllable", catControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.cat.attributes.max-health", catMaxHealth); -+ set("mobs.cat.attributes.max-health", null); -+ set("mobs.cat.attributes.max_health", oldValue); -+ } -+ catMaxHealth = getDouble("mobs.cat.attributes.max_health", catMaxHealth); - } - - public boolean caveSpiderRidable = false; - public boolean caveSpiderRidableInWater = true; - public boolean caveSpiderControllable = true; -+ public double caveSpiderMaxHealth = 12.0D; - private void caveSpiderSettings() { - caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable); - caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater); - caveSpiderControllable = getBoolean("mobs.cave_spider.controllable", caveSpiderControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.cave_spider.attributes.max-health", caveSpiderMaxHealth); -+ set("mobs.cave_spider.attributes.max-health", null); -+ set("mobs.cave_spider.attributes.max_health", oldValue); -+ } -+ caveSpiderMaxHealth = getDouble("mobs.cave_spider.attributes.max_health", caveSpiderMaxHealth); - } - - public boolean chickenRidable = false; - public boolean chickenRidableInWater = false; - public boolean chickenControllable = true; -+ public double chickenMaxHealth = 4.0D; - private void chickenSettings() { - chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); - chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); - chickenControllable = getBoolean("mobs.chicken.controllable", chickenControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.chicken.attributes.max-health", chickenMaxHealth); -+ set("mobs.chicken.attributes.max-health", null); -+ set("mobs.chicken.attributes.max_health", oldValue); -+ } -+ chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth); - } - - public boolean codRidable = false; - public boolean codControllable = true; -+ public double codMaxHealth = 3.0D; - private void codSettings() { - codRidable = getBoolean("mobs.cod.ridable", codRidable); - codControllable = getBoolean("mobs.cod.controllable", codControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.cod.attributes.max-health", codMaxHealth); -+ set("mobs.cod.attributes.max-health", null); -+ set("mobs.cod.attributes.max_health", oldValue); -+ } -+ codMaxHealth = getDouble("mobs.cod.attributes.max_health", codMaxHealth); - } - - public boolean cowRidable = false; - public boolean cowRidableInWater = true; - public boolean cowControllable = true; -+ public double cowMaxHealth = 10.0D; - private void cowSettings() { - cowRidable = getBoolean("mobs.cow.ridable", cowRidable); - cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); - cowControllable = getBoolean("mobs.cow.controllable", cowControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.cow.attributes.max-health", cowMaxHealth); -+ set("mobs.cow.attributes.max-health", null); -+ set("mobs.cow.attributes.max_health", oldValue); -+ } -+ cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth); - } - - public boolean creeperRidable = false; - public boolean creeperRidableInWater = true; - public boolean creeperControllable = true; -+ public double creeperMaxHealth = 20.0D; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); - creeperControllable = getBoolean("mobs.creeper.controllable", creeperControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.creeper.attributes.max-health", creeperMaxHealth); -+ set("mobs.creeper.attributes.max-health", null); -+ set("mobs.creeper.attributes.max_health", oldValue); -+ } -+ creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth); - } - - public boolean dolphinRidable = false; -@@ -212,80 +303,161 @@ public class PurpurWorldConfig { - public int dolphinSpitCooldown = 20; - public float dolphinSpitSpeed = 1.0F; - public float dolphinSpitDamage = 2.0F; -+ public double dolphinMaxHealth = 10.0D; - private void dolphinSettings() { - dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); - dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable); - dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown); - dolphinSpitSpeed = (float) getDouble("mobs.dolphin.spit.speed", dolphinSpitSpeed); - dolphinSpitDamage = (float) getDouble("mobs.dolphin.spit.damage", dolphinSpitDamage); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.dolphin.attributes.max-health", dolphinMaxHealth); -+ set("mobs.dolphin.attributes.max-health", null); -+ set("mobs.dolphin.attributes.max_health", oldValue); -+ } -+ dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth); - } - - public boolean donkeyRidableInWater = false; -+ public double donkeyMaxHealthMin = 15.0D; -+ public double donkeyMaxHealthMax = 30.0D; -+ public double donkeyJumpStrengthMin = 0.5D; -+ public double donkeyJumpStrengthMax = 0.5D; -+ public double donkeyMovementSpeedMin = 0.175D; -+ public double donkeyMovementSpeedMax = 0.175D; - private void donkeySettings() { - donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); -+ if (PurpurConfig.version < 10) { -+ double oldMin = getDouble("mobs.donkey.attributes.max-health.min", donkeyMaxHealthMin); -+ double oldMax = getDouble("mobs.donkey.attributes.max-health.max", donkeyMaxHealthMax); -+ set("mobs.donkey.attributes.max-health", null); -+ set("mobs.donkey.attributes.max_health.min", oldMin); -+ set("mobs.donkey.attributes.max_health.max", oldMax); -+ } -+ donkeyMaxHealthMin = getDouble("mobs.donkey.attributes.max_health.min", donkeyMaxHealthMin); -+ donkeyMaxHealthMax = getDouble("mobs.donkey.attributes.max_health.max", donkeyMaxHealthMax); -+ donkeyJumpStrengthMin = getDouble("mobs.donkey.attributes.jump_strength.min", donkeyJumpStrengthMin); -+ donkeyJumpStrengthMax = getDouble("mobs.donkey.attributes.jump_strength.max", donkeyJumpStrengthMax); -+ donkeyMovementSpeedMin = getDouble("mobs.donkey.attributes.movement_speed.min", donkeyMovementSpeedMin); -+ donkeyMovementSpeedMax = getDouble("mobs.donkey.attributes.movement_speed.max", donkeyMovementSpeedMax); - } - - public boolean drownedRidable = false; - public boolean drownedRidableInWater = true; - public boolean drownedControllable = true; -+ public double drownedMaxHealth = 20.0D; -+ public double drownedSpawnReinforcements = 0.1D; - private void drownedSettings() { - drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); - drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); - drownedControllable = getBoolean("mobs.drowned.controllable", drownedControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.drowned.attributes.max-health", drownedMaxHealth); -+ set("mobs.drowned.attributes.max-health", null); -+ set("mobs.drowned.attributes.max_health", oldValue); -+ } -+ drownedMaxHealth = getDouble("mobs.drowned.attributes.max_health", drownedMaxHealth); -+ drownedSpawnReinforcements = getDouble("mobs.drowned.attributes.spawn_reinforcements", drownedSpawnReinforcements); - } - - public boolean elderGuardianRidable = false; - public boolean elderGuardianControllable = true; -+ public double elderGuardianMaxHealth = 80.0D; - private void elderGuardianSettings() { - elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable); - elderGuardianControllable = getBoolean("mobs.elder_guardian.controllable", elderGuardianControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.elder_guardian.attributes.max-health", elderGuardianMaxHealth); -+ set("mobs.elder_guardian.attributes.max-health", null); -+ set("mobs.elder_guardian.attributes.max_health", oldValue); -+ } -+ elderGuardianMaxHealth = getDouble("mobs.elder_guardian.attributes.max_health", elderGuardianMaxHealth); - } - - public boolean enderDragonRidable = false; - public boolean enderDragonRidableInWater = true; - public boolean enderDragonControllable = true; - public double enderDragonMaxY = 320D; -+ public double enderDragonMaxHealth = 200.0D; - private void enderDragonSettings() { - enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); - enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); - enderDragonControllable = getBoolean("mobs.ender_dragon.controllable", enderDragonControllable); - enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY); -+ if (PurpurConfig.version < 8) { -+ double oldValue = getDouble("mobs.ender_dragon.max-health", enderDragonMaxHealth); -+ set("mobs.ender_dragon.max-health", null); -+ set("mobs.ender_dragon.attributes.max_health", oldValue); -+ } else if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.ender_dragon.attributes.max-health", enderDragonMaxHealth); -+ set("mobs.ender_dragon.attributes.max-health", null); -+ set("mobs.ender_dragon.attributes.max_health", oldValue); -+ } -+ enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth); - } - - public boolean endermanRidable = false; - public boolean endermanRidableInWater = true; - public boolean endermanControllable = true; -+ public double endermanMaxHealth = 40.0D; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); - endermanControllable = getBoolean("mobs.enderman.controllable", endermanControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.enderman.attributes.max-health", endermanMaxHealth); -+ set("mobs.enderman.attributes.max-health", null); -+ set("mobs.enderman.attributes.max_health", oldValue); -+ } -+ endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); - } - - public boolean endermiteRidable = false; - public boolean endermiteRidableInWater = true; - public boolean endermiteControllable = true; -+ public double endermiteMaxHealth = 8.0D; - private void endermiteSettings() { - endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable); - endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater); - endermiteControllable = getBoolean("mobs.endermite.controllable", endermiteControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.endermite.attributes.max-health", endermiteMaxHealth); -+ set("mobs.endermite.attributes.max-health", null); -+ set("mobs.endermite.attributes.max_health", oldValue); -+ } -+ endermiteMaxHealth = getDouble("mobs.endermite.attributes.max_health", endermiteMaxHealth); - } - - public boolean evokerRidable = false; - public boolean evokerRidableInWater = true; - public boolean evokerControllable = true; -+ public double evokerMaxHealth = 24.0D; - private void evokerSettings() { - evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); - evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); - evokerControllable = getBoolean("mobs.evoker.controllable", evokerControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.evoker.attributes.max-health", evokerMaxHealth); -+ set("mobs.evoker.attributes.max-health", null); -+ set("mobs.evoker.attributes.max_health", oldValue); -+ } -+ evokerMaxHealth = getDouble("mobs.evoker.attributes.max_health", evokerMaxHealth); - } - - public boolean foxRidable = false; - public boolean foxRidableInWater = true; - public boolean foxControllable = true; -+ public double foxMaxHealth = 10.0D; - private void foxSettings() { - foxRidable = getBoolean("mobs.fox.ridable", foxRidable); - foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); - foxControllable = getBoolean("mobs.fox.controllable", foxControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.fox.attributes.max-health", foxMaxHealth); -+ set("mobs.fox.attributes.max-health", null); -+ set("mobs.fox.attributes.max_health", oldValue); -+ } -+ foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth); - } - - public boolean frogRidable = false; -@@ -303,147 +475,316 @@ public class PurpurWorldConfig { - public boolean ghastRidableInWater = true; - public boolean ghastControllable = true; - public double ghastMaxY = 320D; -+ public double ghastMaxHealth = 10.0D; - private void ghastSettings() { - ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); - ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater); - ghastControllable = getBoolean("mobs.ghast.controllable", ghastControllable); - ghastMaxY = getDouble("mobs.ghast.ridable-max-y", ghastMaxY); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.ghast.attributes.max-health", ghastMaxHealth); -+ set("mobs.ghast.attributes.max-health", null); -+ set("mobs.ghast.attributes.max_health", oldValue); -+ } -+ ghastMaxHealth = getDouble("mobs.ghast.attributes.max_health", ghastMaxHealth); - } - - public boolean giantRidable = false; - public boolean giantRidableInWater = true; - public boolean giantControllable = true; -+ public double giantMovementSpeed = 0.5D; -+ public double giantAttackDamage = 50.0D; -+ public double giantMaxHealth = 100.0D; - private void giantSettings() { - giantRidable = getBoolean("mobs.giant.ridable", giantRidable); - giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater); - giantControllable = getBoolean("mobs.giant.controllable", giantControllable); -+ giantMovementSpeed = getDouble("mobs.giant.movement-speed", giantMovementSpeed); -+ giantAttackDamage = getDouble("mobs.giant.attack-damage", giantAttackDamage); -+ if (PurpurConfig.version < 8) { -+ double oldValue = getDouble("mobs.giant.max-health", giantMaxHealth); -+ set("mobs.giant.max-health", null); -+ set("mobs.giant.attributes.max_health", oldValue); -+ } else if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.giant.attributes.max-health", giantMaxHealth); -+ set("mobs.giant.attributes.max-health", null); -+ set("mobs.giant.attributes.max_health", oldValue); -+ } -+ giantMaxHealth = getDouble("mobs.giant.attributes.max_health", giantMaxHealth); - } - - public boolean glowSquidRidable = false; - public boolean glowSquidControllable = true; -+ public double glowSquidMaxHealth = 10.0D; - private void glowSquidSettings() { - glowSquidRidable = getBoolean("mobs.glow_squid.ridable", glowSquidRidable); - glowSquidControllable = getBoolean("mobs.glow_squid.controllable", glowSquidControllable); -+ glowSquidMaxHealth = getDouble("mobs.glow_squid.attributes.max_health", glowSquidMaxHealth); - } - - public boolean goatRidable = false; - public boolean goatRidableInWater = true; - public boolean goatControllable = true; -+ public double goatMaxHealth = 10.0D; - private void goatSettings() { - goatRidable = getBoolean("mobs.goat.ridable", goatRidable); - goatRidableInWater = getBoolean("mobs.goat.ridable-in-water", goatRidableInWater); - goatControllable = getBoolean("mobs.goat.controllable", goatControllable); -+ goatMaxHealth = getDouble("mobs.goat.attributes.max_health", goatMaxHealth); - } - - public boolean guardianRidable = false; - public boolean guardianControllable = true; -+ public double guardianMaxHealth = 30.0D; - private void guardianSettings() { - guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable); - guardianControllable = getBoolean("mobs.guardian.controllable", guardianControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.guardian.attributes.max-health", guardianMaxHealth); -+ set("mobs.guardian.attributes.max-health", null); -+ set("mobs.guardian.attributes.max_health", oldValue); -+ } -+ guardianMaxHealth = getDouble("mobs.guardian.attributes.max_health", guardianMaxHealth); - } - - public boolean hoglinRidable = false; - public boolean hoglinRidableInWater = true; - public boolean hoglinControllable = true; -+ public double hoglinMaxHealth = 40.0D; - private void hoglinSettings() { - hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); - hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); - hoglinControllable = getBoolean("mobs.hoglin.controllable", hoglinControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.hoglin.attributes.max-health", hoglinMaxHealth); -+ set("mobs.hoglin.attributes.max-health", null); -+ set("mobs.hoglin.attributes.max_health", oldValue); -+ } -+ hoglinMaxHealth = getDouble("mobs.hoglin.attributes.max_health", hoglinMaxHealth); - } - - public boolean horseRidableInWater = false; -+ public double horseMaxHealthMin = 15.0D; -+ public double horseMaxHealthMax = 30.0D; -+ public double horseJumpStrengthMin = 0.4D; -+ public double horseJumpStrengthMax = 1.0D; -+ public double horseMovementSpeedMin = 0.1125D; -+ public double horseMovementSpeedMax = 0.3375D; - private void horseSettings() { - horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); -+ if (PurpurConfig.version < 10) { -+ double oldMin = getDouble("mobs.horse.attributes.max-health.min", horseMaxHealthMin); -+ double oldMax = getDouble("mobs.horse.attributes.max-health.max", horseMaxHealthMax); -+ set("mobs.horse.attributes.max-health", null); -+ set("mobs.horse.attributes.max_health.min", oldMin); -+ set("mobs.horse.attributes.max_health.max", oldMax); -+ } -+ horseMaxHealthMin = getDouble("mobs.horse.attributes.max_health.min", horseMaxHealthMin); -+ horseMaxHealthMax = getDouble("mobs.horse.attributes.max_health.max", horseMaxHealthMax); -+ horseJumpStrengthMin = getDouble("mobs.horse.attributes.jump_strength.min", horseJumpStrengthMin); -+ horseJumpStrengthMax = getDouble("mobs.horse.attributes.jump_strength.max", horseJumpStrengthMax); -+ horseMovementSpeedMin = getDouble("mobs.horse.attributes.movement_speed.min", horseMovementSpeedMin); -+ horseMovementSpeedMax = getDouble("mobs.horse.attributes.movement_speed.max", horseMovementSpeedMax); - } - - public boolean huskRidable = false; - public boolean huskRidableInWater = true; - public boolean huskControllable = true; -+ public double huskMaxHealth = 20.0D; -+ public double huskSpawnReinforcements = 0.1D; - private void huskSettings() { - huskRidable = getBoolean("mobs.husk.ridable", huskRidable); - huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); - huskControllable = getBoolean("mobs.husk.controllable", huskControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.husk.attributes.max-health", huskMaxHealth); -+ set("mobs.husk.attributes.max-health", null); -+ set("mobs.husk.attributes.max_health", oldValue); -+ } -+ huskMaxHealth = getDouble("mobs.husk.attributes.max_health", huskMaxHealth); -+ huskSpawnReinforcements = getDouble("mobs.husk.attributes.spawn_reinforcements", huskSpawnReinforcements); - } - - public boolean illusionerRidable = false; - public boolean illusionerRidableInWater = true; - public boolean illusionerControllable = true; -+ public double illusionerMovementSpeed = 0.5D; -+ public double illusionerFollowRange = 18.0D; -+ public double illusionerMaxHealth = 32.0D; - private void illusionerSettings() { - illusionerRidable = getBoolean("mobs.illusioner.ridable", illusionerRidable); - illusionerRidableInWater = getBoolean("mobs.illusioner.ridable-in-water", illusionerRidableInWater); - illusionerControllable = getBoolean("mobs.illusioner.controllable", illusionerControllable); -+ illusionerMovementSpeed = getDouble("mobs.illusioner.movement-speed", illusionerMovementSpeed); -+ illusionerFollowRange = getDouble("mobs.illusioner.follow-range", illusionerFollowRange); -+ if (PurpurConfig.version < 8) { -+ double oldValue = getDouble("mobs.illusioner.max-health", illusionerMaxHealth); -+ set("mobs.illusioner.max-health", null); -+ set("mobs.illusioner.attributes.max_health", oldValue); -+ } else if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth); -+ set("mobs.illusioner.attributes.max-health", null); -+ set("mobs.illusioner.attributes.max_health", oldValue); -+ } -+ illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max_health", illusionerMaxHealth); - } - - public boolean ironGolemRidable = false; - public boolean ironGolemRidableInWater = true; - public boolean ironGolemControllable = true; - public boolean ironGolemCanSwim = false; -+ public double ironGolemMaxHealth = 100.0D; - private void ironGolemSettings() { - ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); - ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); - ironGolemControllable = getBoolean("mobs.iron_golem.controllable", ironGolemControllable); - ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.iron_golem.attributes.max-health", ironGolemMaxHealth); -+ set("mobs.iron_golem.attributes.max-health", null); -+ set("mobs.iron_golem.attributes.max_health", oldValue); -+ } -+ ironGolemMaxHealth = getDouble("mobs.iron_golem.attributes.max_health", ironGolemMaxHealth); - } - - public boolean llamaRidable = false; - public boolean llamaRidableInWater = false; - public boolean llamaControllable = true; -+ public double llamaMaxHealthMin = 15.0D; -+ public double llamaMaxHealthMax = 30.0D; -+ public double llamaJumpStrengthMin = 0.5D; -+ public double llamaJumpStrengthMax = 0.5D; -+ public double llamaMovementSpeedMin = 0.175D; -+ public double llamaMovementSpeedMax = 0.175D; - private void llamaSettings() { - llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); - llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); - llamaControllable = getBoolean("mobs.llama.controllable", llamaControllable); -+ if (PurpurConfig.version < 10) { -+ double oldMin = getDouble("mobs.llama.attributes.max-health.min", llamaMaxHealthMin); -+ double oldMax = getDouble("mobs.llama.attributes.max-health.max", llamaMaxHealthMax); -+ set("mobs.llama.attributes.max-health", null); -+ set("mobs.llama.attributes.max_health.min", oldMin); -+ set("mobs.llama.attributes.max_health.max", oldMax); -+ } -+ llamaMaxHealthMin = getDouble("mobs.llama.attributes.max_health.min", llamaMaxHealthMin); -+ llamaMaxHealthMax = getDouble("mobs.llama.attributes.max_health.max", llamaMaxHealthMax); -+ llamaJumpStrengthMin = getDouble("mobs.llama.attributes.jump_strength.min", llamaJumpStrengthMin); -+ llamaJumpStrengthMax = getDouble("mobs.llama.attributes.jump_strength.max", llamaJumpStrengthMax); -+ llamaMovementSpeedMin = getDouble("mobs.llama.attributes.movement_speed.min", llamaMovementSpeedMin); -+ llamaMovementSpeedMax = getDouble("mobs.llama.attributes.movement_speed.max", llamaMovementSpeedMax); - } - - public boolean magmaCubeRidable = false; - public boolean magmaCubeRidableInWater = true; - public boolean magmaCubeControllable = true; -+ public String magmaCubeMaxHealth = "size * size"; -+ public String magmaCubeAttackDamage = "size"; -+ public Map magmaCubeMaxHealthCache = new HashMap<>(); -+ public Map magmaCubeAttackDamageCache = new HashMap<>(); - private void magmaCubeSettings() { - magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable); - magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater); - magmaCubeControllable = getBoolean("mobs.magma_cube.controllable", magmaCubeControllable); -+ if (PurpurConfig.version < 10) { -+ String oldValue = getString("mobs.magma_cube.attributes.max-health", magmaCubeMaxHealth); -+ set("mobs.magma_cube.attributes.max-health", null); -+ set("mobs.magma_cube.attributes.max_health", oldValue); -+ } -+ magmaCubeMaxHealth = getString("mobs.magma_cube.attributes.max_health", magmaCubeMaxHealth); -+ magmaCubeAttackDamage = getString("mobs.magma_cube.attributes.attack_damage", magmaCubeAttackDamage); -+ magmaCubeMaxHealthCache.clear(); -+ magmaCubeAttackDamageCache.clear(); - } - - public boolean mooshroomRidable = false; - public boolean mooshroomRidableInWater = true; - public boolean mooshroomControllable = true; -+ public double mooshroomMaxHealth = 10.0D; - private void mooshroomSettings() { - mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); - mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); - mooshroomControllable = getBoolean("mobs.mooshroom.controllable", mooshroomControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.mooshroom.attributes.max-health", mooshroomMaxHealth); -+ set("mobs.mooshroom.attributes.max-health", null); -+ set("mobs.mooshroom.attributes.max_health", oldValue); -+ } -+ mooshroomMaxHealth = getDouble("mobs.mooshroom.attributes.max_health", mooshroomMaxHealth); - } - - public boolean muleRidableInWater = false; -+ public double muleMaxHealthMin = 15.0D; -+ public double muleMaxHealthMax = 30.0D; -+ public double muleJumpStrengthMin = 0.5D; -+ public double muleJumpStrengthMax = 0.5D; -+ public double muleMovementSpeedMin = 0.175D; -+ public double muleMovementSpeedMax = 0.175D; - private void muleSettings() { - muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); -+ if (PurpurConfig.version < 10) { -+ double oldMin = getDouble("mobs.mule.attributes.max-health.min", muleMaxHealthMin); -+ double oldMax = getDouble("mobs.mule.attributes.max-health.max", muleMaxHealthMax); -+ set("mobs.mule.attributes.max-health", null); -+ set("mobs.mule.attributes.max_health.min", oldMin); -+ set("mobs.mule.attributes.max_health.max", oldMax); -+ } -+ muleMaxHealthMin = getDouble("mobs.mule.attributes.max_health.min", muleMaxHealthMin); -+ muleMaxHealthMax = getDouble("mobs.mule.attributes.max_health.max", muleMaxHealthMax); -+ muleJumpStrengthMin = getDouble("mobs.mule.attributes.jump_strength.min", muleJumpStrengthMin); -+ muleJumpStrengthMax = getDouble("mobs.mule.attributes.jump_strength.max", muleJumpStrengthMax); -+ muleMovementSpeedMin = getDouble("mobs.mule.attributes.movement_speed.min", muleMovementSpeedMin); -+ muleMovementSpeedMax = getDouble("mobs.mule.attributes.movement_speed.max", muleMovementSpeedMax); - } - - public boolean ocelotRidable = false; - public boolean ocelotRidableInWater = true; - public boolean ocelotControllable = true; -+ public double ocelotMaxHealth = 10.0D; - private void ocelotSettings() { - ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); - ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); - ocelotControllable = getBoolean("mobs.ocelot.controllable", ocelotControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.ocelot.attributes.max-health", ocelotMaxHealth); -+ set("mobs.ocelot.attributes.max-health", null); -+ set("mobs.ocelot.attributes.max_health", oldValue); -+ } -+ ocelotMaxHealth = getDouble("mobs.ocelot.attributes.max_health", ocelotMaxHealth); - } - - public boolean pandaRidable = false; - public boolean pandaRidableInWater = true; - public boolean pandaControllable = true; -+ public double pandaMaxHealth = 20.0D; - private void pandaSettings() { - pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); - pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); - pandaControllable = getBoolean("mobs.panda.controllable", pandaControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.panda.attributes.max-health", pandaMaxHealth); -+ set("mobs.panda.attributes.max-health", null); -+ set("mobs.panda.attributes.max_health", oldValue); -+ } -+ pandaMaxHealth = getDouble("mobs.panda.attributes.max_health", pandaMaxHealth); - } - - public boolean parrotRidable = false; - public boolean parrotRidableInWater = true; - public boolean parrotControllable = true; - public double parrotMaxY = 320D; -+ public double parrotMaxHealth = 6.0D; - private void parrotSettings() { - parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); - parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); - parrotControllable = getBoolean("mobs.parrot.controllable", parrotControllable); - parrotMaxY = getDouble("mobs.parrot.ridable-max-y", parrotMaxY); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.parrot.attributes.max-health", parrotMaxHealth); -+ set("mobs.parrot.attributes.max-health", null); -+ set("mobs.parrot.attributes.max_health", oldValue); -+ } -+ parrotMaxHealth = getDouble("mobs.parrot.attributes.max_health", parrotMaxHealth); - } - - public boolean phantomRidable = false; -@@ -453,6 +794,10 @@ public class PurpurWorldConfig { - public float phantomFlameDamage = 1.0F; - public int phantomFlameFireTime = 8; - public boolean phantomAllowGriefing = false; -+ public String phantomMaxHealth = "20.0"; -+ public String phantomAttackDamage = "6 + size"; -+ public Map phantomMaxHealthCache = new HashMap<>(); -+ public Map phantomAttackDamageCache = new HashMap<>(); - private void phantomSettings() { - phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); - phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -@@ -461,191 +806,363 @@ public class PurpurWorldConfig { - phantomFlameDamage = (float) getDouble("mobs.phantom.flames.damage", phantomFlameDamage); - phantomFlameFireTime = getInt("mobs.phantom.flames.fire-time", phantomFlameFireTime); - phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.phantom.attributes.max-health", Double.parseDouble(phantomMaxHealth)); -+ set("mobs.phantom.attributes.max-health", null); -+ set("mobs.phantom.attributes.max_health", String.valueOf(oldValue)); -+ } -+ if (PurpurConfig.version < 25) { -+ double oldValue = getDouble("mobs.phantom.attributes.max_health", Double.parseDouble(phantomMaxHealth)); -+ set("mobs.phantom.attributes.max_health", String.valueOf(oldValue)); -+ } -+ phantomMaxHealth = getString("mobs.phantom.attributes.max_health", phantomMaxHealth); -+ phantomAttackDamage = getString("mobs.phantom.attributes.attack_damage", phantomAttackDamage); -+ phantomMaxHealthCache.clear(); -+ phantomAttackDamageCache.clear(); - } - - public boolean pigRidable = false; - public boolean pigRidableInWater = false; - public boolean pigControllable = true; -+ public double pigMaxHealth = 10.0D; - private void pigSettings() { - pigRidable = getBoolean("mobs.pig.ridable", pigRidable); - pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); - pigControllable = getBoolean("mobs.pig.controllable", pigControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.pig.attributes.max-health", pigMaxHealth); -+ set("mobs.pig.attributes.max-health", null); -+ set("mobs.pig.attributes.max_health", oldValue); -+ } -+ pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth); - } - - public boolean piglinRidable = false; - public boolean piglinRidableInWater = true; - public boolean piglinControllable = true; -+ public double piglinMaxHealth = 16.0D; - private void piglinSettings() { - piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); - piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); - piglinControllable = getBoolean("mobs.piglin.controllable", piglinControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.piglin.attributes.max-health", piglinMaxHealth); -+ set("mobs.piglin.attributes.max-health", null); -+ set("mobs.piglin.attributes.max_health", oldValue); -+ } -+ piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth); - } - - public boolean piglinBruteRidable = false; - public boolean piglinBruteRidableInWater = true; - public boolean piglinBruteControllable = true; -+ public double piglinBruteMaxHealth = 50.0D; - private void piglinBruteSettings() { - piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable); - piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater); - piglinBruteControllable = getBoolean("mobs.piglin_brute.controllable", piglinBruteControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.piglin_brute.attributes.max-health", piglinBruteMaxHealth); -+ set("mobs.piglin_brute.attributes.max-health", null); -+ set("mobs.piglin_brute.attributes.max_health", oldValue); -+ } -+ piglinBruteMaxHealth = getDouble("mobs.piglin_brute.attributes.max_health", piglinBruteMaxHealth); - } - - public boolean pillagerRidable = false; - public boolean pillagerRidableInWater = true; - public boolean pillagerControllable = true; -+ public double pillagerMaxHealth = 24.0D; - private void pillagerSettings() { - pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); - pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); - pillagerControllable = getBoolean("mobs.pillager.controllable", pillagerControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.pillager.attributes.max-health", pillagerMaxHealth); -+ set("mobs.pillager.attributes.max-health", null); -+ set("mobs.pillager.attributes.max_health", oldValue); -+ } -+ pillagerMaxHealth = getDouble("mobs.pillager.attributes.max_health", pillagerMaxHealth); - } - - public boolean polarBearRidable = false; - public boolean polarBearRidableInWater = true; - public boolean polarBearControllable = true; -+ public double polarBearMaxHealth = 30.0D; - private void polarBearSettings() { - polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); - polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); - polarBearControllable = getBoolean("mobs.polar_bear.controllable", polarBearControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.polar_bear.attributes.max-health", polarBearMaxHealth); -+ set("mobs.polar_bear.attributes.max-health", null); -+ set("mobs.polar_bear.attributes.max_health", oldValue); -+ } -+ polarBearMaxHealth = getDouble("mobs.polar_bear.attributes.max_health", polarBearMaxHealth); - } - - public boolean pufferfishRidable = false; - public boolean pufferfishControllable = true; -+ public double pufferfishMaxHealth = 3.0D; - private void pufferfishSettings() { - pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable); - pufferfishControllable = getBoolean("mobs.pufferfish.controllable", pufferfishControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.pufferfish.attributes.max-health", pufferfishMaxHealth); -+ set("mobs.pufferfish.attributes.max-health", null); -+ set("mobs.pufferfish.attributes.max_health", oldValue); -+ } -+ pufferfishMaxHealth = getDouble("mobs.pufferfish.attributes.max_health", pufferfishMaxHealth); - } - - public boolean rabbitRidable = false; - public boolean rabbitRidableInWater = true; - public boolean rabbitControllable = true; -+ public double rabbitMaxHealth = 3.0D; - private void rabbitSettings() { - rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); - rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); - rabbitControllable = getBoolean("mobs.rabbit.controllable", rabbitControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.rabbit.attributes.max-health", rabbitMaxHealth); -+ set("mobs.rabbit.attributes.max-health", null); -+ set("mobs.rabbit.attributes.max_health", oldValue); -+ } -+ rabbitMaxHealth = getDouble("mobs.rabbit.attributes.max_health", rabbitMaxHealth); - } - - public boolean ravagerRidable = false; - public boolean ravagerRidableInWater = false; - public boolean ravagerControllable = true; -+ public double ravagerMaxHealth = 100.0D; - private void ravagerSettings() { - ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); - ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); - ravagerControllable = getBoolean("mobs.ravager.controllable", ravagerControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.ravager.attributes.max-health", ravagerMaxHealth); -+ set("mobs.ravager.attributes.max-health", null); -+ set("mobs.ravager.attributes.max_health", oldValue); -+ } -+ ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth); - } - - public boolean salmonRidable = false; - public boolean salmonControllable = true; -+ public double salmonMaxHealth = 3.0D; - private void salmonSettings() { - salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable); - salmonControllable = getBoolean("mobs.salmon.controllable", salmonControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.salmon.attributes.max-health", salmonMaxHealth); -+ set("mobs.salmon.attributes.max-health", null); -+ set("mobs.salmon.attributes.max_health", oldValue); -+ } -+ salmonMaxHealth = getDouble("mobs.salmon.attributes.max_health", salmonMaxHealth); - } - - public boolean sheepRidable = false; - public boolean sheepRidableInWater = true; - public boolean sheepControllable = true; -+ public double sheepMaxHealth = 8.0D; - private void sheepSettings() { - sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); - sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); - sheepControllable = getBoolean("mobs.sheep.controllable", sheepControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.sheep.attributes.max-health", sheepMaxHealth); -+ set("mobs.sheep.attributes.max-health", null); -+ set("mobs.sheep.attributes.max_health", oldValue); -+ } -+ sheepMaxHealth = getDouble("mobs.sheep.attributes.max_health", sheepMaxHealth); - } - - public boolean shulkerRidable = false; - public boolean shulkerRidableInWater = true; - public boolean shulkerControllable = true; -+ public double shulkerMaxHealth = 30.0D; - private void shulkerSettings() { - shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); - shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); - shulkerControllable = getBoolean("mobs.shulker.controllable", shulkerControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.shulker.attributes.max-health", shulkerMaxHealth); -+ set("mobs.shulker.attributes.max-health", null); -+ set("mobs.shulker.attributes.max_health", oldValue); -+ } -+ shulkerMaxHealth = getDouble("mobs.shulker.attributes.max_health", shulkerMaxHealth); - } - - public boolean silverfishRidable = false; - public boolean silverfishRidableInWater = true; - public boolean silverfishControllable = true; -+ public double silverfishMaxHealth = 8.0D; - private void silverfishSettings() { - silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); - silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); - silverfishControllable = getBoolean("mobs.silverfish.controllable", silverfishControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.silverfish.attributes.max-health", silverfishMaxHealth); -+ set("mobs.silverfish.attributes.max-health", null); -+ set("mobs.silverfish.attributes.max_health", oldValue); -+ } -+ silverfishMaxHealth = getDouble("mobs.silverfish.attributes.max_health", silverfishMaxHealth); - } - - public boolean skeletonRidable = false; - public boolean skeletonRidableInWater = true; - public boolean skeletonControllable = true; -+ public double skeletonMaxHealth = 20.0D; - private void skeletonSettings() { - skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); - skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); - skeletonControllable = getBoolean("mobs.skeleton.controllable", skeletonControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.skeleton.attributes.max-health", skeletonMaxHealth); -+ set("mobs.skeleton.attributes.max-health", null); -+ set("mobs.skeleton.attributes.max_health", oldValue); -+ } -+ skeletonMaxHealth = getDouble("mobs.skeleton.attributes.max_health", skeletonMaxHealth); - } - - public boolean skeletonHorseRidable = false; - public boolean skeletonHorseRidableInWater = true; - public boolean skeletonHorseCanSwim = false; -+ public double skeletonHorseMaxHealthMin = 15.0D; -+ public double skeletonHorseMaxHealthMax = 15.0D; -+ public double skeletonHorseJumpStrengthMin = 0.4D; -+ public double skeletonHorseJumpStrengthMax = 1.0D; -+ public double skeletonHorseMovementSpeedMin = 0.2D; -+ public double skeletonHorseMovementSpeedMax = 0.2D; - private void skeletonHorseSettings() { - skeletonHorseRidable = getBoolean("mobs.skeleton_horse.ridable", skeletonHorseRidable); - skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater); - skeletonHorseCanSwim = getBoolean("mobs.skeleton_horse.can-swim", skeletonHorseCanSwim); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.skeleton_horse.attributes.max-health", skeletonHorseMaxHealthMin); -+ set("mobs.skeleton_horse.attributes.max-health", null); -+ set("mobs.skeleton_horse.attributes.max_health.min", oldValue); -+ set("mobs.skeleton_horse.attributes.max_health.max", oldValue); -+ } -+ skeletonHorseMaxHealthMin = getDouble("mobs.skeleton_horse.attributes.max_health.min", skeletonHorseMaxHealthMin); -+ skeletonHorseMaxHealthMax = getDouble("mobs.skeleton_horse.attributes.max_health.max", skeletonHorseMaxHealthMax); -+ skeletonHorseJumpStrengthMin = getDouble("mobs.skeleton_horse.attributes.jump_strength.min", skeletonHorseJumpStrengthMin); -+ skeletonHorseJumpStrengthMax = getDouble("mobs.skeleton_horse.attributes.jump_strength.max", skeletonHorseJumpStrengthMax); -+ skeletonHorseMovementSpeedMin = getDouble("mobs.skeleton_horse.attributes.movement_speed.min", skeletonHorseMovementSpeedMin); -+ skeletonHorseMovementSpeedMax = getDouble("mobs.skeleton_horse.attributes.movement_speed.max", skeletonHorseMovementSpeedMax); - } - - public boolean slimeRidable = false; - public boolean slimeRidableInWater = true; - public boolean slimeControllable = true; -+ public String slimeMaxHealth = "size * size"; -+ public String slimeAttackDamage = "size"; -+ public Map slimeMaxHealthCache = new HashMap<>(); -+ public Map slimeAttackDamageCache = new HashMap<>(); - private void slimeSettings() { - slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable); - slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater); - slimeControllable = getBoolean("mobs.slime.controllable", slimeControllable); -+ if (PurpurConfig.version < 10) { -+ String oldValue = getString("mobs.slime.attributes.max-health", slimeMaxHealth); -+ set("mobs.slime.attributes.max-health", null); -+ set("mobs.slime.attributes.max_health", oldValue); -+ } -+ slimeMaxHealth = getString("mobs.slime.attributes.max_health", slimeMaxHealth); -+ slimeAttackDamage = getString("mobs.slime.attributes.attack_damage", slimeAttackDamage); -+ slimeMaxHealthCache.clear(); -+ slimeAttackDamageCache.clear(); - } - - public boolean snowGolemRidable = false; - public boolean snowGolemRidableInWater = true; - public boolean snowGolemControllable = true; - public boolean snowGolemLeaveTrailWhenRidden = false; -+ public double snowGolemMaxHealth = 4.0D; - private void snowGolemSettings() { - snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); - snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); - snowGolemControllable = getBoolean("mobs.snow_golem.controllable", snowGolemControllable); - snowGolemLeaveTrailWhenRidden = getBoolean("mobs.snow_golem.leave-trail-when-ridden", snowGolemLeaveTrailWhenRidden); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.snow_golem.attributes.max-health", snowGolemMaxHealth); -+ set("mobs.snow_golem.attributes.max-health", null); -+ set("mobs.snow_golem.attributes.max_health", oldValue); -+ } -+ snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth); - } - - public boolean snifferRidable = false; - public boolean snifferRidableInWater = true; - public boolean snifferControllable = true; -+ public double snifferMaxHealth = 14.0D; - private void snifferSettings() { - snifferRidable = getBoolean("mobs.sniffer.ridable", snifferRidable); - snifferRidableInWater = getBoolean("mobs.sniffer.ridable-in-water", snifferRidableInWater); - snifferControllable = getBoolean("mobs.sniffer.controllable", snifferControllable); -+ snifferMaxHealth = getDouble("mobs.sniffer.attributes.max_health", snifferMaxHealth); - } - - public boolean squidRidable = false; - public boolean squidControllable = true; -+ public double squidMaxHealth = 10.0D; - private void squidSettings() { - squidRidable = getBoolean("mobs.squid.ridable", squidRidable); - squidControllable = getBoolean("mobs.squid.controllable", squidControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.squid.attributes.max-health", squidMaxHealth); -+ set("mobs.squid.attributes.max-health", null); -+ set("mobs.squid.attributes.max_health", oldValue); -+ } -+ squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth); - } - - public boolean spiderRidable = false; - public boolean spiderRidableInWater = false; - public boolean spiderControllable = true; -+ public double spiderMaxHealth = 16.0D; - private void spiderSettings() { - spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable); - spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater); - spiderControllable = getBoolean("mobs.spider.controllable", spiderControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.spider.attributes.max-health", spiderMaxHealth); -+ set("mobs.spider.attributes.max-health", null); -+ set("mobs.spider.attributes.max_health", oldValue); -+ } -+ spiderMaxHealth = getDouble("mobs.spider.attributes.max_health", spiderMaxHealth); - } - - public boolean strayRidable = false; - public boolean strayRidableInWater = true; - public boolean strayControllable = true; -+ public double strayMaxHealth = 20.0D; - private void straySettings() { - strayRidable = getBoolean("mobs.stray.ridable", strayRidable); - strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater); - strayControllable = getBoolean("mobs.stray.controllable", strayControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.stray.attributes.max-health", strayMaxHealth); -+ set("mobs.stray.attributes.max-health", null); -+ set("mobs.stray.attributes.max_health", oldValue); -+ } -+ strayMaxHealth = getDouble("mobs.stray.attributes.max_health", strayMaxHealth); - } - - public boolean striderRidable = false; - public boolean striderRidableInWater = false; - public boolean striderControllable = true; -+ public double striderMaxHealth = 20.0D; - private void striderSettings() { - striderRidable = getBoolean("mobs.strider.ridable", striderRidable); - striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); - striderControllable = getBoolean("mobs.strider.controllable", striderControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.strider.attributes.max-health", striderMaxHealth); -+ set("mobs.strider.attributes.max-health", null); -+ set("mobs.strider.attributes.max_health", oldValue); -+ } -+ striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth); - } - - public boolean tadpoleRidable = false; -@@ -660,64 +1177,125 @@ public class PurpurWorldConfig { - public boolean traderLlamaRidable = false; - public boolean traderLlamaRidableInWater = false; - public boolean traderLlamaControllable = true; -+ public double traderLlamaMaxHealthMin = 15.0D; -+ public double traderLlamaMaxHealthMax = 30.0D; -+ public double traderLlamaJumpStrengthMin = 0.5D; -+ public double traderLlamaJumpStrengthMax = 0.5D; -+ public double traderLlamaMovementSpeedMin = 0.175D; -+ public double traderLlamaMovementSpeedMax = 0.175D; - private void traderLlamaSettings() { - traderLlamaRidable = getBoolean("mobs.trader_llama.ridable", traderLlamaRidable); - traderLlamaRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", traderLlamaRidableInWater); - traderLlamaControllable = getBoolean("mobs.trader_llama.controllable", traderLlamaControllable); -+ if (PurpurConfig.version < 10) { -+ double oldMin = getDouble("mobs.trader_llama.attributes.max-health.min", traderLlamaMaxHealthMin); -+ double oldMax = getDouble("mobs.trader_llama.attributes.max-health.max", traderLlamaMaxHealthMax); -+ set("mobs.trader_llama.attributes.max-health", null); -+ set("mobs.trader_llama.attributes.max_health.min", oldMin); -+ set("mobs.trader_llama.attributes.max_health.max", oldMax); -+ } -+ traderLlamaMaxHealthMin = getDouble("mobs.trader_llama.attributes.max_health.min", traderLlamaMaxHealthMin); -+ traderLlamaMaxHealthMax = getDouble("mobs.trader_llama.attributes.max_health.max", traderLlamaMaxHealthMax); -+ traderLlamaJumpStrengthMin = getDouble("mobs.trader_llama.attributes.jump_strength.min", traderLlamaJumpStrengthMin); -+ traderLlamaJumpStrengthMax = getDouble("mobs.trader_llama.attributes.jump_strength.max", traderLlamaJumpStrengthMax); -+ traderLlamaMovementSpeedMin = getDouble("mobs.trader_llama.attributes.movement_speed.min", traderLlamaMovementSpeedMin); -+ traderLlamaMovementSpeedMax = getDouble("mobs.trader_llama.attributes.movement_speed.max", traderLlamaMovementSpeedMax); - } - - public boolean tropicalFishRidable = false; - public boolean tropicalFishControllable = true; -+ public double tropicalFishMaxHealth = 3.0D; - private void tropicalFishSettings() { - tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable); - tropicalFishControllable = getBoolean("mobs.tropical_fish.controllable", tropicalFishControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.tropical_fish.attributes.max-health", tropicalFishMaxHealth); -+ set("mobs.tropical_fish.attributes.max-health", null); -+ set("mobs.tropical_fish.attributes.max_health", oldValue); -+ } -+ tropicalFishMaxHealth = getDouble("mobs.tropical_fish.attributes.max_health", tropicalFishMaxHealth); - } - - public boolean turtleRidable = false; - public boolean turtleRidableInWater = true; - public boolean turtleControllable = true; -+ public double turtleMaxHealth = 30.0D; - private void turtleSettings() { - turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); - turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); - turtleControllable = getBoolean("mobs.turtle.controllable", turtleControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.turtle.attributes.max-health", turtleMaxHealth); -+ set("mobs.turtle.attributes.max-health", null); -+ set("mobs.turtle.attributes.max_health", oldValue); -+ } -+ turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth); - } - - public boolean vexRidable = false; - public boolean vexRidableInWater = true; - public boolean vexControllable = true; - public double vexMaxY = 320D; -+ public double vexMaxHealth = 14.0D; - private void vexSettings() { - vexRidable = getBoolean("mobs.vex.ridable", vexRidable); - vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater); - vexControllable = getBoolean("mobs.vex.controllable", vexControllable); - vexMaxY = getDouble("mobs.vex.ridable-max-y", vexMaxY); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.vex.attributes.max-health", vexMaxHealth); -+ set("mobs.vex.attributes.max-health", null); -+ set("mobs.vex.attributes.max_health", oldValue); -+ } -+ vexMaxHealth = getDouble("mobs.vex.attributes.max_health", vexMaxHealth); - } - - public boolean villagerRidable = false; - public boolean villagerRidableInWater = true; - public boolean villagerControllable = true; -+ public double villagerMaxHealth = 20.0D; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); - villagerControllable = getBoolean("mobs.villager.controllable", villagerControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.villager.attributes.max-health", villagerMaxHealth); -+ set("mobs.villager.attributes.max-health", null); -+ set("mobs.villager.attributes.max_health", oldValue); -+ } -+ villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth); - } - - public boolean vindicatorRidable = false; - public boolean vindicatorRidableInWater = true; - public boolean vindicatorControllable = true; -+ public double vindicatorMaxHealth = 24.0D; - private void vindicatorSettings() { - vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); - vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); - vindicatorControllable = getBoolean("mobs.vindicator.controllable", vindicatorControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.vindicator.attributes.max-health", vindicatorMaxHealth); -+ set("mobs.vindicator.attributes.max-health", null); -+ set("mobs.vindicator.attributes.max_health", oldValue); -+ } -+ vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth); - } - - public boolean wanderingTraderRidable = false; - public boolean wanderingTraderRidableInWater = true; - public boolean wanderingTraderControllable = true; -+ public double wanderingTraderMaxHealth = 20.0D; - private void wanderingTraderSettings() { - wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); - wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); - wanderingTraderControllable = getBoolean("mobs.wandering_trader.controllable", wanderingTraderControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.wandering_trader.attributes.max-health", wanderingTraderMaxHealth); -+ set("mobs.wandering_trader.attributes.max-health", null); -+ set("mobs.wandering_trader.attributes.max_health", oldValue); -+ } -+ wanderingTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", wanderingTraderMaxHealth); - } - - public boolean wardenRidable = false; -@@ -732,83 +1310,167 @@ public class PurpurWorldConfig { - public boolean witchRidable = false; - public boolean witchRidableInWater = true; - public boolean witchControllable = true; -+ public double witchMaxHealth = 26.0D; - private void witchSettings() { - witchRidable = getBoolean("mobs.witch.ridable", witchRidable); - witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater); - witchControllable = getBoolean("mobs.witch.controllable", witchControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.witch.attributes.max-health", witchMaxHealth); -+ set("mobs.witch.attributes.max-health", null); -+ set("mobs.witch.attributes.max_health", oldValue); -+ } -+ witchMaxHealth = getDouble("mobs.witch.attributes.max_health", witchMaxHealth); - } - - public boolean witherRidable = false; - public boolean witherRidableInWater = true; - public boolean witherControllable = true; - public double witherMaxY = 320D; -+ public double witherMaxHealth = 300.0D; - private void witherSettings() { - witherRidable = getBoolean("mobs.wither.ridable", witherRidable); - witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); - witherControllable = getBoolean("mobs.wither.controllable", witherControllable); - witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); -+ if (PurpurConfig.version < 8) { -+ double oldValue = getDouble("mobs.wither.max-health", witherMaxHealth); -+ set("mobs.wither.max_health", null); -+ set("mobs.wither.attributes.max-health", oldValue); -+ } else if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.wither.attributes.max-health", witherMaxHealth); -+ set("mobs.wither.attributes.max-health", null); -+ set("mobs.wither.attributes.max_health", oldValue); -+ } -+ witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth); - } - - public boolean witherSkeletonRidable = false; - public boolean witherSkeletonRidableInWater = true; - public boolean witherSkeletonControllable = true; -+ public double witherSkeletonMaxHealth = 20.0D; - private void witherSkeletonSettings() { - witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable); - witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater); - witherSkeletonControllable = getBoolean("mobs.wither_skeleton.controllable", witherSkeletonControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.wither_skeleton.attributes.max-health", witherSkeletonMaxHealth); -+ set("mobs.wither_skeleton.attributes.max-health", null); -+ set("mobs.wither_skeleton.attributes.max_health", oldValue); -+ } -+ witherSkeletonMaxHealth = getDouble("mobs.wither_skeleton.attributes.max_health", witherSkeletonMaxHealth); - } - - public boolean wolfRidable = false; - public boolean wolfRidableInWater = true; - public boolean wolfControllable = true; -+ public double wolfMaxHealth = 8.0D; - private void wolfSettings() { - wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); - wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); - wolfControllable = getBoolean("mobs.wolf.controllable", wolfControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.wolf.attributes.max-health", wolfMaxHealth); -+ set("mobs.wolf.attributes.max-health", null); -+ set("mobs.wolf.attributes.max_health", oldValue); -+ } -+ wolfMaxHealth = getDouble("mobs.wolf.attributes.max_health", wolfMaxHealth); - } - - public boolean zoglinRidable = false; - public boolean zoglinRidableInWater = true; - public boolean zoglinControllable = true; -+ public double zoglinMaxHealth = 40.0D; - private void zoglinSettings() { - zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable); - zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater); - zoglinControllable = getBoolean("mobs.zoglin.controllable", zoglinControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.zoglin.attributes.max-health", zoglinMaxHealth); -+ set("mobs.zoglin.attributes.max-health", null); -+ set("mobs.zoglin.attributes.max_health", oldValue); -+ } -+ zoglinMaxHealth = getDouble("mobs.zoglin.attributes.max_health", zoglinMaxHealth); - } - - public boolean zombieRidable = false; - public boolean zombieRidableInWater = true; - public boolean zombieControllable = true; -+ public double zombieMaxHealth = 20.0D; -+ public double zombieSpawnReinforcements = 0.1D; - private void zombieSettings() { - zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); - zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); - zombieControllable = getBoolean("mobs.zombie.controllable", zombieControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.zombie.attributes.max-health", zombieMaxHealth); -+ set("mobs.zombie.attributes.max-health", null); -+ set("mobs.zombie.attributes.max_health", oldValue); -+ } -+ zombieMaxHealth = getDouble("mobs.zombie.attributes.max_health", zombieMaxHealth); -+ zombieSpawnReinforcements = getDouble("mobs.zombie.attributes.spawn_reinforcements", zombieSpawnReinforcements); - } - - public boolean zombieHorseRidable = false; - public boolean zombieHorseRidableInWater = false; - public boolean zombieHorseCanSwim = false; -+ public double zombieHorseMaxHealthMin = 15.0D; -+ public double zombieHorseMaxHealthMax = 15.0D; -+ public double zombieHorseJumpStrengthMin = 0.4D; -+ public double zombieHorseJumpStrengthMax = 1.0D; -+ public double zombieHorseMovementSpeedMin = 0.2D; -+ public double zombieHorseMovementSpeedMax = 0.2D; - private void zombieHorseSettings() { - zombieHorseRidable = getBoolean("mobs.zombie_horse.ridable", zombieHorseRidable); - zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); - zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.zombie_horse.attributes.max-health", zombieHorseMaxHealthMin); -+ set("mobs.zombie_horse.attributes.max-health", null); -+ set("mobs.zombie_horse.attributes.max_health.min", oldValue); -+ set("mobs.zombie_horse.attributes.max_health.max", oldValue); -+ } -+ zombieHorseMaxHealthMin = getDouble("mobs.zombie_horse.attributes.max_health.min", zombieHorseMaxHealthMin); -+ zombieHorseMaxHealthMax = getDouble("mobs.zombie_horse.attributes.max_health.max", zombieHorseMaxHealthMax); -+ zombieHorseJumpStrengthMin = getDouble("mobs.zombie_horse.attributes.jump_strength.min", zombieHorseJumpStrengthMin); -+ zombieHorseJumpStrengthMax = getDouble("mobs.zombie_horse.attributes.jump_strength.max", zombieHorseJumpStrengthMax); -+ zombieHorseMovementSpeedMin = getDouble("mobs.zombie_horse.attributes.movement_speed.min", zombieHorseMovementSpeedMin); -+ zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax); - } - - public boolean zombieVillagerRidable = false; - public boolean zombieVillagerRidableInWater = true; - public boolean zombieVillagerControllable = true; -+ public double zombieVillagerMaxHealth = 20.0D; -+ public double zombieVillagerSpawnReinforcements = 0.1D; - private void zombieVillagerSettings() { - zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); - zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); - zombieVillagerControllable = getBoolean("mobs.zombie_villager.controllable", zombieVillagerControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.zombie_villager.attributes.max-health", zombieVillagerMaxHealth); -+ set("mobs.zombie_villager.attributes.max-health", null); -+ set("mobs.zombie_villager.attributes.max_health", oldValue); -+ } -+ zombieVillagerMaxHealth = getDouble("mobs.zombie_villager.attributes.max_health", zombieVillagerMaxHealth); -+ zombieVillagerSpawnReinforcements = getDouble("mobs.zombie_villager.attributes.spawn_reinforcements", zombieVillagerSpawnReinforcements); - } - - public boolean zombifiedPiglinRidable = false; - public boolean zombifiedPiglinRidableInWater = true; - public boolean zombifiedPiglinControllable = true; -+ public double zombifiedPiglinMaxHealth = 20.0D; -+ public double zombifiedPiglinSpawnReinforcements = 0.0D; - private void zombifiedPiglinSettings() { - zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); - zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); - zombifiedPiglinControllable = getBoolean("mobs.zombified_piglin.controllable", zombifiedPiglinControllable); -+ if (PurpurConfig.version < 10) { -+ double oldValue = getDouble("mobs.zombified_piglin.attributes.max-health", zombifiedPiglinMaxHealth); -+ set("mobs.zombified_piglin.attributes.max-health", null); -+ set("mobs.zombified_piglin.attributes.max_health", oldValue); -+ } -+ zombifiedPiglinMaxHealth = getDouble("mobs.zombified_piglin.attributes.max_health", zombifiedPiglinMaxHealth); -+ zombifiedPiglinSpawnReinforcements = getDouble("mobs.zombified_piglin.attributes.spawn_reinforcements", zombifiedPiglinSpawnReinforcements); - } - } diff --git a/patches/server/0008-Barrels-and-enderchests-6-rows.patch b/patches/server/0008-Barrels-and-enderchests-6-rows.patch deleted file mode 100644 index c21c377e1..000000000 --- a/patches/server/0008-Barrels-and-enderchests-6-rows.patch +++ /dev/null @@ -1,298 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 23 May 2019 21:50:37 -0500 -Subject: [PATCH] Barrels and enderchests 6 rows - - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 2d6b6795703431939005aa09d1ed590c3f755163..f10dcc0debcdd2077ee53cb1aefca8abd12f3ecd 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1188,6 +1188,27 @@ public abstract class PlayerList { - player.getBukkitEntity().recalculatePermissions(); // CraftBukkit - this.server.getCommands().sendCommands(player); - } // Paper - Add sendOpLevel API -+ -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.enderChestSixRows && org.purpurmc.purpur.PurpurConfig.enderChestPermissionRows) { -+ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkit = player.getBukkitEntity(); -+ if (bukkit.hasPermission("purpur.enderchest.rows.six")) { -+ player.sixRowEnderchestSlotCount = 54; -+ } else if (bukkit.hasPermission("purpur.enderchest.rows.five")) { -+ player.sixRowEnderchestSlotCount = 45; -+ } else if (bukkit.hasPermission("purpur.enderchest.rows.four")) { -+ player.sixRowEnderchestSlotCount = 36; -+ } else if (bukkit.hasPermission("purpur.enderchest.rows.three")) { -+ player.sixRowEnderchestSlotCount = 27; -+ } else if (bukkit.hasPermission("purpur.enderchest.rows.two")) { -+ player.sixRowEnderchestSlotCount = 18; -+ } else if (bukkit.hasPermission("purpur.enderchest.rows.one")) { -+ player.sixRowEnderchestSlotCount = 9; -+ } -+ } else { -+ player.sixRowEnderchestSlotCount = -1; -+ } -+ //Purpur end - } - - public boolean isWhiteListed(GameProfile profile) { -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 90e44c7281935bc7ceb3b220bbcd73187fed44fb..0641e448e0e98694976b820c2e9c4868f2b76909 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -195,6 +195,7 @@ public abstract class Player extends LivingEntity { - public boolean ignoreFallDamageFromCurrentImpulse; - public boolean affectsSpawning = true; // Paper - Affects Spawning API - public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage -+ public int sixRowEnderchestSlotCount = -1; // Purpur - - // CraftBukkit start - public boolean fauxSleeping; -diff --git a/src/main/java/net/minecraft/world/inventory/ChestMenu.java b/src/main/java/net/minecraft/world/inventory/ChestMenu.java -index 0dbfd23bbfc6ad203f048142f8c90ef741849fe1..9a80427d2bb470b6b1638e59aba57216676dcbd2 100644 ---- a/src/main/java/net/minecraft/world/inventory/ChestMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/ChestMenu.java -@@ -67,10 +67,30 @@ public class ChestMenu extends AbstractContainerMenu { - return new ChestMenu(MenuType.GENERIC_9x6, syncId, playerInventory, 6); - } - -+ // Purpur start -+ public static ChestMenu oneRow(int syncId, Inventory playerInventory, Container inventory) { -+ return new ChestMenu(MenuType.GENERIC_9x1, syncId, playerInventory, inventory, 1); -+ } -+ -+ public static ChestMenu twoRows(int syncId, Inventory playerInventory, Container inventory) { -+ return new ChestMenu(MenuType.GENERIC_9x2, syncId, playerInventory, inventory, 2); -+ } -+ // Purpur end -+ - public static ChestMenu threeRows(int syncId, Inventory playerInventory, Container inventory) { - return new ChestMenu(MenuType.GENERIC_9x3, syncId, playerInventory, inventory, 3); - } - -+ // Purpur start -+ public static ChestMenu fourRows(int syncId, Inventory playerInventory, Container inventory) { -+ return new ChestMenu(MenuType.GENERIC_9x4, syncId, playerInventory, inventory, 4); -+ } -+ -+ public static ChestMenu fiveRows(int syncId, Inventory playerInventory, Container inventory) { -+ return new ChestMenu(MenuType.GENERIC_9x5, syncId, playerInventory, inventory, 5); -+ } -+ // Purpur end -+ - public static ChestMenu sixRows(int syncId, Inventory playerInventory, Container inventory) { - return new ChestMenu(MenuType.GENERIC_9x6, syncId, playerInventory, inventory, 6); - } -diff --git a/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java b/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java -index a15d5ff872dbd77f3c3145e0328f3d02e431ff8c..1dcf36d502990d32fc4cd3ea69c3ea334baed69a 100644 ---- a/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java -+++ b/src/main/java/net/minecraft/world/inventory/PlayerEnderChestContainer.java -@@ -31,11 +31,18 @@ public class PlayerEnderChestContainer extends SimpleContainer { - } - - public PlayerEnderChestContainer(Player owner) { -- super(27); -+ super(org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? 54 : 27); // Purpur - this.owner = owner; - // CraftBukkit end - } - -+ // Purpur start -+ @Override -+ public int getContainerSize() { -+ return owner.sixRowEnderchestSlotCount < 0 ? super.getContainerSize() : owner.sixRowEnderchestSlotCount; -+ } -+ // Purpur end -+ - public void setActiveChest(EnderChestBlockEntity blockEntity) { - this.activeChest = blockEntity; - } -diff --git a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -index 5f9858ef8d0ec1a74d469ab4426eb1db068873fd..d7ef772444b301d0a3f167679027195e4150b064 100644 ---- a/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EnderChestBlock.java -@@ -91,7 +91,7 @@ public class EnderChestBlock extends AbstractChestBlock i - EnderChestBlockEntity enderChestBlockEntity = (EnderChestBlockEntity)blockEntity; - playerEnderChestContainer.setActiveChest(enderChestBlockEntity); - player.openMenu( -- new SimpleMenuProvider((i, inventory, playerx) -> ChestMenu.threeRows(i, inventory, playerEnderChestContainer), CONTAINER_TITLE) -+ new SimpleMenuProvider((i, inventory, playerx) -> org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? getEnderChestSixRows(i, inventory, player, playerEnderChestContainer) : ChestMenu.threeRows(i, inventory, playerEnderChestContainer), CONTAINER_TITLE) // Purpur - ); - player.awardStat(Stats.OPEN_ENDERCHEST); - PiglinAi.angerNearbyPiglins(player, true); -@@ -102,6 +102,35 @@ public class EnderChestBlock extends AbstractChestBlock i - } - } - -+ // Purpur start -+ private ChestMenu getEnderChestSixRows(int syncId, net.minecraft.world.entity.player.Inventory inventory, Player player, PlayerEnderChestContainer playerEnderChestContainer) { -+ if (org.purpurmc.purpur.PurpurConfig.enderChestPermissionRows) { -+ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkitPlayer = player.getBukkitEntity(); -+ if (bukkitPlayer.hasPermission("purpur.enderchest.rows.six")) { -+ player.sixRowEnderchestSlotCount = 54; -+ return ChestMenu.sixRows(syncId, inventory, playerEnderChestContainer); -+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.five")) { -+ player.sixRowEnderchestSlotCount = 45; -+ return ChestMenu.fiveRows(syncId, inventory, playerEnderChestContainer); -+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.four")) { -+ player.sixRowEnderchestSlotCount = 36; -+ return ChestMenu.fourRows(syncId, inventory, playerEnderChestContainer); -+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.three")) { -+ player.sixRowEnderchestSlotCount = 27; -+ return ChestMenu.threeRows(syncId, inventory, playerEnderChestContainer); -+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.two")) { -+ player.sixRowEnderchestSlotCount = 18; -+ return ChestMenu.twoRows(syncId, inventory, playerEnderChestContainer); -+ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.one")) { -+ player.sixRowEnderchestSlotCount = 9; -+ return ChestMenu.oneRow(syncId, inventory, playerEnderChestContainer); -+ } -+ } -+ player.sixRowEnderchestSlotCount = -1; -+ return ChestMenu.sixRows(syncId, inventory, playerEnderChestContainer); -+ } -+ // Purpur end -+ - @Override - public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { - return new EnderChestBlockEntity(pos, state); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -index 6186e55014bbb9d5bedaa0e9d196879c55339d42..f4f11292d6d00f4a7c65e3e2a157bba595f70889 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -@@ -68,7 +68,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { - - public BarrelBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.BARREL, pos, state); -- this.items = NonNullList.withSize(27, ItemStack.EMPTY); -+ // Purpur start -+ this.items = NonNullList.withSize(switch (org.purpurmc.purpur.PurpurConfig.barrelRows) { -+ case 6 -> 54; -+ case 5 -> 45; -+ case 4 -> 36; -+ case 2 -> 18; -+ case 1 -> 9; -+ default -> 27; -+ }, ItemStack.EMPTY); -+ // Purpur end - this.openersCounter = new ContainerOpenersCounter() { - @Override - protected void onOpen(Level world, BlockPos pos, BlockState state) { -@@ -119,7 +128,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { - - @Override - public int getContainerSize() { -- return 27; -+ // Purpur start -+ return switch (org.purpurmc.purpur.PurpurConfig.barrelRows) { -+ case 6 -> 54; -+ case 5 -> 45; -+ case 4 -> 36; -+ case 2 -> 18; -+ case 1 -> 9; -+ default -> 27; -+ }; -+ // Purpur end - } - - @Override -@@ -139,7 +157,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { - - @Override - protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) { -- return ChestMenu.threeRows(syncId, playerInventory, this); -+ // Purpur start -+ return switch (org.purpurmc.purpur.PurpurConfig.barrelRows) { -+ case 6 -> ChestMenu.sixRows(syncId, playerInventory, this); -+ case 5 -> ChestMenu.fiveRows(syncId, playerInventory, this); -+ case 4 -> ChestMenu.fourRows(syncId, playerInventory, this); -+ case 2 -> ChestMenu.twoRows(syncId, playerInventory, this); -+ case 1 -> ChestMenu.oneRow(syncId, playerInventory, this); -+ default -> ChestMenu.threeRows(syncId, playerInventory, this); -+ }; -+ // Purpur end - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java -index 977b77547f7ba62cef3640cf8d4f1c8e7cded53a..beae43e9b6fe447e7515d878ac175f461968768a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java -@@ -184,8 +184,19 @@ public class CraftContainer extends AbstractContainerMenu { - case PLAYER: - case CHEST: - case ENDER_CHEST: -+ // Purpur start -+ this.delegate = new ChestMenu(org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? MenuType.GENERIC_9x6 : MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9); -+ break; - case BARREL: -- this.delegate = new ChestMenu(MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9); -+ this.delegate = new ChestMenu(switch (org.purpurmc.purpur.PurpurConfig.barrelRows) { -+ case 6 -> MenuType.GENERIC_9x6; -+ case 5 -> MenuType.GENERIC_9x5; -+ case 4 -> MenuType.GENERIC_9x4; -+ case 2 -> MenuType.GENERIC_9x2; -+ case 1 -> MenuType.GENERIC_9x1; -+ default -> MenuType.GENERIC_9x3; -+ }, windowId, bottom, top, top.getContainerSize() / 9); -+ // Purpur end - break; - case DISPENSER: - case DROPPER: -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -index af1ae3dacb628da23f7d2988c6e76d3fb2d64103..4ee2d501f882279b48edb4b8bf0824587c276bf6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -@@ -84,7 +84,7 @@ public class CraftInventory implements Inventory { - - @Override - public void setContents(ItemStack[] items) { -- Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize()); -+ // Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize()); // Purpur - - for (int i = 0; i < this.getSize(); i++) { - if (i >= items.length) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 463af65182c0894a75a138df8100f3f616143f4c..a0eb18409f72afe393581e6dc8e2260b3a25197f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -177,4 +177,39 @@ public class PurpurConfig { - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); - } -+ -+ public static int barrelRows = 3; -+ public static boolean enderChestSixRows = false; -+ public static boolean enderChestPermissionRows = false; -+ private static void blockSettings() { -+ if (version < 3) { -+ boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); -+ set("settings.blocks.barrel.six-rows", oldValue); -+ set("settings.packed-barrels", null); -+ oldValue = getBoolean("settings.large-ender-chests", true); -+ set("settings.blocks.ender_chest.six-rows", oldValue); -+ set("settings.large-ender-chests", null); -+ } -+ if (version < 20) { -+ boolean oldValue = getBoolean("settings.blocks.barrel.six-rows", false); -+ set("settings.blocks.barrel.rows", oldValue ? 6 : 3); -+ set("settings.blocks.barrel.six-rows", null); -+ } -+ barrelRows = getInt("settings.blocks.barrel.rows", barrelRows); -+ if (barrelRows < 1 || barrelRows > 6) { -+ Bukkit.getLogger().severe("settings.blocks.barrel.rows must be 1-6, resetting to default"); -+ barrelRows = 3; -+ } -+ org.bukkit.event.inventory.InventoryType.BARREL.setDefaultSize(switch (barrelRows) { -+ case 6 -> 54; -+ case 5 -> 45; -+ case 4 -> 36; -+ case 2 -> 18; -+ case 1 -> 9; -+ default -> 27; -+ }); -+ enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows); -+ org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); -+ enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); -+ } - } diff --git a/patches/server/0009-Llama-API.patch b/patches/server/0009-Llama-API.patch deleted file mode 100644 index 784f0c6a1..000000000 --- a/patches/server/0009-Llama-API.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 18 Oct 2019 22:50:12 -0500 -Subject: [PATCH] Llama API - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -index df695b444fa2a993d381e2f197182c3e91a68502..eb0faf58fa1a408f294fc62120b140def97f998d 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -@@ -22,6 +22,7 @@ public class LlamaFollowCaravanGoal extends Goal { - - @Override - public boolean canUse() { -+ if (!this.llama.shouldJoinCaravan) return false; // Purpur - if (!this.llama.isLeashed() && !this.llama.inCaravan()) { - List list = this.llama.level().getEntities(this.llama, this.llama.getBoundingBox().inflate(9.0, 4.0, 9.0), entity -> { - EntityType entityType = entity.getType(); -@@ -71,6 +72,7 @@ public class LlamaFollowCaravanGoal extends Goal { - - @Override - public boolean canContinueToUse() { -+ if (!this.llama.shouldJoinCaravan) return false; // Purpur - if (this.llama.inCaravan() && this.llama.getCaravanHead().isAlive() && this.firstIsLeashed(this.llama, 0)) { - double d = this.llama.distanceToSqr(this.llama.getCaravanHead()); - if (d > 676.0) { -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 697895661826e4a1ecbdfd2c3a195b9d0ee7e00a..05614fb50a5509331ac15bb819e827365a4cefcf 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -@@ -75,6 +75,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, Level world) { - super(type, world); -@@ -167,6 +168,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder -Date: Thu, 8 Aug 2019 15:29:15 -0500 -Subject: [PATCH] AFK API - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 2820333cbcd2cb972c4408cb0d9cc1be37a844cf..bc6a5de72d52627b3ceca4b52b95e12ceddf1247 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -2326,8 +2326,68 @@ public class ServerPlayer extends Player { - - public void resetLastActionTime() { - this.lastActionTime = Util.getMillis(); -+ this.setAfk(false); // Purpur - } - -+ // Purpur Start -+ private boolean isAfk = false; -+ -+ @Override -+ public void setAfk(boolean afk) { -+ if (this.isAfk == afk) { -+ return; -+ } -+ -+ String msg = afk ? org.purpurmc.purpur.PurpurConfig.afkBroadcastAway : org.purpurmc.purpur.PurpurConfig.afkBroadcastBack; -+ -+ org.purpurmc.purpur.event.PlayerAFKEvent event = new org.purpurmc.purpur.event.PlayerAFKEvent(this.getBukkitEntity(), afk, this.level().purpurConfig.idleTimeoutKick, msg, !Bukkit.isPrimaryThread()); -+ if (!event.callEvent() || event.shouldKick()) { -+ return; -+ } -+ -+ this.isAfk = afk; -+ -+ if (!afk) { -+ resetLastActionTime(); -+ } -+ -+ msg = event.getBroadcastMsg(); -+ if (msg != null && !msg.isEmpty()) { -+ String playerName = this.getGameProfile().getName(); -+ if (org.purpurmc.purpur.PurpurConfig.afkBroadcastUseDisplayName) { -+ net.kyori.adventure.text.Component playerDisplayNameComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.getBukkitEntity().getDisplayName()); -+ playerName = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(playerDisplayNameComponent); -+ } -+ server.getPlayerList().broadcastMiniMessage(String.format(msg, playerName), false); -+ } -+ -+ if (this.level().purpurConfig.idleTimeoutUpdateTabList) { -+ String scoreboardName = getScoreboardName(); -+ String playerListName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().serialize(getBukkitEntity().playerListName()); -+ String[] split = playerListName.split(scoreboardName); -+ String prefix = (split.length > 0 ? split[0] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix, ""); -+ String suffix = (split.length > 1 ? split[1] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, ""); -+ if (afk) { -+ getBukkitEntity().setPlayerListName(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix + prefix + scoreboardName + suffix + org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, true); -+ } else { -+ getBukkitEntity().setPlayerListName(prefix + scoreboardName + suffix); -+ } -+ } -+ -+ ((ServerLevel) this.level()).updateSleepingPlayerList(); -+ } -+ -+ @Override -+ public boolean isAfk() { -+ return this.isAfk; -+ } -+ -+ @Override -+ public boolean canBeCollidedWith() { -+ return !this.isAfk() && super.canBeCollidedWith(); -+ } -+ // Purpur End -+ - public ServerStatsCounter getStats() { - return this.stats; - } -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 1377d7abfe024b8ac977aa1a071b401836c3c048..510a4391463026dd0c896027a579a94174c24299 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -332,6 +332,20 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private boolean justTeleported = false; - // CraftBukkit end - -+ // Purpur start -+ private final com.google.common.cache.LoadingCache kickPermissionCache = com.google.common.cache.CacheBuilder.newBuilder() -+ .maximumSize(1000) -+ .expireAfterWrite(1, java.util.concurrent.TimeUnit.MINUTES) -+ .build( -+ new com.google.common.cache.CacheLoader<>() { -+ @Override -+ public Boolean load(CraftPlayer player) { -+ return player.hasPermission("purpur.bypassIdleKick"); -+ } -+ } -+ ); -+ // Purpur end -+ - @Override - public void tick() { - if (this.ackBlockChangesUpTo > -1) { -@@ -399,6 +413,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - - if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits -+ // Purpur start -+ this.player.setAfk(true); -+ if (!this.player.level().purpurConfig.idleTimeoutKick || (!Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK")) && kickPermissionCache.getUnchecked(this.player.getBukkitEntity()))) { -+ return; -+ } -+ // Purpur end - this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 - this.disconnect(Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause - } -@@ -658,6 +678,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.lastYaw = to.getYaw(); - this.lastPitch = to.getPitch(); - -+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur -+ - Location oldTo = to.clone(); - PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); - this.cserver.getPluginManager().callEvent(event); -@@ -1494,7 +1516,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - movedWrongly = true; - if (event.getLogWarning()) - // Paper end -- ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString()); -+ ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), d11); // Purpur - } // Paper - } - -@@ -1562,6 +1584,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.lastYaw = to.getYaw(); - this.lastPitch = to.getPitch(); - -+ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur -+ - Location oldTo = to.clone(); - PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); - this.cserver.getPluginManager().callEvent(event); -diff --git a/src/main/java/net/minecraft/server/players/SleepStatus.java b/src/main/java/net/minecraft/server/players/SleepStatus.java -index 823efad652d8ff9e96b99375b102fef6f017716e..caa8a69bde0c212c36dd990a67836ac2f95548c0 100644 ---- a/src/main/java/net/minecraft/server/players/SleepStatus.java -+++ b/src/main/java/net/minecraft/server/players/SleepStatus.java -@@ -19,7 +19,7 @@ public class SleepStatus { - - public boolean areEnoughDeepSleeping(int percentage, List players) { - // CraftBukkit start -- int j = (int) players.stream().filter((eh) -> { return eh.isSleepingLongEnough() || eh.fauxSleeping; }).count(); -+ int j = (int) players.stream().filter((eh) -> { return eh.isSleepingLongEnough() || eh.fauxSleeping || (eh.level().purpurConfig.idleTimeoutCountAsSleeping && eh.isAfk()); }).count(); // Purpur - boolean anyDeepSleep = players.stream().anyMatch(Player::isSleepingLongEnough); - - return anyDeepSleep && j >= this.sleepersNeeded(percentage); -@@ -52,7 +52,7 @@ public class SleepStatus { - - if (!entityplayer.isSpectator()) { - ++this.activePlayers; -- if (entityplayer.isSleeping() || entityplayer.fauxSleeping) { // CraftBukkit -+ if ((entityplayer.isSleeping() || entityplayer.fauxSleeping) || (entityplayer.level().purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk())) { // CraftBukkit // Purpur - ++this.sleepingPlayers; - } - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java -index d8cc5614502db7025349e085381b6b32ad32296a..f1b9e83206cc67e6ef29ebe088351b0aaa5eb349 100644 ---- a/src/main/java/net/minecraft/world/entity/EntitySelector.java -+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java -@@ -40,6 +40,7 @@ public final class EntitySelector { - return net.minecraft.util.Mth.clamp(serverPlayer.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= playerInsomniaTicks; - }; - // Paper end - Ability to control player's insomnia and phantoms -+ public static Predicate notAfk = (player) -> !player.isAfk(); // Purpur - - private EntitySelector() {} - // Paper start - Affects Spawning API -diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -index d2f0c3b26d4beedb49d86e0242d843590d469d02..7463eefb7d09ea55fe8780210e7e967c2fe7896d 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -@@ -64,6 +64,10 @@ public class TargetingConditions { - return false; - } else if (this.selector != null && !this.selector.test(targetEntity)) { - return false; -+ // Purpur start -+ } else if (!targetEntity.level().purpurConfig.idleTimeoutTargetPlayer && targetEntity instanceof net.minecraft.server.level.ServerPlayer player && player.isAfk()) { -+ return false; -+ // Purpur end - } else { - if (baseEntity == null) { - if (this.isCombat && (!targetEntity.canBeSeenAsEnemy() || targetEntity.level().getDifficulty() == Difficulty.PEACEFUL)) { -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 054c905085b70ba72a3b76649bf5a20106f239d1..cd0992ec6b70f88c17cf7492847ae7f35e9c1e0d 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -201,6 +201,13 @@ public abstract class Player extends LivingEntity { - public boolean fauxSleeping; - public int oldLevel = -1; - -+ public void setAfk(boolean afk) { -+ } -+ -+ public boolean isAfk() { -+ return false; -+ } -+ - @Override - public CraftHumanEntity getBukkitEntity() { - return (CraftHumanEntity) super.getBukkitEntity(); -diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java -index ea0aee88c7d901034427db201c1b2430f8a1d522..1f28bfb435c1e4d97da713f96c452abab3fda91a 100644 ---- a/src/main/java/net/minecraft/world/level/EntityGetter.java -+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java -@@ -192,7 +192,7 @@ public interface EntityGetter { - - default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) { - for (Player player : this.players()) { -- if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) { -+ if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player) && EntitySelector.notAfk.test(player)) { // Purpur - double d = player.distanceToSqr(x, y, z); - if (range < 0.0 || d < range * range) { - return true; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 7f78db4e0331d0f4801807ed1242642ee940d0f8..a4e4babedbf5bbf09bfbabd4f55ecd6301dae302 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -574,10 +574,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void setPlayerListName(String name) { -+ // Purpur start -+ setPlayerListName(name, false); -+ } -+ public void setPlayerListName(String name, boolean useMM) { -+ // Purpur end - if (name == null) { - name = this.getName(); - } -- this.getHandle().listName = name.equals(this.getName()) ? null : CraftChatMessage.fromStringOrNull(name); -+ this.getHandle().listName = name.equals(this.getName()) ? null : useMM ? io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name)) : CraftChatMessage.fromStringOrNull(name); // Purpur - if (this.getHandle().connection == null) return; // Paper - Updates are possible before the player has fully joined - for (ServerPlayer player : (List) this.server.getHandle().players) { - if (player.getBukkitEntity().canSee(this)) { -@@ -3528,5 +3533,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - public boolean usesPurpurClient() { - return getHandle().purpurClient; - } -+ -+ @Override -+ public boolean isAfk() { -+ return getHandle().isAfk(); -+ } -+ -+ @Override -+ public void setAfk(boolean setAfk) { -+ getHandle().setAfk(setAfk); -+ } -+ -+ @Override -+ public void resetIdleTimer() { -+ getHandle().resetLastActionTime(); -+ } - // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 940438c4b86d38be618dca8af95e3a7bf97bfa3c..beab078faaa6ea72539fdfd626ec64ff800d030c 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -174,8 +174,18 @@ public class PurpurConfig { - } - - public static String cannotRideMob = "You cannot mount that mob"; -+ public static String afkBroadcastAway = "%s is now AFK"; -+ public static String afkBroadcastBack = "%s is no longer AFK"; -+ public static boolean afkBroadcastUseDisplayName = false; -+ public static String afkTabListPrefix = "[AFK] "; -+ public static String afkTabListSuffix = ""; - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); -+ afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); -+ afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); -+ afkBroadcastUseDisplayName = getBoolean("settings.messages.afk-broadcast-use-display-name", afkBroadcastUseDisplayName); -+ afkTabListPrefix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix))); -+ afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix))); - } - - public static int barrelRows = 3; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e248395ad5f5f012aeefecf367d54f90cade0996..70f53ccb22de2c05c9ead68f8bd29d0b69d0993f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -90,6 +90,24 @@ public class PurpurWorldConfig { - return value.isEmpty() ? fallback : value; - } - -+ public boolean idleTimeoutKick = true; -+ public boolean idleTimeoutTickNearbyEntities = true; -+ public boolean idleTimeoutCountAsSleeping = false; -+ public boolean idleTimeoutUpdateTabList = false; -+ public boolean idleTimeoutTargetPlayer = true; -+ private void playerSettings() { -+ if (PurpurConfig.version < 19) { -+ boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -+ set("gameplay-mechanics.player.idle-timeout.mods-target", null); -+ set("gameplay-mechanics.player.idle-timeout.mobs-target", oldVal); -+ } -+ idleTimeoutKick = System.getenv("PURPUR_FORCE_IDLE_KICK") == null ? getBoolean("gameplay-mechanics.player.idle-timeout.kick-if-idle", idleTimeoutKick) : Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK")); -+ idleTimeoutTickNearbyEntities = getBoolean("gameplay-mechanics.player.idle-timeout.tick-nearby-entities", idleTimeoutTickNearbyEntities); -+ idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping); -+ idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); -+ idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer); -+ } -+ - public boolean babiesAreRidable = true; - public boolean untamedTamablesAreRidable = true; - public boolean useNightVisionWhenRiding = false; -diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 3283ed99c35ffed6805567705e0518d9f84feedc..a9a39f0da7b09410d8171172a4219c7d509fdb99 100644 ---- a/src/main/java/org/spigotmc/ActivationRange.java -+++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -201,6 +201,7 @@ public class ActivationRange - continue; - } - -+ if (!player.level().purpurConfig.idleTimeoutTickNearbyEntities && player.isAfk()) continue; // Purpur - // Paper start - int worldHeight = world.getHeight(); - ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, worldHeight, maxRange ); diff --git a/patches/server/0011-Bring-back-server-name.patch b/patches/server/0011-Bring-back-server-name.patch deleted file mode 100644 index d72709ac6..000000000 --- a/patches/server/0011-Bring-back-server-name.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 26 May 2019 15:19:14 -0500 -Subject: [PATCH] Bring back server name - - -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java -index 9d10cdacb3aed2c00dc60aeb6f2cbeb48905e21f..842f382de43df5d5c321422372ec30ccdd7859d7 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java -@@ -56,6 +56,7 @@ public class DedicatedServerProperties extends Settings -Date: Sat, 21 Mar 2020 11:47:39 -0500 -Subject: [PATCH] Configurable server mod name - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 73b77367039eb6a4445d1ef2d66fb3410e91f4b8..8a6f7681d97c48886f5a78b61763e718e56ec015 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1925,7 +1925,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Pufferfish > // Paper -+ return org.purpurmc.purpur.PurpurConfig.serverModName; // Purpur - Purpur > // Pufferfish > // Paper - } - - public SystemReport fillSystemReport(SystemReport details) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 7312ae7323032a0ba3c47aa7bdfe5dffe9674535..881c5654f181ea9b66e1cdf3bc3bf46869e8557f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -188,6 +188,11 @@ public class PurpurConfig { - afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix))); - } - -+ public static String serverModName = "Purpur"; -+ private static void serverModName() { -+ serverModName = getString("settings.server-mod-name", serverModName); -+ } -+ - public static int barrelRows = 3; - public static boolean enderChestSixRows = false; - public static boolean enderChestPermissionRows = false; diff --git a/patches/server/0013-Lagging-threshold.patch b/patches/server/0013-Lagging-threshold.patch deleted file mode 100644 index bad5618fe..000000000 --- a/patches/server/0013-Lagging-threshold.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 23 Jul 2019 10:07:16 -0500 -Subject: [PATCH] Lagging threshold - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 8a6f7681d97c48886f5a78b61763e718e56ec015..dfa332c4ff52033eb95248518bc44bbd22697697 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -315,6 +315,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Fri, 5 Jul 2019 18:21:00 -0500 -Subject: [PATCH] PlayerSetSpawnerTypeWithEggEvent - - -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index a46bf73c608641bf1f00fd55242de71a0f2ee06e..9b3bf5ac043262c6cd00d83b750c3313122d92a9 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -330,6 +330,16 @@ public class EntityType implements FeatureElement, EntityTypeT - return (EntityType) Registry.register(BuiltInRegistries.ENTITY_TYPE, id, (EntityType) type.build(id)); // CraftBukkit - decompile error - } - -+ // Purpur start -+ public static EntityType getFromBukkitType(org.bukkit.entity.EntityType bukkitType) { -+ return getFromKey(new ResourceLocation(bukkitType.getKey().toString())); -+ } -+ -+ public static EntityType getFromKey(ResourceLocation location) { -+ return BuiltInRegistries.ENTITY_TYPE.get(location); -+ } -+ // Purpur end -+ - public static ResourceLocation getKey(EntityType type) { - return BuiltInRegistries.ENTITY_TYPE.getKey(type); - } -@@ -537,6 +547,16 @@ public class EntityType implements FeatureElement, EntityTypeT - return this.category; - } - -+ // Purpur start -+ public String getName() { -+ return BuiltInRegistries.ENTITY_TYPE.getKey(this).getPath(); -+ } -+ -+ public String getTranslatedName() { -+ return getDescription().getString(); -+ } -+ // Purpur end -+ - public String getDescriptionId() { - if (this.descriptionId == null) { - this.descriptionId = Util.makeDescriptionId("entity", BuiltInRegistries.ENTITY_TYPE.getKey(this)); -diff --git a/src/main/java/net/minecraft/world/item/SpawnEggItem.java b/src/main/java/net/minecraft/world/item/SpawnEggItem.java -index 9cea8da84f39bb3f687139ef213ccea358724dee..076e6858222b92f8409f1f5cad398582c1fd6bcb 100644 ---- a/src/main/java/net/minecraft/world/item/SpawnEggItem.java -+++ b/src/main/java/net/minecraft/world/item/SpawnEggItem.java -@@ -74,6 +74,15 @@ public class SpawnEggItem extends Item { - Spawner spawner = (Spawner) tileentity; - - entitytypes = this.getType(itemstack); -+ -+ // Purpur start -+ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); -+ org.purpurmc.purpur.event.PlayerSetSpawnerTypeWithEggEvent event = new org.purpurmc.purpur.event.PlayerSetSpawnerTypeWithEggEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), bukkitBlock, (org.bukkit.block.CreatureSpawner) bukkitBlock.getState(), org.bukkit.entity.EntityType.fromName(entitytypes.getName())); -+ if (!event.callEvent()) { -+ return InteractionResult.FAIL; -+ } -+ entitytypes = EntityType.getFromBukkitType(event.getEntityType()); -+ // Purpur end - spawner.setEntityId(entitytypes, world.getRandom()); - world.sendBlockUpdated(blockposition, iblockdata, iblockdata, 3); - world.gameEvent((Entity) context.getPlayer(), (Holder) GameEvent.BLOCK_CHANGE, blockposition); diff --git a/patches/server/0015-Anvil-API.patch b/patches/server/0015-Anvil-API.patch deleted file mode 100644 index 588aaa9d2..000000000 --- a/patches/server/0015-Anvil-API.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 19 Apr 2020 00:17:56 -0500 -Subject: [PATCH] Anvil API - - -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index 32910f677b0522ac8ec513fa0d00b714b52cfae4..f85eef14b91a0ada1f6f4b13ab3966f051ff92d3 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -76,6 +76,7 @@ public abstract class AbstractContainerMenu { - @Nullable - private ContainerSynchronizer synchronizer; - private boolean suppressRemoteUpdates; -+ @javax.annotation.Nullable protected ItemStack activeQuickItem = null; // Purpur - - // CraftBukkit start - public boolean checkReachable = true; -diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index 2bd91b48eaa06f85a5b9b1ae052c70e966ae8e4c..9036426256f87b3ba4a78e6fa2cea4e028f84481 100644 ---- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -@@ -25,6 +25,13 @@ import org.slf4j.Logger; - import org.bukkit.craftbukkit.inventory.CraftInventoryView; - // CraftBukkit end - -+// Purpur start -+import net.minecraft.nbt.IntTag; -+import net.minecraft.network.protocol.game.ClientboundContainerSetDataPacket; -+import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; -+import net.minecraft.server.level.ServerPlayer; -+// Purpur end -+ - public class AnvilMenu extends ItemCombinerMenu { - - public static final int INPUT_SLOT = 0; -@@ -53,6 +60,8 @@ public class AnvilMenu extends ItemCombinerMenu { - public int maximumRepairCost = 40; - private CraftInventoryView bukkitEntity; - // CraftBukkit end -+ public boolean bypassCost = false; // Purpur -+ public boolean canDoUnsafeEnchants = false; // Purpur - - public AnvilMenu(int syncId, Inventory inventory) { - this(syncId, inventory, ContainerLevelAccess.NULL); -@@ -80,12 +89,15 @@ public class AnvilMenu extends ItemCombinerMenu { - - @Override - protected boolean mayPickup(Player player, boolean present) { -- return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && present; // CraftBukkit - allow cost 0 like a free item -+ return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && (bypassCost || this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST) && present; // CraftBukkit - allow cost 0 like a free item // Purpur - } - - @Override - protected void onTake(Player player, ItemStack stack) { -+ ItemStack itemstack = activeQuickItem == null ? stack : activeQuickItem; // Purpur -+ if (org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)).callEvent(); // Purpur - if (!player.getAbilities().instabuild) { -+ if (bypassCost) ((ServerPlayer) player).lastSentExp = -1; else // Purpur - player.giveExperienceLevels(-this.cost.get()); - } - -@@ -136,6 +148,12 @@ public class AnvilMenu extends ItemCombinerMenu { - - @Override - public void createResult() { -+ // Purpur start -+ bypassCost = false; -+ canDoUnsafeEnchants = false; -+ if (org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent(getBukkitView()).callEvent(); -+ // Purpur end -+ - ItemStack itemstack = this.inputSlots.getItem(0); - - this.cost.set(1); -@@ -143,7 +161,7 @@ public class AnvilMenu extends ItemCombinerMenu { - long j = 0L; - byte b0 = 0; - -- if (!itemstack.isEmpty() && EnchantmentHelper.canStoreEnchantments(itemstack)) { -+ if (!itemstack.isEmpty() && canDoUnsafeEnchants || EnchantmentHelper.canStoreEnchantments(itemstack)) { // Purpur - ItemStack itemstack1 = itemstack.copy(); - ItemStack itemstack2 = this.inputSlots.getItem(1); - ItemEnchantments.Mutable itemenchantments_a = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(itemstack1)); -@@ -222,7 +240,7 @@ public class AnvilMenu extends ItemCombinerMenu { - Holder holder1 = (Holder) iterator1.next(); - - if (!holder1.equals(holder) && !enchantment.isCompatibleWith((Enchantment) holder1.value())) { -- flag3 = false; -+ flag3 = canDoUnsafeEnchants; // Purpur - ++i; - } - } -@@ -280,6 +298,12 @@ public class AnvilMenu extends ItemCombinerMenu { - this.cost.set(this.maximumRepairCost - 1); // CraftBukkit - } - -+ // Purpur start -+ if (bypassCost && cost.get() >= maximumRepairCost) { -+ cost.set(maximumRepairCost - 1); -+ } -+ // Purpur end -+ - if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit - itemstack1 = ItemStack.EMPTY; - } -@@ -301,6 +325,12 @@ public class AnvilMenu extends ItemCombinerMenu { - org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit - this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client - this.broadcastChanges(); -+ // Purpur start -+ if (canDoUnsafeEnchants && itemstack1 != ItemStack.EMPTY) { -+ ((ServerPlayer) player).connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 2, itemstack1)); -+ ((ServerPlayer) player).connection.send(new ClientboundContainerSetDataPacket(containerId, 0, cost.get())); -+ } -+ // Purpur end - } else { - org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit - this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item -diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -index 7de5e47f9a54263734eeef855a2dc07ef64d30ea..7215af6cc91f48b040c23c54536d4aac8d293497 100644 ---- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java -@@ -178,7 +178,9 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { - return ItemStack.EMPTY; - } - -+ this.activeQuickItem = itemstack; // Purpur - slot1.onTake(player, itemstack1); -+ this.activeQuickItem = null; // Purpur - } - - return itemstack; -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java -index 9ee14589d63bbfc0880f2eee5e924fe946ee0035..0a5841fa26698e60bdeadbb58b9343fe1ff08a28 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java -@@ -9,7 +9,7 @@ import org.bukkit.inventory.AnvilInventory; - public class CraftInventoryAnvil extends CraftResultInventory implements AnvilInventory { - - private final Location location; -- private final AnvilMenu container; -+ public final AnvilMenu container; // Purpur - private -> public - - public CraftInventoryAnvil(Location location, Container inventory, Container resultInventory, AnvilMenu container) { - super(inventory, resultInventory); -@@ -57,4 +57,26 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn - Preconditions.checkArgument(levels >= 0, "Maximum repair cost must be positive (or 0)"); - this.container.maximumRepairCost = levels; - } -+ -+ // Purpur start -+ @Override -+ public boolean canBypassCost() { -+ return container.bypassCost; -+ } -+ -+ @Override -+ public void setBypassCost(boolean bypassCost) { -+ container.bypassCost = bypassCost; -+ } -+ -+ @Override -+ public boolean canDoUnsafeEnchants() { -+ return container.canDoUnsafeEnchants; -+ } -+ -+ @Override -+ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) { -+ container.canDoUnsafeEnchants = canDoUnsafeEnchants; -+ } -+ // Purpur end - } diff --git a/patches/server/0016-Alternative-Keepalive-Handling.patch b/patches/server/0016-Alternative-Keepalive-Handling.patch deleted file mode 100644 index 224feaaf5..000000000 --- a/patches/server/0016-Alternative-Keepalive-Handling.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 11 Oct 2019 00:17:39 -0500 -Subject: [PATCH] Alternative Keepalive Handling - - -diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 4228fd441f8350d43bd545e31c920304f07968bc..3a15085e0421f46800f779066d235ef21b463289 100644 ---- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -73,6 +73,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - private long keepAliveChallenge; - private long closedListenerTime; - private boolean closed = false; -+ private it.unimi.dsi.fastutil.longs.LongList keepAlives = new it.unimi.dsi.fastutil.longs.LongArrayList(); // Purpur - private int latency; - private volatile boolean suspendFlushingOnServerThread = false; - public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks -@@ -124,6 +125,16 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - @Override - public void handleKeepAlive(ServerboundKeepAlivePacket packet) { -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.useAlternateKeepAlive) { -+ long id = packet.getId(); -+ if (keepAlives.size() > 0 && keepAlives.contains(id)) { -+ int ping = (int) (Util.getMillis() - id); -+ this.latency = (this.latency * 3 + ping) / 4; -+ keepAlives.clear(); // we got a valid response, lets roll with it and forget the rest -+ } -+ } else -+ // Purpur end - //PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // CraftBukkit // Paper - handle ServerboundKeepAlivePacket async - if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) { - int i = (int) (Util.getMillis() - this.keepAliveTime); -@@ -260,6 +271,21 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - long currentTime = Util.getMillis(); - long elapsedTime = currentTime - this.keepAliveTime; - -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.useAlternateKeepAlive) { -+ if (elapsedTime >= 1000L) { // 1 second -+ if (!processedDisconnect && keepAlives.size() * 1000L >= KEEPALIVE_LIMIT) { -+ LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); -+ disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); -+ } else { -+ keepAliveTime = currentTime; // hijack this field for 1 second intervals -+ keepAlives.add(currentTime); // currentTime is ID -+ send(new ClientboundKeepAlivePacket(currentTime)); -+ } -+ } -+ } else -+ // Purpur end -+ - if (!this.isSingleplayerOwner() && elapsedTime >= KEEPALIVE_LIMIT) { // Paper - check keepalive limit, don't fire if already disconnected - if (this.keepAlivePending && !this.processedDisconnect) { // Paper - this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 9c5bba0ae119f8d42274455e322530ceb5f67d9b..a14cf3a5dc2ba265de5e400404afcbd9faa3f25a 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -198,6 +198,11 @@ public class PurpurConfig { - laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold); - } - -+ public static boolean useAlternateKeepAlive = false; -+ private static void useAlternateKeepAlive() { -+ useAlternateKeepAlive = getBoolean("settings.use-alternate-keepalive", useAlternateKeepAlive); -+ } -+ - public static int barrelRows = 3; - public static boolean enderChestSixRows = false; - public static boolean enderChestPermissionRows = false; diff --git a/patches/server/0017-Silk-touch-spawners.patch b/patches/server/0017-Silk-touch-spawners.patch deleted file mode 100644 index d1ee5a1b5..000000000 --- a/patches/server/0017-Silk-touch-spawners.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 9 May 2019 14:27:37 -0500 -Subject: [PATCH] Silk touch spawners - - -diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index 96fb69ec6db2e7c8c728435f0c537b076259b2fb..3253361d91e2a2e68d354eaf3dd3e3cd486e191d 100644 ---- a/src/main/java/net/minecraft/world/item/BlockItem.java -+++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -219,6 +219,7 @@ public class BlockItem extends Item { - - if (tileentity != null) { - if (!world.isClientSide && tileentity.onlyOpCanSetNbt() && (player == null || !(player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place"))))) { // Spigot - add permission -+ if (!(!world.isClientSide && world.purpurConfig.silkTouchEnabled && tileentity instanceof net.minecraft.world.level.block.entity.SpawnerBlockEntity && player.getBukkitEntity().hasPermission("purpur.drop.spawners"))) - return false; - } - -diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java -index d00b59efb754594cf532f8598f4b6d3b29693232..6467358f5fdf4cd4f7c1e2cc65c834a9da39596a 100644 ---- a/src/main/java/net/minecraft/world/item/Items.java -+++ b/src/main/java/net/minecraft/world/item/Items.java -@@ -338,7 +338,7 @@ public class Items { - public static final Item PURPUR_BLOCK = registerBlock(Blocks.PURPUR_BLOCK); - public static final Item PURPUR_PILLAR = registerBlock(Blocks.PURPUR_PILLAR); - public static final Item PURPUR_STAIRS = registerBlock(Blocks.PURPUR_STAIRS); -- public static final Item SPAWNER = registerBlock(Blocks.SPAWNER); -+ public static final Item SPAWNER = registerBlock(new org.purpurmc.purpur.item.SpawnerItem(Blocks.SPAWNER, new Item.Properties().rarity(Rarity.EPIC))); // Purpur - public static final Item CHEST = registerBlock(Blocks.CHEST, settings -> settings.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY)); - public static final Item CRAFTING_TABLE = registerBlock(Blocks.CRAFTING_TABLE); - public static final Item FARMLAND = registerBlock(Blocks.FARMLAND); -diff --git a/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java b/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java -index 4f190a40b8474aa06a92c8afcc06d0044120ff7b..66c17bdfecdfbcfb2d853e561432dd51a8f7ed46 100644 ---- a/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SpawnerBlock.java -@@ -42,6 +42,57 @@ public class SpawnerBlock extends BaseEntityBlock { - return createTickerHelper(type, BlockEntityType.MOB_SPAWNER, world.isClientSide ? SpawnerBlockEntity::clientTick : SpawnerBlockEntity::serverTick); - } - -+ // Purpur start -+ @Override -+ public void playerDestroy(Level level, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) { -+ if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.drop.spawners") && isSilkTouch(level, stack)) { -+ ItemStack item = new ItemStack(Blocks.SPAWNER.asItem()); -+ -+ net.minecraft.world.level.SpawnData nextSpawnData = blockEntity instanceof SpawnerBlockEntity spawnerBlock ? spawnerBlock.getSpawner().nextSpawnData : null; -+ java.util.Optional> type = java.util.Optional.empty(); -+ if (nextSpawnData != null) { -+ type = net.minecraft.world.entity.EntityType.by(nextSpawnData.getEntityToSpawn()); -+ net.minecraft.world.level.SpawnData.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, nextSpawnData).result().ifPresent(tag -> item.set(net.minecraft.core.component.DataComponents.CUSTOM_DATA, net.minecraft.world.item.component.CustomData.EMPTY.update(compoundTag -> compoundTag.put("Purpur.SpawnData", tag)))); -+ } -+ -+ if (type.isPresent()) { -+ final net.kyori.adventure.text.Component mobName = io.papermc.paper.adventure.PaperAdventure.asAdventure(type.get().getDescription()); -+ -+ String name = level.purpurConfig.silkTouchSpawnerName; -+ if (name != null && !name.isEmpty() && !name.equals("Monster Spawner")) { -+ net.kyori.adventure.text.Component displayName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName)); -+ if (name.startsWith("")) { -+ displayName = displayName.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); -+ } -+ item.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName)); -+ } -+ -+ List lore = level.purpurConfig.silkTouchSpawnerLore; -+ if (lore != null && !lore.isEmpty()) { -+ -+ List loreComponentList = new java.util.ArrayList<>(); -+ for (String line : lore) { -+ net.kyori.adventure.text.Component lineComponent = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(line, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName)); -+ if (line.startsWith("")) { -+ lineComponent = lineComponent.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); -+ } -+ loreComponentList.add(io.papermc.paper.adventure.PaperAdventure.asVanilla(lineComponent)); -+ } -+ -+ item.set(net.minecraft.core.component.DataComponents.LORE, new net.minecraft.world.item.component.ItemLore(loreComponentList, loreComponentList)); -+ } -+ item.set(net.minecraft.core.component.DataComponents.HIDE_ADDITIONAL_TOOLTIP, net.minecraft.util.Unit.INSTANCE); -+ } -+ popResource(level, pos, item); -+ } -+ super.playerDestroy(level, player, pos, state, blockEntity, stack, includeDrops, dropExp); -+ } -+ -+ private boolean isSilkTouch(Level level, ItemStack stack) { -+ return stack != null && level.purpurConfig.silkTouchTools.contains(stack.getItem()) && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.SILK_TOUCH, stack) >= level.purpurConfig.minimumSilkTouchSpawnerRequire; -+ } -+ // Purpur end -+ - @Override - protected void spawnAfterBreak(BlockState state, ServerLevel world, BlockPos pos, ItemStack tool, boolean dropExperience) { - super.spawnAfterBreak(state, world, pos, tool, dropExperience); -@@ -50,6 +101,7 @@ public class SpawnerBlock extends BaseEntityBlock { - - @Override - public int getExpDrop(BlockState iblockdata, ServerLevel worldserver, BlockPos blockposition, ItemStack itemstack, boolean flag) { -+ if (isSilkTouch(worldserver, itemstack)) return 0; // Purpur - if (flag) { - int i = 15 + worldserver.random.nextInt(15) + worldserver.random.nextInt(15); - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 70f53ccb22de2c05c9ead68f8bd29d0b69d0993f..d4bca5b5f3d10c3a04befd8c365f46433491f299 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -108,6 +108,38 @@ public class PurpurWorldConfig { - idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer); - } - -+ public boolean silkTouchEnabled = false; -+ public String silkTouchSpawnerName = "Monster Spawner"; -+ public List silkTouchSpawnerLore = new ArrayList<>(); -+ public List silkTouchTools = new ArrayList<>(); -+ public int minimumSilkTouchSpawnerRequire = 1; -+ private void silkTouchSettings() { -+ if (PurpurConfig.version < 21) { -+ String oldName = getString("gameplay-mechanics.silk-touch.spawner-name", silkTouchSpawnerName); -+ set("gameplay-mechanics.silk-touch.spawner-name", "" + ChatColor.toMM(oldName.replace("{mob}", ""))); -+ List list = new ArrayList<>(); -+ getList("gameplay-mechanics.silk-touch.spawner-lore", List.of("Spawns a ")) -+ .forEach(line -> list.add("" + ChatColor.toMM(line.toString().replace("{mob}", "")))); -+ set("gameplay-mechanics.silk-touch.spawner-lore", list); -+ } -+ silkTouchEnabled = getBoolean("gameplay-mechanics.silk-touch.enabled", silkTouchEnabled); -+ silkTouchSpawnerName = getString("gameplay-mechanics.silk-touch.spawner-name", silkTouchSpawnerName); -+ minimumSilkTouchSpawnerRequire = getInt("gameplay-mechanics.silk-touch.minimal-level", minimumSilkTouchSpawnerRequire); -+ silkTouchSpawnerLore.clear(); -+ getList("gameplay-mechanics.silk-touch.spawner-lore", List.of("Spawns a ")) -+ .forEach(line -> silkTouchSpawnerLore.add(line.toString())); -+ silkTouchTools.clear(); -+ getList("gameplay-mechanics.silk-touch.tools", List.of( -+ "minecraft:iron_pickaxe", -+ "minecraft:golden_pickaxe", -+ "minecraft:diamond_pickaxe", -+ "minecraft:netherite_pickaxe" -+ )).forEach(key -> { -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(key.toString())); -+ if (item != Items.AIR) silkTouchTools.add(item); -+ }); -+ } -+ - public boolean babiesAreRidable = true; - public boolean untamedTamablesAreRidable = true; - public boolean useNightVisionWhenRiding = false; -diff --git a/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java b/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ed50cb2115401c9039df4136caf5a087a5f5991c ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java -@@ -0,0 +1,40 @@ -+package org.purpurmc.purpur.item; -+ -+import net.minecraft.core.BlockPos; -+import net.minecraft.core.component.DataComponents; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.entity.player.Player; -+import net.minecraft.world.item.BlockItem; -+import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.item.component.CustomData; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.Block; -+import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -+import net.minecraft.world.level.block.state.BlockState; -+ -+public class SpawnerItem extends BlockItem { -+ -+ public SpawnerItem(Block block, Properties settings) { -+ super(block, settings); -+ } -+ -+ @Override -+ protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, Player player, ItemStack stack, BlockState state) { -+ boolean handled = super.updateCustomBlockEntityTag(pos, level, player, stack, state); -+ if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.place.spawners")) { -+ BlockEntity blockEntity = level.getBlockEntity(pos); -+ if (blockEntity instanceof SpawnerBlockEntity spawner) { -+ CompoundTag customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); -+ if (customData.contains("Purpur.mob_type")) { -+ EntityType.byString(customData.getString("Purpur.mob_type")).ifPresent(type -> spawner.getSpawner().setEntityId(type, level, level.random, pos)); -+ } else if (customData.contains("Purpur.SpawnData")) { -+ net.minecraft.world.level.SpawnData.CODEC.parse(net.minecraft.nbt.NbtOps.INSTANCE, customData.getCompound("Purpur.SpawnData")).result() -+ .ifPresent(spawnData -> spawner.getSpawner().nextSpawnData = spawnData); -+ } -+ } -+ } -+ return handled; -+ } -+} diff --git a/patches/server/0018-Add-turtle-egg-block-options.patch b/patches/server/0018-Add-turtle-egg-block-options.patch deleted file mode 100644 index efb936f2b..000000000 --- a/patches/server/0018-Add-turtle-egg-block-options.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 6 Jun 2019 22:15:46 -0500 -Subject: [PATCH] Add turtle egg block options - - -diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -index a6f408e56fa6c9de82fd93555fe21e1b11ce1022..c7377d04ceac3ea624117439783a443c6d6f6d08 100644 ---- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -@@ -203,6 +203,25 @@ public class TurtleEggBlock extends Block { - } - - private boolean canDestroyEgg(Level world, Entity entity) { -- return !(entity instanceof Turtle) && !(entity instanceof Bat) ? (!(entity instanceof LivingEntity) ? false : entity instanceof Player || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) : false; -+ // Purpur start -+ if (entity instanceof Turtle || entity instanceof Bat) { -+ return false; -+ } -+ if (world.purpurConfig.turtleEggsBreakFromExpOrbs && entity instanceof net.minecraft.world.entity.ExperienceOrb) { -+ return true; -+ } -+ if (world.purpurConfig.turtleEggsBreakFromItems && entity instanceof net.minecraft.world.entity.item.ItemEntity) { -+ return true; -+ } -+ if (world.purpurConfig.turtleEggsBreakFromMinecarts && entity instanceof net.minecraft.world.entity.vehicle.AbstractMinecart) { -+ return true; -+ } -+ if (!(entity instanceof LivingEntity)) { -+ return false; -+ } -+ if (entity instanceof Player) return true; -+ -+ return world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); -+ // Purpur end - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index d4bca5b5f3d10c3a04befd8c365f46433491f299..ac44ee7789b96e60e6d1d964d64ca33a3d3c2c62 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -140,6 +140,15 @@ public class PurpurWorldConfig { - }); - } - -+ public boolean turtleEggsBreakFromExpOrbs = false; -+ public boolean turtleEggsBreakFromItems = false; -+ public boolean turtleEggsBreakFromMinecarts = false; -+ private void turtleEggSettings() { -+ turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs); -+ turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems); -+ turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); -+ } -+ - public boolean babiesAreRidable = true; - public boolean untamedTamablesAreRidable = true; - public boolean useNightVisionWhenRiding = false; diff --git a/patches/server/0019-Logger-settings-suppressing-pointless-logs.patch b/patches/server/0019-Logger-settings-suppressing-pointless-logs.patch deleted file mode 100644 index 06fe35a02..000000000 --- a/patches/server/0019-Logger-settings-suppressing-pointless-logs.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 19 Oct 2019 00:52:12 -0500 -Subject: [PATCH] Logger settings (suppressing pointless logs) - - -diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java -index c7e1f2bac3eca9bb72bf1f8c26cccb2905e1ddfc..94893039363b5fe2d7d0622d0592bce2c867b1c3 100644 ---- a/src/main/java/net/minecraft/server/PlayerAdvancements.java -+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java -@@ -199,6 +199,7 @@ public class PlayerAdvancements { - - if (advancementholder == null) { - if (!minecraftkey.getNamespace().equals("minecraft")) return; // CraftBukkit -+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressIgnoredAdvancementWarnings) // Purpur - PlayerAdvancements.LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", minecraftkey, this.playerSavePath); - } else { - this.startProgress(advancementholder, advancementprogress); -diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -index 1351423a12c19a01f602a202832372a399e6a867..1e2025674eafcf56460c741083c91e2e42d61b19 100644 ---- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java -+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -@@ -326,6 +326,7 @@ public class WorldGenRegion implements WorldGenLevel { - return true; - } else { - // Paper start - Buffer OOB setBlock calls -+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressSetBlockFarChunk) // Purpur - if (!hasSetFarWarned) { - Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + String.valueOf(pos) + ", status: " + String.valueOf(this.generatingStatus) + (this.currentlyGenerating == null ? "" : ", currently generating: " + (String) this.currentlyGenerating.get())); - hasSetFarWarned = true; -diff --git a/src/main/java/net/minecraft/stats/ServerRecipeBook.java b/src/main/java/net/minecraft/stats/ServerRecipeBook.java -index 4103ddf16164e3992fef0765d368282572537e29..a0cb49233b1dbf53ce9d1bcc52b8967829d0530e 100644 ---- a/src/main/java/net/minecraft/stats/ServerRecipeBook.java -+++ b/src/main/java/net/minecraft/stats/ServerRecipeBook.java -@@ -125,6 +125,7 @@ public class ServerRecipeBook extends RecipeBook { - Optional> optional = recipeManager.byKey(minecraftkey); - - if (optional.isEmpty()) { -+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressUnrecognizedRecipeErrors) // Purpur - ServerRecipeBook.LOGGER.error("Tried to load unrecognized recipe: {} removed now.", minecraftkey); - } else { - handler.accept((RecipeHolder) optional.get()); -diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java -index 71d057dc8c7362f8e7aaca5e31c9f02b2bf3f281..9d9405af0db28c0f3ffff2881b54f1dc84675a9d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java -+++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java -@@ -256,6 +256,7 @@ public final class CraftLegacy { - } - - static { -+ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressInitLegacyMaterialError) // Purpur - LOGGER.warn("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); // Paper - Improve logging and errors; doesn't need to be an error - if (MinecraftServer.getServer() != null && MinecraftServer.getServer().isDebugging()) { - new Exception().printStackTrace(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index a14cf3a5dc2ba265de5e400404afcbd9faa3f25a..a14879f4266c71b7493c05e105114590c6709045 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -237,4 +237,15 @@ public class PurpurConfig { - org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); - enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); - } -+ -+ public static boolean loggerSuppressInitLegacyMaterialError = false; -+ public static boolean loggerSuppressIgnoredAdvancementWarnings = false; -+ public static boolean loggerSuppressUnrecognizedRecipeErrors = false; -+ public static boolean loggerSuppressSetBlockFarChunk = false; -+ private static void loggerSettings() { -+ loggerSuppressInitLegacyMaterialError = getBoolean("settings.logger.suppress-init-legacy-material-errors", loggerSuppressInitLegacyMaterialError); -+ loggerSuppressIgnoredAdvancementWarnings = getBoolean("settings.logger.suppress-ignored-advancement-warnings", loggerSuppressIgnoredAdvancementWarnings); -+ loggerSuppressUnrecognizedRecipeErrors = getBoolean("settings.logger.suppress-unrecognized-recipe-errors", loggerSuppressUnrecognizedRecipeErrors); -+ loggerSuppressSetBlockFarChunk = getBoolean("settings.logger.suppress-setblock-in-far-chunk-errors", loggerSuppressSetBlockFarChunk); -+ } - } diff --git a/patches/server/0021-Giants-AI-settings.patch b/patches/server/0021-Giants-AI-settings.patch deleted file mode 100644 index 1f14b308e..000000000 --- a/patches/server/0021-Giants-AI-settings.patch +++ /dev/null @@ -1,133 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 12 May 2019 00:43:12 -0500 -Subject: [PATCH] Giants AI settings - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Giant.java b/src/main/java/net/minecraft/world/entity/monster/Giant.java -index 9602e59cbebeedc85ea75d2a41d3e74f0ff45b46..3c1217d36522b1fd3d1a099d3a12d99016f34c4b 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Giant.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Giant.java -@@ -1,11 +1,34 @@ - package net.minecraft.world.entity.monster; - - import net.minecraft.core.BlockPos; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.world.Difficulty; -+import net.minecraft.world.DifficultyInstance; - import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.entity.EquipmentSlot; -+import net.minecraft.world.entity.MobSpawnType; -+import net.minecraft.world.entity.SpawnGroupData; - import net.minecraft.world.entity.ai.attributes.AttributeSupplier; - import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.entity.ai.goal.FloatGoal; -+import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; -+import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; -+import net.minecraft.world.entity.ai.goal.MoveTowardsRestrictionGoal; -+import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; -+import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; -+import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; -+import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; -+import net.minecraft.world.entity.animal.IronGolem; -+import net.minecraft.world.entity.animal.Turtle; -+import net.minecraft.world.entity.npc.Villager; -+import net.minecraft.world.entity.player.Player; -+import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.item.Items; - import net.minecraft.world.level.Level; - import net.minecraft.world.level.LevelReader; -+import net.minecraft.world.level.ServerLevelAccessor; -+ -+import javax.annotation.Nullable; - - public class Giant extends Monster { - public Giant(EntityType type, Level world) { -@@ -30,8 +53,23 @@ public class Giant extends Monster { - - @Override - protected void registerGoals() { -- this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); -- this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); -+ if (level().purpurConfig.giantHaveAI) { -+ this.goalSelector.addGoal(0, new FloatGoal(this)); -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); -+ this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D)); -+ this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 16.0F)); -+ this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); -+ this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0D)); -+ if (level().purpurConfig.giantHaveHostileAI) { -+ this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false)); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); -+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class)); -+ this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); -+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Villager.class, false)); -+ this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); -+ this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, true)); -+ } -+ } - } - - @Override -@@ -47,8 +85,34 @@ public class Giant extends Monster { - return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0); - } - -+ @Override -+ public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { -+ SpawnGroupData groupData = super.finalizeSpawn(world, difficulty, spawnReason, entityData); -+ if (groupData == null) { -+ populateDefaultEquipmentSlots(this.random, difficulty); -+ populateDefaultEquipmentEnchantments(this.random, difficulty); -+ } -+ return groupData; -+ } -+ -+ @Override -+ protected void populateDefaultEquipmentSlots(net.minecraft.util.RandomSource random, DifficultyInstance difficulty) { -+ super.populateDefaultEquipmentSlots(this.random, difficulty); -+ // TODO make configurable -+ if (random.nextFloat() < (level().getDifficulty() == Difficulty.HARD ? 0.1F : 0.05F)) { -+ this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SWORD)); -+ } -+ } -+ -+ @Override -+ public float getJumpPower() { -+ // make giants jump as high as everything else relative to their size -+ // 1.0 makes bottom of feet about as high as their waist when they jump -+ return level().purpurConfig.giantJumpHeight; -+ } -+ - @Override - public float getWalkTargetValue(BlockPos pos, LevelReader world) { -- return world.getPathfindingCostFromLightLevels(pos); -+ return super.getWalkTargetValue(pos, world); // Purpur - fix light requirements for natural spawns - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ac44ee7789b96e60e6d1d964d64ca33a3d3c2c62..fb61cd498955fee2dec15fa584273a6e19ca58c9 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -554,6 +554,10 @@ public class PurpurWorldConfig { - public double giantMovementSpeed = 0.5D; - public double giantAttackDamage = 50.0D; - public double giantMaxHealth = 100.0D; -+ public float giantStepHeight = 2.0F; -+ public float giantJumpHeight = 1.0F; -+ public boolean giantHaveAI = false; -+ public boolean giantHaveHostileAI = false; - private void giantSettings() { - giantRidable = getBoolean("mobs.giant.ridable", giantRidable); - giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater); -@@ -570,6 +574,10 @@ public class PurpurWorldConfig { - set("mobs.giant.attributes.max_health", oldValue); - } - giantMaxHealth = getDouble("mobs.giant.attributes.max_health", giantMaxHealth); -+ giantStepHeight = (float) getDouble("mobs.giant.step-height", giantStepHeight); -+ giantJumpHeight = (float) getDouble("mobs.giant.jump-height", giantJumpHeight); -+ giantHaveAI = getBoolean("mobs.giant.have-ai", giantHaveAI); -+ giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI); - } - - public boolean glowSquidRidable = false; diff --git a/patches/server/0022-Zombie-horse-naturally-spawn.patch b/patches/server/0022-Zombie-horse-naturally-spawn.patch deleted file mode 100644 index 8ff2f18f1..000000000 --- a/patches/server/0022-Zombie-horse-naturally-spawn.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 7 Jul 2019 19:52:16 -0500 -Subject: [PATCH] Zombie horse naturally spawn - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index fc791a66d299905798c2c1ca542467e4c7933caf..b02d9db8442b209a9df27e417be71b11d426878b 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1006,10 +1006,18 @@ public class ServerLevel extends Level implements WorldGenLevel { - boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper - Configurable spawn chances for skeleton horses - - if (flag1) { -- SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this); -+ // Purpur start -+ net.minecraft.world.entity.animal.horse.AbstractHorse entityhorseskeleton; -+ if (purpurConfig.zombieHorseSpawnChance > 0D && random.nextDouble() <= purpurConfig.zombieHorseSpawnChance) { -+ entityhorseskeleton = EntityType.ZOMBIE_HORSE.create(this); -+ } else { -+ entityhorseskeleton = EntityType.SKELETON_HORSE.create(this); -+ if (entityhorseskeleton != null) ((SkeletonHorse) entityhorseskeleton).setTrap(true); -+ } -+ // Purpur end - - if (entityhorseskeleton != null) { -- entityhorseskeleton.setTrap(true); -+ //entityhorseskeleton.setTrap(true); // Purpur - moved up - entityhorseskeleton.setAge(0); - entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()); - this.addFreshEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index fb61cd498955fee2dec15fa584273a6e19ca58c9..41822b9b050f4267cc0151ea85682523f89af57f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1487,6 +1487,7 @@ public class PurpurWorldConfig { - public double zombieHorseJumpStrengthMax = 1.0D; - public double zombieHorseMovementSpeedMin = 0.2D; - public double zombieHorseMovementSpeedMax = 0.2D; -+ public double zombieHorseSpawnChance = 0.0D; - private void zombieHorseSettings() { - zombieHorseRidable = getBoolean("mobs.zombie_horse.ridable", zombieHorseRidable); - zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); -@@ -1503,6 +1504,7 @@ public class PurpurWorldConfig { - zombieHorseJumpStrengthMax = getDouble("mobs.zombie_horse.attributes.jump_strength.max", zombieHorseJumpStrengthMax); - zombieHorseMovementSpeedMin = getDouble("mobs.zombie_horse.attributes.movement_speed.min", zombieHorseMovementSpeedMin); - zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax); -+ zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); - } - - public boolean zombieVillagerRidable = false; diff --git a/patches/server/0023-Charged-creeper-naturally-spawn.patch b/patches/server/0023-Charged-creeper-naturally-spawn.patch deleted file mode 100644 index 3796f4ab6..000000000 --- a/patches/server/0023-Charged-creeper-naturally-spawn.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 29 Nov 2019 22:37:44 -0600 -Subject: [PATCH] Charged creeper naturally spawn - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index 624ae0e10ef9f51d484e45ec9a15e4a120bf2af2..84114356ea4c06998572c03f2e2a75b49e539980 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -257,6 +257,14 @@ public class Creeper extends Monster implements PowerableMob { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.creeperMaxHealth); - } - -+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData entityData) { -+ double chance = world.getLevel().purpurConfig.creeperChargedChance; -+ if (chance > 0D && random.nextDouble() <= chance) { -+ setPowered(true); -+ } -+ return super.finalizeSpawn(world, difficulty, spawnReason, entityData); -+ } -+ - @Override - protected SoundEvent getHurtSound(DamageSource source) { - return SoundEvents.CREEPER_HURT; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 41822b9b050f4267cc0151ea85682523f89af57f..e033ef722d9b6336f1cbc6bdf404f35c34b45db9 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -345,6 +345,7 @@ public class PurpurWorldConfig { - public boolean creeperRidableInWater = true; - public boolean creeperControllable = true; - public double creeperMaxHealth = 20.0D; -+ public double creeperChargedChance = 0.0D; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -355,6 +356,7 @@ public class PurpurWorldConfig { - set("mobs.creeper.attributes.max_health", oldValue); - } - creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth); -+ creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); - } - - public boolean dolphinRidable = false; diff --git a/patches/server/0024-Rabbit-naturally-spawn-toast-and-killer.patch b/patches/server/0024-Rabbit-naturally-spawn-toast-and-killer.patch deleted file mode 100644 index da9dd0eab..000000000 --- a/patches/server/0024-Rabbit-naturally-spawn-toast-and-killer.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 31 Aug 2019 17:47:11 -0500 -Subject: [PATCH] Rabbit naturally spawn toast and killer - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -index 9eb1158213064ddb37ae76e445b5861b963a1f55..4abcde662ed78b16632ee575f695ee4329f11b2f 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -@@ -466,10 +466,23 @@ public class Rabbit extends Animal implements VariantHolder { - } - - this.setVariant(entityrabbit_variant); -+ -+ // Purpur start -+ if (entityrabbit_variant != Variant.EVIL && world.getLevel().purpurConfig.rabbitNaturalToast > 0D && random.nextDouble() <= world.getLevel().purpurConfig.rabbitNaturalToast) { -+ setCustomName(Component.translatable("Toast")); -+ } -+ // Purpur end -+ - return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData); - } - - private static Rabbit.Variant getRandomRabbitVariant(LevelAccessor world, BlockPos pos) { -+ // Purpur start -+ Level level = world.getMinecraftWorld(); -+ if (level.purpurConfig.rabbitNaturalKiller > 0D && world.getRandom().nextDouble() <= level.purpurConfig.rabbitNaturalKiller) { -+ return Rabbit.Variant.EVIL; -+ } -+ // Purpur end - Holder holder = world.getBiome(pos); - int i = world.getRandom().nextInt(100); - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e033ef722d9b6336f1cbc6bdf404f35c34b45db9..a96aa7f127467a6ea8025c09f4e336f1910cc8af 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -988,6 +988,8 @@ public class PurpurWorldConfig { - public boolean rabbitRidableInWater = true; - public boolean rabbitControllable = true; - public double rabbitMaxHealth = 3.0D; -+ public double rabbitNaturalToast = 0.0D; -+ public double rabbitNaturalKiller = 0.0D; - private void rabbitSettings() { - rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); - rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); -@@ -998,6 +1000,8 @@ public class PurpurWorldConfig { - set("mobs.rabbit.attributes.max_health", oldValue); - } - rabbitMaxHealth = getDouble("mobs.rabbit.attributes.max_health", rabbitMaxHealth); -+ rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); -+ rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); - } - - public boolean ravagerRidable = false; diff --git a/patches/server/0025-Fix-outdated-server-showing-in-ping-before-server-fu.patch b/patches/server/0025-Fix-outdated-server-showing-in-ping-before-server-fu.patch deleted file mode 100644 index 7699f3fc7..000000000 --- a/patches/server/0025-Fix-outdated-server-showing-in-ping-before-server-fu.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 4 Jun 2019 15:50:08 -0500 -Subject: [PATCH] Fix 'outdated server' showing in ping before server fully - boots - - -diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java -index 6f1c9fa89e718cbc01a8d72de34154f49c5f46db..2455f8e9679914660ec4fcd081138dabfe9c225b 100644 ---- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java -@@ -153,6 +153,7 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene - this.connection.send(new ClientboundStatusResponsePacket(ping)); - // CraftBukkit end - */ -+ if (MinecraftServer.getServer().getStatus().version().isEmpty()) return; // Purpur - do not respond to pings before we know the protocol version - com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(MinecraftServer.getServer(), this.connection); - // Paper end - } diff --git a/patches/server/0026-Tulips-change-fox-type.patch b/patches/server/0026-Tulips-change-fox-type.patch deleted file mode 100644 index 50f08714b..000000000 --- a/patches/server/0026-Tulips-change-fox-type.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 13 Jul 2019 15:56:22 -0500 -Subject: [PATCH] Tulips change fox type - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java -index 8666d82775570b812d5bdd80336c8e14db6ddf47..d2be8c1c23f291e98b9a31a63ba5fa7d44fc7402 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Fox.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java -@@ -37,6 +37,7 @@ import net.minecraft.util.RandomSource; - import net.minecraft.util.StringRepresentable; - import net.minecraft.world.DifficultyInstance; - import net.minecraft.world.InteractionHand; -+import net.minecraft.world.InteractionResult; - import net.minecraft.world.damagesource.DamageSource; - import net.minecraft.world.entity.AgeableMob; - import net.minecraft.world.entity.Entity; -@@ -389,6 +390,11 @@ public class Fox extends Animal implements VariantHolder { - } - - private void setTargetGoals() { -+ // Purpur start - do not add duplicate goals -+ this.targetSelector.removeGoal(this.landTargetGoal); -+ this.targetSelector.removeGoal(this.turtleEggTargetGoal); -+ this.targetSelector.removeGoal(this.fishTargetGoal); -+ // Purpur end - if (this.getVariant() == Fox.Type.RED) { - this.targetSelector.addGoal(4, this.landTargetGoal); - this.targetSelector.addGoal(4, this.turtleEggTargetGoal); -@@ -422,6 +428,7 @@ public class Fox extends Animal implements VariantHolder { - - public void setVariant(Fox.Type variant) { - this.entityData.set(Fox.DATA_TYPE_ID, variant.getId()); -+ this.setTargetGoals(); // Purpur - fix API bug not updating pathfinders on type change - } - - List getTrustedUUIDs() { -@@ -762,6 +769,29 @@ public class Fox extends Animal implements VariantHolder { - } - // Paper end - -+ // Purpur start -+ @Override -+ public InteractionResult mobInteract(Player player, InteractionHand hand) { -+ if (level().purpurConfig.foxTypeChangesWithTulips) { -+ ItemStack itemstack = player.getItemInHand(hand); -+ if (getVariant() == Type.RED && itemstack.getItem() == Items.WHITE_TULIP) { -+ setVariant(Type.SNOW); -+ if (!player.getAbilities().instabuild) { -+ itemstack.shrink(1); -+ } -+ return InteractionResult.SUCCESS; -+ } else if (getVariant() == Type.SNOW && itemstack.getItem() == Items.ORANGE_TULIP) { -+ setVariant(Type.RED); -+ if (!player.getAbilities().instabuild) { -+ itemstack.shrink(1); -+ } -+ return InteractionResult.SUCCESS; -+ } -+ } -+ return super.mobInteract(player, hand); -+ } -+ // Purpur end -+ - @Override - // Paper start - Cancellable death event - protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource source) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index a96aa7f127467a6ea8025c09f4e336f1910cc8af..d084d5ef20b2fb4d3b5479cb51003fb82a0358fc 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -509,6 +509,7 @@ public class PurpurWorldConfig { - public boolean foxRidableInWater = true; - public boolean foxControllable = true; - public double foxMaxHealth = 10.0D; -+ public boolean foxTypeChangesWithTulips = false; - private void foxSettings() { - foxRidable = getBoolean("mobs.fox.ridable", foxRidable); - foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); -@@ -519,6 +520,7 @@ public class PurpurWorldConfig { - set("mobs.fox.attributes.max_health", oldValue); - } - foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth); -+ foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); - } - - public boolean frogRidable = false; diff --git a/patches/server/0027-Breedable-Polar-Bears.patch b/patches/server/0027-Breedable-Polar-Bears.patch deleted file mode 100644 index 952012279..000000000 --- a/patches/server/0027-Breedable-Polar-Bears.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 12 Apr 2024 15:40:12 -0700 -Subject: [PATCH] Breedable Polar Bears - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -index 00afde0ec4811992aac306a42d473026b7e7e468..067bb175c457d6de089f18826dfce6c3661dad67 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -+++ b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -@@ -98,6 +98,27 @@ public class PolarBear extends Animal implements NeutralMob { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.polarBearMaxHealth); - } - -+ public boolean canMate(Animal other) { -+ if (other == this) { -+ return false; -+ } else if (this.isStanding()) { -+ return false; -+ } else if (this.getTarget() != null) { -+ return false; -+ } else if (!(other instanceof PolarBear)) { -+ return false; -+ } else { -+ PolarBear bear = (PolarBear) other; -+ if (bear.isStanding()) { -+ return false; -+ } -+ if (bear.getTarget() != null) { -+ return false; -+ } -+ return this.isInLove() && bear.isInLove(); -+ } -+ } -+ - @Nullable - @Override - public AgeableMob getBreedOffspring(ServerLevel world, AgeableMob entity) { -@@ -106,7 +127,7 @@ public class PolarBear extends Animal implements NeutralMob { - - @Override - public boolean isFood(ItemStack stack) { -- return false; -+ return level().purpurConfig.polarBearBreedableItem != null && stack.getItem() == level().purpurConfig.polarBearBreedableItem; // Purpur - } - - @Override -@@ -116,6 +137,12 @@ public class PolarBear extends Animal implements NeutralMob { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal()); - this.goalSelector.addGoal(1, new PolarBear.PolarBearPanicGoal()); -+ // Purpur start -+ if (level().purpurConfig.polarBearBreedableItem != null) { -+ this.goalSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.BreedGoal(this, 1.0D)); -+ this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, net.minecraft.world.item.crafting.Ingredient.of(level().purpurConfig.polarBearBreedableItem), false)); -+ } -+ // Purpur end - this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25)); - this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index d084d5ef20b2fb4d3b5479cb51003fb82a0358fc..ae6383c3d8435caba2bae551f36e3562e724361a 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -960,6 +960,8 @@ public class PurpurWorldConfig { - public boolean polarBearRidableInWater = true; - public boolean polarBearControllable = true; - public double polarBearMaxHealth = 30.0D; -+ public String polarBearBreedableItemString = ""; -+ public Item polarBearBreedableItem = null; - private void polarBearSettings() { - polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); - polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); -@@ -970,6 +972,9 @@ public class PurpurWorldConfig { - set("mobs.polar_bear.attributes.max_health", oldValue); - } - polarBearMaxHealth = getDouble("mobs.polar_bear.attributes.max_health", polarBearMaxHealth); -+ polarBearBreedableItemString = getString("mobs.polar_bear.breedable-item", polarBearBreedableItemString); -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(polarBearBreedableItemString)); -+ if (item != Items.AIR) polarBearBreedableItem = item; - } - - public boolean pufferfishRidable = false; diff --git a/patches/server/0028-Chickens-can-retaliate.patch b/patches/server/0028-Chickens-can-retaliate.patch deleted file mode 100644 index b7479c92c..000000000 --- a/patches/server/0028-Chickens-can-retaliate.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 12 Apr 2020 13:19:34 -0500 -Subject: [PATCH] Chickens can retaliate - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Chicken.java b/src/main/java/net/minecraft/world/entity/animal/Chicken.java -index a7c76e1d89f54f0dc3b27a8a8db168ea4570bf60..14210dac8a4fa8caaf69ec830f83d15525bb1bea 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Chicken.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Chicken.java -@@ -74,13 +74,16 @@ public class Chicken extends Animal { - @Override - public void initAttributes() { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.chickenMaxHealth); -+ if (level().purpurConfig.chickenRetaliate) { -+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(2.0D); -+ } - } - - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -- this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); -+ // this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); // Purpur - moved down - this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, (itemstack) -> { - return itemstack.is(ItemTags.CHICKEN_FOOD); -@@ -89,6 +92,14 @@ public class Chicken extends Animal { - this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); - this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); -+ // Purpur start -+ if (level().purpurConfig.chickenRetaliate) { -+ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.0D, false)); -+ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this)); -+ } else { -+ this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); -+ } -+ // Purpur end - } - - @Override -@@ -97,7 +108,7 @@ public class Chicken extends Animal { - } - - public static AttributeSupplier.Builder createAttributes() { -- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 4.0D).add(Attributes.MOVEMENT_SPEED, 0.25D); -+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 4.0D).add(Attributes.MOVEMENT_SPEED, 0.25D).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ae6383c3d8435caba2bae551f36e3562e724361a..4cd6d9309ed81956d59063fe4d229c6f930922ed 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -299,6 +299,7 @@ public class PurpurWorldConfig { - public boolean chickenRidableInWater = false; - public boolean chickenControllable = true; - public double chickenMaxHealth = 4.0D; -+ public boolean chickenRetaliate = false; - private void chickenSettings() { - chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); - chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); -@@ -309,6 +310,7 @@ public class PurpurWorldConfig { - set("mobs.chicken.attributes.max_health", oldValue); - } - chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth); -+ chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); - } - - public boolean codRidable = false; diff --git a/patches/server/0029-Add-option-to-set-armorstand-step-height.patch b/patches/server/0029-Add-option-to-set-armorstand-step-height.patch deleted file mode 100644 index cb9752a8c..000000000 --- a/patches/server/0029-Add-option-to-set-armorstand-step-height.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 6 Oct 2019 12:46:35 -0500 -Subject: [PATCH] Add option to set armorstand step height - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index e49dda27dd609ebf377f679c4f60c13a5f610c8e..429d1a3fd7a75fe3dc8eb8d467ad4f2bd99e0212 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -340,6 +340,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public double xOld; - public double yOld; - public double zOld; -+ public float maxUpStep; // Purpur - public boolean noPhysics; - public final RandomSource random; - public int tickCount; -@@ -4852,7 +4853,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public float maxUpStep() { -- return 0.0F; -+ return maxUpStep; - } - - public void onExplosionHit(@Nullable Entity entity) {} -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -index c2bd2e303f956d390319f6bbbe9a6492ebec5154..5abbc0caf90cafc1a06dfff158c158b1538f827c 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -676,6 +676,7 @@ public class ArmorStand extends LivingEntity { - - @Override - public void tick() { -+ maxUpStep = level().purpurConfig.armorstandStepHeight; - // Paper start - Allow ArmorStands not to tick - if (!this.canTick) { - if (this.noTickPoseDirty) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 4cd6d9309ed81956d59063fe4d229c6f930922ed..6649787fc15ca06ec2d4e7ac7b0ff061c4d4de82 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -90,6 +90,11 @@ public class PurpurWorldConfig { - return value.isEmpty() ? fallback : value; - } - -+ public float armorstandStepHeight = 0.0F; -+ private void armorstandSettings() { -+ armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); -+ } -+ - public boolean idleTimeoutKick = true; - public boolean idleTimeoutTickNearbyEntities = true; - public boolean idleTimeoutCountAsSleeping = false; diff --git a/patches/server/0030-Cat-spawning-options.patch b/patches/server/0030-Cat-spawning-options.patch deleted file mode 100644 index 862db1dc6..000000000 --- a/patches/server/0030-Cat-spawning-options.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 26 Dec 2019 18:52:55 -0600 -Subject: [PATCH] Cat spawning options - - -diff --git a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -index e0e5046c84941a8d17e18c177f3daea9cb631940..d503d7a5837dbeb98e58dbe8f7e5de45f6d88990 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -+++ b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -@@ -27,7 +27,7 @@ public class CatSpawner implements CustomSpawner { - if (this.nextTick > 0) { - return 0; - } else { -- this.nextTick = 1200; -+ this.nextTick = world.purpurConfig.catSpawnDelay; // Purpur - Player player = world.getRandomPlayer(); - if (player == null) { - return 0; -@@ -61,8 +61,12 @@ public class CatSpawner implements CustomSpawner { - - private int spawnInVillage(ServerLevel world, BlockPos pos) { - int i = 48; -- if (world.getPoiManager().getCountInRange(entry -> entry.is(PoiTypes.HOME), pos, 48, PoiManager.Occupancy.IS_OCCUPIED) > 4L) { -- List list = world.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(48.0, 8.0, 48.0)); -+ // Purpur start -+ int range = world.purpurConfig.catSpawnVillageScanRange; -+ if (range <= 0) return 0; -+ if (world.getPoiManager().getCountInRange(entry -> entry.is(PoiTypes.HOME), pos, range, PoiManager.Occupancy.IS_OCCUPIED) > 4L) { -+ List list = world.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(range, 8.0, range)); -+ // Purpur end - if (list.size() < 5) { - return this.spawnCat(pos, world); - } -@@ -73,7 +77,11 @@ public class CatSpawner implements CustomSpawner { - - private int spawnInHut(ServerLevel world, BlockPos pos) { - int i = 16; -- List list = world.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(16.0, 8.0, 16.0)); -+ // Purpur start -+ int range = world.purpurConfig.catSpawnSwampHutScanRange; -+ if (range <= 0) return 0; -+ List list = world.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(range, 8.0, range)); -+ // Purpur end - return list.size() < 1 ? this.spawnCat(pos, world) : 0; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 6649787fc15ca06ec2d4e7ac7b0ff061c4d4de82..c9dbbe9dde5b463bdde68604d6e5b1c2902d57fa 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -272,6 +272,9 @@ public class PurpurWorldConfig { - public boolean catRidableInWater = true; - public boolean catControllable = true; - public double catMaxHealth = 10.0D; -+ public int catSpawnDelay = 1200; -+ public int catSpawnSwampHutScanRange = 16; -+ public int catSpawnVillageScanRange = 48; - private void catSettings() { - catRidable = getBoolean("mobs.cat.ridable", catRidable); - catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); -@@ -282,6 +285,9 @@ public class PurpurWorldConfig { - set("mobs.cat.attributes.max_health", oldValue); - } - catMaxHealth = getDouble("mobs.cat.attributes.max_health", catMaxHealth); -+ catSpawnDelay = getInt("mobs.cat.spawn-delay", catSpawnDelay); -+ catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange); -+ catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange); - } - - public boolean caveSpiderRidable = false; diff --git a/patches/server/0031-Cows-eat-mushrooms.patch b/patches/server/0031-Cows-eat-mushrooms.patch deleted file mode 100644 index 4b9bf527b..000000000 --- a/patches/server/0031-Cows-eat-mushrooms.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 4 May 2019 01:10:30 -0500 -Subject: [PATCH] Cows eat mushrooms - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java -index bee1a275f242866206dc461461b7962e04289ddc..bda0d933ccbee613aa7fb31534351a0d2dbab0a7 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java -@@ -2,6 +2,7 @@ package net.minecraft.world.entity.animal; - - import javax.annotation.Nullable; - import net.minecraft.core.BlockPos; -+import net.minecraft.core.particles.ParticleTypes; - import net.minecraft.server.level.ServerLevel; - import net.minecraft.sounds.SoundEvent; - import net.minecraft.sounds.SoundEvents; -@@ -29,6 +30,7 @@ import net.minecraft.world.item.ItemStack; - import net.minecraft.world.item.ItemUtils; - import net.minecraft.world.item.Items; - import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.state.BlockState; - // CraftBukkit start - import org.bukkit.craftbukkit.event.CraftEventFactory; -@@ -73,7 +75,7 @@ public class Cow extends Animal { - this.goalSelector.addGoal(1, new PanicGoal(this, 2.0D)); - this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, (itemstack) -> { -- return itemstack.is(ItemTags.COW_FOOD); -+ return level().purpurConfig.cowFeedMushrooms > 0 && (itemstack.is(Blocks.RED_MUSHROOM.asItem()) || itemstack.is(Blocks.BROWN_MUSHROOM.asItem())) || itemstack.is(ItemTags.COW_FOOD); // Purpur - }, false)); - this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25D)); - this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); -@@ -134,6 +136,10 @@ public class Cow extends Animal { - - player.setItemInHand(hand, itemstack1); - return InteractionResult.sidedSuccess(this.level().isClientSide); -+ // Purpur start - feed mushroom to change to mooshroom -+ } else if (level().purpurConfig.cowFeedMushrooms > 0 && this.getType() != EntityType.MOOSHROOM && isMushroom(itemstack)) { -+ return this.feedMushroom(player, itemstack); -+ // Purpur end - } else { - return super.mobInteract(player, hand); - } -@@ -149,4 +155,69 @@ public class Cow extends Animal { - public EntityDimensions getDefaultDimensions(Pose pose) { - return this.isBaby() ? Cow.BABY_DIMENSIONS : super.getDefaultDimensions(pose); - } -+ -+ // Purpur start - feed mushroom to change to mooshroom -+ private int redMushroomsFed = 0; -+ private int brownMushroomsFed = 0; -+ -+ private boolean isMushroom(ItemStack stack) { -+ return stack.getItem() == Blocks.RED_MUSHROOM.asItem() || stack.getItem() == Blocks.BROWN_MUSHROOM.asItem(); -+ } -+ -+ private int incrementFeedCount(ItemStack stack) { -+ if (stack.getItem() == Blocks.RED_MUSHROOM.asItem()) { -+ return ++redMushroomsFed; -+ } else { -+ return ++brownMushroomsFed; -+ } -+ } -+ -+ private InteractionResult feedMushroom(Player player, ItemStack stack) { -+ level().broadcastEntityEvent(this, (byte) 18); // hearts -+ playSound(SoundEvents.COW_MILK, 1.0F, 1.0F); -+ if (incrementFeedCount(stack) < level().purpurConfig.cowFeedMushrooms) { -+ if (!player.getAbilities().instabuild) { -+ stack.shrink(1); -+ } -+ return InteractionResult.CONSUME; // require 5 mushrooms to transform (prevents mushroom duping) -+ } -+ MushroomCow mooshroom = EntityType.MOOSHROOM.create(level()); -+ if (mooshroom == null) { -+ return InteractionResult.PASS; -+ } -+ if (stack.getItem() == Blocks.BROWN_MUSHROOM.asItem()) { -+ mooshroom.setVariant(MushroomCow.MushroomType.BROWN); -+ } else { -+ mooshroom.setVariant(MushroomCow.MushroomType.RED); -+ } -+ mooshroom.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); -+ mooshroom.setHealth(this.getHealth()); -+ mooshroom.setAge(getAge()); -+ mooshroom.copyPosition(this); -+ mooshroom.setYBodyRot(this.yBodyRot); -+ mooshroom.setYHeadRot(this.getYHeadRot()); -+ mooshroom.yRotO = this.yRotO; -+ mooshroom.xRotO = this.xRotO; -+ if (this.hasCustomName()) { -+ mooshroom.setCustomName(this.getCustomName()); -+ } -+ if (CraftEventFactory.callEntityTransformEvent(this, mooshroom, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) { -+ return InteractionResult.PASS; -+ } -+ if (!new com.destroystokyo.paper.event.entity.EntityTransformedEvent(this.getBukkitEntity(), mooshroom.getBukkitEntity(), com.destroystokyo.paper.event.entity.EntityTransformedEvent.TransformedReason.INFECTED).callEvent()) { -+ return InteractionResult.PASS; -+ } -+ this.level().addFreshEntity(mooshroom); -+ this.remove(RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ if (!player.getAbilities().instabuild) { -+ stack.shrink(1); -+ } -+ for (int i = 0; i < 15; ++i) { -+ ((ServerLevel) level()).sendParticles(((ServerLevel) level()).players(), null, ParticleTypes.HAPPY_VILLAGER, -+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1, -+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true); -+ } -+ return InteractionResult.SUCCESS; -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index c9dbbe9dde5b463bdde68604d6e5b1c2902d57fa..ab5960b9104d362852ee3d6ba151cf78dd58a0ee 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -342,6 +342,7 @@ public class PurpurWorldConfig { - public boolean cowRidableInWater = true; - public boolean cowControllable = true; - public double cowMaxHealth = 10.0D; -+ public int cowFeedMushrooms = 0; - private void cowSettings() { - cowRidable = getBoolean("mobs.cow.ridable", cowRidable); - cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); -@@ -352,6 +353,7 @@ public class PurpurWorldConfig { - set("mobs.cow.attributes.max_health", oldValue); - } - cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth); -+ cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); - } - - public boolean creeperRidable = false; diff --git a/patches/server/0032-Fix-cow-rotation-when-shearing-mooshroom.patch b/patches/server/0032-Fix-cow-rotation-when-shearing-mooshroom.patch deleted file mode 100644 index b487f483e..000000000 --- a/patches/server/0032-Fix-cow-rotation-when-shearing-mooshroom.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 3 May 2019 23:53:16 -0500 -Subject: [PATCH] Fix cow rotation when shearing mooshroom - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index b47dddb2fc6058a90665ccbd362088d9a2e837b5..41b52f128fbc174939a7f2d1cd937ab19432de25 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -218,7 +218,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder -Date: Sun, 12 May 2019 01:14:46 -0500 -Subject: [PATCH] Pigs give saddle back - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Pig.java b/src/main/java/net/minecraft/world/entity/animal/Pig.java -index a365573c5c5e640f165701bc79f7c605674c5709..4f84406304114abbaff9f96a5df6a48616983fa9 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Pig.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Pig.java -@@ -178,6 +178,17 @@ public class Pig extends Animal implements ItemSteerable, Saddleable { - public InteractionResult mobInteract(Player player, InteractionHand hand) { - boolean flag = this.isFood(player.getItemInHand(hand)); - -+ if (level().purpurConfig.pigGiveSaddleBack && player.isSecondaryUseActive() && !flag && isSaddled() && !isVehicle()) { -+ this.steering.setSaddle(false); -+ if (!player.getAbilities().instabuild) { -+ ItemStack saddle = new ItemStack(Items.SADDLE); -+ if (!player.getInventory().add(saddle)) { -+ player.drop(saddle, false); -+ } -+ } -+ return InteractionResult.SUCCESS; -+ } -+ - if (!flag && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) { - if (!this.level().isClientSide) { - player.startRiding(this); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ab5960b9104d362852ee3d6ba151cf78dd58a0ee..1c530384c9040236ce525329f37913cdd3e424ff 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -911,6 +911,7 @@ public class PurpurWorldConfig { - public boolean pigRidableInWater = false; - public boolean pigControllable = true; - public double pigMaxHealth = 10.0D; -+ public boolean pigGiveSaddleBack = false; - private void pigSettings() { - pigRidable = getBoolean("mobs.pig.ridable", pigRidable); - pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); -@@ -921,6 +922,7 @@ public class PurpurWorldConfig { - set("mobs.pig.attributes.max_health", oldValue); - } - pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth); -+ pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); - } - - public boolean piglinRidable = false; diff --git a/patches/server/0034-Snowman-drop-and-put-back-pumpkin.patch b/patches/server/0034-Snowman-drop-and-put-back-pumpkin.patch deleted file mode 100644 index 4ac6f1b7e..000000000 --- a/patches/server/0034-Snowman-drop-and-put-back-pumpkin.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 3 May 2019 23:58:44 -0500 -Subject: [PATCH] Snowman drop and put back pumpkin - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index a54893d51cc1ce204e59a6ffe8b84228775af4da..0060414b1d5afde56372ce121e9d37a1668cd03b 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -189,6 +189,14 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - } - - return InteractionResult.sidedSuccess(this.level().isClientSide); -+ // Purpur start -+ } else if (level().purpurConfig.snowGolemPutPumpkinBack && !hasPumpkin() && itemstack.getItem() == Blocks.CARVED_PUMPKIN.asItem()) { -+ setPumpkin(true); -+ if (!player.getAbilities().instabuild) { -+ itemstack.shrink(1); -+ } -+ return InteractionResult.SUCCESS; -+ // Purpur end - } else { - return tryRide(player, hand); // Purpur - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 1c530384c9040236ce525329f37913cdd3e424ff..acec5455e9c16508ae474e1307e3cc234d17e6ee 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1176,6 +1176,7 @@ public class PurpurWorldConfig { - public boolean snowGolemControllable = true; - public boolean snowGolemLeaveTrailWhenRidden = false; - public double snowGolemMaxHealth = 4.0D; -+ public boolean snowGolemPutPumpkinBack = false; - private void snowGolemSettings() { - snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); - snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); -@@ -1187,6 +1188,7 @@ public class PurpurWorldConfig { - set("mobs.snow_golem.attributes.max_health", oldValue); - } - snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth); -+ snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack); - } - - public boolean snifferRidable = false; diff --git a/patches/server/0035-Ender-dragon-always-drop-full-exp.patch b/patches/server/0035-Ender-dragon-always-drop-full-exp.patch deleted file mode 100644 index 2226fff2e..000000000 --- a/patches/server/0035-Ender-dragon-always-drop-full-exp.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 24 Aug 2019 14:42:54 -0500 -Subject: [PATCH] Ender dragon always drop full exp - - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -index 0a7f87ac09f9ef6ad69974090f0d6f437d232b11..f751444603e4a1a2ef53e7232b5abfff82c316e8 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -@@ -747,7 +747,7 @@ public class EnderDragon extends Mob implements Enemy { - boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT); - short short0 = 500; - -- if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) { -+ if (this.dragonFight != null && (level().purpurConfig.enderDragonAlwaysDropsFullExp || !this.dragonFight.hasPreviouslyKilledDragon())) { - short0 = 12000; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index acec5455e9c16508ae474e1307e3cc234d17e6ee..a9d6c6713a098ca87d62b43d491bc2d9a8590741 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -455,6 +455,7 @@ public class PurpurWorldConfig { - public boolean enderDragonControllable = true; - public double enderDragonMaxY = 320D; - public double enderDragonMaxHealth = 200.0D; -+ public boolean enderDragonAlwaysDropsFullExp = false; - private void enderDragonSettings() { - enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); - enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); -@@ -470,6 +471,7 @@ public class PurpurWorldConfig { - set("mobs.ender_dragon.attributes.max_health", oldValue); - } - enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth); -+ enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); - } - - public boolean endermanRidable = false; diff --git a/patches/server/0036-Allow-soil-to-moisten-from-water-directly-under-it.patch b/patches/server/0036-Allow-soil-to-moisten-from-water-directly-under-it.patch deleted file mode 100644 index 184d03b5d..000000000 --- a/patches/server/0036-Allow-soil-to-moisten-from-water-directly-under-it.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 21 Jun 2019 14:37:10 -0500 -Subject: [PATCH] Allow soil to moisten from water directly under it - - -diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index d59e33e7326489c6d55d316d0130f22235f4c63c..da85fabd75e9bd5ebece7127ef5b512df16fe3ac 100644 ---- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -172,7 +172,7 @@ public class FarmBlock extends Block { - } - } - -- return false; -+ return ((ServerLevel) world).purpurConfig.farmlandGetsMoistFromBelow && world.getFluidState(pos.relative(Direction.DOWN)).is(FluidTags.WATER); // Purpur; - // Paper end - Perf: remove abstract block iteration - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index a9d6c6713a098ca87d62b43d491bc2d9a8590741..41b804abeab390a259eb0c8ed72f75ad403471dd 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -145,6 +145,11 @@ public class PurpurWorldConfig { - }); - } - -+ public boolean farmlandGetsMoistFromBelow = false; -+ private void farmlandSettings() { -+ farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); -+ } -+ - public boolean turtleEggsBreakFromExpOrbs = false; - public boolean turtleEggsBreakFromItems = false; - public boolean turtleEggsBreakFromMinecarts = false; diff --git a/patches/server/0037-Minecart-settings-and-WASD-controls.patch b/patches/server/0037-Minecart-settings-and-WASD-controls.patch deleted file mode 100644 index b38b1d122..000000000 --- a/patches/server/0037-Minecart-settings-and-WASD-controls.patch +++ /dev/null @@ -1,223 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 29 Jun 2019 02:32:40 -0500 -Subject: [PATCH] Minecart settings and WASD controls - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index bc6a5de72d52627b3ceca4b52b95e12ceddf1247..a17de781053a2c2caf615e5ac48a45c14386b0af 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1189,6 +1189,7 @@ public class ServerPlayer extends Player { - if (this.isInvulnerableTo(source)) { - return false; - } else { -+ if (source.is(DamageTypeTags.IS_FALL) && getRootVehicle() instanceof net.minecraft.world.entity.vehicle.AbstractMinecart && level().purpurConfig.minecartControllable && !level().purpurConfig.minecartControllableFallDamage) return false; // Purpur - boolean flag = this.server.isDedicatedServer() && this.isPvpAllowed() && source.is(DamageTypeTags.IS_FALL); - - if (!flag && this.spawnInvulnerableTime > 0 && !source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -index 4d7454e5a64fc18e63793a221daa94617f17c666..97172e9c53c381d451111227feb4d1fa19d38ad8 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -@@ -102,12 +102,14 @@ public abstract class AbstractMinecart extends VehicleEntity { - private double flyingY = 0.95; - private double flyingZ = 0.95; - public double maxSpeed = 0.4D; -+ public double storedMaxSpeed; // Purpur - // CraftBukkit end - - protected AbstractMinecart(EntityType type, Level world) { - super(type, world); - this.targetDeltaMovement = Vec3.ZERO; - this.blocksBuilding = true; -+ if (world != null) maxSpeed = storedMaxSpeed = world.purpurConfig.minecartMaxSpeed; // Purpur - } - - protected AbstractMinecart(EntityType type, Level world, double x, double y, double z) { -@@ -296,6 +298,12 @@ public abstract class AbstractMinecart extends VehicleEntity { - - @Override - public void tick() { -+ // Purpur start -+ if (storedMaxSpeed != level().purpurConfig.minecartMaxSpeed) { -+ maxSpeed = storedMaxSpeed = level().purpurConfig.minecartMaxSpeed; -+ } -+ // Purpur end -+ - // CraftBukkit start - double prevX = this.getX(); - double prevY = this.getY(); -@@ -448,16 +456,62 @@ public abstract class AbstractMinecart extends VehicleEntity { - - public void activateMinecart(int x, int y, int z, boolean powered) {} - -+ // Purpur start -+ private Double lastSpeed; -+ -+ public double getControllableSpeed() { -+ BlockState blockState = level().getBlockState(this.blockPosition()); -+ if (!blockState.isSolid()) { -+ blockState = level().getBlockState(this.blockPosition().relative(Direction.DOWN)); -+ } -+ Double speed = level().purpurConfig.minecartControllableBlockSpeeds.get(blockState.getBlock()); -+ if (!blockState.isSolid()) { -+ speed = lastSpeed; -+ } -+ if (speed == null) { -+ speed = level().purpurConfig.minecartControllableBaseSpeed; -+ } -+ return lastSpeed = speed; -+ } -+ // Purpur end -+ - protected void comeOffTrack() { - double d0 = this.getMaxSpeed(); - Vec3 vec3d = this.getDeltaMovement(); - - this.setDeltaMovement(Mth.clamp(vec3d.x, -d0, d0), vec3d.y, Mth.clamp(vec3d.z, -d0, d0)); -+ -+ // Purpur start -+ if (level().purpurConfig.minecartControllable && !isInWater() && !isInLava() && !passengers.isEmpty()) { -+ Entity passenger = passengers.get(0); -+ if (passenger instanceof Player) { -+ Player player = (Player) passenger; -+ if (player.jumping && this.onGround) { -+ setDeltaMovement(new Vec3(getDeltaMovement().x, level().purpurConfig.minecartControllableHopBoost, getDeltaMovement().z)); -+ } -+ if (player.zza != 0.0F) { -+ Vector velocity = player.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(getControllableSpeed()); -+ if (player.zza < 0.0) { -+ velocity.multiply(-0.5); -+ } -+ setDeltaMovement(new Vec3(velocity.getX(), getDeltaMovement().y, velocity.getZ())); -+ } -+ this.setYRot(passenger.getYRot() - 90); -+ maxUpStep = level().purpurConfig.minecartControllableStepHeight; -+ } else { -+ maxUpStep = 0.0F; -+ } -+ } else { -+ maxUpStep = 0.0F; -+ } -+ // Purpur end -+ - if (this.onGround()) { - // CraftBukkit start - replace magic numbers with our variables - this.setDeltaMovement(new Vec3(this.getDeltaMovement().x * this.derailedX, this.getDeltaMovement().y * this.derailedY, this.getDeltaMovement().z * this.derailedZ)); - // CraftBukkit end - } -+ else if (level().purpurConfig.minecartControllable) setDeltaMovement(new Vec3(getDeltaMovement().x * derailedX, getDeltaMovement().y, getDeltaMovement().z * derailedZ)); // Purpur - - this.move(MoverType.SELF, this.getDeltaMovement()); - if (!this.onGround()) { -diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java -index 66074445d3908b9bb1c8d70e1e27d057720ec8e5..0fd4f2ab929df479360755a3f1e58a933ae59520 100644 ---- a/src/main/java/net/minecraft/world/item/MinecartItem.java -+++ b/src/main/java/net/minecraft/world/item/MinecartItem.java -@@ -120,8 +120,9 @@ public class MinecartItem extends Item { - BlockState iblockdata = world.getBlockState(blockposition); - - if (!iblockdata.is(BlockTags.RAILS)) { -- return InteractionResult.FAIL; -- } else { -+ if (!world.purpurConfig.minecartPlaceAnywhere) return InteractionResult.FAIL; -+ if (iblockdata.isSolid()) blockposition = blockposition.relative(context.getClickedFace()); -+ } // else { // Purpur - place minecarts anywhere - ItemStack itemstack = context.getItemInHand(); - - if (world instanceof ServerLevel) { -@@ -146,6 +147,6 @@ public class MinecartItem extends Item { - - itemstack.shrink(1); - return InteractionResult.sidedSuccess(world.isClientSide); -- } -+ // } // Purpur - place minecarts anywhere - } - } -diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 2034ca2edd3aff61d94416266e75402babd3e741..3c1091f2a729b7d06ba6e21c37f788edb2ad1775 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -94,7 +94,7 @@ public abstract class BlockBehaviour implements FeatureElement { - protected final float jumpFactor; - protected final boolean dynamicShape; - protected final FeatureFlagSet requiredFeatures; -- protected final BlockBehaviour.Properties properties; -+ public final BlockBehaviour.Properties properties; // Purpur - protected -> public - @Nullable - protected ResourceKey drops; - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 41b804abeab390a259eb0c8ed72f75ad403471dd..755d53e04bb0ed678bebc3497476e252dd5a736e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -95,6 +95,68 @@ public class PurpurWorldConfig { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); - } - -+ public double minecartMaxSpeed = 0.4D; -+ public boolean minecartPlaceAnywhere = false; -+ public boolean minecartControllable = false; -+ public float minecartControllableStepHeight = 1.0F; -+ public double minecartControllableHopBoost = 0.5D; -+ public boolean minecartControllableFallDamage = true; -+ public double minecartControllableBaseSpeed = 0.1D; -+ public Map minecartControllableBlockSpeeds = new HashMap<>(); -+ private void minecartSettings() { -+ if (PurpurConfig.version < 12) { -+ boolean oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.place-anywhere", minecartPlaceAnywhere); -+ set("gameplay-mechanics.controllable-minecarts.place-anywhere", null); -+ set("gameplay-mechanics.minecart.place-anywhere", oldBool); -+ oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.enabled", minecartControllable); -+ set("gameplay-mechanics.controllable-minecarts.enabled", null); -+ set("gameplay-mechanics.minecart.controllable.enabled", oldBool); -+ double oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.step-height", minecartControllableStepHeight); -+ set("gameplay-mechanics.controllable-minecarts.step-height", null); -+ set("gameplay-mechanics.minecart.controllable.step-height", oldDouble); -+ oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.hop-boost", minecartControllableHopBoost); -+ set("gameplay-mechanics.controllable-minecarts.hop-boost", null); -+ set("gameplay-mechanics.minecart.controllable.hop-boost", oldDouble); -+ oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.fall-damage", minecartControllableFallDamage); -+ set("gameplay-mechanics.controllable-minecarts.fall-damage", null); -+ set("gameplay-mechanics.minecart.controllable.fall-damage", oldBool); -+ oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.base-speed", minecartControllableBaseSpeed); -+ set("gameplay-mechanics.controllable-minecarts.base-speed", null); -+ set("gameplay-mechanics.minecart.controllable.base-speed", oldDouble); -+ ConfigurationSection section = getConfigurationSection("gameplay-mechanics.controllable-minecarts.block-speed"); -+ if (section != null) { -+ for (String key : section.getKeys(false)) { -+ if ("grass-block".equals(key)) key = "grass_block"; // oopsie -+ oldDouble = section.getDouble(key, minecartControllableBaseSpeed); -+ set("gameplay-mechanics.controllable-minecarts.block-speed." + key, null); -+ set("gameplay-mechanics.minecart.controllable.block-speed." + key, oldDouble); -+ } -+ set("gameplay-mechanics.controllable-minecarts.block-speed", null); -+ } -+ set("gameplay-mechanics.controllable-minecarts", null); -+ } -+ -+ minecartMaxSpeed = getDouble("gameplay-mechanics.minecart.max-speed", minecartMaxSpeed); -+ minecartPlaceAnywhere = getBoolean("gameplay-mechanics.minecart.place-anywhere", minecartPlaceAnywhere); -+ minecartControllable = getBoolean("gameplay-mechanics.minecart.controllable.enabled", minecartControllable); -+ minecartControllableStepHeight = (float) getDouble("gameplay-mechanics.minecart.controllable.step-height", minecartControllableStepHeight); -+ minecartControllableHopBoost = getDouble("gameplay-mechanics.minecart.controllable.hop-boost", minecartControllableHopBoost); -+ minecartControllableFallDamage = getBoolean("gameplay-mechanics.minecart.controllable.fall-damage", minecartControllableFallDamage); -+ minecartControllableBaseSpeed = getDouble("gameplay-mechanics.minecart.controllable.base-speed", minecartControllableBaseSpeed); -+ ConfigurationSection section = getConfigurationSection("gameplay-mechanics.minecart.controllable.block-speed"); -+ if (section != null) { -+ for (String key : section.getKeys(false)) { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(key)); -+ if (block != Blocks.AIR) { -+ minecartControllableBlockSpeeds.put(block, section.getDouble(key, minecartControllableBaseSpeed)); -+ } -+ } -+ } else { -+ set("gameplay-mechanics.minecart.controllable.block-speed.grass_block", 0.3D); -+ set("gameplay-mechanics.minecart.controllable.block-speed.stone", 0.5D); -+ } -+ } -+ - public boolean idleTimeoutKick = true; - public boolean idleTimeoutTickNearbyEntities = true; - public boolean idleTimeoutCountAsSleeping = false; diff --git a/patches/server/0038-Disable-loot-drops-on-death-by-cramming.patch b/patches/server/0038-Disable-loot-drops-on-death-by-cramming.patch deleted file mode 100644 index 996296e66..000000000 --- a/patches/server/0038-Disable-loot-drops-on-death-by-cramming.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 3 Jul 2019 23:58:31 -0500 -Subject: [PATCH] Disable loot drops on death by cramming - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index a3ee2af337acef86a15b12c9e6d8cd8452980a87..7b210484fd10e6e994c66afb45f8a28ffb5812f1 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1864,6 +1864,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - - this.dropEquipment(); // CraftBukkit - from below - if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { -+ if (!(source.is(net.minecraft.world.damagesource.DamageTypes.CRAMMING) && level().purpurConfig.disableDropsOnCrammingDeath)) { // Purpur - this.dropFromLootTable(source, flag); - // Paper start - final boolean prev = this.clearEquipmentSlots; -@@ -1872,6 +1873,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - // Paper end - this.dropCustomDeathLoot(source, i, flag); - this.clearEquipmentSlots = prev; // Paper -+ } // Purpur - } - // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment - org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops, () -> { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 755d53e04bb0ed678bebc3497476e252dd5a736e..b7bf1a6e59e33d13887ae3d98f37658f52030e37 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -95,6 +95,11 @@ public class PurpurWorldConfig { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); - } - -+ public boolean disableDropsOnCrammingDeath = false; -+ private void miscGameplayMechanicsSettings() { -+ disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); -+ } -+ - public double minecartMaxSpeed = 0.4D; - public boolean minecartPlaceAnywhere = false; - public boolean minecartControllable = false; diff --git a/patches/server/0039-Option-to-toggle-milk-curing-bad-omen.patch b/patches/server/0039-Option-to-toggle-milk-curing-bad-omen.patch deleted file mode 100644 index 90595d0c8..000000000 --- a/patches/server/0039-Option-to-toggle-milk-curing-bad-omen.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 10 Jul 2019 20:43:05 -0500 -Subject: [PATCH] Option to toggle milk curing bad omen - - -diff --git a/src/main/java/net/minecraft/world/item/MilkBucketItem.java b/src/main/java/net/minecraft/world/item/MilkBucketItem.java -index 0f83ae4b0d5f52ff9ccfff6bbcc31153d45bd619..d0751274e89042715cab8e9e72387042356e3244 100644 ---- a/src/main/java/net/minecraft/world/item/MilkBucketItem.java -+++ b/src/main/java/net/minecraft/world/item/MilkBucketItem.java -@@ -26,7 +26,9 @@ public class MilkBucketItem extends Item { - - stack.consume(1, user); - if (!world.isClientSide) { -+ net.minecraft.world.effect.MobEffectInstance badOmen = user.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN); // Purpur - user.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.MILK); // CraftBukkit -+ if (!world.purpurConfig.milkCuresBadOmen && badOmen != null) user.addEffect(badOmen); // Purpur - } - - return stack.isEmpty() ? new ItemStack(Items.BUCKET) : stack; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b7bf1a6e59e33d13887ae3d98f37658f52030e37..40493cbb1b14f16549b95aa439e4c25c04a0627c 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -96,8 +96,10 @@ public class PurpurWorldConfig { - } - - public boolean disableDropsOnCrammingDeath = false; -+ public boolean milkCuresBadOmen = true; - private void miscGameplayMechanicsSettings() { - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); -+ milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); - } - - public double minecartMaxSpeed = 0.4D; diff --git a/patches/server/0041-Skip-events-if-there-s-no-listeners.patch b/patches/server/0041-Skip-events-if-there-s-no-listeners.patch deleted file mode 100644 index a34b98f86..000000000 --- a/patches/server/0041-Skip-events-if-there-s-no-listeners.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 4 Apr 2020 03:07:59 -0500 -Subject: [PATCH] Skip events if there's no listeners - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index aa2fca6917fb67fe0e9ba067d11487c3a274f675..5c7287ef8c2d59215aff81cb138a55676bfa6356 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -501,6 +501,7 @@ public class Commands { - private void runSync(ServerPlayer player, Collection bukkit, RootCommandNode rootcommandnode) { - // Paper end - Perf: Async command map building - new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - Brigadier API -+ if (PlayerCommandSendEvent.getHandlerList().getRegisteredListeners().length > 0) { // Purpur - skip all this crap if there's nothing listening - PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit)); - event.getPlayer().getServer().getPluginManager().callEvent(event); - -@@ -511,6 +512,7 @@ public class Commands { - } - } - // CraftBukkit end -+ } // Purpur - skip event - player.connection.send(new ClientboundCommandsPacket(rootcommandnode)); - } - diff --git a/patches/server/0042-Add-permission-for-F3-N-debug.patch b/patches/server/0042-Add-permission-for-F3-N-debug.patch deleted file mode 100644 index 8b2ac074b..000000000 --- a/patches/server/0042-Add-permission-for-F3-N-debug.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 28 Dec 2019 04:21:54 -0600 -Subject: [PATCH] Add permission for F3+N debug - - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index f10dcc0debcdd2077ee53cb1aefca8abd12f3ecd..338808ba1138f62d89f3f1338a4c5068426df0e4 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1180,6 +1180,7 @@ public abstract class PlayerList { - } else { - b0 = (byte) (24 + permissionLevel); - } -+ if (b0 < 28 && player.getBukkitEntity().hasPermission("purpur.debug.f3n")) b0 = 28; // Purpur - - player.connection.send(new ClientboundEntityEventPacket(player, b0)); - } diff --git a/patches/server/0043-Configurable-TPS-Catchup.patch b/patches/server/0043-Configurable-TPS-Catchup.patch deleted file mode 100644 index 2bed1436e..000000000 --- a/patches/server/0043-Configurable-TPS-Catchup.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 26 Mar 2020 19:06:22 -0500 -Subject: [PATCH] Configurable TPS Catchup - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index dfa332c4ff52033eb95248518bc44bbd22697697..f3ad4ee45ba48a10bbae1084f291ae0bcccdf624 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1240,6 +1240,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Thu, 19 Mar 2020 19:39:34 -0500 -Subject: [PATCH] Add option to allow loyalty on tridents to work in the void - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -index 3ff06cc6ad35567bcb1f29115db63c11a8e79dbb..f7dd785bdb0dbd0706b367b48235215ff1a0e08f 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownTrident.java -@@ -67,7 +67,7 @@ public class ThrownTrident extends AbstractArrow { - Entity entity = this.getOwner(); - byte b0 = (Byte) this.entityData.get(ThrownTrident.ID_LOYALTY); - -- if (b0 > 0 && (this.dealtDamage || this.isNoPhysics()) && entity != null) { -+ if (b0 > 0 && (this.dealtDamage || this.isNoPhysics() || (level().purpurConfig.tridentLoyaltyVoidReturnHeight < 0.0D && getY() < level().purpurConfig.tridentLoyaltyVoidReturnHeight)) && entity != null) { // Purpur - if (!this.isAcceptibleReturnOwner()) { - if (!this.level().isClientSide && this.pickup == AbstractArrow.Pickup.ALLOWED) { - this.spawnAtLocation(this.getPickupItem(), 0.1F); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 40493cbb1b14f16549b95aa439e4c25c04a0627c..a5ec746fc30af0093430bb7a7f6848081220ec57 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -97,9 +97,11 @@ public class PurpurWorldConfig { - - public boolean disableDropsOnCrammingDeath = false; - public boolean milkCuresBadOmen = true; -+ public double tridentLoyaltyVoidReturnHeight = 0.0D; - private void miscGameplayMechanicsSettings() { - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); -+ tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); - } - - public double minecartMaxSpeed = 0.4D; diff --git a/patches/server/0045-Add-enderman-and-creeper-griefing-controls.patch b/patches/server/0045-Add-enderman-and-creeper-griefing-controls.patch deleted file mode 100644 index d66f9a8f4..000000000 --- a/patches/server/0045-Add-enderman-and-creeper-griefing-controls.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 26 Apr 2020 16:28:38 -0500 -Subject: [PATCH] Add enderman and creeper griefing controls - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index 84114356ea4c06998572c03f2e2a75b49e539980..98c93c46694f1e67be803a7ca0c0f55532df2e95 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -361,7 +361,7 @@ public class Creeper extends Monster implements PowerableMob { - if (!event.isCancelled()) { - // CraftBukkit end - this.dead = true; -- this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API -+ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), this.level().getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) && level().purpurConfig.creeperAllowGriefing ? Level.ExplosionInteraction.MOB : Level.ExplosionInteraction.NONE); // CraftBukkit // Paper - fix DamageSource API // Purpur - this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause - this.spawnLingeringCloud(); - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index 3abfc4f449552ec60a1f7c4e3faa9fd0ebfdc300..89275ac02fcfab963b520efae6135d6f5ac13465 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -524,6 +524,7 @@ public class EnderMan extends Monster implements NeutralMob { - - @Override - public boolean canUse() { -+ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - return this.enderman.getCarriedBlock() == null ? false : (!this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0); - } - -@@ -569,6 +570,7 @@ public class EnderMan extends Monster implements NeutralMob { - - @Override - public boolean canUse() { -+ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - return this.enderman.getCarriedBlock() != null ? false : (!this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index a5ec746fc30af0093430bb7a7f6848081220ec57..b266fc52508106f1f0f449b8eb900e4c04316fec 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -437,6 +437,7 @@ public class PurpurWorldConfig { - public boolean creeperControllable = true; - public double creeperMaxHealth = 20.0D; - public double creeperChargedChance = 0.0D; -+ public boolean creeperAllowGriefing = true; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -448,6 +449,7 @@ public class PurpurWorldConfig { - } - creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth); - creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); -+ creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); - } - - public boolean dolphinRidable = false; -@@ -554,6 +556,7 @@ public class PurpurWorldConfig { - public boolean endermanRidableInWater = true; - public boolean endermanControllable = true; - public double endermanMaxHealth = 40.0D; -+ public boolean endermanAllowGriefing = true; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -@@ -564,6 +567,7 @@ public class PurpurWorldConfig { - set("mobs.enderman.attributes.max_health", oldValue); - } - endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); -+ endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); - } - - public boolean endermiteRidable = false; diff --git a/patches/server/0046-Villagers-follow-emerald-blocks.patch b/patches/server/0046-Villagers-follow-emerald-blocks.patch deleted file mode 100644 index ca38dbc6b..000000000 --- a/patches/server/0046-Villagers-follow-emerald-blocks.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 29 Nov 2019 22:10:12 -0600 -Subject: [PATCH] Villagers follow emerald blocks - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java -index 13f8c2cb42334ba3b573ca44ace1d3df76e41ff7..baca552e52c728867fcb0527b6c3eb394b2b9c7f 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/TemptGoal.java -@@ -64,7 +64,7 @@ public class TemptGoal extends Goal { - } - - private boolean shouldFollow(LivingEntity entity) { -- return this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem()); -+ return (this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem())) && (!(this.mob instanceof net.minecraft.world.entity.npc.Villager villager) || !villager.isSleeping()); // Purpur Fix #512 - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -index d323cf157f2a910916baa9ce3f7e5bc81648c47d..6cbbca1db5362fa2dd5c5704c7fbaa612d3cbab1 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -@@ -48,6 +48,7 @@ import org.bukkit.event.entity.VillagerAcquireTradeEvent; - // CraftBukkit end - - public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant { -+ static final net.minecraft.world.item.crafting.Ingredient TEMPT_ITEMS = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.level.block.Blocks.EMERALD_BLOCK.asItem()); // Purpur - - // CraftBukkit start - private CraftMerchant craftMerchant; -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index ff86c7d4878e43fc9d375b9b60213a2271b92cff..fad0d393a96d818e90aaa42f3d8d32fa97f7b337 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -154,6 +154,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - this.getNavigation().setCanFloat(true); - this.setCanPickUpLoot(true); - this.setVillagerData(this.getVillagerData().setType(type).setProfession(VillagerProfession.NONE)); -+ if (level().purpurConfig.villagerFollowEmeraldBlock) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, TEMPT_ITEMS, false)); - } - - // Purpur start -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index ac3cca0db4478841f91d966bd49ca4e5b5e91229..30f13bc35a96950f05b065b5c77830834e5792d1 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -113,6 +113,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - this.goalSelector.addGoal(1, new PanicGoal(this, 0.5D)); - this.goalSelector.addGoal(1, new LookAtTradingPlayerGoal(this)); - this.goalSelector.addGoal(2, new WanderingTrader.WanderToPositionGoal(this, 2.0D, 0.35D)); -+ if (level().purpurConfig.wanderingTraderFollowEmeraldBlock) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, TEMPT_ITEMS, false)); // Purpur - this.goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 0.35D)); - this.goalSelector.addGoal(8, new WaterAvoidingRandomStrollGoal(this, 0.35D)); - this.goalSelector.addGoal(9, new InteractGoal(this, Player.class, 3.0F, 1.0F)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b266fc52508106f1f0f449b8eb900e4c04316fec..f42a1205a66f4842ca43aad456dcb42481c041e9 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1435,6 +1435,7 @@ public class PurpurWorldConfig { - public boolean villagerRidableInWater = true; - public boolean villagerControllable = true; - public double villagerMaxHealth = 20.0D; -+ public boolean villagerFollowEmeraldBlock = false; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -1445,6 +1446,7 @@ public class PurpurWorldConfig { - set("mobs.villager.attributes.max_health", oldValue); - } - villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth); -+ villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); - } - - public boolean vindicatorRidable = false; -@@ -1467,6 +1469,7 @@ public class PurpurWorldConfig { - public boolean wanderingTraderRidableInWater = true; - public boolean wanderingTraderControllable = true; - public double wanderingTraderMaxHealth = 20.0D; -+ public boolean wanderingTraderFollowEmeraldBlock = false; - private void wanderingTraderSettings() { - wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); - wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); -@@ -1477,6 +1480,7 @@ public class PurpurWorldConfig { - set("mobs.wandering_trader.attributes.max_health", oldValue); - } - wanderingTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", wanderingTraderMaxHealth); -+ wanderingTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", wanderingTraderFollowEmeraldBlock); - } - - public boolean wardenRidable = false; diff --git a/patches/server/0047-Allow-leashing-villagers.patch b/patches/server/0047-Allow-leashing-villagers.patch deleted file mode 100644 index 33f1f3212..000000000 --- a/patches/server/0047-Allow-leashing-villagers.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 3 Oct 2019 18:08:03 -0500 -Subject: [PATCH] Allow leashing villagers - - -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 26b03594b6ccd69ca35156472e27543d11ba2077..3d5f08d673f6b95c8f87070345f1fb200b5f4bde 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1450,6 +1450,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - if (!this.isAlive()) { - return InteractionResult.PASS; - } else if (this.getLeashHolder() == player) { -+ if (hand == InteractionHand.OFF_HAND && (level().purpurConfig.villagerCanBeLeashed || level().purpurConfig.wanderingTraderCanBeLeashed) && this instanceof net.minecraft.world.entity.npc.AbstractVillager) return InteractionResult.CONSUME; // Purpur - // CraftBukkit start - fire PlayerUnleashEntityEvent - // Paper start - Expand EntityUnleashEvent - org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.hasInfiniteMaterials()); -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index fad0d393a96d818e90aaa42f3d8d32fa97f7b337..051940da69567274f48485f060cbc3ac21a0907f 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -184,6 +184,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.villagerMaxHealth); - } - -+ @Override -+ public boolean canBeLeashed(Player player) { -+ return level().purpurConfig.villagerCanBeLeashed && !this.isLeashed(); -+ } -+ - @Override - public Brain getBrain() { - return (Brain) super.getBrain(); // CraftBukkit - decompile error -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index 30f13bc35a96950f05b065b5c77830834e5792d1..9d5eaaf1869a3ecb61947ab0c09af558fa1cd283 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -93,6 +93,11 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.wanderingTraderMaxHealth); - } - -+ @Override -+ public boolean canBeLeashed(Player player) { -+ return level().purpurConfig.wanderingTraderCanBeLeashed && !this.isLeashed(); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index f42a1205a66f4842ca43aad456dcb42481c041e9..c07064174a0ef81a9bbe628251ee1346af890ae0 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1436,6 +1436,7 @@ public class PurpurWorldConfig { - public boolean villagerControllable = true; - public double villagerMaxHealth = 20.0D; - public boolean villagerFollowEmeraldBlock = false; -+ public boolean villagerCanBeLeashed = false; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -1447,6 +1448,7 @@ public class PurpurWorldConfig { - } - villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth); - villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); -+ villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed); - } - - public boolean vindicatorRidable = false; -@@ -1470,6 +1472,7 @@ public class PurpurWorldConfig { - public boolean wanderingTraderControllable = true; - public double wanderingTraderMaxHealth = 20.0D; - public boolean wanderingTraderFollowEmeraldBlock = false; -+ public boolean wanderingTraderCanBeLeashed = false; - private void wanderingTraderSettings() { - wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); - wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); -@@ -1481,6 +1484,7 @@ public class PurpurWorldConfig { - } - wanderingTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", wanderingTraderMaxHealth); - wanderingTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", wanderingTraderFollowEmeraldBlock); -+ wanderingTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", wanderingTraderCanBeLeashed); - } - - public boolean wardenRidable = false; diff --git a/patches/server/0048-Implement-infinite-liquids.patch b/patches/server/0048-Implement-infinite-liquids.patch deleted file mode 100644 index e52ee6bdf..000000000 --- a/patches/server/0048-Implement-infinite-liquids.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 23 Nov 2019 17:55:42 -0600 -Subject: [PATCH] Implement infinite liquids - - -diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -index c2943d892b067b3f1fb3b93301a092e912d71f08..a091c51476214977d7a9729b5c72e8478fe4a391 100644 ---- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -@@ -217,7 +217,7 @@ public abstract class FlowingFluid extends Fluid { - } - } - -- if (this.canConvertToSource(world) && j >= 2) { -+ if (this.canConvertToSource(world) && j >= getRequiredSources(world)) { - BlockState iblockdata2 = world.getBlockState(pos.below()); - FluidState fluid1 = iblockdata2.getFluidState(); - -@@ -301,6 +301,12 @@ public abstract class FlowingFluid extends Fluid { - - protected abstract boolean canConvertToSource(Level world); - -+ // Purpur start -+ protected int getRequiredSources(Level level) { -+ return 2; -+ } -+ // Purpur end -+ - protected void spreadTo(LevelAccessor world, BlockPos pos, BlockState state, Direction direction, FluidState fluidState) { - if (state.getBlock() instanceof LiquidBlockContainer) { - ((LiquidBlockContainer) state.getBlock()).placeLiquid(world, pos, state, fluidState); -diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java -index 3bb4a9a1a6249e8ba2de237f801210e7f4fd5825..4c230136d832d50ae16ffa037b0b30ff1101b50a 100644 ---- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java -@@ -198,6 +198,13 @@ public abstract class LavaFluid extends FlowingFluid { - world.levelEvent(1501, pos, 0); - } - -+ // Purpur start -+ @Override -+ protected int getRequiredSources(Level level) { -+ return level.purpurConfig.lavaInfiniteRequiredSources; -+ } -+ // Purpur end -+ - @Override - protected boolean canConvertToSource(Level world) { - return world.getGameRules().getBoolean(GameRules.RULE_LAVA_SOURCE_CONVERSION); -diff --git a/src/main/java/net/minecraft/world/level/material/WaterFluid.java b/src/main/java/net/minecraft/world/level/material/WaterFluid.java -index 109f71401c65f476ccf6813137386fc9fef10254..9dcdb2f4001115db0c26fdbf86531dbe6098485d 100644 ---- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java -@@ -80,6 +80,13 @@ public abstract class WaterFluid extends FlowingFluid { - return world.getGameRules().getBoolean(GameRules.RULE_WATER_SOURCE_CONVERSION); - } - -+ // Purpur start -+ @Override -+ protected int getRequiredSources(Level level) { -+ return level.purpurConfig.waterInfiniteRequiredSources; -+ } -+ // Purpur end -+ - // Paper start - Add BlockBreakBlockEvent - @Override - protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state, BlockPos source) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index c07064174a0ef81a9bbe628251ee1346af890ae0..5e9ce4502f5219b941ffc6f341c95d39755af664 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -221,6 +221,11 @@ public class PurpurWorldConfig { - farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); - } - -+ public int lavaInfiniteRequiredSources = 2; -+ private void lavaSettings() { -+ lavaInfiniteRequiredSources = getInt("blocks.lava.infinite-required-sources", lavaInfiniteRequiredSources); -+ } -+ - public boolean turtleEggsBreakFromExpOrbs = false; - public boolean turtleEggsBreakFromItems = false; - public boolean turtleEggsBreakFromMinecarts = false; -@@ -230,6 +235,11 @@ public class PurpurWorldConfig { - turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); - } - -+ public int waterInfiniteRequiredSources = 2; -+ private void waterSources() { -+ waterInfiniteRequiredSources = getInt("blocks.water.infinite-required-sources", waterInfiniteRequiredSources); -+ } -+ - public boolean babiesAreRidable = true; - public boolean untamedTamablesAreRidable = true; - public boolean useNightVisionWhenRiding = false; diff --git a/patches/server/0049-Make-lava-flow-speed-configurable.patch b/patches/server/0049-Make-lava-flow-speed-configurable.patch deleted file mode 100644 index ba688f13d..000000000 --- a/patches/server/0049-Make-lava-flow-speed-configurable.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 2 Jan 2020 11:31:36 -0600 -Subject: [PATCH] Make lava flow speed configurable - - -diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java -index 4c230136d832d50ae16ffa037b0b30ff1101b50a..2d492d849ff73a738dfbcb16507feb89bf19a962 100644 ---- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java -@@ -180,7 +180,7 @@ public abstract class LavaFluid extends FlowingFluid { - - @Override - public int getTickDelay(LevelReader world) { -- return world.dimensionType().ultraWarm() ? 10 : 30; -+ return world.dimensionType().ultraWarm() ? world.getWorldBorder().world.purpurConfig.lavaSpeedNether : world.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 5e9ce4502f5219b941ffc6f341c95d39755af664..09c131e3b5282d1ac1230ddc2677f2a49449dc48 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -222,8 +222,12 @@ public class PurpurWorldConfig { - } - - public int lavaInfiniteRequiredSources = 2; -+ public int lavaSpeedNether = 10; -+ public int lavaSpeedNotNether = 30; - private void lavaSettings() { - lavaInfiniteRequiredSources = getInt("blocks.lava.infinite-required-sources", lavaInfiniteRequiredSources); -+ lavaSpeedNether = getInt("blocks.lava.speed.nether", lavaSpeedNether); -+ lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether); - } - - public boolean turtleEggsBreakFromExpOrbs = false; diff --git a/patches/server/0050-Add-player-death-exp-control-options.patch b/patches/server/0050-Add-player-death-exp-control-options.patch deleted file mode 100644 index ae4a16619..000000000 --- a/patches/server/0050-Add-player-death-exp-control-options.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 26 Dec 2019 22:08:37 -0600 -Subject: [PATCH] Add player death exp control options - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index d5383e9cbbee2f9d4223319ae38abed41a13cfb3..a838f339dd0085660164b0eb1597e0a14e4de6f4 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1962,9 +1962,19 @@ public abstract class Player extends LivingEntity { - @Override - public int getExperienceReward() { - if (!this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator()) { -- int i = this.experienceLevel * 7; -- -- return i > 100 ? 100 : i; -+ // Purpur start -+ int toDrop; -+ try { -+ toDrop = Math.round(((Number) scriptEngine.eval("let expLevel = " + experienceLevel + "; " + -+ "let expTotal = " + totalExperience + "; " + -+ "let exp = " + experienceProgress + "; " + -+ level().purpurConfig.playerDeathExpDropEquation)).floatValue()); -+ } catch (javax.script.ScriptException e) { -+ e.printStackTrace(); -+ toDrop = experienceLevel * 7; -+ } -+ return Math.min(toDrop, level().purpurConfig.playerDeathExpDropMax); -+ // Purpur end - } else { - return 0; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 09c131e3b5282d1ac1230ddc2677f2a49449dc48..66e12893bb9d8984a8cd2916834c5e86058f47bb 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -171,6 +171,8 @@ public class PurpurWorldConfig { - public boolean idleTimeoutCountAsSleeping = false; - public boolean idleTimeoutUpdateTabList = false; - public boolean idleTimeoutTargetPlayer = true; -+ public String playerDeathExpDropEquation = "expLevel * 7"; -+ public int playerDeathExpDropMax = 100; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -182,6 +184,8 @@ public class PurpurWorldConfig { - idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping); - idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); - idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer); -+ playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation); -+ playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0051-Configurable-void-damage-height-and-damage.patch b/patches/server/0051-Configurable-void-damage-height-and-damage.patch deleted file mode 100644 index 8adbee6ec..000000000 --- a/patches/server/0051-Configurable-void-damage-height-and-damage.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 27 Feb 2020 21:42:19 -0600 -Subject: [PATCH] Configurable void damage height and damage - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 429d1a3fd7a75fe3dc8eb8d467ad4f2bd99e0212..f0ba7603795eb1fde01dc86cd3d8b02d73a55869 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -948,7 +948,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - public void checkBelowWorld() { - // Paper start - Configurable nether ceiling damage -- if (this.getY() < (double) (this.level.getMinBuildHeight() - 64) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER -+ if (this.getY() < (double) (this.level.getMinBuildHeight() + level().purpurConfig.voidDamageHeight) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER // Purpur - && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> this.getY() >= v) - && (!(this instanceof Player player) || !player.getAbilities().invulnerable))) { - // Paper end - Configurable nether ceiling damage -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 7b210484fd10e6e994c66afb45f8a28ffb5812f1..ed8833ed95584cdf9be2b931915277c04beac6ee 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2592,7 +2592,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - - @Override - protected void onBelowWorld() { -- this.hurt(this.damageSources().fellOutOfWorld(), 4.0F); -+ this.hurt(this.damageSources().fellOutOfWorld(), (float) level().purpurConfig.voidDamageDealt); // Purpur - } - - protected void updateSwingTime() { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 66e12893bb9d8984a8cd2916834c5e86058f47bb..03c35e455b405517114ffc043732359c112e343f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -98,10 +98,14 @@ public class PurpurWorldConfig { - public boolean disableDropsOnCrammingDeath = false; - public boolean milkCuresBadOmen = true; - public double tridentLoyaltyVoidReturnHeight = 0.0D; -+ public double voidDamageHeight = -64.0D; -+ public double voidDamageDealt = 4.0D; - private void miscGameplayMechanicsSettings() { - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); -+ voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); -+ voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); - } - - public double minecartMaxSpeed = 0.4D; diff --git a/patches/server/0052-Add-canSaveToDisk-to-Entity.patch b/patches/server/0052-Add-canSaveToDisk-to-Entity.patch deleted file mode 100644 index 0503b956b..000000000 --- a/patches/server/0052-Add-canSaveToDisk-to-Entity.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 18 Feb 2020 20:07:08 -0600 -Subject: [PATCH] Add canSaveToDisk to Entity - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index f0ba7603795eb1fde01dc86cd3d8b02d73a55869..a99d04b820c230422bc82a3e0e094a79ab0c5c33 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -558,6 +558,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return false; - } - -+ public boolean canSaveToDisk() { -+ return true; -+ } -+ - public final boolean hardCollides() { - return this.hardCollides; - } -diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -index 4117260538e47c978ea31c76f439d43369ebedfb..c753f715710ec4bb8337e035ac5a4c11371a84a0 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -@@ -117,6 +117,11 @@ public class WitherSkull extends AbstractHurtingProjectile { - // do not hit rider - return target != this.getRider() && super.canHitEntity(target); - } -+ -+ @Override -+ public boolean canSaveToDisk() { -+ return false; -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -index bee39dee1b96023c907407877aedf3aafaf5e1b8..5b6bc200381a486c99061f9f5b7121c2c355b477 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -@@ -107,6 +107,7 @@ public class EntityStorage implements EntityPersistentStorage { - ListTag listTag = new ListTag(); - final java.util.Map, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk - entities.forEach((entity) -> { // diff here: use entities parameter -+ if (!entity.canSaveToDisk()) return; // Purpur - // Paper start - Entity load/save limit per chunk - final EntityType entityType = entity.getType(); - final int saveLimit = level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1); -diff --git a/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java b/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java -index 89c476c740b4efb4f44c1dcd384b908626d96780..f25abee6dbf99c8d08f8e09db02b41df86115faa 100644 ---- a/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java -+++ b/src/main/java/org/purpurmc/purpur/entity/DolphinSpit.java -@@ -36,6 +36,13 @@ public class DolphinSpit extends LlamaSpit { - dolphin.getZ() + (double) (dolphin.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(dolphin.yBodyRot * 0.017453292F)); - } - -+ // Purpur start -+ @Override -+ public boolean canSaveToDisk() { -+ return false; -+ } -+ // Purpur end -+ - public void tick() { - super_tick(); - -diff --git a/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java b/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java -index c0b7e0eeffdf31b88662232b07944bf3e6fa2148..75e31aee6e706f042398444f272888f9ad0fa3f4 100644 ---- a/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java -+++ b/src/main/java/org/purpurmc/purpur/entity/PhantomFlames.java -@@ -38,6 +38,13 @@ public class PhantomFlames extends LlamaSpit { - phantom.getZ() + (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(phantom.yBodyRot * 0.017453292F)); - } - -+ // Purpur start -+ @Override -+ public boolean canSaveToDisk() { -+ return false; -+ } -+ // Purpur end -+ - public void tick() { - super_tick(); - diff --git a/patches/server/0053-Dispenser-curse-of-binding-protection.patch b/patches/server/0053-Dispenser-curse-of-binding-protection.patch deleted file mode 100644 index 9ceca7396..000000000 --- a/patches/server/0053-Dispenser-curse-of-binding-protection.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 25 Aug 2019 00:09:52 -0500 -Subject: [PATCH] Dispenser curse of binding protection - - -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 3d5f08d673f6b95c8f87070345f1fb200b5f4bde..c4392a997061aa4939e5ad7dcacf5e39cbecc55a 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -75,6 +75,7 @@ import net.minecraft.world.item.SpawnEggItem; - import net.minecraft.world.item.SwordItem; - import net.minecraft.world.item.component.ItemAttributeModifiers; - import net.minecraft.world.item.enchantment.EnchantmentHelper; -+import net.minecraft.world.item.enchantment.Enchantments; - import net.minecraft.world.level.GameRules; - import net.minecraft.world.level.ItemLike; - import net.minecraft.world.level.Level; -@@ -1309,6 +1310,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - - } - -+ // Purpur start -+ public static @Nullable EquipmentSlot getSlotForDispenser(ItemStack itemstack) { -+ return EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BINDING_CURSE, itemstack) > 0 ? null : getEquipmentSlotForItem(itemstack); -+ } -+ // Purpur end -+ - @Nullable - public static Item getEquipmentForSlot(EquipmentSlot equipmentSlot, int equipmentLevel) { - switch (equipmentSlot) { -diff --git a/src/main/java/net/minecraft/world/item/ArmorItem.java b/src/main/java/net/minecraft/world/item/ArmorItem.java -index 786e4a8700cb84b16dd9b8892a0d1d5803924d81..b108ca4c7900ccf6a14ebea01c21c103459054f8 100644 ---- a/src/main/java/net/minecraft/world/item/ArmorItem.java -+++ b/src/main/java/net/minecraft/world/item/ArmorItem.java -@@ -69,7 +69,7 @@ public class ArmorItem extends Item implements Equipable { - return false; - } else { - LivingEntity entityliving = (LivingEntity) list.get(0); -- EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(armor); -+ EquipmentSlot enumitemslot = pointer.level().purpurConfig.dispenserApplyCursedArmor ? Mob.getEquipmentSlotForItem(armor) : Mob.getSlotForDispenser(armor); if (enumitemslot == null) return false; // Purpur - ItemStack itemstack1 = armor.copyWithCount(1); // Paper - shrink below and single item in event - // CraftBukkit start - Level world = pointer.level(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 03c35e455b405517114ffc043732359c112e343f..27c1f09be7d664073263a02a8854ff1e8c6f9ab1 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -224,6 +224,11 @@ public class PurpurWorldConfig { - }); - } - -+ public boolean dispenserApplyCursedArmor = true; -+ private void dispenserSettings() { -+ dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor); -+ } -+ - public boolean farmlandGetsMoistFromBelow = false; - private void farmlandSettings() { - farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); diff --git a/patches/server/0054-Add-option-for-boats-to-eject-players-on-land.patch b/patches/server/0054-Add-option-for-boats-to-eject-players-on-land.patch deleted file mode 100644 index dfbc74be0..000000000 --- a/patches/server/0054-Add-option-for-boats-to-eject-players-on-land.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 7 Sep 2019 22:47:59 -0500 -Subject: [PATCH] Add option for boats to eject players on land - - -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -index b068cff9b5aa457d65b679529956e8210296d799..0b23e05f936cab7a9867828c2d69417cfde1d2ce 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java -@@ -514,6 +514,7 @@ public class Boat extends VehicleEntity implements VariantHolder { - - if (f > 0.0F) { - this.landFriction = f; -+ if (level().purpurConfig.boatEjectPlayersOnLand) ejectPassengers(); // Purpur - return Boat.Status.ON_LAND; - } else { - return Boat.Status.IN_AIR; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 27c1f09be7d664073263a02a8854ff1e8c6f9ab1..76c1cfc35b598eab2ca27656feeb17f79dde7e00 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -95,12 +95,14 @@ public class PurpurWorldConfig { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); - } - -+ public boolean boatEjectPlayersOnLand = false; - public boolean disableDropsOnCrammingDeath = false; - public boolean milkCuresBadOmen = true; - public double tridentLoyaltyVoidReturnHeight = 0.0D; - public double voidDamageHeight = -64.0D; - public double voidDamageDealt = 4.0D; - private void miscGameplayMechanicsSettings() { -+ boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); diff --git a/patches/server/0055-Mending-mends-most-damages-equipment-first.patch b/patches/server/0055-Mending-mends-most-damages-equipment-first.patch deleted file mode 100644 index e79a10187..000000000 --- a/patches/server/0055-Mending-mends-most-damages-equipment-first.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 14 Jul 2019 19:52:47 -0500 -Subject: [PATCH] Mending mends most damages equipment first - - -diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -index a207a31d80a302dbdfe80f8727222542d3a78da2..7ca70e9ddda24e2fe661c7b13fa439a6c19726dd 100644 ---- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -@@ -338,7 +338,7 @@ public class ExperienceOrb extends Entity { - } - - private int repairPlayerItems(Player player, int amount) { -- Entry entry = EnchantmentHelper.getRandomItemWith(Enchantments.MENDING, player, ItemStack::isDamaged); -+ Entry entry = level().purpurConfig.useBetterMending ? EnchantmentHelper.getMostDamagedEquipment(Enchantments.MENDING, player) : EnchantmentHelper.getRandomItemWith(Enchantments.MENDING, player, ItemStack::isDamaged); // Purpur - - if (entry != null) { - ItemStack itemstack = (ItemStack) entry.getValue(); -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index a45389d64c04cd4c2a35fbc511595be0535a8665..e51bbab02b816a431f18c520fc67eeb1880fbfa0 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -636,6 +636,16 @@ public final class ItemStack implements DataComponentHolder { - return this.isDamageableItem() && this.getDamageValue() > 0; - } - -+ // Purpur start -+ public float getDamagePercent() { -+ if (isDamaged()) { -+ return (float) getDamageValue() / (float) getMaxDamage(); -+ } else { -+ return 0F; -+ } -+ } -+ // Purpur end -+ - public int getDamageValue() { - return Mth.clamp((Integer) this.getOrDefault(DataComponents.DAMAGE, 0), 0, this.getMaxDamage()); - } -diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java -index d2f0463b0e74983eb2e3dfca9a268e9502b86257..6d0363cec691996be416ab22ef9d825196399158 100644 ---- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java -+++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java -@@ -237,6 +237,29 @@ public class EnchantmentHelper { - return getItemEnchantmentLevel(Enchantments.CHANNELING, stack) > 0; - } - -+ // Purpur start -+ @Nullable -+ public static Map.Entry getMostDamagedEquipment(Enchantment enchantment, LivingEntity entity) { -+ Map map = enchantment.getSlotItems(entity); -+ if (map.isEmpty()) { -+ return null; -+ } -+ Map.Entry item = null; -+ float maxPercent = 0F; -+ for (Map.Entry entry : map.entrySet()) { -+ ItemStack itemstack = entry.getValue(); -+ if (!itemstack.isEmpty() && itemstack.isDamaged() && getItemEnchantmentLevel(enchantment, itemstack) > 0) { -+ float percent = itemstack.getDamagePercent(); -+ if (item == null || percent > maxPercent) { -+ item = entry; -+ maxPercent = percent; -+ } -+ } -+ } -+ return item; -+ } -+ // Purpur end -+ - @Nullable - public static java.util.Map.Entry getRandomItemWith(Enchantment enchantment, LivingEntity entity) { - return getRandomItemWith(enchantment, entity, stack -> true); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 76c1cfc35b598eab2ca27656feeb17f79dde7e00..6705d722e1abe678a5cb90503904dc7888bf55ee 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -95,6 +95,7 @@ public class PurpurWorldConfig { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); - } - -+ public boolean useBetterMending = false; - public boolean boatEjectPlayersOnLand = false; - public boolean disableDropsOnCrammingDeath = false; - public boolean milkCuresBadOmen = true; -@@ -102,6 +103,7 @@ public class PurpurWorldConfig { - public double voidDamageHeight = -64.0D; - public double voidDamageDealt = 4.0D; - private void miscGameplayMechanicsSettings() { -+ useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); diff --git a/patches/server/0056-Add-5-second-tps-average-in-tps.patch b/patches/server/0056-Add-5-second-tps-average-in-tps.patch deleted file mode 100644 index 9623dcb7d..000000000 --- a/patches/server/0056-Add-5-second-tps-average-in-tps.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 28 Jul 2019 01:27:37 -0500 -Subject: [PATCH] Add 5 second tps average in /tps - - -diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java -index 039a86034928a5eb7aaa2d7ca76a7bddcca346bd..308f67d0616e2d6bb135258f1fda53ccdee01430 100644 ---- a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java -+++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java -@@ -68,7 +68,7 @@ public class RAMDetails extends JList { - vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)"); - vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb"); - vector.add("Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms"); -- vector.add("TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg)); -+ vector.add("TPS from last 5s, 1m, 5m, 15m: " + String.join(", ", tpsAvg)); // Purpur - setListData(vector); - } - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index f3ad4ee45ba48a10bbae1084f291ae0bcccdf624..3a622f5274f036608950702291c1e624488a6faa 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -310,7 +310,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) { diff --git a/patches/server/0057-Implement-elytra-settings.patch b/patches/server/0057-Implement-elytra-settings.patch deleted file mode 100644 index e2c58c260..000000000 --- a/patches/server/0057-Implement-elytra-settings.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 25 Jul 2019 18:07:37 -0500 -Subject: [PATCH] Implement elytra settings - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index ed8833ed95584cdf9be2b931915277c04beac6ee..9a2725e3f61a7d37943518cc760b17859a0938bb 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -3554,7 +3554,16 @@ public abstract class LivingEntity extends Entity implements Attackable { - int j = i / 10; - - if (j % 2 == 0) { -- itemstack.hurtAndBreak(1, this, EquipmentSlot.CHEST); -+ // Purpur start -+ int damage = level().purpurConfig.elytraDamagePerSecond; -+ if (level().purpurConfig.elytraDamageMultiplyBySpeed > 0) { -+ double speed = getDeltaMovement().lengthSqr(); -+ if (speed > level().purpurConfig.elytraDamageMultiplyBySpeed) { -+ damage *= (int) speed; -+ } -+ } -+ itemstack.hurtAndBreak(damage, this, EquipmentSlot.CHEST); -+ // Purpur end - } - - this.gameEvent(GameEvent.ELYTRA_GLIDE); -diff --git a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java -index 218f2f085309f04438f8b07bc41cf242583db2dc..ea8e49b42b9dde74784189430be66ed6978015dd 100644 ---- a/src/main/java/net/minecraft/world/item/FireworkRocketItem.java -+++ b/src/main/java/net/minecraft/world/item/FireworkRocketItem.java -@@ -65,6 +65,14 @@ public class FireworkRocketItem extends Item implements ProjectileItem { - com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) fireworkRocketEntity.getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand)); - if (event.callEvent() && world.addFreshEntity(fireworkRocketEntity)) { - user.awardStat(Stats.ITEM_USED.get(this)); -+ // Purpur start -+ if (world.purpurConfig.elytraDamagePerFireworkBoost > 0) { -+ ItemStack chestItem = user.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.CHEST); -+ if (chestItem.getItem() == Items.ELYTRA) { -+ chestItem.hurtAndBreak(world.purpurConfig.elytraDamagePerFireworkBoost, user, net.minecraft.world.entity.EquipmentSlot.CHEST); -+ } -+ } -+ // Purpur end - if (event.shouldConsume() && !user.hasInfiniteMaterials()) { - itemStack.shrink(1); - } else ((net.minecraft.server.level.ServerPlayer) user).getBukkitEntity().updateInventory(); -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index e51bbab02b816a431f18c520fc67eeb1880fbfa0..b2c5581b126ceb9e47a13f6eda8cc132d11bfb09 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -663,7 +663,7 @@ public final class ItemStack implements DataComponentHolder { - int j; - - if (amount > 0) { -- j = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.UNBREAKING, this); -+ j = (getItem() == Items.ELYTRA && player != null && player.level().purpurConfig.elytraIgnoreUnbreaking) ? 0 : EnchantmentHelper.getItemEnchantmentLevel(Enchantments.UNBREAKING, this); - int k = 0; - - for (int l = 0; j > 0 && l < amount; ++l) { -@@ -739,6 +739,12 @@ public final class ItemStack implements DataComponentHolder { - this.hurtAndBreak(amount, randomsource, entity, () -> { // Paper - Add EntityDamageItemEvent - entity.broadcastBreakEvent(slot); - Item item = this.getItem(); -+ // Purpur start -+ if (item == Items.ELYTRA) { -+ setDamageValue(getMaxDamage() - 1); -+ return; -+ } -+ // Purpur end - // CraftBukkit start - Check for item breaking - if (this.count == 1 && entity instanceof net.minecraft.world.entity.player.Player) { - org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent((net.minecraft.world.entity.player.Player) entity, this); -diff --git a/src/main/java/net/minecraft/world/item/TridentItem.java b/src/main/java/net/minecraft/world/item/TridentItem.java -index 47de500fddb0716d142f8f5876a82a95afaa06fa..b094f4ec513194e10442156d8f7f2205da2384ac 100644 ---- a/src/main/java/net/minecraft/world/item/TridentItem.java -+++ b/src/main/java/net/minecraft/world/item/TridentItem.java -@@ -123,6 +123,14 @@ public class TridentItem extends Item implements ProjectileItem { - f3 *= f6 / f5; - f4 *= f6 / f5; - org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(entityhuman, stack, f2, f3, f4); // CraftBukkit -+ -+ // Purpur start -+ ItemStack chestItem = entityhuman.getItemBySlot(EquipmentSlot.CHEST); -+ if (chestItem.getItem() == Items.ELYTRA && world.purpurConfig.elytraDamagePerTridentBoost > 0) { -+ chestItem.hurtAndBreak(world.purpurConfig.elytraDamagePerTridentBoost, entityhuman, EquipmentSlot.CHEST); -+ } -+ // Purpur end -+ - entityhuman.push((double) f2, (double) f3, (double) f4); - entityhuman.startAutoSpinAttack(20); - if (entityhuman.onGround()) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 6705d722e1abe678a5cb90503904dc7888bf55ee..88aabe09118cbbad3add3cee44e237580294f685 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -112,6 +112,19 @@ public class PurpurWorldConfig { - voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); - } - -+ public int elytraDamagePerSecond = 1; -+ public double elytraDamageMultiplyBySpeed = 0; -+ public boolean elytraIgnoreUnbreaking = false; -+ public int elytraDamagePerFireworkBoost = 0; -+ public int elytraDamagePerTridentBoost = 0; -+ private void elytraSettings() { -+ elytraDamagePerSecond = getInt("gameplay-mechanics.elytra.damage-per-second", elytraDamagePerSecond); -+ elytraDamageMultiplyBySpeed = getDouble("gameplay-mechanics.elytra.damage-multiplied-by-speed", elytraDamageMultiplyBySpeed); -+ elytraIgnoreUnbreaking = getBoolean("gameplay-mechanics.elytra.ignore-unbreaking", elytraIgnoreUnbreaking); -+ elytraDamagePerFireworkBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.firework", elytraDamagePerFireworkBoost); -+ elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost); -+ } -+ - public double minecartMaxSpeed = 0.4D; - public boolean minecartPlaceAnywhere = false; - public boolean minecartControllable = false; diff --git a/patches/server/0058-Item-entity-immunities.patch b/patches/server/0058-Item-entity-immunities.patch deleted file mode 100644 index c45cb2d67..000000000 --- a/patches/server/0058-Item-entity-immunities.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 22 Feb 2020 15:54:08 -0600 -Subject: [PATCH] Item entity immunities - - -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 4f103f731623a8570238a6867fda1c5f83fca4e4..39e7dcf3c92c9203c190782be401c00c010b8aeb 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -77,7 +77,7 @@ public class ServerEntity { - @Nullable - private List> trackedDataValues; - // CraftBukkit start -- private final Set trackedPlayers; -+ public final Set trackedPlayers; // Purpur - private -> public - - public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer> consumer, Set trackedPlayers) { - this.trackedPlayers = trackedPlayers; -diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -index 8fd3845c4965843be9c37498760d93f1ebdff541..7dae2a7c759fc3e004f806c59e083f52c3a460b2 100644 ---- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -@@ -63,6 +63,12 @@ public class ItemEntity extends Entity implements TraceableEntity { - public boolean canMobPickup = true; // Paper - Item#canEntityPickup - private int despawnRate = -1; // Paper - Alternative item-despawn-rate - public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API -+ // Purpur start -+ public boolean immuneToCactus = false; -+ public boolean immuneToExplosion = false; -+ public boolean immuneToFire = false; -+ public boolean immuneToLightning = false; -+ // Purpur end - - public ItemEntity(EntityType type, Level world) { - super(type, world); -@@ -371,7 +377,16 @@ public class ItemEntity extends Entity implements TraceableEntity { - - @Override - public boolean hurt(DamageSource source, float amount) { -- if (this.isInvulnerableTo(source)) { -+ // Purpur start -+ if ( -+ (immuneToCactus && source.is(net.minecraft.world.damagesource.DamageTypes.CACTUS)) || -+ (immuneToFire && (source.is(DamageTypeTags.IS_FIRE) || source.is(net.minecraft.world.damagesource.DamageTypes.ON_FIRE) || source.is(net.minecraft.world.damagesource.DamageTypes.IN_FIRE))) || -+ (immuneToLightning && source.is(net.minecraft.world.damagesource.DamageTypes.LIGHTNING_BOLT)) || -+ (immuneToExplosion && source.is(DamageTypeTags.IS_EXPLOSION)) -+ ) { -+ return false; -+ } else if (this.isInvulnerableTo(source)) { -+ // Purpur end - return false; - } else if (!this.getItem().isEmpty() && this.getItem().is(Items.NETHER_STAR) && source.is(DamageTypeTags.IS_EXPLOSION)) { - return false; -@@ -579,6 +594,12 @@ public class ItemEntity extends Entity implements TraceableEntity { - public void setItem(ItemStack stack) { - this.getEntityData().set(ItemEntity.DATA_ITEM, stack); - this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper - Alternative item-despawn-rate -+ // Purpur start -+ if (level().purpurConfig.itemImmuneToCactus.contains(stack.getItem())) immuneToCactus = true; -+ if (level().purpurConfig.itemImmuneToExplosion.contains(stack.getItem())) immuneToExplosion = true; -+ if (level().purpurConfig.itemImmuneToFire.contains(stack.getItem())) immuneToFire = true; -+ if (level().purpurConfig.itemImmuneToLightning.contains(stack.getItem())) immuneToLightning = true; -+ // level end - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -index 30d62ee4d5cd2ddacb8783b5bbbf475d592b3e02..01e4395f1669d21c30465aa1366bd2f1ae17678f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -@@ -151,4 +151,46 @@ public class CraftItem extends CraftEntity implements Item { - public String toString() { - return "CraftItem"; - } -+ -+ // Purpur start -+ @Override -+ public void setImmuneToCactus(boolean immuneToCactus) { -+ this.getHandle().immuneToCactus = immuneToCactus; -+ } -+ -+ @Override -+ public boolean isImmuneToCactus() { -+ return this.getHandle().immuneToCactus; -+ } -+ -+ @Override -+ public void setImmuneToExplosion(boolean immuneToExplosion) { -+ this.getHandle().immuneToExplosion = immuneToExplosion; -+ } -+ -+ @Override -+ public boolean isImmuneToExplosion() { -+ return this.getHandle().immuneToExplosion; -+ } -+ -+ @Override -+ public void setImmuneToFire(boolean immuneToFire) { -+ item.immuneToFire = immuneToFire; -+ } -+ -+ @Override -+ public boolean isImmuneToFire() { -+ return this.getHandle().immuneToFire; -+ } -+ -+ @Override -+ public void setImmuneToLightning(boolean immuneToLightning) { -+ this.getHandle().immuneToLightning = immuneToLightning; -+ } -+ -+ @Override -+ public boolean isImmuneToLightning() { -+ return this.getHandle().immuneToLightning; -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 88aabe09118cbbad3add3cee44e237580294f685..62074152a0a494bbde4c39074942425a8b850ffd 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -125,6 +125,49 @@ public class PurpurWorldConfig { - elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost); - } - -+ public List itemImmuneToCactus = new ArrayList<>(); -+ public List itemImmuneToExplosion = new ArrayList<>(); -+ public List itemImmuneToFire = new ArrayList<>(); -+ public List itemImmuneToLightning = new ArrayList<>(); -+ private void itemSettings() { -+ itemImmuneToCactus.clear(); -+ getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { -+ if (key.toString().equals("*")) { -+ BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToCactus.add(item)); -+ return; -+ } -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(key.toString())); -+ if (item != Items.AIR) itemImmuneToCactus.add(item); -+ }); -+ itemImmuneToExplosion.clear(); -+ getList("gameplay-mechanics.item.immune.explosion", new ArrayList<>()).forEach(key -> { -+ if (key.toString().equals("*")) { -+ BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToExplosion.add(item)); -+ return; -+ } -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(key.toString())); -+ if (item != Items.AIR) itemImmuneToExplosion.add(item); -+ }); -+ itemImmuneToFire.clear(); -+ getList("gameplay-mechanics.item.immune.fire", new ArrayList<>()).forEach(key -> { -+ if (key.toString().equals("*")) { -+ BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToFire.add(item)); -+ return; -+ } -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(key.toString())); -+ if (item != Items.AIR) itemImmuneToFire.add(item); -+ }); -+ itemImmuneToLightning.clear(); -+ getList("gameplay-mechanics.item.immune.lightning", new ArrayList<>()).forEach(key -> { -+ if (key.toString().equals("*")) { -+ BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToLightning.add(item)); -+ return; -+ } -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(key.toString())); -+ if (item != Items.AIR) itemImmuneToLightning.add(item); -+ }); -+ } -+ - public double minecartMaxSpeed = 0.4D; - public boolean minecartPlaceAnywhere = false; - public boolean minecartControllable = false; diff --git a/patches/server/0059-Add-ping-command.patch b/patches/server/0059-Add-ping-command.patch deleted file mode 100644 index 2c351459d..000000000 --- a/patches/server/0059-Add-ping-command.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 13 Mar 2020 22:29:10 -0500 -Subject: [PATCH] Add ping command - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 5c7287ef8c2d59215aff81cb138a55676bfa6356..a5f1bfd8a6a6c374fbb72ea7957dd7d05073b93d 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -252,6 +252,7 @@ public class Commands { - StopCommand.register(this.dispatcher); - TransferCommand.register(this.dispatcher); - WhitelistCommand.register(this.dispatcher); -+ org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur - } - - if (environment.includeIntegrated) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 909cfeba89c2370adc2eebf72ba8ad46d33bce7b..e8160e63470cf2f3d15eeb2e7f83d3694cfc4db8 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -179,6 +179,7 @@ public class PurpurConfig { - public static boolean afkBroadcastUseDisplayName = false; - public static String afkTabListPrefix = "[AFK] "; - public static String afkTabListSuffix = ""; -+ public static String pingCommandOutput = "%s's ping is %sms"; - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); - afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); -@@ -186,6 +187,7 @@ public class PurpurConfig { - afkBroadcastUseDisplayName = getBoolean("settings.messages.afk-broadcast-use-display-name", afkBroadcastUseDisplayName); - afkTabListPrefix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix))); - afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix))); -+ pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); - } - - public static String serverModName = "Purpur"; -diff --git a/src/main/java/org/purpurmc/purpur/command/PingCommand.java b/src/main/java/org/purpurmc/purpur/command/PingCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f202b98a194604e39798fdb8e417c6d2835f71c8 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/PingCommand.java -@@ -0,0 +1,33 @@ -+package org.purpurmc.purpur.command; -+ -+import com.mojang.brigadier.CommandDispatcher; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import net.minecraft.commands.arguments.EntityArgument; -+import net.minecraft.server.level.ServerPlayer; -+import org.purpurmc.purpur.PurpurConfig; -+import org.bukkit.craftbukkit.util.CraftChatMessage; -+ -+import java.util.Collection; -+import java.util.Collections; -+ -+public class PingCommand { -+ public static void register(CommandDispatcher dispatcher) { -+ dispatcher.register(Commands.literal("ping") -+ .requires((listener) -> listener.hasPermission(2, "bukkit.command.ping")) -+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) -+ .then(Commands.argument("targets", EntityArgument.players()) -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.ping.other")) -+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) -+ ) -+ ); -+ } -+ -+ private static int execute(CommandSourceStack sender, Collection targets) { -+ for (ServerPlayer player : targets) { -+ String output = String.format(PurpurConfig.pingCommandOutput, player.getGameProfile().getName(), player.connection.latency()); -+ sender.sendSuccess(output, false); -+ } -+ return targets.size(); -+ } -+} diff --git a/patches/server/0060-Add-demo-command.patch b/patches/server/0060-Add-demo-command.patch deleted file mode 100644 index 0b3873fc7..000000000 --- a/patches/server/0060-Add-demo-command.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 30 Nov 2020 03:12:04 -0600 -Subject: [PATCH] Add demo command - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index a5f1bfd8a6a6c374fbb72ea7957dd7d05073b93d..4568c4b02a87deb299ffd77b8e76329bb2b1dd70 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -252,6 +252,7 @@ public class Commands { - StopCommand.register(this.dispatcher); - TransferCommand.register(this.dispatcher); - WhitelistCommand.register(this.dispatcher); -+ org.purpurmc.purpur.command.DemoCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index e8160e63470cf2f3d15eeb2e7f83d3694cfc4db8..994da2c5bbba190507bbcee7029bee974eb3c641 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -179,6 +179,7 @@ public class PurpurConfig { - public static boolean afkBroadcastUseDisplayName = false; - public static String afkTabListPrefix = "[AFK] "; - public static String afkTabListSuffix = ""; -+ public static String demoCommandOutput = "%s has been shown the demo screen"; - public static String pingCommandOutput = "%s's ping is %sms"; - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); -@@ -187,6 +188,7 @@ public class PurpurConfig { - afkBroadcastUseDisplayName = getBoolean("settings.messages.afk-broadcast-use-display-name", afkBroadcastUseDisplayName); - afkTabListPrefix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix))); - afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix))); -+ demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput); - pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); - } - -diff --git a/src/main/java/org/purpurmc/purpur/command/DemoCommand.java b/src/main/java/org/purpurmc/purpur/command/DemoCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..235f3cd89f675b70a6152a00534608c0902f19fd ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/DemoCommand.java -@@ -0,0 +1,35 @@ -+package org.purpurmc.purpur.command; -+ -+import com.mojang.brigadier.CommandDispatcher; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import net.minecraft.commands.arguments.EntityArgument; -+import net.minecraft.network.protocol.game.ClientboundGameEventPacket; -+import net.minecraft.server.level.ServerPlayer; -+import org.purpurmc.purpur.PurpurConfig; -+ -+import java.util.Collection; -+import java.util.Collections; -+ -+public class DemoCommand { -+ public static void register(CommandDispatcher dispatcher) { -+ dispatcher.register(Commands.literal("demo") -+ .requires((listener) -> listener.hasPermission(2, "bukkit.command.demo")) -+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) -+ .then(Commands.argument("targets", EntityArgument.players()) -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.demo.other")) -+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) -+ ) -+ ); -+ } -+ -+ private static int execute(CommandSourceStack sender, Collection targets) { -+ for (ServerPlayer player : targets) { -+ ClientboundGameEventPacket packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.DEMO_EVENT, 0); -+ player.connection.send(packet); -+ String output = String.format(PurpurConfig.demoCommandOutput, player.getGameProfile().getName()); -+ sender.sendSuccess(output, false); -+ } -+ return targets.size(); -+ } -+} diff --git a/patches/server/0061-Add-credits-command.patch b/patches/server/0061-Add-credits-command.patch deleted file mode 100644 index 9f08a380f..000000000 --- a/patches/server/0061-Add-credits-command.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Fri, 30 Apr 2021 14:03:06 -0400 -Subject: [PATCH] Add credits command - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 4568c4b02a87deb299ffd77b8e76329bb2b1dd70..6af3e1e08048869ac28ab4a93e03d086872f866b 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -252,6 +252,7 @@ public class Commands { - StopCommand.register(this.dispatcher); - TransferCommand.register(this.dispatcher); - WhitelistCommand.register(this.dispatcher); -+ org.purpurmc.purpur.command.CreditsCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.DemoCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 994da2c5bbba190507bbcee7029bee974eb3c641..2e78d67201e66c1f3fd1f45ed625e682ea074848 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -179,6 +179,7 @@ public class PurpurConfig { - public static boolean afkBroadcastUseDisplayName = false; - public static String afkTabListPrefix = "[AFK] "; - public static String afkTabListSuffix = ""; -+ public static String creditsCommandOutput = "%s has been shown the end credits"; - public static String demoCommandOutput = "%s has been shown the demo screen"; - public static String pingCommandOutput = "%s's ping is %sms"; - private static void messages() { -@@ -188,6 +189,7 @@ public class PurpurConfig { - afkBroadcastUseDisplayName = getBoolean("settings.messages.afk-broadcast-use-display-name", afkBroadcastUseDisplayName); - afkTabListPrefix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix))); - afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix))); -+ creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput); - demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput); - pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); - } -diff --git a/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java b/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..40d2fab4a9728ac90c36e30c130f3116b7025d11 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java -@@ -0,0 +1,35 @@ -+package org.purpurmc.purpur.command; -+ -+import com.mojang.brigadier.CommandDispatcher; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import net.minecraft.commands.arguments.EntityArgument; -+import net.minecraft.network.protocol.game.ClientboundGameEventPacket; -+import net.minecraft.server.level.ServerPlayer; -+import org.purpurmc.purpur.PurpurConfig; -+ -+import java.util.Collection; -+import java.util.Collections; -+ -+public class CreditsCommand { -+ public static void register(CommandDispatcher dispatcher) { -+ dispatcher.register(Commands.literal("credits") -+ .requires((listener) -> listener.hasPermission(2, "bukkit.command.credits")) -+ .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) -+ .then(Commands.argument("targets", EntityArgument.players()) -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.credits.other")) -+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) -+ ) -+ ); -+ } -+ -+ private static int execute(CommandSourceStack sender, Collection targets) { -+ for (ServerPlayer player : targets) { -+ ClientboundGameEventPacket packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1F); -+ player.connection.send(packet); -+ String output = String.format(PurpurConfig.creditsCommandOutput, player.getGameProfile().getName()); -+ sender.sendSuccess(output, false); -+ } -+ return targets.size(); -+ } -+} diff --git a/patches/server/0062-Configurable-jockey-options.patch b/patches/server/0062-Configurable-jockey-options.patch deleted file mode 100644 index 8b8ec6285..000000000 --- a/patches/server/0062-Configurable-jockey-options.patch +++ /dev/null @@ -1,271 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 26 Mar 2020 21:39:32 -0500 -Subject: [PATCH] Configurable jockey options - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -index 02bceb31c517b94653573380ed29d9401a6b9ce8..1d283484be270497859e23e3bb4ab38c09af23e6 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -@@ -98,6 +98,21 @@ public class Drowned extends Zombie implements RangedAttackMob { - this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.drownedSpawnReinforcements); - } - -+ @Override -+ public boolean jockeyOnlyBaby() { -+ return level().purpurConfig.drownedJockeyOnlyBaby; -+ } -+ -+ @Override -+ public double jockeyChance() { -+ return level().purpurConfig.drownedJockeyChance; -+ } -+ -+ @Override -+ public boolean jockeyTryExistingChickens() { -+ return level().purpurConfig.drownedJockeyTryExistingChickens; -+ } -+ - @Override - protected void addBehaviourGoals() { - this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0D)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Husk.java b/src/main/java/net/minecraft/world/entity/monster/Husk.java -index 805bfee8b061445de5b5d8aeb13c792178e25f7b..6673c0bff3a4e3d11a09e9dc8aeb0c2418dc7f59 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Husk.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Husk.java -@@ -49,6 +49,21 @@ public class Husk extends Zombie { - this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.huskSpawnReinforcements); - } - -+ @Override -+ public boolean jockeyOnlyBaby() { -+ return level().purpurConfig.huskJockeyOnlyBaby; -+ } -+ -+ @Override -+ public double jockeyChance() { -+ return level().purpurConfig.huskJockeyChance; -+ } -+ -+ @Override -+ public boolean jockeyTryExistingChickens() { -+ return level().purpurConfig.huskJockeyTryExistingChickens; -+ } -+ - public static boolean checkHuskSpawnRules(EntityType type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - return checkMonsterSpawnRules(type, world, spawnReason, pos, random) && (MobSpawnType.isSpawner(spawnReason) || world.canSeeSky(pos)); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index 9af1c4b794ddaf8640076f172cf0317acad6bcb2..555b86925b8d848fad40a838dd98607db8741e3b 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -126,6 +126,18 @@ public class Zombie extends Monster { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieMaxHealth); - } - -+ public boolean jockeyOnlyBaby() { -+ return level().purpurConfig.zombieJockeyOnlyBaby; -+ } -+ -+ public double jockeyChance() { -+ return level().purpurConfig.zombieJockeyChance; -+ } -+ -+ public boolean jockeyTryExistingChickens() { -+ return level().purpurConfig.zombieJockeyTryExistingChickens; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -@@ -533,19 +545,20 @@ public class Zombie extends Monster { - } - - if (object instanceof Zombie.ZombieGroupData entityzombie_groupdatazombie) { -- if (entityzombie_groupdatazombie.isBaby) { -- this.setBaby(true); -+ // Purpur start -+ if (!jockeyOnlyBaby() || entityzombie_groupdatazombie.isBaby) { -+ this.setBaby(entityzombie_groupdatazombie.isBaby); - if (entityzombie_groupdatazombie.canSpawnJockey) { -- if ((double) randomsource.nextFloat() < 0.05D) { -- List list = world.getEntitiesOfClass(Chicken.class, this.getBoundingBox().inflate(5.0D, 3.0D, 5.0D), EntitySelector.ENTITY_NOT_BEING_RIDDEN); -+ if ((double) randomsource.nextFloat() < jockeyChance()) { -+ List list = jockeyTryExistingChickens() ? world.getEntitiesOfClass(Chicken.class, this.getBoundingBox().inflate(5.0D, 3.0D, 5.0D), EntitySelector.ENTITY_NOT_BEING_RIDDEN) : java.util.Collections.emptyList(); -+ // Purpur end - - if (!list.isEmpty()) { - Chicken entitychicken = (Chicken) list.get(0); - - entitychicken.setChickenJockey(true); - this.startRiding(entitychicken); -- } -- } else if ((double) randomsource.nextFloat() < 0.05D) { -+ } else { // Purpur - Chicken entitychicken1 = (Chicken) EntityType.CHICKEN.create(this.level()); - - if (entitychicken1 != null) { -@@ -555,6 +568,7 @@ public class Zombie extends Monster { - this.startRiding(entitychicken1); - world.addFreshEntity(entitychicken1, CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit - } -+ } // Purpur - } - } - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index 8e7f0f2069c3382f3a7b08b80f829398e62377f7..ffe2144e307acebd4a8bed043db0ee0bb6bf611c 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -107,6 +107,21 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieVillagerSpawnReinforcements); - } - -+ @Override -+ public boolean jockeyOnlyBaby() { -+ return level().purpurConfig.zombieVillagerJockeyOnlyBaby; -+ } -+ -+ @Override -+ public double jockeyChance() { -+ return level().purpurConfig.zombieVillagerJockeyChance; -+ } -+ -+ @Override -+ public boolean jockeyTryExistingChickens() { -+ return level().purpurConfig.zombieVillagerJockeyTryExistingChickens; -+ } -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -index 138f3f6a9b0754d54e5f8000962bb52b224f677d..75c34d9fcc4b33d30b18f1ce4c8749a068744abc 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -84,6 +84,21 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombifiedPiglinMaxHealth); - } - -+ @Override -+ public boolean jockeyOnlyBaby() { -+ return level().purpurConfig.zombifiedPiglinJockeyOnlyBaby; -+ } -+ -+ @Override -+ public double jockeyChance() { -+ return level().purpurConfig.zombifiedPiglinJockeyChance; -+ } -+ -+ @Override -+ public boolean jockeyTryExistingChickens() { -+ return level().purpurConfig.zombifiedPiglinJockeyTryExistingChickens; -+ } -+ - @Override - public void setPersistentAngerTarget(@Nullable UUID angryAt) { - this.persistentAngerTarget = angryAt; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 62074152a0a494bbde4c39074942425a8b850ffd..7fabef36d3f9a5294a62ed956010d7ef853e00ab 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -588,6 +588,9 @@ public class PurpurWorldConfig { - public boolean drownedControllable = true; - public double drownedMaxHealth = 20.0D; - public double drownedSpawnReinforcements = 0.1D; -+ public boolean drownedJockeyOnlyBaby = true; -+ public double drownedJockeyChance = 0.05D; -+ public boolean drownedJockeyTryExistingChickens = true; - private void drownedSettings() { - drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); - drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); -@@ -599,6 +602,9 @@ public class PurpurWorldConfig { - } - drownedMaxHealth = getDouble("mobs.drowned.attributes.max_health", drownedMaxHealth); - drownedSpawnReinforcements = getDouble("mobs.drowned.attributes.spawn_reinforcements", drownedSpawnReinforcements); -+ drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby); -+ drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance); -+ drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens); - } - - public boolean elderGuardianRidable = false; -@@ -847,6 +853,9 @@ public class PurpurWorldConfig { - public boolean huskControllable = true; - public double huskMaxHealth = 20.0D; - public double huskSpawnReinforcements = 0.1D; -+ public boolean huskJockeyOnlyBaby = true; -+ public double huskJockeyChance = 0.05D; -+ public boolean huskJockeyTryExistingChickens = true; - private void huskSettings() { - huskRidable = getBoolean("mobs.husk.ridable", huskRidable); - huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); -@@ -858,6 +867,9 @@ public class PurpurWorldConfig { - } - huskMaxHealth = getDouble("mobs.husk.attributes.max_health", huskMaxHealth); - huskSpawnReinforcements = getDouble("mobs.husk.attributes.spawn_reinforcements", huskSpawnReinforcements); -+ huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby); -+ huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance); -+ huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens); - } - - public boolean illusionerRidable = false; -@@ -1674,6 +1686,9 @@ public class PurpurWorldConfig { - public boolean zombieControllable = true; - public double zombieMaxHealth = 20.0D; - public double zombieSpawnReinforcements = 0.1D; -+ public boolean zombieJockeyOnlyBaby = true; -+ public double zombieJockeyChance = 0.05D; -+ public boolean zombieJockeyTryExistingChickens = true; - private void zombieSettings() { - zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); - zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); -@@ -1685,6 +1700,9 @@ public class PurpurWorldConfig { - } - zombieMaxHealth = getDouble("mobs.zombie.attributes.max_health", zombieMaxHealth); - zombieSpawnReinforcements = getDouble("mobs.zombie.attributes.spawn_reinforcements", zombieSpawnReinforcements); -+ zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby); -+ zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); -+ zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); - } - - public boolean zombieHorseRidable = false; -@@ -1721,6 +1739,9 @@ public class PurpurWorldConfig { - public boolean zombieVillagerControllable = true; - public double zombieVillagerMaxHealth = 20.0D; - public double zombieVillagerSpawnReinforcements = 0.1D; -+ public boolean zombieVillagerJockeyOnlyBaby = true; -+ public double zombieVillagerJockeyChance = 0.05D; -+ public boolean zombieVillagerJockeyTryExistingChickens = true; - private void zombieVillagerSettings() { - zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); - zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); -@@ -1732,6 +1753,9 @@ public class PurpurWorldConfig { - } - zombieVillagerMaxHealth = getDouble("mobs.zombie_villager.attributes.max_health", zombieVillagerMaxHealth); - zombieVillagerSpawnReinforcements = getDouble("mobs.zombie_villager.attributes.spawn_reinforcements", zombieVillagerSpawnReinforcements); -+ zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby); -+ zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance); -+ zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens); - } - - public boolean zombifiedPiglinRidable = false; -@@ -1739,6 +1763,9 @@ public class PurpurWorldConfig { - public boolean zombifiedPiglinControllable = true; - public double zombifiedPiglinMaxHealth = 20.0D; - public double zombifiedPiglinSpawnReinforcements = 0.0D; -+ public boolean zombifiedPiglinJockeyOnlyBaby = true; -+ public double zombifiedPiglinJockeyChance = 0.05D; -+ public boolean zombifiedPiglinJockeyTryExistingChickens = true; - private void zombifiedPiglinSettings() { - zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); - zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); -@@ -1750,5 +1777,8 @@ public class PurpurWorldConfig { - } - zombifiedPiglinMaxHealth = getDouble("mobs.zombified_piglin.attributes.max_health", zombifiedPiglinMaxHealth); - zombifiedPiglinSpawnReinforcements = getDouble("mobs.zombified_piglin.attributes.spawn_reinforcements", zombifiedPiglinSpawnReinforcements); -+ zombifiedPiglinJockeyOnlyBaby = getBoolean("mobs.zombified_piglin.jockey.only-babies", zombifiedPiglinJockeyOnlyBaby); -+ zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance); -+ zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); - } - } diff --git a/patches/server/0064-Add-phantom-spawning-options.patch b/patches/server/0064-Add-phantom-spawning-options.patch deleted file mode 100644 index 3bd99a5d7..000000000 --- a/patches/server/0064-Add-phantom-spawning-options.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 3 Jul 2020 00:03:52 -0500 -Subject: [PATCH] Add phantom spawning options - - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -index 1b1b475ca27e799e251d6f8a8c9fe1a4fd8bae83..04f67f7b43d2f461c776c76614dc3e5f060aea63 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -@@ -48,7 +48,7 @@ public class PhantomSpawner implements CustomSpawner { - int spawnAttemptMaxSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds; - this.nextTick += (spawnAttemptMinSeconds + randomsource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; - // Paper end - Ability to control player's insomnia and phantoms -- if (world.getSkyDarken() < 5 && world.dimensionType().hasSkyLight()) { -+ if (world.getSkyDarken() < world.purpurConfig.phantomSpawnMinSkyDarkness && world.dimensionType().hasSkyLight()) { // Purpur - return 0; - } else { - int i = 0; -@@ -60,10 +60,10 @@ public class PhantomSpawner implements CustomSpawner { - if (!entityplayer.isSpectator() && (!world.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !entityplayer.isCreative())) { // Paper - Add phantom creative and insomniac controls - BlockPos blockposition = entityplayer.blockPosition(); - -- if (!world.dimensionType().hasSkyLight() || blockposition.getY() >= world.getSeaLevel() && world.canSeeSky(blockposition)) { -+ if (!world.dimensionType().hasSkyLight() || (!world.purpurConfig.phantomSpawnOnlyAboveSeaLevel || blockposition.getY() >= world.getSeaLevel()) && (!world.purpurConfig.phantomSpawnOnlyWithVisibleSky || world.canSeeSky(blockposition))) { // Purpur - DifficultyInstance difficultydamagescaler = world.getCurrentDifficultyAt(blockposition); - -- if (difficultydamagescaler.isHarderThan(randomsource.nextFloat() * 3.0F)) { -+ if (difficultydamagescaler.isHarderThan(randomsource.nextFloat() * (float) world.purpurConfig.phantomSpawnLocalDifficultyChance)) { // Purpur - ServerStatsCounter serverstatisticmanager = entityplayer.getStats(); - int j = Mth.clamp(serverstatisticmanager.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE); - boolean flag2 = true; -@@ -75,7 +75,7 @@ public class PhantomSpawner implements CustomSpawner { - - if (NaturalSpawner.isValidEmptySpawnBlock(world, blockposition1, iblockdata, fluid, EntityType.PHANTOM)) { - SpawnGroupData groupdataentity = null; -- int k = 1 + randomsource.nextInt(difficultydamagescaler.getDifficulty().getId() + 1); -+ int k = world.purpurConfig.phantomSpawnMinPerAttempt + world.random.nextInt((world.purpurConfig.phantomSpawnMaxPerAttempt < 0 ? difficultydamagescaler.getDifficulty().getId() : world.purpurConfig.phantomSpawnMaxPerAttempt - world.purpurConfig.phantomSpawnMinPerAttempt) + 1); // Purpur - - for (int l = 0; l < k; ++l) { - // Paper start - PhantomPreSpawnEvent -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e1652079b92a5c951b5191997803e9d486892c61..10de2140aa89f75e7f67b38f6c1286f4330d127b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1068,6 +1068,12 @@ public class PurpurWorldConfig { - public double phantomAttackedByCrystalRadius = 0.0D; - public float phantomAttackedByCrystalDamage = 1.0F; - public double phantomOrbitCrystalRadius = 0.0D; -+ public int phantomSpawnMinSkyDarkness = 5; -+ public boolean phantomSpawnOnlyAboveSeaLevel = true; -+ public boolean phantomSpawnOnlyWithVisibleSky = true; -+ public double phantomSpawnLocalDifficultyChance = 3.0D; -+ public int phantomSpawnMinPerAttempt = 1; -+ public int phantomSpawnMaxPerAttempt = -1; - private void phantomSettings() { - phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); - phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -@@ -1092,6 +1098,12 @@ public class PurpurWorldConfig { - phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius); - phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage); - phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius); -+ phantomSpawnMinSkyDarkness = getInt("mobs.phantom.spawn.min-sky-darkness", phantomSpawnMinSkyDarkness); -+ phantomSpawnOnlyAboveSeaLevel = getBoolean("mobs.phantom.spawn.only-above-sea-level", phantomSpawnOnlyAboveSeaLevel); -+ phantomSpawnOnlyWithVisibleSky = getBoolean("mobs.phantom.spawn.only-with-visible-sky", phantomSpawnOnlyWithVisibleSky); -+ phantomSpawnLocalDifficultyChance = getDouble("mobs.phantom.spawn.local-difficulty-chance", phantomSpawnLocalDifficultyChance); -+ phantomSpawnMinPerAttempt = getInt("mobs.phantom.spawn.per-attempt.min", phantomSpawnMinPerAttempt); -+ phantomSpawnMaxPerAttempt = getInt("mobs.phantom.spawn.per-attempt.max", phantomSpawnMaxPerAttempt); - } - - public boolean pigRidable = false; diff --git a/patches/server/0065-Implement-bed-explosion-options.patch b/patches/server/0065-Implement-bed-explosion-options.patch deleted file mode 100644 index bdfcce98a..000000000 --- a/patches/server/0065-Implement-bed-explosion-options.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 4 Jul 2020 13:12:43 -0500 -Subject: [PATCH] Implement bed explosion options - - -diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java -index 4459685d1fb655f93a523ae50b62d6b97785ed90..549e3dd09a91ddf319fe0c1ec09924cbb600c1b8 100644 ---- a/src/main/java/net/minecraft/world/level/block/BedBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java -@@ -104,7 +104,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock - - Vec3 vec3d = pos.getCenter(); - -- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); -+ if (world.purpurConfig.bedExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d), (ExplosionDamageCalculator) null, vec3d, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // Purpur - return InteractionResult.SUCCESS; - } else if ((Boolean) state.getValue(BedBlock.OCCUPIED)) { - if (!BedBlock.canSetSpawn(world)) return this.explodeBed(state, world, pos); // Paper - check explode first -@@ -157,7 +157,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock - - Vec3 vec3d = blockposition.getCenter(); - -- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, world, iblockdata, blockposition, blockEntity), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state // Paper - add BlockEntity -+ if (world.purpurConfig.bedExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, world, iblockdata, blockposition, blockEntity), (ExplosionDamageCalculator) null, vec3d, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // CraftBukkit - add state // Paper - add BlockEntity // Purpur - return InteractionResult.SUCCESS; - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 10de2140aa89f75e7f67b38f6c1286f4330d127b..95f016b7c127129b71e266a3daefd55502fdb299 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -284,6 +284,27 @@ public class PurpurWorldConfig { - }); - } - -+ public boolean bedExplode = true; -+ public double bedExplosionPower = 5.0D; -+ public boolean bedExplosionFire = true; -+ public net.minecraft.world.level.Level.ExplosionInteraction bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ private void bedSettings() { -+ if (PurpurConfig.version < 31) { -+ if ("DESTROY".equals(getString("blocks.bed.explosion-effect", bedExplosionEffect.name()))) { -+ set("blocks.bed.explosion-effect", "BLOCK"); -+ } -+ } -+ bedExplode = getBoolean("blocks.bed.explode", bedExplode); -+ bedExplosionPower = getDouble("blocks.bed.explosion-power", bedExplosionPower); -+ bedExplosionFire = getBoolean("blocks.bed.explosion-fire", bedExplosionFire); -+ try { -+ bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.bed.explosion-effect", bedExplosionEffect.name())); -+ } catch (IllegalArgumentException e) { -+ log(Level.SEVERE, "Unknown value for `blocks.bed.explosion-effect`! Using default of `BLOCK`"); -+ bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ } -+ } -+ - public boolean dispenserApplyCursedArmor = true; - private void dispenserSettings() { - dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor); diff --git a/patches/server/0066-Implement-respawn-anchor-explosion-options.patch b/patches/server/0066-Implement-respawn-anchor-explosion-options.patch deleted file mode 100644 index c8af656e0..000000000 --- a/patches/server/0066-Implement-respawn-anchor-explosion-options.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 4 Jul 2020 13:23:19 -0500 -Subject: [PATCH] Implement respawn anchor explosion options - - -diff --git a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java -index 0699211428f182d8d56a2ba019d89ce05c920430..351fb74d2cccd7f63c2efee197a2968f822eda42 100644 ---- a/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/RespawnAnchorBlock.java -@@ -149,7 +149,7 @@ public class RespawnAnchorBlock extends Block { - }; - Vec3 vec3d = explodedPos.getCenter(); - -- world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, world, state, explodedPos, null), explosiondamagecalculator, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state // Paper -+ if (world.purpurConfig.respawnAnchorExplode) world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, world, state, explodedPos, null), explosiondamagecalculator, vec3d, (float) world.purpurConfig.respawnAnchorExplosionPower, world.purpurConfig.respawnAnchorExplosionFire, world.purpurConfig.respawnAnchorExplosionEffect); // CraftBukkit - add state // Paper // Purpur - } - - public static boolean canSetSpawn(Level world) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 95f016b7c127129b71e266a3daefd55502fdb299..55ae989ae13ae9c0730f6f8df5f7eba52a560b1f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -324,6 +324,27 @@ public class PurpurWorldConfig { - lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether); - } - -+ public boolean respawnAnchorExplode = true; -+ public double respawnAnchorExplosionPower = 5.0D; -+ public boolean respawnAnchorExplosionFire = true; -+ public net.minecraft.world.level.Level.ExplosionInteraction respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ private void respawnAnchorSettings() { -+ if (PurpurConfig.version < 31) { -+ if ("DESTROY".equals(getString("blocks.respawn_anchor.explosion-effect", respawnAnchorExplosionEffect.name()))) { -+ set("blocks.respawn_anchor.explosion-effect", "BLOCK"); -+ } -+ } -+ respawnAnchorExplode = getBoolean("blocks.respawn_anchor.explode", respawnAnchorExplode); -+ respawnAnchorExplosionPower = getDouble("blocks.respawn_anchor.explosion-power", respawnAnchorExplosionPower); -+ respawnAnchorExplosionFire = getBoolean("blocks.respawn_anchor.explosion-fire", respawnAnchorExplosionFire); -+ try { -+ respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.respawn_anchor.explosion-effect", respawnAnchorExplosionEffect.name())); -+ } catch (IllegalArgumentException e) { -+ log(Level.SEVERE, "Unknown value for `blocks.respawn_anchor.explosion-effect`! Using default of `BLOCK`"); -+ respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ } -+ } -+ - public boolean turtleEggsBreakFromExpOrbs = false; - public boolean turtleEggsBreakFromItems = false; - public boolean turtleEggsBreakFromMinecarts = false; diff --git a/patches/server/0067-Add-allow-water-in-end-world-option.patch b/patches/server/0067-Add-allow-water-in-end-world-option.patch deleted file mode 100644 index 6cc34bdc5..000000000 --- a/patches/server/0067-Add-allow-water-in-end-world-option.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 5 Jul 2020 23:40:16 -0500 -Subject: [PATCH] Add allow water in end world option - - -diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java -index 49557d6f22c5725c663a231deab019d4f6fe95fa..046652e8f9c5dcdf7c90acb9391214cac46bd7d8 100644 ---- a/src/main/java/net/minecraft/world/item/BucketItem.java -+++ b/src/main/java/net/minecraft/world/item/BucketItem.java -@@ -194,7 +194,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { - // CraftBukkit end - if (!flag2) { - return movingobjectpositionblock != null && this.emptyContents(entityhuman, world, movingobjectpositionblock.getBlockPos().relative(movingobjectpositionblock.getDirection()), (BlockHitResult) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit -- } else if (world.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) { -+ } else if ((world.dimensionType().ultraWarm() || (world.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) && this.content.is(FluidTags.WATER)) { // Purpur - int i = blockposition.getX(); - int j = blockposition.getY(); - int k = blockposition.getZ(); -@@ -202,7 +202,7 @@ public class BucketItem extends Item implements DispensibleContainerItem { - world.playSound(entityhuman, blockposition, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); - - for (int l = 0; l < 8; ++l) { -- world.addParticle(ParticleTypes.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 0.0D, 0.0D, 0.0D); -+ ((ServerLevel) world).sendParticles(null, ParticleTypes.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 1, 0.0D, 0.0D, 0.0D, 0.0D, true); // Purpur - } - - return true; -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 04f7f6743aabdca54892b2b155386f86032cf807..2e44e9ea9558ebc1456d9bbf53561988e33ce845 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -1902,4 +1902,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - return null; - } - // Paper end - optimize redstone (Alternate Current) -+ // Purpur start -+ public boolean isNether() { -+ return getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER; -+ } -+ -+ public boolean isTheEnd() { -+ return getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END; -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java -index 013302623d3ca3ff88f242d740af935dcf4844a6..13dd8bc7d2f6b71a5f1779dde53c5c84d83538ce 100644 ---- a/src/main/java/net/minecraft/world/level/block/IceBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java -@@ -41,7 +41,7 @@ public class IceBlock extends HalfTransparentBlock { - public void afterDestroy(Level world, BlockPos pos, ItemStack tool) { - // Paper end - Improve Block#breakNaturally API - if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) == 0) { -- if (world.dimensionType().ultraWarm()) { -+ if (world.isNether() || (world.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur - world.removeBlock(pos, false); - return; - } -@@ -69,7 +69,7 @@ public class IceBlock extends HalfTransparentBlock { - return; - } - // CraftBukkit end -- if (world.dimensionType().ultraWarm()) { -+ if (world.isNether() || (world.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur - world.removeBlock(pos, false); - } else { - world.setBlockAndUpdate(pos, IceBlock.meltsInto()); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 2e78d67201e66c1f3fd1f45ed625e682ea074848..de202a20cdc133d68fb44c56ee017cca153e1cf8 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -244,6 +244,11 @@ public class PurpurConfig { - enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); - } - -+ public static boolean allowWaterPlacementInTheEnd = true; -+ private static void allowWaterPlacementInEnd() { -+ allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd); -+ } -+ - public static boolean loggerSuppressInitLegacyMaterialError = false; - public static boolean loggerSuppressIgnoredAdvancementWarnings = false; - public static boolean loggerSuppressUnrecognizedRecipeErrors = false; diff --git a/patches/server/0068-Allow-color-codes-in-books.patch b/patches/server/0068-Allow-color-codes-in-books.patch deleted file mode 100644 index 2122c64dd..000000000 --- a/patches/server/0068-Allow-color-codes-in-books.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 3 Nov 2020 01:25:06 -0600 -Subject: [PATCH] Allow color codes in books - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 510a4391463026dd0c896027a579a94174c24299..c647629ef404e983240577c87306bb76bf0cc4a5 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1234,10 +1234,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - Objects.requireNonNull(list); - stream.forEach(list::add); -+ // Purpur start -+ boolean hasEditPerm = getCraftPlayer().hasPermission("purpur.book.color.edit"); -+ boolean hasSignPerm = hasEditPerm || getCraftPlayer().hasPermission("purpur.book.color.sign"); -+ // Purpur end - Consumer> consumer = optional.isPresent() ? (list1) -> { -- this.signBook((FilteredText) list1.get(0), list1.subList(1, list1.size()), i); -+ this.signBook((FilteredText) list1.get(0), list1.subList(1, list1.size()), i, hasSignPerm); // Purpur - } : (list1) -> { -- this.updateBookContents(list1, i); -+ this.updateBookContents(list1, i, hasEditPerm); // Purpur - }; - - this.filterTextPacket((List) list).thenAcceptAsync(consumer, this.server); -@@ -1245,13 +1249,18 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - - private void updateBookContents(List pages, int slotId) { -+ // Purpur start -+ updateBookContents(pages, slotId, false); -+ } -+ private void updateBookContents(List pages, int slotId, boolean hasPerm) { -+ // Purpur end - // CraftBukkit start - ItemStack handItem = this.player.getInventory().getItem(slotId); - ItemStack itemstack = handItem.copy(); - // CraftBukkit end - - if (itemstack.is(Items.WRITABLE_BOOK)) { -- List> list1 = pages.stream().map(this::filterableFromOutgoing).toList(); -+ List> list1 = pages.stream().map(filteredText -> filterableFromOutgoing(filteredText).map(s -> color(s, hasPerm))).toList(); // Purpur - - itemstack.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(list1)); - this.player.getInventory().setItem(slotId, CraftEventFactory.handleEditBookEvent(this.player, slotId, handItem, itemstack)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent) -@@ -1259,6 +1268,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - - private void signBook(FilteredText title, List pages, int slotId) { -+ // Purpur start -+ signBook(title, pages, slotId, false); -+ } -+ private void signBook(FilteredText title, List pages, int slotId, boolean hasPerm) { -+ // Purpur end - ItemStack itemstack = this.player.getInventory().getItem(slotId); - - if (itemstack.is(Items.WRITABLE_BOOK)) { -@@ -1266,10 +1280,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - itemstack1.remove(DataComponents.WRITABLE_BOOK_CONTENT); - List> list1 = (List>) (List) pages.stream().map((filteredtext1) -> { // CraftBukkit - decompile error -- return this.filterableFromOutgoing(filteredtext1).map(Component::literal); -+ return this.filterableFromOutgoing(filteredtext1).map(s -> hexColor(s, hasPerm)); // Purpur - }).toList(); - -- itemstack1.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(this.filterableFromOutgoing(title), this.player.getName().getString(), 0, list1, true)); -+ itemstack1.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(this.filterableFromOutgoing(title).map(s -> color(s, hasPerm)), this.player.getName().getString(), 0, list1, true)); // Purpur - CraftEventFactory.handleEditBookEvent(this.player, slotId, itemstack, itemstack1); // CraftBukkit - this.player.getInventory().setItem(slotId, itemstack); // CraftBukkit - event factory updates the hand book - } -@@ -1279,6 +1293,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - return this.player.isTextFilteringEnabled() ? Filterable.passThrough(message.filteredOrEmpty()) : Filterable.from(message); - } - -+ // Purpur start -+ private Component hexColor(String str, boolean hasPerm) { -+ return hasPerm ? PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize(str)) : Component.literal(str); -+ } -+ -+ private String color(String str, boolean hasPerm) { -+ return hasPerm ? org.bukkit.ChatColor.color(str, false) : str; -+ } -+ // Purpur end -+ - @Override - public void handleEntityTagQuery(ServerboundEntityTagQueryPacket packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); diff --git a/patches/server/0069-Entity-lifespan.patch b/patches/server/0069-Entity-lifespan.patch deleted file mode 100644 index de7376432..000000000 --- a/patches/server/0069-Entity-lifespan.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 11 Jul 2020 19:41:34 -0500 -Subject: [PATCH] Entity lifespan - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index c647629ef404e983240577c87306bb76bf0cc4a5..e5df5583ef6084e59c8375c82c9909ff2d2bdc3f 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2824,6 +2824,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - AABB axisalignedbb = entity.getBoundingBox(); - - if (this.player.canInteractWithEntity(axisalignedbb, 1.0D)) { -+ if (entity instanceof Mob mob) mob.ticksSinceLastInteraction = 0; // Purpur - packet.dispatch(new ServerboundInteractPacket.Handler() { - private void performInteraction(InteractionHand enumhand, ServerGamePacketListenerImpl.EntityInteraction playerconnection_a, PlayerInteractEntityEvent event) { // CraftBukkit - ItemStack itemstack = ServerGamePacketListenerImpl.this.player.getItemInHand(enumhand); -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index c4392a997061aa4939e5ad7dcacf5e39cbecc55a..e7251ac940b49564c83b4b603e49c3990fc85db1 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -152,6 +152,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - private BlockPos restrictCenter; - private float restrictRadius; - -+ public int ticksSinceLastInteraction; // Purpur - public boolean aware = true; // CraftBukkit - - protected Mob(EntityType type, Level world) { -@@ -339,6 +340,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - entityliving = null; - } - } -+ if (entityliving instanceof ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur - this.target = entityliving; - return true; - // CraftBukkit end -@@ -381,8 +383,28 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - } - - this.level().getProfiler().pop(); -+ incrementTicksSinceLastInteraction(); // Purpur - } - -+ // Purpur start -+ private void incrementTicksSinceLastInteraction() { -+ ++this.ticksSinceLastInteraction; -+ if (getRider() != null) { -+ this.ticksSinceLastInteraction = 0; -+ return; -+ } -+ if (this.level().purpurConfig.entityLifeSpan <= 0) { -+ return; // feature disabled -+ } -+ if (!this.removeWhenFarAway(0) || isPersistenceRequired() || requiresCustomPersistence() || hasCustomName()) { -+ return; // mob persistent -+ } -+ if (this.ticksSinceLastInteraction > this.level().purpurConfig.entityLifeSpan) { -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ } -+ } -+ // Purpur end -+ - @Override - protected void playHurtSound(DamageSource damageSource) { - this.resetAmbientSoundTime(); -@@ -585,6 +607,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - } - - nbt.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit -+ nbt.putInt("Purpur.ticksSinceLastInteraction", this.ticksSinceLastInteraction); // Purpur - } - - @Override -@@ -669,6 +692,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - this.aware = nbt.getBoolean("Bukkit.Aware"); - } - // CraftBukkit end -+ // Purpur start -+ if (nbt.contains("Purpur.ticksSinceLastInteraction")) { -+ this.ticksSinceLastInteraction = nbt.getInt("Purpur.ticksSinceLastInteraction"); -+ } -+ // Purpur end - } - - @Override -@@ -1848,6 +1876,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - this.setLastHurtMob(target); - } - -+ if (target instanceof ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur - return flag; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 55ae989ae13ae9c0730f6f8df5f7eba52a560b1f..9ba3a90e1af9c733949c52988c56c05af46356e8 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -125,6 +125,11 @@ public class PurpurWorldConfig { - elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost); - } - -+ public int entityLifeSpan = 0; -+ private void entitySettings() { -+ entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan); -+ } -+ - public List itemImmuneToCactus = new ArrayList<>(); - public List itemImmuneToExplosion = new ArrayList<>(); - public List itemImmuneToFire = new ArrayList<>(); diff --git a/patches/server/0070-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch b/patches/server/0070-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch deleted file mode 100644 index 21154237b..000000000 --- a/patches/server/0070-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 13 Jul 2020 11:40:00 -0500 -Subject: [PATCH] Add option to teleport to spawn if outside world border - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index a17de781053a2c2caf615e5ac48a45c14386b0af..03b206289d103a36d19dcf3154f10ad98f976ba2 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -2956,4 +2956,26 @@ public class ServerPlayer extends Player { - return (CraftPlayer) super.getBukkitEntity(); - } - // CraftBukkit end -+ -+ // Purpur start -+ public void teleport(Location to) { -+ this.ejectPassengers(); -+ this.stopRiding(true); -+ -+ if (this.isSleeping()) { -+ this.stopSleepInBed(true, false); -+ } -+ -+ if (this.containerMenu != this.inventoryMenu) { -+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); -+ } -+ -+ ServerLevel toLevel = ((CraftWorld) to.getWorld()).getHandle(); -+ if (this.level() == toLevel) { -+ this.connection.internalTeleport(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch(), java.util.EnumSet.noneOf(net.minecraft.world.entity.RelativeMovement.class)); -+ } else { -+ this.server.getPlayerList().respawn(this, toLevel, true, to, !toLevel.paperConfig().environment.disableTeleportationSuffocationCheck, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.DEATH); -+ } -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 9a2725e3f61a7d37943518cc760b17859a0938bb..9a912752b12730a8fb09f5a6ab5a8638b555e3e3 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -440,6 +440,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - double d1 = this.level().getWorldBorder().getDamagePerBlock(); - - if (d1 > 0.0D) { -+ if (level().purpurConfig.teleportIfOutsideBorder && this instanceof ServerPlayer serverPlayer) { serverPlayer.teleport(io.papermc.paper.util.MCUtil.toLocation(level(), ((ServerLevel) level()).getSharedSpawnPos())); return; } // Purpur - this.hurt(this.damageSources().outOfBorder(), (float) Math.max(1, Mth.floor(-d0 * d1))); - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 9ba3a90e1af9c733949c52988c56c05af46356e8..98e6faaeeaf8a983f9d730591a9d85c314c112d3 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -242,6 +242,7 @@ public class PurpurWorldConfig { - public boolean idleTimeoutTargetPlayer = true; - public String playerDeathExpDropEquation = "expLevel * 7"; - public int playerDeathExpDropMax = 100; -+ public boolean teleportIfOutsideBorder = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -255,6 +256,7 @@ public class PurpurWorldConfig { - idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer); - playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation); - playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax); -+ teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0071-Squid-EAR-immunity.patch b/patches/server/0071-Squid-EAR-immunity.patch deleted file mode 100644 index 6e6183b7a..000000000 --- a/patches/server/0071-Squid-EAR-immunity.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 13 Jul 2020 13:49:41 -0500 -Subject: [PATCH] Squid EAR immunity - - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 98e6faaeeaf8a983f9d730591a9d85c314c112d3..27d279d76fd3632fd023edded3b10630629ec132 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1453,6 +1453,7 @@ public class PurpurWorldConfig { - public boolean squidRidable = false; - public boolean squidControllable = true; - public double squidMaxHealth = 10.0D; -+ public boolean squidImmuneToEAR = true; - private void squidSettings() { - squidRidable = getBoolean("mobs.squid.ridable", squidRidable); - squidControllable = getBoolean("mobs.squid.controllable", squidControllable); -@@ -1462,6 +1463,7 @@ public class PurpurWorldConfig { - set("mobs.squid.attributes.max_health", oldValue); - } - squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth); -+ squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); - } - - public boolean spiderRidable = false; -diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index a9a39f0da7b09410d8171172a4219c7d509fdb99..a8fc07e06039e1418e020f7c1ad2cd36b9b94eb4 100644 ---- a/src/main/java/org/spigotmc/ActivationRange.java -+++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -15,6 +15,7 @@ import net.minecraft.world.entity.ambient.AmbientCreature; - import net.minecraft.world.entity.animal.Animal; - import net.minecraft.world.entity.animal.Bee; - import net.minecraft.world.entity.animal.Sheep; -+import net.minecraft.world.entity.animal.Squid; - import net.minecraft.world.entity.animal.WaterAnimal; - import net.minecraft.world.entity.animal.horse.Llama; - import net.minecraft.world.entity.boss.EnderDragonPart; -@@ -380,6 +381,7 @@ public class ActivationRange - */ - public static boolean checkIfActive(Entity entity) - { -+ if (entity.level().purpurConfig.squidImmuneToEAR && entity instanceof Squid) return true; // Purpur - // Never safe to skip fireworks or entities not yet added to chunk - if ( entity instanceof FireworkRocketEntity ) { - return true; diff --git a/patches/server/0072-Phantoms-burn-in-light.patch b/patches/server/0072-Phantoms-burn-in-light.patch deleted file mode 100644 index d35474462..000000000 --- a/patches/server/0072-Phantoms-burn-in-light.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: draycia -Date: Sun, 12 Apr 2020 20:41:59 -0700 -Subject: [PATCH] Phantoms burn in light - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index e0b1b0106fd3bbb6764d1b0a58ab2810181cac02..1ddccb9fa438682c2ebad7c071c7a4f8dd00b463 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -48,6 +48,7 @@ public class Phantom extends FlyingMob implements Enemy { - Vec3 moveTargetPoint; - public BlockPos anchorPoint; - Phantom.AttackPhase attackPhase; -+ private static final net.minecraft.world.item.crafting.Ingredient TORCH = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.item.Items.TORCH, net.minecraft.world.item.Items.SOUL_TORCH); // Purpur - Vec3 crystalPosition; // Purpur - - public Phantom(EntityType type, Level world) { -@@ -240,7 +241,11 @@ public class Phantom extends FlyingMob implements Enemy { - - @Override - public void aiStep() { -- if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API -+ // Purpur start -+ boolean burnFromDaylight = this.shouldBurnInDay && this.isSunBurnTick() && this.level().purpurConfig.phantomBurnInDaylight; -+ boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight; -+ if (this.isAlive() && (burnFromDaylight || burnFromLightSource)) { // Paper - shouldBurnInDay API -+ // Purpur end - if (getRider() == null || !this.isControllable()) // Purpur - this.igniteForSeconds(8); - } -@@ -641,6 +646,12 @@ public class Phantom extends FlyingMob implements Enemy { - return false; - } else if (!entityliving.isAlive()) { - return false; -+ // Purpur start -+ } else if (level().purpurConfig.phantomBurnInLight > 0 && level().getLightEmission(new BlockPos(Phantom.this)) >= level().purpurConfig.phantomBurnInLight) { -+ return false; -+ } else if (level().purpurConfig.phantomIgnorePlayersWithTorch && (TORCH.test(entityliving.getItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND)) || TORCH.test(entityliving.getItemInHand(net.minecraft.world.InteractionHand.OFF_HAND)))) { -+ return false; -+ // Purpur end - } else { - if (entityliving instanceof Player) { - Player entityhuman = (Player) entityliving; -@@ -786,6 +797,7 @@ public class Phantom extends FlyingMob implements Enemy { - this.nextScanTick = reducedTickDelay(60); - List list = Phantom.this.level().getNearbyPlayers(this.attackTargeting, Phantom.this, Phantom.this.getBoundingBox().inflate(16.0D, 64.0D, 16.0D)); - -+ if (level().purpurConfig.phantomIgnorePlayersWithTorch) list.removeIf(human -> TORCH.test(human.getItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND)) || TORCH.test(human.getItemInHand(net.minecraft.world.InteractionHand.OFF_HAND)));// Purpur - if (!list.isEmpty()) { - list.sort(Comparator.comparing((Entity e) -> { return e.getY(); }).reversed()); // CraftBukkit - decompile error - Iterator iterator = list.iterator(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 27d279d76fd3632fd023edded3b10630629ec132..dcd9f80eb69e34b514f57158568e4cb59e9860ec 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1123,6 +1123,9 @@ public class PurpurWorldConfig { - public double phantomSpawnLocalDifficultyChance = 3.0D; - public int phantomSpawnMinPerAttempt = 1; - public int phantomSpawnMaxPerAttempt = -1; -+ public int phantomBurnInLight = 0; -+ public boolean phantomIgnorePlayersWithTorch = false; -+ public boolean phantomBurnInDaylight = true; - private void phantomSettings() { - phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); - phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -@@ -1153,6 +1156,9 @@ public class PurpurWorldConfig { - phantomSpawnLocalDifficultyChance = getDouble("mobs.phantom.spawn.local-difficulty-chance", phantomSpawnLocalDifficultyChance); - phantomSpawnMinPerAttempt = getInt("mobs.phantom.spawn.per-attempt.min", phantomSpawnMinPerAttempt); - phantomSpawnMaxPerAttempt = getInt("mobs.phantom.spawn.per-attempt.max", phantomSpawnMaxPerAttempt); -+ phantomBurnInLight = getInt("mobs.phantom.burn-in-light", phantomBurnInLight); -+ phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight); -+ phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); - } - - public boolean pigRidable = false; diff --git a/patches/server/0073-Configurable-villager-breeding.patch b/patches/server/0073-Configurable-villager-breeding.patch deleted file mode 100644 index 71c318976..000000000 --- a/patches/server/0073-Configurable-villager-breeding.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: draycia -Date: Tue, 31 Mar 2020 23:48:55 -0700 -Subject: [PATCH] Configurable villager breeding - - -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 051940da69567274f48485f060cbc3ac21a0907f..6de74d992bd8b2845ab98d56201e7eeabd1dfc6b 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -777,7 +777,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - - @Override - public boolean canBreed() { -- return this.foodLevel + this.countFoodPointsInInventory() >= 12 && !this.isSleeping() && this.getAge() == 0; -+ return this.level().purpurConfig.villagerCanBreed && this.foodLevel + this.countFoodPointsInInventory() >= 12 && !this.isSleeping() && this.getAge() == 0; // Purpur - } - - private boolean hungry() { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index dcd9f80eb69e34b514f57158568e4cb59e9860ec..df4f384032f398fc9852e753dee820ffa33e10bb 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1611,6 +1611,7 @@ public class PurpurWorldConfig { - public double villagerMaxHealth = 20.0D; - public boolean villagerFollowEmeraldBlock = false; - public boolean villagerCanBeLeashed = false; -+ public boolean villagerCanBreed = true; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -1623,6 +1624,7 @@ public class PurpurWorldConfig { - villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth); - villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); - villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed); -+ villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed); - } - - public boolean vindicatorRidable = false; diff --git a/patches/server/0074-Redstone-deactivates-spawners.patch b/patches/server/0074-Redstone-deactivates-spawners.patch deleted file mode 100644 index 41653f9a7..000000000 --- a/patches/server/0074-Redstone-deactivates-spawners.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: draycia -Date: Tue, 14 Apr 2020 00:35:12 -0700 -Subject: [PATCH] Redstone deactivates spawners - - -diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java -index f57e1b78204dff661ad5d3ee93a88a00330af2dc..967af8771ff8564c715d89f4b4b69b16c25add59 100644 ---- a/src/main/java/net/minecraft/world/level/BaseSpawner.java -+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java -@@ -59,6 +59,7 @@ public abstract class BaseSpawner { - } - - public boolean isNearPlayer(Level world, BlockPos pos) { -+ if (world.purpurConfig.spawnerDeactivateByRedstone && world.hasNeighborSignal(pos)) return false; // Purpur - return world.hasNearbyAlivePlayerThatAffectsSpawning((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper - Affects Spawning API - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index df4f384032f398fc9852e753dee820ffa33e10bb..85d2030c58fb97be82c97a042bc5d73e76274268 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -352,6 +352,11 @@ public class PurpurWorldConfig { - } - } - -+ public boolean spawnerDeactivateByRedstone = false; -+ private void spawnerSettings() { -+ spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); -+ } -+ - public boolean turtleEggsBreakFromExpOrbs = false; - public boolean turtleEggsBreakFromItems = false; - public boolean turtleEggsBreakFromMinecarts = false; diff --git a/patches/server/0075-Totems-work-in-inventory.patch b/patches/server/0075-Totems-work-in-inventory.patch deleted file mode 100644 index 1babbff8a..000000000 --- a/patches/server/0075-Totems-work-in-inventory.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: draycia -Date: Wed, 29 Apr 2020 00:45:58 -0700 -Subject: [PATCH] Totems work in inventory - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 9a912752b12730a8fb09f5a6ab5a8638b555e3e3..2ea60043f3bbf6cce77799f6c74ffe1f4b226374 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1653,6 +1653,18 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - } - -+ // Purpur start -+ if (level().purpurConfig.totemOfUndyingWorksInInventory && this instanceof ServerPlayer player && (itemstack == null || itemstack.getItem() != Items.TOTEM_OF_UNDYING) && player.getBukkitEntity().hasPermission("purpur.inventory_totem")) { -+ for (ItemStack item : player.getInventory().items) { -+ if (item.getItem() == Items.TOTEM_OF_UNDYING) { -+ itemstack1 = item; -+ itemstack = item.copy(); -+ break; -+ } -+ } -+ } -+ // Purpur end -+ - org.bukkit.inventory.EquipmentSlot handSlot = (hand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand) : null; - EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot); - event.setCancelled(itemstack == null); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 85d2030c58fb97be82c97a042bc5d73e76274268..be916fe3a8bc8996be8b0835e3bd8f7920c15055 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -243,6 +243,7 @@ public class PurpurWorldConfig { - public String playerDeathExpDropEquation = "expLevel * 7"; - public int playerDeathExpDropMax = 100; - public boolean teleportIfOutsideBorder = false; -+ public boolean totemOfUndyingWorksInInventory = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -257,6 +258,7 @@ public class PurpurWorldConfig { - playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation); - playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax); - teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); -+ totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0076-Add-vindicator-johnny-spawn-chance.patch b/patches/server/0076-Add-vindicator-johnny-spawn-chance.patch deleted file mode 100644 index 34abb4304..000000000 --- a/patches/server/0076-Add-vindicator-johnny-spawn-chance.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 24 Jul 2020 19:38:21 -0500 -Subject: [PATCH] Add vindicator johnny spawn chance - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -index e270da29fdab5060b6a936bba67c433a78c54b5b..61f1778d454cebaab5580179614ff48ab67b8fe6 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -@@ -148,6 +148,12 @@ public class Vindicator extends AbstractIllager { - RandomSource randomSource = world.getRandom(); - this.populateDefaultEquipmentSlots(randomSource, difficulty); - this.populateDefaultEquipmentEnchantments(randomSource, difficulty); -+ // Purpur start -+ Level level = world.getMinecraftWorld(); -+ if (level().purpurConfig.vindicatorJohnnySpawnChance > 0D && random.nextDouble() <= level().purpurConfig.vindicatorJohnnySpawnChance) { -+ setCustomName(Component.translatable("Johnny")); -+ } -+ // Purpur end - return spawnGroupData; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index be916fe3a8bc8996be8b0835e3bd8f7920c15055..7b584d5c8460e90dfea250591e4ca36cb1db004a 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1638,6 +1638,7 @@ public class PurpurWorldConfig { - public boolean vindicatorRidableInWater = true; - public boolean vindicatorControllable = true; - public double vindicatorMaxHealth = 24.0D; -+ public double vindicatorJohnnySpawnChance = 0D; - private void vindicatorSettings() { - vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); - vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); -@@ -1648,6 +1649,7 @@ public class PurpurWorldConfig { - set("mobs.vindicator.attributes.max_health", oldValue); - } - vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth); -+ vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance); - } - - public boolean wanderingTraderRidable = false; diff --git a/patches/server/0077-Dispensers-place-anvils-option.patch b/patches/server/0077-Dispensers-place-anvils-option.patch deleted file mode 100644 index 0dbf632e9..000000000 --- a/patches/server/0077-Dispensers-place-anvils-option.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 4 Aug 2020 21:11:03 -0500 -Subject: [PATCH] Dispensers place anvils option - - -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index 5dab1e10303177e5a4d97a91ee46ede66f30ae35..68236139e3571791b891dbbef6e3ee20031e16d9 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -1048,5 +1048,22 @@ public interface DispenseItemBehavior { - } - } - }); -+ // Purpur start -+ DispenserBlock.registerBehavior(Items.ANVIL, (new OptionalDispenseItemBehavior() { -+ @Override -+ public ItemStack execute(BlockSource dispenser, ItemStack stack) { -+ net.minecraft.world.level.Level level = dispenser.level(); -+ if (!level.purpurConfig.dispenserPlaceAnvils) return super.execute(dispenser, stack); -+ Direction facing = dispenser.blockEntity().getBlockState().getValue(DispenserBlock.FACING); -+ BlockPos pos = dispenser.pos().relative(facing); -+ BlockState state = level.getBlockState(pos); -+ if (state.isAir()) { -+ level.setBlockAndUpdate(pos, Blocks.ANVIL.defaultBlockState().setValue(net.minecraft.world.level.block.AnvilBlock.FACING, facing.getAxis() == Direction.Axis.Y ? Direction.NORTH : facing.getClockWise())); -+ stack.shrink(1); -+ } -+ return stack; -+ } -+ })); -+ // Purpur end - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 7b584d5c8460e90dfea250591e4ca36cb1db004a..00c4cda4ca21195c4fbfeb47f92e197be18aa4c6 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -315,8 +315,10 @@ public class PurpurWorldConfig { - } - - public boolean dispenserApplyCursedArmor = true; -+ public boolean dispenserPlaceAnvils = false; - private void dispenserSettings() { - dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor); -+ dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils); - } - - public boolean farmlandGetsMoistFromBelow = false; diff --git a/patches/server/0078-Allow-anvil-colors.patch b/patches/server/0078-Allow-anvil-colors.patch deleted file mode 100644 index cdcf19f9a..000000000 --- a/patches/server/0078-Allow-anvil-colors.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 4 Aug 2020 22:08:23 -0500 -Subject: [PATCH] Allow anvil colors - - -diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index 9036426256f87b3ba4a78e6fa2cea4e028f84481..5cadd69bcae33b1de58806fcf40533850d976154 100644 ---- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -@@ -279,6 +279,54 @@ public class AnvilMenu extends ItemCombinerMenu { - if (!this.itemName.equals(itemstack.getHoverName().getString())) { - b0 = 1; - i += b0; -+ // Purpur start -+ if (this.player != null) { -+ org.bukkit.craftbukkit.entity.CraftHumanEntity player = this.player.getBukkitEntity(); -+ String name = this.itemName; -+ boolean removeItalics = false; -+ if (player.hasPermission("purpur.anvil.remove_italics")) { -+ if (name.startsWith("&r")) { -+ name = name.substring(2); -+ removeItalics = true; -+ } else if (name.startsWith("")) { -+ name = name.substring(3); -+ removeItalics = true; -+ } else if (name.startsWith("")) { -+ name = name.substring(7); -+ removeItalics = true; -+ } -+ } -+ if (this.player.level().purpurConfig.anvilAllowColors) { -+ if (player.hasPermission("purpur.anvil.color")) { -+ java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("(?i)&([0-9a-fr])").matcher(name); -+ while (matcher.find()) { -+ String match = matcher.group(1); -+ name = name.replace("&" + match, "\u00a7" + match.toLowerCase(java.util.Locale.ROOT)); -+ } -+ //name = name.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1"); -+ } -+ if (player.hasPermission("purpur.anvil.format")) { -+ java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("(?i)&([k-or])").matcher(name); -+ while (matcher.find()) { -+ String match = matcher.group(1); -+ name = name.replace("&" + match, "\u00a7" + match.toLowerCase(java.util.Locale.ROOT)); -+ } -+ //name = name.replaceAll("(?i)&([l-or])", "\u00a7$1"); -+ } -+ } -+ net.kyori.adventure.text.Component component; -+ if (this.player.level().purpurConfig.anvilColorsUseMiniMessage && player.hasPermission("purpur.anvil.minimessage")) { -+ component = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.bukkit.ChatColor.stripColor(name)); -+ } else { -+ component = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(name); -+ } -+ if (removeItalics) { -+ component = component.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); -+ } -+ itemstack1.set(DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(component)); -+ } -+ else -+ // Purpur end - itemstack1.set(DataComponents.CUSTOM_NAME, Component.literal(this.itemName)); - } - } else if (itemstack.has(DataComponents.CUSTOM_NAME)) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 00c4cda4ca21195c4fbfeb47f92e197be18aa4c6..4c80796777c5a90c5e7a9e8ef0beedfcb49f0aa9 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -293,6 +293,13 @@ public class PurpurWorldConfig { - }); - } - -+ public boolean anvilAllowColors = false; -+ public boolean anvilColorsUseMiniMessage; -+ private void anvilSettings() { -+ anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors); -+ anvilColorsUseMiniMessage = getBoolean("blocks.anvil.use-mini-message", anvilColorsUseMiniMessage); -+ } -+ - public boolean bedExplode = true; - public double bedExplosionPower = 5.0D; - public boolean bedExplosionFire = true; diff --git a/patches/server/0079-Add-option-to-disable-dolphin-treasure-searching.patch b/patches/server/0079-Add-option-to-disable-dolphin-treasure-searching.patch deleted file mode 100644 index 23dbd04de..000000000 --- a/patches/server/0079-Add-option-to-disable-dolphin-treasure-searching.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 8 Aug 2020 16:11:51 -0500 -Subject: [PATCH] Add option to disable dolphin treasure searching - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -index 4f294b3ecf061f34046b52bf2b6a3d0ff1ed347b..366d583926e7e33a8c1e5a803bb75a456b4838d0 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -@@ -471,6 +471,7 @@ public class Dolphin extends WaterAnimal { - - @Override - public boolean canUse() { -+ if (this.dolphin.level().purpurConfig.dolphinDisableTreasureSearching) return false; // Purpur - return this.dolphin.gotFish() && this.dolphin.getAirSupply() >= 100; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 4c80796777c5a90c5e7a9e8ef0beedfcb49f0aa9..b9faaf71e0cd5918b072d068bbc2096aa2805616 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -610,6 +610,7 @@ public class PurpurWorldConfig { - public float dolphinSpitSpeed = 1.0F; - public float dolphinSpitDamage = 2.0F; - public double dolphinMaxHealth = 10.0D; -+ public boolean dolphinDisableTreasureSearching = false; - private void dolphinSettings() { - dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); - dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable); -@@ -622,6 +623,7 @@ public class PurpurWorldConfig { - set("mobs.dolphin.attributes.max_health", oldValue); - } - dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth); -+ dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching); - } - - public boolean donkeyRidableInWater = false; diff --git a/patches/server/0080-Short-enderman-height.patch b/patches/server/0080-Short-enderman-height.patch deleted file mode 100644 index 8bad988ef..000000000 --- a/patches/server/0080-Short-enderman-height.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 10 Aug 2020 21:46:22 -0500 -Subject: [PATCH] Short enderman height - - -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index 9b3bf5ac043262c6cd00d83b750c3313122d92a9..3097529a9066841a58c899ce55b3bc0cd6af7e88 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -322,7 +322,8 @@ public class EntityType implements FeatureElement, EntityTypeT - private Component description; - @Nullable - private ResourceKey lootTable; -- private final EntityDimensions dimensions; -+ private EntityDimensions dimensions; // Purpur - remove final -+ public void setDimensions(EntityDimensions dimensions) { this.dimensions = dimensions; } // Purpur - private final float spawnDimensionsScale; - private final FeatureFlagSet requiredFeatures; - -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index 89275ac02fcfab963b520efae6135d6f5ac13465..cb307a9419399e33a895376a584456f084691965 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -419,6 +419,7 @@ public class EnderMan extends Monster implements NeutralMob { - if (this.isInvulnerableTo(source)) { - return false; - } else if (getRider() != null && this.isControllable()) { return super.hurt(source, amount); // Purpur - no teleporting on damage -+ } else if (org.purpurmc.purpur.PurpurConfig.endermanShortHeight && source.is(net.minecraft.world.damagesource.DamageTypes.IN_WALL)) { return false; // Purpur - no suffocation damage if short height - } else { - boolean flag = source.getDirectEntity() instanceof ThrownPotion; - boolean flag1; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 43f42895c745be0fb809db856083dbea5def5776..68b19f66b38ffecfa05aaa7ec1187fb0967ebd57 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -244,6 +244,12 @@ public class PurpurConfig { - enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); - } - -+ public static boolean endermanShortHeight = false; -+ private static void entitySettings() { -+ endermanShortHeight = getBoolean("settings.entity.enderman.short-height", endermanShortHeight); -+ if (endermanShortHeight) EntityType.ENDERMAN.setDimensions(EntityDimensions.scalable(0.6F, 1.9F)); -+ } -+ - public static boolean allowWaterPlacementInTheEnd = true; - private static void allowWaterPlacementInEnd() { - allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd); diff --git a/patches/server/0081-Stop-squids-floating-on-top-of-water.patch b/patches/server/0081-Stop-squids-floating-on-top-of-water.patch deleted file mode 100644 index 0ce118bf6..000000000 --- a/patches/server/0081-Stop-squids-floating-on-top-of-water.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 13 Aug 2020 04:00:26 -0500 -Subject: [PATCH] Stop squids floating on top of water - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index a99d04b820c230422bc82a3e0e094a79ab0c5c33..9a3796a69dd8745a498be5f2bb06c50355af44ce 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4511,6 +4511,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.yRotO = this.getYRot(); - } - -+ // Purpur start -+ public AABB getAxisForFluidCheck() { -+ return this.getBoundingBox().deflate(0.001D); -+ } -+ // Purpur end -+ - public boolean updateFluidHeightAndDoFluidPushing(TagKey tag, double speed) { - if (this.touchingUnloadedChunk()) { - return false; -diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index e38416189d9dc72f0b5951a1f6430dbc4578c422..c562eeb5e865a57fbc595de47c5d4e2b90430026 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Squid.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -73,6 +73,12 @@ public class Squid extends WaterAnimal { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.squidMaxHealth); - } - -+ @Override -+ public net.minecraft.world.phys.AABB getAxisForFluidCheck() { -+ // Stops squids from floating just over the water -+ return super.getAxisForFluidCheck().offsetY(level().purpurConfig.squidOffsetWaterCheck); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); -diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java -index 92394960fc76886f393cba02ac33c57739a4b383..494808b7bc2fb296b78e229ce138a937b7ac2c59 100644 ---- a/src/main/java/net/minecraft/world/phys/AABB.java -+++ b/src/main/java/net/minecraft/world/phys/AABB.java -@@ -502,4 +502,10 @@ public class AABB { - public static AABB ofSize(Vec3 center, double dx, double dy, double dz) { - return new AABB(center.x - dx / 2.0, center.y - dy / 2.0, center.z - dz / 2.0, center.x + dx / 2.0, center.y + dy / 2.0, center.z + dz / 2.0); - } -+ -+ // Purpur - tuinity added method -+ public final AABB offsetY(double dy) { -+ return new AABB(this.minX, this.minY + dy, this.minZ, this.maxX, this.maxY + dy, this.maxZ); -+ } -+ // Purpur - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b9faaf71e0cd5918b072d068bbc2096aa2805616..56f34c0a0f7bc94a90bb1db32f8e30a590a3b38c 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1478,6 +1478,7 @@ public class PurpurWorldConfig { - public boolean squidControllable = true; - public double squidMaxHealth = 10.0D; - public boolean squidImmuneToEAR = true; -+ public double squidOffsetWaterCheck = 0.0D; - private void squidSettings() { - squidRidable = getBoolean("mobs.squid.ridable", squidRidable); - squidControllable = getBoolean("mobs.squid.controllable", squidControllable); -@@ -1488,6 +1489,7 @@ public class PurpurWorldConfig { - } - squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth); - squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); -+ squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); - } - - public boolean spiderRidable = false; diff --git a/patches/server/0082-Crying-obsidian-valid-for-portal-frames.patch b/patches/server/0082-Crying-obsidian-valid-for-portal-frames.patch deleted file mode 100644 index f67874c24..000000000 --- a/patches/server/0082-Crying-obsidian-valid-for-portal-frames.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 17 Aug 2020 17:34:33 -0500 -Subject: [PATCH] Crying obsidian valid for portal frames - - -diff --git a/src/main/java/net/minecraft/world/level/portal/PortalShape.java b/src/main/java/net/minecraft/world/level/portal/PortalShape.java -index af24467ee37cfc06f692b3b02e68f6cfbaaa8d59..afe6b2170846273b41b694aa53dca4c31bf78b3f 100644 ---- a/src/main/java/net/minecraft/world/level/portal/PortalShape.java -+++ b/src/main/java/net/minecraft/world/level/portal/PortalShape.java -@@ -33,7 +33,7 @@ public class PortalShape { - private static final int MIN_HEIGHT = 3; - public static final int MAX_HEIGHT = 21; - private static final BlockBehaviour.StatePredicate FRAME = (iblockdata, iblockaccess, blockposition) -> { -- return iblockdata.is(Blocks.OBSIDIAN); -+ return iblockdata.is(Blocks.OBSIDIAN) || (org.purpurmc.purpur.PurpurConfig.cryingObsidianValidForPortalFrame && iblockdata.is(Blocks.CRYING_OBSIDIAN)); // Purpur - }; - private static final float SAFE_TRAVEL_MAX_ENTITY_XY = 4.0F; - private static final double SAFE_TRAVEL_MAX_VERTICAL_DELTA = 1.0D; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 68b19f66b38ffecfa05aaa7ec1187fb0967ebd57..2f68cf2fc064a38ca059504a39d563d95d01643e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -212,6 +212,7 @@ public class PurpurConfig { - public static int barrelRows = 3; - public static boolean enderChestSixRows = false; - public static boolean enderChestPermissionRows = false; -+ public static boolean cryingObsidianValidForPortalFrame = false; - private static void blockSettings() { - if (version < 3) { - boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); -@@ -242,6 +243,7 @@ public class PurpurConfig { - enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows); - org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); - enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); -+ cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame); - } - - public static boolean endermanShortHeight = false; diff --git a/patches/server/0083-Entities-can-use-portals-configuration.patch b/patches/server/0083-Entities-can-use-portals-configuration.patch deleted file mode 100644 index 571526817..000000000 --- a/patches/server/0083-Entities-can-use-portals-configuration.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 17 Aug 2020 19:32:05 -0500 -Subject: [PATCH] Entities can use portals configuration - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 9a3796a69dd8745a498be5f2bb06c50355af44ce..a93ae9de698ce97e8603deb1075e6dc5aeaab274 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3220,7 +3220,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public void handleInsidePortal(BlockPos pos) { - if (this.isOnPortalCooldown()) { - this.setPortalCooldown(); -- } else { -+ } else if (level().purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer) { // Purpur - if (!this.level().isClientSide && !pos.equals(this.portalEntrancePos)) { - this.portalEntrancePos = pos.immutable(); - } -@@ -3914,7 +3914,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public boolean canChangeDimensions() { -- return !this.isPassenger() && !this.isVehicle() && isAlive() && valid; // Paper - Fix item duplication and teleport issues -+ return !this.isPassenger() && !this.isVehicle() && isAlive() && valid && (level().purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer); // Paper - Fix item duplication and teleport issues // Purpur - } - - public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 56f34c0a0f7bc94a90bb1db32f8e30a590a3b38c..1f25407aafba71762a482f0b1982302fed14387f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -98,6 +98,7 @@ public class PurpurWorldConfig { - public boolean useBetterMending = false; - public boolean boatEjectPlayersOnLand = false; - public boolean disableDropsOnCrammingDeath = false; -+ public boolean entitiesCanUsePortals = true; - public boolean milkCuresBadOmen = true; - public double tridentLoyaltyVoidReturnHeight = 0.0D; - public double voidDamageHeight = -64.0D; -@@ -106,6 +107,7 @@ public class PurpurWorldConfig { - useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); -+ entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); - voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); diff --git a/patches/server/0085-Customizable-wither-health-and-healing.patch b/patches/server/0085-Customizable-wither-health-and-healing.patch deleted file mode 100644 index 0ce62c319..000000000 --- a/patches/server/0085-Customizable-wither-health-and-healing.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Thu, 20 Aug 2020 17:38:12 -0700 -Subject: [PATCH] Customizable wither health and healing - -Adds the ability to customize the health of the wither, as well as the amount that it heals, and how often. - -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 0cc32342cf6c65466dd1e45f9097ca89b01036e4..8d2894bb1ae70f63c8fa67de3e9f7c6a9c940f3e 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -520,8 +520,10 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - } - } - -- if (this.tickCount % 20 == 0) { -- this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit -+ // Purpur start - customizable heal rate and amount -+ if (this.tickCount % level().purpurConfig.witherHealthRegenDelay == 0) { -+ this.heal(level().purpurConfig.witherHealthRegenAmount, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit -+ // Purpur end - } - - this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 1f25407aafba71762a482f0b1982302fed14387f..beea39d7cdbca783de7248a5c40ea2c7ab02e5b5 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1717,6 +1717,8 @@ public class PurpurWorldConfig { - public boolean witherControllable = true; - public double witherMaxY = 320D; - public double witherMaxHealth = 300.0D; -+ public float witherHealthRegenAmount = 1.0f; -+ public int witherHealthRegenDelay = 20; - private void witherSettings() { - witherRidable = getBoolean("mobs.wither.ridable", witherRidable); - witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); -@@ -1732,6 +1734,8 @@ public class PurpurWorldConfig { - set("mobs.wither.attributes.max_health", oldValue); - } - witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth); -+ witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount); -+ witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); - } - - public boolean witherSkeletonRidable = false; diff --git a/patches/server/0086-Allow-toggling-special-MobSpawners-per-world.patch b/patches/server/0086-Allow-toggling-special-MobSpawners-per-world.patch deleted file mode 100644 index a123bfffa..000000000 --- a/patches/server/0086-Allow-toggling-special-MobSpawners-per-world.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 22 Aug 2020 20:47:11 -0700 -Subject: [PATCH] Allow toggling special MobSpawners per world - -In vanilla, these are all hardcoded on for world type 0 (overworld) and hardcoded off for every other world type. Default config behaviour matches this. - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index b02d9db8442b209a9df27e417be71b11d426878b..1c74802577e056b9023dcc2cbec5885d02fe2c92 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -714,7 +714,24 @@ public class ServerLevel extends Level implements WorldGenLevel { - this.dragonParts = new Int2ObjectOpenHashMap(); - this.tickTime = flag1; - this.server = minecraftserver; -- this.customSpawners = list; -+ // Purpur start - enable/disable MobSpawners per world -+ this.customSpawners = Lists.newArrayList(); -+ if (purpurConfig.phantomSpawning) { -+ customSpawners.add(new net.minecraft.world.level.levelgen.PhantomSpawner()); -+ } -+ if (purpurConfig.patrolSpawning) { -+ customSpawners.add(new net.minecraft.world.level.levelgen.PatrolSpawner()); -+ } -+ if (purpurConfig.catSpawning) { -+ customSpawners.add(new net.minecraft.world.entity.npc.CatSpawner()); -+ } -+ if (purpurConfig.villageSiegeSpawning) { -+ customSpawners.add(new net.minecraft.world.entity.ai.village.VillageSiege()); -+ } -+ if (purpurConfig.villagerTraderSpawning) { -+ customSpawners.add(new net.minecraft.world.entity.npc.WanderingTraderSpawner(iworlddataserver)); -+ } -+ // Purpur end - this.serverLevelData = iworlddataserver; - ChunkGenerator chunkgenerator = worlddimension.generator(); - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -index c72b6ea5530e54fc373c701028e1c147cea34b59..96e9fce5f9084737d2fcf4deb83305733b480179 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -@@ -160,7 +160,17 @@ public class WanderingTraderSpawner implements CustomSpawner { - int k = pos.getX() + this.random.nextInt(range * 2) - range; - int l = pos.getZ() + this.random.nextInt(range * 2) - range; - int i1 = world.getHeight(Heightmap.Types.WORLD_SURFACE, k, l); -- BlockPos blockposition2 = new BlockPos(k, i1, l); -+ // Purpur start - allow traders to spawn below nether roof -+ BlockPos.MutableBlockPos blockposition2 = new BlockPos.MutableBlockPos(k, i1, l); -+ if (world.dimensionType().hasCeiling()) { -+ do { -+ blockposition2.relative(net.minecraft.core.Direction.DOWN); -+ } while (!world.getBlockState(blockposition2).isAir()); -+ do { -+ blockposition2.relative(net.minecraft.core.Direction.DOWN); -+ } while (world.getBlockState(blockposition2).isAir() && blockposition2.getY() > 0); -+ } -+ // Purpur end - - if (spawnplacementtype.isSpawnPositionOk(world, blockposition2, EntityType.WANDERING_TRADER)) { - blockposition1 = blockposition2; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index beea39d7cdbca783de7248a5c40ea2c7ab02e5b5..ce5db64c233bac3800a715e66aada4740bdad95b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -69,6 +69,12 @@ public class PurpurWorldConfig { - return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path)); - } - -+ private boolean getBoolean(String path, Predicate predicate) { -+ String val = getString(path, "default").toLowerCase(); -+ Boolean bool = BooleanUtils.toBooleanObject(val, "true", "false", "default"); -+ return predicate.test(bool); -+ } -+ - private double getDouble(String path, double def) { - PurpurConfig.config.addDefault("world-settings.default." + path, def); - return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path)); -@@ -237,6 +243,21 @@ public class PurpurWorldConfig { - } - } - -+ public boolean catSpawning; -+ public boolean patrolSpawning; -+ public boolean phantomSpawning; -+ public boolean villagerTraderSpawning; -+ public boolean villageSiegeSpawning; -+ private void mobSpawnerSettings() { -+ // values of "default" or null will default to true only if the world environment is normal (aka overworld) -+ Predicate predicate = (bool) -> (bool != null && bool) || (bool == null && environment == World.Environment.NORMAL); -+ catSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-cats", predicate); -+ patrolSpawning = getBoolean("gameplay-mechanics.mob-spawning.raid-patrols", predicate); -+ phantomSpawning = getBoolean("gameplay-mechanics.mob-spawning.phantoms", predicate); -+ villagerTraderSpawning = getBoolean("gameplay-mechanics.mob-spawning.wandering-traders", predicate); -+ villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate); -+ } -+ - public boolean idleTimeoutKick = true; - public boolean idleTimeoutTickNearbyEntities = true; - public boolean idleTimeoutCountAsSleeping = false; diff --git a/patches/server/0087-Raid-cooldown-setting.patch b/patches/server/0087-Raid-cooldown-setting.patch deleted file mode 100644 index 439cbff14..000000000 --- a/patches/server/0087-Raid-cooldown-setting.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Thu, 27 Aug 2020 13:48:52 -0700 -Subject: [PATCH] Raid cooldown setting - - -diff --git a/src/main/java/net/minecraft/world/entity/raid/Raids.java b/src/main/java/net/minecraft/world/entity/raid/Raids.java -index 8c60f71270d909c10e6617eb64b8fdb42deb73e9..eedce2a3d67d875d5174ee125e2679480d4d412c 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raids.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raids.java -@@ -26,6 +26,7 @@ import net.minecraft.world.phys.Vec3; - public class Raids extends SavedData { - - private static final String RAID_FILE_ID = "raids"; -+ public final Map playerCooldowns = Maps.newHashMap(); - public final Map raidMap = Maps.newHashMap(); - private final ServerLevel level; - private int nextAvailableID; -@@ -51,6 +52,17 @@ public class Raids extends SavedData { - - public void tick() { - ++this.tick; -+ // Purpur start -+ if (level.purpurConfig.raidCooldownSeconds != 0 && this.tick % 20 == 0) { -+ com.google.common.collect.ImmutableMap.copyOf(playerCooldowns).forEach((uuid, i) -> { -+ if (i < 1) { -+ playerCooldowns.remove(uuid); -+ } else { -+ playerCooldowns.put(uuid, i - 1); -+ } -+ }); -+ } -+ // Purpur end - Iterator iterator = this.raidMap.values().iterator(); - - while (iterator.hasNext()) { -@@ -122,11 +134,13 @@ public class Raids extends SavedData { - */ - - if (!raid.isStarted() || (raid.isInProgress() && raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel())) { // CraftBukkit - fixed a bug with raid: players could add up Bad Omen level even when the raid had finished -+ if (level.purpurConfig.raidCooldownSeconds != 0 && playerCooldowns.containsKey(player.getUUID())) return null; // Purpur - // CraftBukkit start - if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(raid, player)) { - player.removeEffect(net.minecraft.world.effect.MobEffects.RAID_OMEN); - return null; - } -+ if (level.purpurConfig.raidCooldownSeconds != 0) playerCooldowns.put(player.getUUID(), level.purpurConfig.raidCooldownSeconds); // Purpur - - if (!raid.isStarted() && !this.raidMap.containsKey(raid.getId())) { - this.raidMap.put(raid.getId(), raid); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ce5db64c233bac3800a715e66aada4740bdad95b..9654023afbb0569d5d814368b93b74dedda905a4 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -109,6 +109,7 @@ public class PurpurWorldConfig { - public double tridentLoyaltyVoidReturnHeight = 0.0D; - public double voidDamageHeight = -64.0D; - public double voidDamageDealt = 4.0D; -+ public int raidCooldownSeconds = 0; - private void miscGameplayMechanicsSettings() { - useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); -@@ -118,6 +119,7 @@ public class PurpurWorldConfig { - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); - voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); - voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); -+ raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); - } - - public int elytraDamagePerSecond = 1; diff --git a/patches/server/0088-Despawn-rate-config-options-per-projectile-type.patch b/patches/server/0088-Despawn-rate-config-options-per-projectile-type.patch deleted file mode 100644 index b197ba556..000000000 --- a/patches/server/0088-Despawn-rate-config-options-per-projectile-type.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Mon, 14 Sep 2020 10:09:05 -0700 -Subject: [PATCH] Despawn rate config options per projectile type - -This patch's implementation has been removed in favor of Pufferfish's entity-timeouts. -The config remains for migration purposes. - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 9654023afbb0569d5d814368b93b74dedda905a4..8a577d78d63adc799de71f96b45320372c346552 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -318,6 +318,40 @@ public class PurpurWorldConfig { - }); - } - -+ private static boolean projectileDespawnRateSettingsMigrated = false; -+ private void projectileDespawnRateSettings() { -+ if (PurpurConfig.version < 28 && !projectileDespawnRateSettingsMigrated) { -+ migrateProjectileDespawnRateSettings(EntityType.DRAGON_FIREBALL); -+ migrateProjectileDespawnRateSettings(EntityType.EGG); -+ migrateProjectileDespawnRateSettings(EntityType.ENDER_PEARL); -+ migrateProjectileDespawnRateSettings(EntityType.EXPERIENCE_BOTTLE); -+ migrateProjectileDespawnRateSettings(EntityType.FIREWORK_ROCKET); -+ migrateProjectileDespawnRateSettings(EntityType.FISHING_BOBBER); -+ migrateProjectileDespawnRateSettings(EntityType.FIREBALL); -+ migrateProjectileDespawnRateSettings(EntityType.LLAMA_SPIT); -+ migrateProjectileDespawnRateSettings(EntityType.POTION); -+ migrateProjectileDespawnRateSettings(EntityType.SHULKER_BULLET); -+ migrateProjectileDespawnRateSettings(EntityType.SMALL_FIREBALL); -+ migrateProjectileDespawnRateSettings(EntityType.SNOWBALL); -+ migrateProjectileDespawnRateSettings(EntityType.WITHER_SKULL); -+ //PufferfishConfig.save(); // TODO: Pufferfish -+ set("gameplay-mechanics.projectile-despawn-rates", null); -+ // pufferfish's entity_timeout is a global config -+ // we only want to migrate values from the -+ // default world (first world loaded) -+ projectileDespawnRateSettingsMigrated = true; -+ } -+ } -+ private void migrateProjectileDespawnRateSettings(EntityType type) { -+ // TODO: Pufferfish -+ //String pufferName = "entity_timeouts." + type.id.toUpperCase(Locale.ROOT); -+ //int value = getInt("gameplay-mechanics.projectile-despawn-rates." + type.id, -1); -+ //if (value != -1 && PufferfishConfig.getRawInt(pufferName, -1) == -1) { -+ // PufferfishConfig.setInt(pufferName, value); -+ // type.ttl = value; -+ //} -+ } -+ - public boolean anvilAllowColors = false; - public boolean anvilColorsUseMiniMessage; - private void anvilSettings() { diff --git a/patches/server/0089-Add-option-to-disable-zombie-aggressiveness-towards-.patch b/patches/server/0089-Add-option-to-disable-zombie-aggressiveness-towards-.patch deleted file mode 100644 index af48746e7..000000000 --- a/patches/server/0089-Add-option-to-disable-zombie-aggressiveness-towards-.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: nitricspace -Date: Mon, 21 Sep 2020 23:19:43 +0100 -Subject: [PATCH] Add option to disable zombie aggressiveness towards villagers - - -diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -index c72d6bccf7d72d08d388c65936a89c92261c7860..ee746753515c9cea8dd246f4f56e6781956726c1 100644 ---- a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -@@ -137,6 +137,10 @@ public class MobGoalHelper { - static { - // TODO these kinda should be checked on each release, in case obfuscation changes - deobfuscationMap.put("abstract_skeleton_1", "abstract_skeleton_melee"); -+ // Purpur start -+ deobfuscationMap.put("zombie_1", "zombie_attack_villager"); -+ deobfuscationMap.put("drowned_1", "drowned_attack_villager"); -+ // Purpur end - - ignored.add("goal_selector_1"); - ignored.add("goal_selector_2"); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -index 1d283484be270497859e23e3bb4ab38c09af23e6..b02cdbaa0455319b1e8a7e777e64ff4a56590388 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -@@ -123,7 +123,19 @@ public class Drowned extends Zombie implements RangedAttackMob { - this.goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0D)); - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Drowned.class})).setAlertOthers(ZombifiedPiglin.class)); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::okTarget)); -- if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Paper - Check drowned for villager aggression config -+ // Purpur start -+ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false) { // Paper - Check drowned for villager aggression config -+ @Override -+ public boolean canUse() { -+ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canUse(); -+ } -+ -+ @Override -+ public boolean canContinueToUse() { -+ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canContinueToUse(); -+ } -+ }); -+ // Purpur end - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Axolotl.class, true, false)); - this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index 555b86925b8d848fad40a838dd98607db8741e3b..3d42b2ea26217243dba96174ff0eadbcdd81a6cd 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -154,7 +154,19 @@ public class Zombie extends Monster { - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D)); - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers(ZombifiedPiglin.class)); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); -- if ( this.level().spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Spigot -+ // Purpur start -+ if ( this.level().spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false) { // Spigot -+ @Override -+ public boolean canUse() { -+ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canUse(); -+ } -+ -+ @Override -+ public boolean canContinueToUse() { -+ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canContinueToUse(); -+ } -+ }); -+ // Purpur end - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); - this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 8a577d78d63adc799de71f96b45320372c346552..69c433dd27be4a67052d73620c80d48ed6566034 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1851,6 +1851,7 @@ public class PurpurWorldConfig { - public boolean zombieJockeyOnlyBaby = true; - public double zombieJockeyChance = 0.05D; - public boolean zombieJockeyTryExistingChickens = true; -+ public boolean zombieAggressiveTowardsVillagerWhenLagging = true; - private void zombieSettings() { - zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); - zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); -@@ -1865,6 +1866,7 @@ public class PurpurWorldConfig { - zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby); - zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); - zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); -+ zombieAggressiveTowardsVillagerWhenLagging = getBoolean("mobs.zombie.aggressive-towards-villager-when-lagging", zombieAggressiveTowardsVillagerWhenLagging); - } - - public boolean zombieHorseRidable = false; diff --git a/patches/server/0090-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch b/patches/server/0090-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch deleted file mode 100644 index 4358026f2..000000000 --- a/patches/server/0090-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Oct 2020 17:40:52 -0500 -Subject: [PATCH] Add predicate to recipe's ExactChoice ingredient - - -diff --git a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java -index e314f36951e9ac15c57137e24fce8c410373130a..21dfb8e91c5427ac12133de2c05d923d87adf5ba 100644 ---- a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java -+++ b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java -@@ -41,6 +41,7 @@ public final class Ingredient implements Predicate { - @Nullable - private IntList stackingIds; - public boolean exact; // CraftBukkit -+ public Predicate predicate; // Purpur - public static final Codec CODEC = Ingredient.codec(true); - public static final Codec CODEC_NONEMPTY = Ingredient.codec(false); - -@@ -72,6 +73,12 @@ public final class Ingredient implements Predicate { - } else if (this.isEmpty()) { - return itemstack.isEmpty(); - } else { -+ // Purpur start -+ if (predicate != null) { -+ return predicate.test(itemstack.asBukkitCopy()); -+ } -+ // Purpur end -+ - ItemStack[] aitemstack = this.getItems(); - int i = aitemstack.length; - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java -index 6ba29875d78ede4aa7978ff689e588f7fed11528..4afec4387971612f62b825e9e56c2ead7424a7c2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java -@@ -29,6 +29,7 @@ public interface CraftRecipe extends Recipe { - } else if (bukkit instanceof RecipeChoice.ExactChoice) { - stack = new Ingredient(((RecipeChoice.ExactChoice) bukkit).getChoices().stream().map((mat) -> new net.minecraft.world.item.crafting.Ingredient.ItemValue(CraftItemStack.asNMSCopy(mat)))); - stack.exact = true; -+ stack.predicate = ((RecipeChoice.ExactChoice) bukkit).getPredicate(); // Purpur - } else { - throw new IllegalArgumentException("Unknown recipe stack instance " + bukkit); - } diff --git a/patches/server/0091-Flying-squids-Oh-my.patch b/patches/server/0091-Flying-squids-Oh-my.patch deleted file mode 100644 index b0907f34a..000000000 --- a/patches/server/0091-Flying-squids-Oh-my.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 4 Oct 2020 12:00:42 -0500 -Subject: [PATCH] Flying squids! Oh my! - - -diff --git a/src/main/java/net/minecraft/world/entity/GlowSquid.java b/src/main/java/net/minecraft/world/entity/GlowSquid.java -index 8211c152e6f4232e82e452b08047e4579465d770..4cd57672c548950cb4e0aa97af75ecca84be6823 100644 ---- a/src/main/java/net/minecraft/world/entity/GlowSquid.java -+++ b/src/main/java/net/minecraft/world/entity/GlowSquid.java -@@ -41,6 +41,11 @@ public class GlowSquid extends Squid { - this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.glowSquidMaxHealth); - } - -+ @Override -+ public boolean canFly() { -+ return this.level().purpurConfig.glowSquidsCanFly; -+ } -+ - @Override - protected ParticleOptions getInkParticle() { - return ParticleTypes.GLOW_SQUID_INK; -diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index c562eeb5e865a57fbc595de47c5d4e2b90430026..f0261117a4f8ae240b3b991053deaf8d6419b5b4 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Squid.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -79,6 +79,15 @@ public class Squid extends WaterAnimal { - return super.getAxisForFluidCheck().offsetY(level().purpurConfig.squidOffsetWaterCheck); - } - -+ public boolean canFly() { -+ return this.level().purpurConfig.squidsCanFly; -+ } -+ -+ @Override -+ public boolean isInWater() { -+ return this.wasTouchingWater || canFly(); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); -@@ -151,6 +160,7 @@ public class Squid extends WaterAnimal { - } - - if (this.isInWaterOrBubble()) { -+ if (canFly()) setNoGravity(!wasTouchingWater); // Purpur - if (this.tentacleMovement < (float) Math.PI) { - float f = this.tentacleMovement / (float) Math.PI; - this.tentacleAngle = Mth.sin(f * f * (float) Math.PI) * (float) Math.PI * 0.25F; -@@ -358,7 +368,7 @@ public class Squid extends WaterAnimal { - int i = this.squid.getNoActionTime(); - if (i > 100) { - this.squid.setMovementVector(0.0F, 0.0F, 0.0F); -- } else if (this.squid.getRandom().nextInt(reducedTickDelay(50)) == 0 || !this.squid.wasTouchingWater || !this.squid.hasMovementVector()) { -+ } else if (this.squid.getRandom().nextInt(reducedTickDelay(50)) == 0 || !this.squid.isInWater() || !this.squid.hasMovementVector()) { // Purpur - float f = this.squid.getRandom().nextFloat() * (float) (Math.PI * 2); - float g = Mth.cos(f) * 0.2F; - float h = -0.1F + this.squid.getRandom().nextFloat() * 0.2F; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 69c433dd27be4a67052d73620c80d48ed6566034..636f1a2962ee48a42a644b241569f08e7d57097c 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -903,10 +903,12 @@ public class PurpurWorldConfig { - public boolean glowSquidRidable = false; - public boolean glowSquidControllable = true; - public double glowSquidMaxHealth = 10.0D; -+ public boolean glowSquidsCanFly = false; - private void glowSquidSettings() { - glowSquidRidable = getBoolean("mobs.glow_squid.ridable", glowSquidRidable); - glowSquidControllable = getBoolean("mobs.glow_squid.controllable", glowSquidControllable); - glowSquidMaxHealth = getDouble("mobs.glow_squid.attributes.max_health", glowSquidMaxHealth); -+ glowSquidsCanFly = getBoolean("mobs.glow_squid.can-fly", glowSquidsCanFly); - } - - public boolean goatRidable = false; -@@ -1538,6 +1540,7 @@ public class PurpurWorldConfig { - public double squidMaxHealth = 10.0D; - public boolean squidImmuneToEAR = true; - public double squidOffsetWaterCheck = 0.0D; -+ public boolean squidsCanFly = false; - private void squidSettings() { - squidRidable = getBoolean("mobs.squid.ridable", squidRidable); - squidControllable = getBoolean("mobs.squid.controllable", squidControllable); -@@ -1549,6 +1552,7 @@ public class PurpurWorldConfig { - squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth); - squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); - squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); -+ squidsCanFly = getBoolean("mobs.squid.can-fly", squidsCanFly); - } - - public boolean spiderRidable = false; diff --git a/patches/server/0092-Infinity-bow-settings.patch b/patches/server/0092-Infinity-bow-settings.patch deleted file mode 100644 index 1349ffb70..000000000 --- a/patches/server/0092-Infinity-bow-settings.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 4 Oct 2020 19:08:53 -0500 -Subject: [PATCH] Infinity bow settings - - -diff --git a/src/main/java/net/minecraft/world/item/BowItem.java b/src/main/java/net/minecraft/world/item/BowItem.java -index 5ca843df5b4caa668953e5e36a9b20fabeb35046..abe6da2d70e8080461f70014757c1e1b5878bbf7 100644 ---- a/src/main/java/net/minecraft/world/item/BowItem.java -+++ b/src/main/java/net/minecraft/world/item/BowItem.java -@@ -81,7 +81,7 @@ public class BowItem extends ProjectileWeaponItem { - public InteractionResultHolder use(Level world, Player user, InteractionHand hand) { - ItemStack itemStack = user.getItemInHand(hand); - boolean bl = !user.getProjectile(itemStack).isEmpty(); -- if (!user.hasInfiniteMaterials() && !bl) { -+ if (!(world.purpurConfig.infinityWorksWithoutArrows && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, itemStack) > 0) && !user.hasInfiniteMaterials() && !bl) { // Purpur - return InteractionResultHolder.fail(itemStack); - } else { - user.startUsingItem(hand); -diff --git a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -index d27e83c08c45b8514207f26e48ceb1a91ded94be..d6d91de1639a180eb39bb85ac825e992c477d0f9 100644 ---- a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -+++ b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -@@ -135,7 +135,13 @@ public abstract class ProjectileWeaponItem extends Item { - } - - protected static boolean hasInfiniteArrows(ItemStack weaponStack, ItemStack projectileStack, boolean creative) { -- return creative || projectileStack.is(Items.ARROW) && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY, weaponStack) > 0; -+ // Purpur start -+ return hasInfiniteArrows(weaponStack, projectileStack, creative, null); -+ } -+ protected static boolean hasInfiniteArrows(ItemStack weaponStack, ItemStack projectileStack, boolean creative, @javax.annotation.Nullable Level level) { -+ boolean canBeInfinity = level == null ? projectileStack.is(Items.ARROW) : ((projectileStack.is(Items.ARROW) && level.purpurConfig.infinityWorksWithNormalArrows) || (projectileStack.is(Items.TIPPED_ARROW) && level.purpurConfig.infinityWorksWithTippedArrows) || (projectileStack.is(Items.SPECTRAL_ARROW) && level.purpurConfig.infinityWorksWithSpectralArrows)); -+ return creative || canBeInfinity && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY, weaponStack) > 0; -+ // Purpur end - } - - protected static List draw(ItemStack weaponStack, ItemStack projectileStack, LivingEntity shooter) { -@@ -161,7 +167,7 @@ public abstract class ProjectileWeaponItem extends Item { - } - - protected static ItemStack useAmmo(ItemStack weaponStack, ItemStack projectileStack, LivingEntity shooter, boolean multishot) { -- boolean flag1 = !multishot && !ProjectileWeaponItem.hasInfiniteArrows(weaponStack, projectileStack, shooter.hasInfiniteMaterials()); -+ boolean flag1 = !multishot && !ProjectileWeaponItem.hasInfiniteArrows(weaponStack, projectileStack, shooter.hasInfiniteMaterials(), shooter.level()); // Purpur - ItemStack itemstack2; - - if (!flag1) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 636f1a2962ee48a42a644b241569f08e7d57097c..b66182a7b52d16aac78b61cd9c077236a2abbe33 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -140,6 +140,17 @@ public class PurpurWorldConfig { - entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan); - } - -+ public boolean infinityWorksWithoutArrows = false; -+ public boolean infinityWorksWithNormalArrows = true; -+ public boolean infinityWorksWithSpectralArrows = false; -+ public boolean infinityWorksWithTippedArrows = false; -+ private void infinityArrowsSettings() { -+ infinityWorksWithoutArrows = getBoolean("gameplay-mechanics.infinity-bow.works-without-arrows", infinityWorksWithoutArrows); -+ infinityWorksWithNormalArrows = getBoolean("gameplay-mechanics.infinity-bow.normal-arrows", infinityWorksWithNormalArrows); -+ infinityWorksWithSpectralArrows = getBoolean("gameplay-mechanics.infinity-bow.spectral-arrows", infinityWorksWithSpectralArrows); -+ infinityWorksWithTippedArrows = getBoolean("gameplay-mechanics.infinity-bow.tipped-arrows", infinityWorksWithTippedArrows); -+ } -+ - public List itemImmuneToCactus = new ArrayList<>(); - public List itemImmuneToExplosion = new ArrayList<>(); - public List itemImmuneToFire = new ArrayList<>(); diff --git a/patches/server/0093-Configurable-daylight-cycle.patch b/patches/server/0093-Configurable-daylight-cycle.patch deleted file mode 100644 index c0d9a51e8..000000000 --- a/patches/server/0093-Configurable-daylight-cycle.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 10 Oct 2020 14:29:55 -0500 -Subject: [PATCH] Configurable daylight cycle - - -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTimePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTimePacket.java -index 76ef195a5074006b009acd9cc1744667c6aecbb9..659577549e132754281df76a7a1bfd884443c56a 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTimePacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTimePacket.java -@@ -10,7 +10,7 @@ public class ClientboundSetTimePacket implements Packet -Date: Mon, 19 Oct 2020 15:14:01 -0500 -Subject: [PATCH] Furnace uses lava from underneath - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -index a99fe191c429bb528209dd0f31b509acf9cccbb5..ce2c424068001eec16032361baa206f6a5aa5332 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -45,6 +45,7 @@ import net.minecraft.world.level.Level; - import net.minecraft.world.level.block.AbstractFurnaceBlock; - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.material.FluidState; - import net.minecraft.world.phys.Vec3; - // CraftBukkit start - import org.bukkit.craftbukkit.block.CraftBlock; -@@ -335,6 +336,21 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - } - - ItemStack itemstack = (ItemStack) blockEntity.items.get(1); -+ // Purpur start -+ boolean usedLavaFromUnderneath = false; -+ if (world.purpurConfig.furnaceUseLavaFromUnderneath && !blockEntity.isLit() && itemstack.isEmpty() && !blockEntity.items.get(0).isEmpty() && world.getGameTime() % 20 == 0) { -+ BlockPos below = blockEntity.getBlockPos().below(); -+ BlockState belowState = world.getBlockStateIfLoaded(below); -+ if (belowState != null && belowState.is(Blocks.LAVA)) { -+ FluidState fluidState = belowState.getFluidState(); -+ if (fluidState != null && fluidState.isSource()) { -+ world.setBlock(below, Blocks.AIR.defaultBlockState(), 3); -+ itemstack = Items.LAVA_BUCKET.getDefaultInstance(); -+ usedLavaFromUnderneath = true; -+ } -+ } -+ } -+ // Purpur end - boolean flag2 = !((ItemStack) blockEntity.items.get(0)).isEmpty(); - boolean flag3 = !itemstack.isEmpty(); - -@@ -420,6 +436,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - setChanged(world, pos, state); - } - -+ if (usedLavaFromUnderneath) blockEntity.items.set(1, ItemStack.EMPTY); // Purpur - } - - private static boolean canBurn(RegistryAccess registryManager, @Nullable RecipeHolder recipe, NonNullList slots, int count) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index d2ab4fe9ccb19f837a41bddddf29cfcc96fc3f96..163d2cfaeaa301c34f04ed13d8ff881ecb868224 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -410,6 +410,17 @@ public class PurpurWorldConfig { - farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); - } - -+ public boolean furnaceUseLavaFromUnderneath = false; -+ private void furnaceSettings() { -+ if (PurpurConfig.version < 17) { -+ furnaceUseLavaFromUnderneath = getBoolean("blocks.furnace.infinite-fuel", furnaceUseLavaFromUnderneath); -+ boolean oldValue = getBoolean("blocks.furnace.infinite-fuel", furnaceUseLavaFromUnderneath); -+ set("blocks.furnace.infinite-fuel", null); -+ set("blocks.furnace.use-lava-from-underneath", oldValue); -+ } -+ furnaceUseLavaFromUnderneath = getBoolean("blocks.furnace.use-lava-from-underneath", furnaceUseLavaFromUnderneath); -+ } -+ - public int lavaInfiniteRequiredSources = 2; - public int lavaSpeedNether = 10; - public int lavaSpeedNotNether = 30; diff --git a/patches/server/0096-Arrows-should-not-reset-despawn-counter.patch b/patches/server/0096-Arrows-should-not-reset-despawn-counter.patch deleted file mode 100644 index 6fe03557a..000000000 --- a/patches/server/0096-Arrows-should-not-reset-despawn-counter.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 4 Nov 2020 13:12:50 -0600 -Subject: [PATCH] Arrows should not reset despawn counter - -This prevents keeping arrows alive indefinitely (such as when the block -the arrow is stuck in gets removed, like a piston head going up/down) - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -index 31b8a8bf78d52b5f11b68e780ec09bf78e7bda84..342eaa0e3b053e9b39dc58fa92cd18cac446a844 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -332,7 +332,7 @@ public abstract class AbstractArrow extends Projectile { - Vec3 vec3d = this.getDeltaMovement(); - - this.setDeltaMovement(vec3d.multiply((double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F))); -- this.life = 0; -+ if (this.level().purpurConfig.arrowMovementResetsDespawnCounter) this.life = 0; // Purpur - do not reset despawn counter - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 163d2cfaeaa301c34f04ed13d8ff881ecb868224..5a49ea28eb227c6d550f3d7e589fb1e98fa2d285 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -101,6 +101,11 @@ public class PurpurWorldConfig { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); - } - -+ public boolean arrowMovementResetsDespawnCounter = true; -+ private void arrowSettings() { -+ arrowMovementResetsDespawnCounter = getBoolean("gameplay-mechanics.arrow.movement-resets-despawn-counter", arrowMovementResetsDespawnCounter); -+ } -+ - public boolean useBetterMending = false; - public boolean boatEjectPlayersOnLand = false; - public boolean disableDropsOnCrammingDeath = false; diff --git a/patches/server/0097-Ability-to-re-add-farmland-mechanics-from-Alpha.patch b/patches/server/0097-Ability-to-re-add-farmland-mechanics-from-Alpha.patch deleted file mode 100644 index a10dc92f4..000000000 --- a/patches/server/0097-Ability-to-re-add-farmland-mechanics-from-Alpha.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Yive -Date: Sat, 14 Nov 2020 08:06:20 -0800 -Subject: [PATCH] Ability to re-add farmland mechanics from Alpha - - -diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index da85fabd75e9bd5ebece7127ef5b512df16fe3ac..dc356bd0931af9bdab9ec71e3de66e88a67375ad 100644 ---- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -125,6 +125,14 @@ public class FarmBlock extends Block { - return; - } - -+ // Purpur start -+ if (world.purpurConfig.farmlandAlpha) { -+ Block block = world.getBlockState(pos.below()).getBlock(); -+ if (block instanceof FenceBlock || block instanceof WallBlock) { -+ return; -+ } -+ } -+ // Purpur end - if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.DIRT.defaultBlockState())) { - return; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 5a49ea28eb227c6d550f3d7e589fb1e98fa2d285..543c7679cf1ac50ff103be3366421d4faa542319 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -411,8 +411,10 @@ public class PurpurWorldConfig { - } - - public boolean farmlandGetsMoistFromBelow = false; -+ public boolean farmlandAlpha = false; - private void farmlandSettings() { - farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); -+ farmlandAlpha = getBoolean("blocks.farmland.use-alpha-farmland", farmlandAlpha); - } - - public boolean furnaceUseLavaFromUnderneath = false; diff --git a/patches/server/0098-Add-adjustable-breeding-cooldown-to-config.patch b/patches/server/0098-Add-adjustable-breeding-cooldown-to-config.patch deleted file mode 100644 index 50177cb6b..000000000 --- a/patches/server/0098-Add-adjustable-breeding-cooldown-to-config.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: montlikadani -Date: Fri, 13 Nov 2020 17:52:40 +0100 -Subject: [PATCH] Add adjustable breeding cooldown to config - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java -index 5193cf1d3c922d750a11e492b7636215e23ad0d6..b1f0fda942559b6d12c12a77088da6ce4a233963 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Animal.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java -@@ -146,7 +146,7 @@ public abstract class Animal extends AgeableMob { - if (this.isFood(itemstack)) { - int i = this.getAge(); - -- if (!this.level().isClientSide && i == 0 && this.canFallInLove()) { -+ if (!this.level().isClientSide && i == 0 && this.canFallInLove() && (this.level().purpurConfig.animalBreedingCooldownSeconds <= 0 || !this.level().hasBreedingCooldown(player.getUUID(), this.getClass()))) { // Purpur - final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying - this.usePlayerItem(player, hand, itemstack); - this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying -@@ -234,12 +234,20 @@ public abstract class Animal extends AgeableMob { - AgeableMob entityageable = this.getBreedOffspring(world, other); - - if (entityageable != null) { -- entityageable.setBaby(true); -- entityageable.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); -- // CraftBukkit start - call EntityBreedEvent -+ // Purpur start - ServerPlayer breeder = Optional.ofNullable(this.getLoveCause()).or(() -> { - return Optional.ofNullable(other.getLoveCause()); - }).orElse(null); -+ if (breeder != null && world.purpurConfig.animalBreedingCooldownSeconds > 0) { -+ if (world.hasBreedingCooldown(breeder.getUUID(), this.getClass())) { -+ return; -+ } -+ world.addBreedingCooldown(breeder.getUUID(), this.getClass()); -+ } -+ entityageable.setBaby(true); -+ entityageable.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); -+ // CraftBukkit start - call EntityBreedEvent -+ // Purpur end - int experience = this.getRandom().nextInt(7) + 1; - EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(entityageable, this, other, breeder, this.breedItem, experience); - if (entityBreedEvent.isCancelled()) { -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 2e44e9ea9558ebc1456d9bbf53561988e33ce845..edd9762e2475aa8828930ada59eb331a8e8d3970 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -188,6 +188,49 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - // Paper end - fix and optimise world upgrading - -+ // Purpur start -+ private com.google.common.cache.Cache playerBreedingCooldowns; -+ -+ private com.google.common.cache.Cache getNewBreedingCooldownCache() { -+ return com.google.common.cache.CacheBuilder.newBuilder().expireAfterWrite(this.purpurConfig.animalBreedingCooldownSeconds, java.util.concurrent.TimeUnit.SECONDS).build(); -+ } -+ -+ public void resetBreedingCooldowns() { -+ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); -+ } -+ -+ public boolean hasBreedingCooldown(java.util.UUID player, Class animalType) { // Purpur -+ return this.playerBreedingCooldowns.getIfPresent(new BreedingCooldownPair(player, animalType)) != null; -+ } -+ -+ public void addBreedingCooldown(java.util.UUID player, Class animalType) { -+ this.playerBreedingCooldowns.put(new BreedingCooldownPair(player, animalType), new Object()); -+ } -+ -+ private static final class BreedingCooldownPair { -+ private final java.util.UUID playerUUID; -+ private final Class animalType; -+ -+ public BreedingCooldownPair(java.util.UUID playerUUID, Class animalType) { -+ this.playerUUID = playerUUID; -+ this.animalType = animalType; -+ } -+ -+ @Override -+ public boolean equals(Object o) { -+ if (this == o) return true; -+ if (o == null || getClass() != o.getClass()) return false; -+ BreedingCooldownPair that = (BreedingCooldownPair) o; -+ return playerUUID.equals(that.playerUUID) && animalType.equals(that.animalType); -+ } -+ -+ @Override -+ public int hashCode() { -+ return java.util.Objects.hash(playerUUID, animalType); -+ } -+ } -+ // Purpur end -+ - public CraftWorld getWorld() { - return this.world; - } -@@ -218,6 +261,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot - this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config - this.purpurConfig = new org.purpurmc.purpur.PurpurWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName(), env); // Purpur -+ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur - this.generator = gen; - this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 543c7679cf1ac50ff103be3366421d4faa542319..37292c309b465fce3b601a3ff8400e58c5a74308 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -115,6 +115,7 @@ public class PurpurWorldConfig { - public double voidDamageHeight = -64.0D; - public double voidDamageDealt = 4.0D; - public int raidCooldownSeconds = 0; -+ public int animalBreedingCooldownSeconds = 0; - private void miscGameplayMechanicsSettings() { - useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); -@@ -125,6 +126,7 @@ public class PurpurWorldConfig { - voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); - voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); - raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); -+ animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds); - } - - public int daytimeTicks = 12000; -diff --git a/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java b/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java -index afdf04f8b22ad0b7c0b41675e44687b49c2f86d6..2621e54879e9ab0029a875f1d09eee67878b90d5 100644 ---- a/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java -+++ b/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java -@@ -49,6 +49,7 @@ public class PurpurCommand extends Command { - PurpurConfig.init((File) console.options.valueOf("purpur-settings")); - for (ServerLevel level : console.getAllLevels()) { - level.purpurConfig.init(); -+ level.resetBreedingCooldowns(); - } - console.server.reloadCount++; - diff --git a/patches/server/0099-Make-entity-breeding-times-configurable.patch b/patches/server/0099-Make-entity-breeding-times-configurable.patch deleted file mode 100644 index 5ef15b6c9..000000000 --- a/patches/server/0099-Make-entity-breeding-times-configurable.patch +++ /dev/null @@ -1,963 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sun, 15 Nov 2020 02:18:15 -0800 -Subject: [PATCH] Make entity breeding times configurable - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java -index 0a608418f87b71d5d71706712e1f82da0d7e4d34..03e7ca83e4c28dfaa5b52bcb100bd542db105970 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java -@@ -125,8 +125,10 @@ public class VillagerMakeLove extends Behavior { - return Optional.empty(); - } - // Move age setting down -- parent.setAge(6000); -- partner.setAge(6000); -+ // Purpur start -+ parent.setAge(world.purpurConfig.villagerBreedingTicks); -+ partner.setAge(world.purpurConfig.villagerBreedingTicks); -+ // Purpur end - world.addFreshEntityWithPassengers(entityvillager2, CreatureSpawnEvent.SpawnReason.BREEDING); - // CraftBukkit end - world.broadcastEntityEvent(entityvillager2, (byte) 12); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java -index b1f0fda942559b6d12c12a77088da6ce4a233963..7f90a0d8f65c96844df06b7c4fa3da28a6f51dd1 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Animal.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java -@@ -42,6 +42,7 @@ public abstract class Animal extends AgeableMob { - @Nullable - public UUID loveCause; - public ItemStack breedItem; // CraftBukkit - Add breedItem variable -+ public abstract int getPurpurBreedTime(); // Purpur - - protected Animal(EntityType type, Level world) { - super(type, world); -@@ -275,8 +276,10 @@ public abstract class Animal extends AgeableMob { - entityplayer.awardStat(Stats.ANIMALS_BRED); - CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer, this, entityanimal, entityageable); - } // Paper -- this.setAge(6000); -- entityanimal.setAge(6000); -+ // Purpur start -+ this.setAge(this.getPurpurBreedTime()); -+ entityanimal.setAge(entityanimal.getPurpurBreedTime()); -+ // Purpur end - this.resetLove(); - entityanimal.resetLove(); - worldserver.broadcastEntityEvent(this, (byte) 18); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index ae4b53f4cdd78368deb7d510be4936ffefce4d9c..cbcfe8177362d9b8af97f21e716a4dce9e227465 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -472,6 +472,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.beeMaxHealth); - } - -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.beeBreedingTicks; -+ } -+ - @Override - public int getRemainingPersistentAngerTime() { - return (Integer) this.entityData.get(Bee.DATA_REMAINING_ANGER_TIME); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 7930e9735abf8357df737798e80b08295c2e06ec..b23d6683bab3d257febb57a6c9c8be4db926af7f 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -134,6 +134,11 @@ public class Cat extends TamableAnimal implements VariantHolder { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.foxMaxHealth); - } - -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.foxBreedingTicks; -+ } -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -@@ -991,8 +996,10 @@ public class Fox extends Animal implements VariantHolder { - CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer2, this.animal, this.partner, entityfox); - } - -- this.animal.setAge(6000); -- this.partner.setAge(6000); -+ // Purpur start -+ this.animal.setAge(this.animal.getPurpurBreedTime()); -+ this.partner.setAge(this.partner.getPurpurBreedTime()); -+ // Purpur end - this.animal.resetLove(); - this.partner.resetLove(); - worldserver.addFreshEntityWithPassengers(entityfox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason -diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index 41b52f128fbc174939a7f2d1cd937ab19432de25..22a2328fe5159c8fed635a62334a3f1028c346a5 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -86,6 +86,11 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder { - public void initAttributes() { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.rabbitMaxHealth); - } -+ -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.rabbitBreedingTicks; -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -index b68886cc72d3055e7745fe4a955192bbad90dc13..c3cc949291d11ae707fa5175d666df2ee81cdcce 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -139,6 +139,11 @@ public class Sheep extends Animal implements Shearable { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.sheepMaxHealth); - } - -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.sheepBreedingTicks; -+ } -+ - @Override - protected void registerGoals() { - this.eatBlockGoal = new EatBlockGoal(this); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index b8dcf3d632c79585ec7e9f50fa040fa9fac5d7c5..a577ec78b2f5bca0166277c499da4fa7988d5395 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -109,6 +109,11 @@ public class Turtle extends Animal { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.turtleMaxHealth); - } - -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.turtleBreedingTicks; -+ } -+ - public void setHomePos(BlockPos pos) { - this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos... - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -index 3235ed40d502722e888656776ba1a218f198f53e..2267f8da1c27ff54b2ced59ef15eb45357b7075d 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -@@ -151,6 +151,11 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder getModelRotationValues() { - return this.modelRotationValues; -diff --git a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -index 07a5599a9370ba167e985006d74caa3c80288e28..ed67fcd2b67bfe581863cc6748692c3348f6c883 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -+++ b/src/main/java/net/minecraft/world/entity/animal/camel/Camel.java -@@ -89,6 +89,10 @@ public class Camel extends AbstractHorse implements PlayerRideableJumping, Saddl - public boolean dismountsUnderwater() { - return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.camelRidableInWater; - } -+ -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.camelBreedingTicks; -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -index b6a4b4e66ca67e4dcb4b14a13ab6586a94e1b020..b0f8115b328eda1e3571051870b5310c5a7e115a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -@@ -162,6 +162,10 @@ public class Frog extends Animal implements VariantHolder> { - } - // Purpur end - -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.frogBreedingTicks; -+ } -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 9cd8220a1e5e43c141ad27df4969e66ef3746ecd..84c04603d50e190430e4e6cf2a7b613537a0c341 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -108,6 +108,11 @@ public class Goat extends Animal { - } - // Purpur end - -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.goatBreedingTicks; -+ } -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(Goat.MEMORY_TYPES, Goat.SENSOR_TYPES); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -index b47a72ffb8b947cea5d4bc6ee37b824c4161be31..2990d50fd5209b272e0cfbd5dd633124048e8129 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -@@ -37,6 +37,11 @@ public class Donkey extends AbstractChestedHorse { - return generateSpeed(this.level().purpurConfig.donkeyMovementSpeedMin, this.level().purpurConfig.donkeyMovementSpeedMax); - } - -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.donkeyBreedingTicks; -+ } -+ - @Override - protected SoundEvent getAmbientSound() { - return SoundEvents.DONKEY_AMBIENT; -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -index 9ad0d3972d1970b11687da174a83e3a0a4180c0e..16d4278d49dad84f72c968ca36914e93d46dc5f6 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -@@ -66,6 +66,11 @@ public class Horse extends AbstractHorse implements VariantHolder { - return generateSpeed(this.level().purpurConfig.horseMovementSpeedMin, this.level().purpurConfig.horseMovementSpeedMax); - } - -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.horseBreedingTicks; -+ } -+ - @Override - protected void randomizeAttributes(RandomSource random) { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)generateMaxHealth(random::nextInt)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 05614fb50a5509331ac15bb819e827365a4cefcf..81d614cf14512464b376575fd2d7e7fbf93d9e03 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -@@ -140,6 +140,11 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); - -diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index 3bfc073fb142e3446044a42c33be6c30587cc3c4..a770ae0e13c4dad296dfb8f33259408ee1531c70 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -112,6 +112,11 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.hoglinMaxHealth); - } - -+ @Override -+ public int getPurpurBreedTime() { -+ return this.level().purpurConfig.hoglinBreedingTicks; -+ } -+ - @Override - public boolean canBeLeashed(Player player) { - return !this.isLeashed(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 37292c309b465fce3b601a3ff8400e58c5a74308..8ba5fc8813ef1cb34f7df801f6d7b2ed42b1c052 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -502,10 +502,12 @@ public class PurpurWorldConfig { - public boolean axolotlRidable = false; - public boolean axolotlControllable = true; - public double axolotlMaxHealth = 14.0D; -+ public int axolotlBreedingTicks = 6000; - private void axolotlSettings() { - axolotlRidable = getBoolean("mobs.axolotl.ridable", axolotlRidable); - axolotlControllable = getBoolean("mobs.axolotl.controllable", axolotlControllable); - axolotlMaxHealth = getDouble("mobs.axolotl.attributes.max_health", axolotlMaxHealth); -+ axolotlBreedingTicks = getInt("mobs.axolotl.breeding-delay-ticks", axolotlBreedingTicks); - } - - public boolean batRidable = false; -@@ -545,6 +547,7 @@ public class PurpurWorldConfig { - public boolean beeControllable = true; - public double beeMaxY = 320D; - public double beeMaxHealth = 10.0D; -+ public int beeBreedingTicks = 6000; - private void beeSettings() { - beeRidable = getBoolean("mobs.bee.ridable", beeRidable); - beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); -@@ -556,6 +559,7 @@ public class PurpurWorldConfig { - set("mobs.bee.attributes.max_health", oldValue); - } - beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth); -+ beeBreedingTicks = getInt("mobs.bee.breeding-delay-ticks", beeBreedingTicks); - } - - public boolean blazeRidable = false; -@@ -583,6 +587,7 @@ public class PurpurWorldConfig { - public double camelJumpStrengthMax = 0.42D; - public double camelMovementSpeedMin = 0.09D; - public double camelMovementSpeedMax = 0.09D; -+ public int camelBreedingTicks = 6000; - private void camelSettings() { - camelRidableInWater = getBoolean("mobs.camel.ridable-in-water", camelRidableInWater); - camelMaxHealthMin = getDouble("mobs.camel.attributes.max_health.min", camelMaxHealthMin); -@@ -591,6 +596,7 @@ public class PurpurWorldConfig { - camelJumpStrengthMax = getDouble("mobs.camel.attributes.jump_strength.max", camelJumpStrengthMax); - camelMovementSpeedMin = getDouble("mobs.camel.attributes.movement_speed.min", camelMovementSpeedMin); - camelMovementSpeedMax = getDouble("mobs.camel.attributes.movement_speed.max", camelMovementSpeedMax); -+ camelBreedingTicks = getInt("mobs.camel.breeding-delay-ticks", camelBreedingTicks); - } - - public boolean catRidable = false; -@@ -600,6 +606,7 @@ public class PurpurWorldConfig { - public int catSpawnDelay = 1200; - public int catSpawnSwampHutScanRange = 16; - public int catSpawnVillageScanRange = 48; -+ public int catBreedingTicks = 6000; - private void catSettings() { - catRidable = getBoolean("mobs.cat.ridable", catRidable); - catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); -@@ -613,6 +620,7 @@ public class PurpurWorldConfig { - catSpawnDelay = getInt("mobs.cat.spawn-delay", catSpawnDelay); - catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange); - catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange); -+ catBreedingTicks = getInt("mobs.cat.breeding-delay-ticks", catBreedingTicks); - } - - public boolean caveSpiderRidable = false; -@@ -636,6 +644,7 @@ public class PurpurWorldConfig { - public boolean chickenControllable = true; - public double chickenMaxHealth = 4.0D; - public boolean chickenRetaliate = false; -+ public int chickenBreedingTicks = 6000; - private void chickenSettings() { - chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); - chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); -@@ -647,6 +656,7 @@ public class PurpurWorldConfig { - } - chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth); - chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); -+ chickenBreedingTicks = getInt("mobs.chicken.breeding-delay-ticks", chickenBreedingTicks); - } - - public boolean codRidable = false; -@@ -668,6 +678,7 @@ public class PurpurWorldConfig { - public boolean cowControllable = true; - public double cowMaxHealth = 10.0D; - public int cowFeedMushrooms = 0; -+ public int cowBreedingTicks = 6000; - private void cowSettings() { - cowRidable = getBoolean("mobs.cow.ridable", cowRidable); - cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); -@@ -679,6 +690,7 @@ public class PurpurWorldConfig { - } - cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth); - cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); -+ cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks); - } - - public boolean creeperRidable = false; -@@ -730,6 +742,7 @@ public class PurpurWorldConfig { - public double donkeyJumpStrengthMax = 0.5D; - public double donkeyMovementSpeedMin = 0.175D; - public double donkeyMovementSpeedMax = 0.175D; -+ public int donkeyBreedingTicks = 6000; - private void donkeySettings() { - donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); - if (PurpurConfig.version < 10) { -@@ -745,6 +758,7 @@ public class PurpurWorldConfig { - donkeyJumpStrengthMax = getDouble("mobs.donkey.attributes.jump_strength.max", donkeyJumpStrengthMax); - donkeyMovementSpeedMin = getDouble("mobs.donkey.attributes.movement_speed.min", donkeyMovementSpeedMin); - donkeyMovementSpeedMax = getDouble("mobs.donkey.attributes.movement_speed.max", donkeyMovementSpeedMax); -+ donkeyBreedingTicks = getInt("mobs.donkey.breeding-delay-ticks", donkeyBreedingTicks); - } - - public boolean drownedRidable = false; -@@ -864,6 +878,7 @@ public class PurpurWorldConfig { - public boolean foxControllable = true; - public double foxMaxHealth = 10.0D; - public boolean foxTypeChangesWithTulips = false; -+ public int foxBreedingTicks = 6000; - private void foxSettings() { - foxRidable = getBoolean("mobs.fox.ridable", foxRidable); - foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); -@@ -875,17 +890,20 @@ public class PurpurWorldConfig { - } - foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth); - foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); -+ foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks); - } - - public boolean frogRidable = false; - public boolean frogRidableInWater = true; - public boolean frogControllable = true; - public float frogRidableJumpHeight = 0.65F; -+ public int frogBreedingTicks = 6000; - private void frogSettings() { - frogRidable = getBoolean("mobs.frog.ridable", frogRidable); - frogRidableInWater = getBoolean("mobs.frog.ridable-in-water", frogRidableInWater); - frogControllable = getBoolean("mobs.frog.controllable", frogControllable); - frogRidableJumpHeight = (float) getDouble("mobs.frog.ridable-jump-height", frogRidableJumpHeight); -+ frogBreedingTicks = getInt("mobs.frog.breeding-delay-ticks", frogBreedingTicks); - } - - public boolean ghastRidable = false; -@@ -953,11 +971,13 @@ public class PurpurWorldConfig { - public boolean goatRidableInWater = true; - public boolean goatControllable = true; - public double goatMaxHealth = 10.0D; -+ public int goatBreedingTicks = 6000; - private void goatSettings() { - goatRidable = getBoolean("mobs.goat.ridable", goatRidable); - goatRidableInWater = getBoolean("mobs.goat.ridable-in-water", goatRidableInWater); - goatControllable = getBoolean("mobs.goat.controllable", goatControllable); - goatMaxHealth = getDouble("mobs.goat.attributes.max_health", goatMaxHealth); -+ goatBreedingTicks = getInt("mobs.goat.breeding-delay-ticks", goatBreedingTicks); - } - - public boolean guardianRidable = false; -@@ -978,6 +998,7 @@ public class PurpurWorldConfig { - public boolean hoglinRidableInWater = true; - public boolean hoglinControllable = true; - public double hoglinMaxHealth = 40.0D; -+ public int hoglinBreedingTicks = 6000; - private void hoglinSettings() { - hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); - hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); -@@ -988,6 +1009,7 @@ public class PurpurWorldConfig { - set("mobs.hoglin.attributes.max_health", oldValue); - } - hoglinMaxHealth = getDouble("mobs.hoglin.attributes.max_health", hoglinMaxHealth); -+ hoglinBreedingTicks = getInt("mobs.hoglin.breeding-delay-ticks", hoglinBreedingTicks); - } - - public boolean horseRidableInWater = false; -@@ -997,6 +1019,7 @@ public class PurpurWorldConfig { - public double horseJumpStrengthMax = 1.0D; - public double horseMovementSpeedMin = 0.1125D; - public double horseMovementSpeedMax = 0.3375D; -+ public int horseBreedingTicks = 6000; - private void horseSettings() { - horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); - if (PurpurConfig.version < 10) { -@@ -1012,6 +1035,7 @@ public class PurpurWorldConfig { - horseJumpStrengthMax = getDouble("mobs.horse.attributes.jump_strength.max", horseJumpStrengthMax); - horseMovementSpeedMin = getDouble("mobs.horse.attributes.movement_speed.min", horseMovementSpeedMin); - horseMovementSpeedMax = getDouble("mobs.horse.attributes.movement_speed.max", horseMovementSpeedMax); -+ horseBreedingTicks = getInt("mobs.horse.breeding-delay-ticks", horseBreedingTicks); - } - - public boolean huskRidable = false; -@@ -1089,6 +1113,7 @@ public class PurpurWorldConfig { - public double llamaJumpStrengthMax = 0.5D; - public double llamaMovementSpeedMin = 0.175D; - public double llamaMovementSpeedMax = 0.175D; -+ public int llamaBreedingTicks = 6000; - private void llamaSettings() { - llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); - llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); -@@ -1106,6 +1131,7 @@ public class PurpurWorldConfig { - llamaJumpStrengthMax = getDouble("mobs.llama.attributes.jump_strength.max", llamaJumpStrengthMax); - llamaMovementSpeedMin = getDouble("mobs.llama.attributes.movement_speed.min", llamaMovementSpeedMin); - llamaMovementSpeedMax = getDouble("mobs.llama.attributes.movement_speed.max", llamaMovementSpeedMax); -+ llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks); - } - - public boolean magmaCubeRidable = false; -@@ -1134,6 +1160,7 @@ public class PurpurWorldConfig { - public boolean mooshroomRidableInWater = true; - public boolean mooshroomControllable = true; - public double mooshroomMaxHealth = 10.0D; -+ public int mooshroomBreedingTicks = 6000; - private void mooshroomSettings() { - mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); - mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); -@@ -1144,6 +1171,7 @@ public class PurpurWorldConfig { - set("mobs.mooshroom.attributes.max_health", oldValue); - } - mooshroomMaxHealth = getDouble("mobs.mooshroom.attributes.max_health", mooshroomMaxHealth); -+ mooshroomBreedingTicks = getInt("mobs.mooshroom.breeding-delay-ticks", mooshroomBreedingTicks); - } - - public boolean muleRidableInWater = false; -@@ -1153,6 +1181,7 @@ public class PurpurWorldConfig { - public double muleJumpStrengthMax = 0.5D; - public double muleMovementSpeedMin = 0.175D; - public double muleMovementSpeedMax = 0.175D; -+ public int muleBreedingTicks = 6000; - private void muleSettings() { - muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); - if (PurpurConfig.version < 10) { -@@ -1168,12 +1197,14 @@ public class PurpurWorldConfig { - muleJumpStrengthMax = getDouble("mobs.mule.attributes.jump_strength.max", muleJumpStrengthMax); - muleMovementSpeedMin = getDouble("mobs.mule.attributes.movement_speed.min", muleMovementSpeedMin); - muleMovementSpeedMax = getDouble("mobs.mule.attributes.movement_speed.max", muleMovementSpeedMax); -+ muleBreedingTicks = getInt("mobs.mule.breeding-delay-ticks", muleBreedingTicks); - } - - public boolean ocelotRidable = false; - public boolean ocelotRidableInWater = true; - public boolean ocelotControllable = true; - public double ocelotMaxHealth = 10.0D; -+ public int ocelotBreedingTicks = 6000; - private void ocelotSettings() { - ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); - ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); -@@ -1184,12 +1215,14 @@ public class PurpurWorldConfig { - set("mobs.ocelot.attributes.max_health", oldValue); - } - ocelotMaxHealth = getDouble("mobs.ocelot.attributes.max_health", ocelotMaxHealth); -+ ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks); - } - - public boolean pandaRidable = false; - public boolean pandaRidableInWater = true; - public boolean pandaControllable = true; - public double pandaMaxHealth = 20.0D; -+ public int pandaBreedingTicks = 6000; - private void pandaSettings() { - pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); - pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); -@@ -1200,6 +1233,7 @@ public class PurpurWorldConfig { - set("mobs.panda.attributes.max_health", oldValue); - } - pandaMaxHealth = getDouble("mobs.panda.attributes.max_health", pandaMaxHealth); -+ pandaBreedingTicks = getInt("mobs.panda.breeding-delay-ticks", pandaBreedingTicks); - } - - public boolean parrotRidable = false; -@@ -1283,6 +1317,7 @@ public class PurpurWorldConfig { - public boolean pigControllable = true; - public double pigMaxHealth = 10.0D; - public boolean pigGiveSaddleBack = false; -+ public int pigBreedingTicks = 6000; - private void pigSettings() { - pigRidable = getBoolean("mobs.pig.ridable", pigRidable); - pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); -@@ -1294,6 +1329,7 @@ public class PurpurWorldConfig { - } - pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth); - pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); -+ pigBreedingTicks = getInt("mobs.pig.breeding-delay-ticks", pigBreedingTicks); - } - - public boolean piglinRidable = false; -@@ -1350,6 +1386,7 @@ public class PurpurWorldConfig { - public double polarBearMaxHealth = 30.0D; - public String polarBearBreedableItemString = ""; - public Item polarBearBreedableItem = null; -+ public int polarBearBreedingTicks = 6000; - private void polarBearSettings() { - polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); - polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); -@@ -1363,6 +1400,7 @@ public class PurpurWorldConfig { - polarBearBreedableItemString = getString("mobs.polar_bear.breedable-item", polarBearBreedableItemString); - Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(polarBearBreedableItemString)); - if (item != Items.AIR) polarBearBreedableItem = item; -+ polarBearBreedingTicks = getInt("mobs.polar_bear.breeding-delay-ticks", polarBearBreedingTicks); - } - - public boolean pufferfishRidable = false; -@@ -1385,6 +1423,7 @@ public class PurpurWorldConfig { - public double rabbitMaxHealth = 3.0D; - public double rabbitNaturalToast = 0.0D; - public double rabbitNaturalKiller = 0.0D; -+ public int rabbitBreedingTicks = 6000; - private void rabbitSettings() { - rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); - rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); -@@ -1397,6 +1436,7 @@ public class PurpurWorldConfig { - rabbitMaxHealth = getDouble("mobs.rabbit.attributes.max_health", rabbitMaxHealth); - rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); - rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); -+ rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks); - } - - public boolean ravagerRidable = false; -@@ -1433,6 +1473,7 @@ public class PurpurWorldConfig { - public boolean sheepRidableInWater = true; - public boolean sheepControllable = true; - public double sheepMaxHealth = 8.0D; -+ public int sheepBreedingTicks = 6000; - private void sheepSettings() { - sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); - sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); -@@ -1443,6 +1484,7 @@ public class PurpurWorldConfig { - set("mobs.sheep.attributes.max_health", oldValue); - } - sheepMaxHealth = getDouble("mobs.sheep.attributes.max_health", sheepMaxHealth); -+ sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks); - } - - public boolean shulkerRidable = false; -@@ -1566,11 +1608,13 @@ public class PurpurWorldConfig { - public boolean snifferRidableInWater = true; - public boolean snifferControllable = true; - public double snifferMaxHealth = 14.0D; -+ public int snifferBreedingTicks = 6000; - private void snifferSettings() { - snifferRidable = getBoolean("mobs.sniffer.ridable", snifferRidable); - snifferRidableInWater = getBoolean("mobs.sniffer.ridable-in-water", snifferRidableInWater); - snifferControllable = getBoolean("mobs.sniffer.controllable", snifferControllable); - snifferMaxHealth = getDouble("mobs.sniffer.attributes.max_health", snifferMaxHealth); -+ snifferBreedingTicks = getInt("mobs.sniffer.breeding-delay-ticks", chickenBreedingTicks); - } - - public boolean squidRidable = false; -@@ -1629,6 +1673,7 @@ public class PurpurWorldConfig { - public boolean striderRidableInWater = false; - public boolean striderControllable = true; - public double striderMaxHealth = 20.0D; -+ public int striderBreedingTicks = 6000; - private void striderSettings() { - striderRidable = getBoolean("mobs.strider.ridable", striderRidable); - striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); -@@ -1639,6 +1684,7 @@ public class PurpurWorldConfig { - set("mobs.strider.attributes.max_health", oldValue); - } - striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth); -+ striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks); - } - - public boolean tadpoleRidable = false; -@@ -1659,6 +1705,7 @@ public class PurpurWorldConfig { - public double traderLlamaJumpStrengthMax = 0.5D; - public double traderLlamaMovementSpeedMin = 0.175D; - public double traderLlamaMovementSpeedMax = 0.175D; -+ public int traderLlamaBreedingTicks = 6000; - private void traderLlamaSettings() { - traderLlamaRidable = getBoolean("mobs.trader_llama.ridable", traderLlamaRidable); - traderLlamaRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", traderLlamaRidableInWater); -@@ -1676,6 +1723,7 @@ public class PurpurWorldConfig { - traderLlamaJumpStrengthMax = getDouble("mobs.trader_llama.attributes.jump_strength.max", traderLlamaJumpStrengthMax); - traderLlamaMovementSpeedMin = getDouble("mobs.trader_llama.attributes.movement_speed.min", traderLlamaMovementSpeedMin); - traderLlamaMovementSpeedMax = getDouble("mobs.trader_llama.attributes.movement_speed.max", traderLlamaMovementSpeedMax); -+ traderLlamaBreedingTicks = getInt("mobs.trader_llama.breeding-delay-ticks", traderLlamaBreedingTicks); - } - - public boolean tropicalFishRidable = false; -@@ -1696,6 +1744,7 @@ public class PurpurWorldConfig { - public boolean turtleRidableInWater = true; - public boolean turtleControllable = true; - public double turtleMaxHealth = 30.0D; -+ public int turtleBreedingTicks = 6000; - private void turtleSettings() { - turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); - turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); -@@ -1706,6 +1755,7 @@ public class PurpurWorldConfig { - set("mobs.turtle.attributes.max_health", oldValue); - } - turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth); -+ turtleBreedingTicks = getInt("mobs.turtle.breeding-delay-ticks", turtleBreedingTicks); - } - - public boolean vexRidable = false; -@@ -1733,6 +1783,7 @@ public class PurpurWorldConfig { - public boolean villagerFollowEmeraldBlock = false; - public boolean villagerCanBeLeashed = false; - public boolean villagerCanBreed = true; -+ public int villagerBreedingTicks = 6000; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -1746,6 +1797,7 @@ public class PurpurWorldConfig { - villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); - villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed); - villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed); -+ villagerBreedingTicks = getInt("mobs.villager.breeding-delay-ticks", villagerBreedingTicks); - } - - public boolean vindicatorRidable = false; -@@ -1857,6 +1909,7 @@ public class PurpurWorldConfig { - public boolean wolfRidableInWater = true; - public boolean wolfControllable = true; - public double wolfMaxHealth = 8.0D; -+ public int wolfBreedingTicks = 6000; - private void wolfSettings() { - wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); - wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); -@@ -1867,6 +1920,7 @@ public class PurpurWorldConfig { - set("mobs.wolf.attributes.max_health", oldValue); - } - wolfMaxHealth = getDouble("mobs.wolf.attributes.max_health", wolfMaxHealth); -+ wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks); - } - - public boolean zoglinRidable = false; diff --git a/patches/server/0100-Apply-display-names-from-item-forms-of-entities-to-e.patch b/patches/server/0100-Apply-display-names-from-item-forms-of-entities-to-e.patch deleted file mode 100644 index f746e667a..000000000 --- a/patches/server/0100-Apply-display-names-from-item-forms-of-entities-to-e.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Tue, 17 Nov 2020 03:23:48 -0800 -Subject: [PATCH] Apply display names from item forms of entities to entities - and vice versa - - -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -index 5abbc0caf90cafc1a06dfff158c158b1538f827c..8b25bb80a913cd002cdaeadf076d811172f10488 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -613,6 +613,7 @@ public class ArmorStand extends LivingEntity { - private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(DamageSource damageSource) { // Paper - ItemStack itemstack = new ItemStack(Items.ARMOR_STAND); - -+ if (this.level().purpurConfig.persistentDroppableEntityDisplayNames) - itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); - this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior - return this.brokenByAnything(damageSource); // Paper -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -index da0d1c9a1c4ae081bff9ca4230c9a1503885c354..9af8fcf6abb9b768829592bc1b091ebe4599ed2e 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -@@ -262,7 +262,13 @@ public class ItemFrame extends HangingEntity { - } - - if (alwaysDrop) { -- this.spawnAtLocation(this.getFrameItemStack()); -+ // Purpur start -+ final ItemStack itemFrame = this.getFrameItemStack(); -+ if (!this.level().purpurConfig.persistentDroppableEntityDisplayNames) { -+ itemFrame.set(DataComponents.CUSTOM_NAME, null); -+ } -+ this.spawnAtLocation(itemFrame); -+ // Purpur end - } - - if (!itemstack.isEmpty()) { -diff --git a/src/main/java/net/minecraft/world/entity/decoration/Painting.java b/src/main/java/net/minecraft/world/entity/decoration/Painting.java -index 40e7112669abb58a0ab6df1846afec3979e95e55..183464f202d4c2774840edfde1dfcab44d05d0d3 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/Painting.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/Painting.java -@@ -151,7 +151,13 @@ public class Painting extends HangingEntity implements VariantHolder { - - @Override - public ItemStack getPickResult() { -- return new ItemStack(this.getDropItem()); -+ // Purpur start -+ final ItemStack boat = new ItemStack(this.getDropItem()); -+ if (!this.level().purpurConfig.persistentDroppableEntityDisplayNames) { -+ boat.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, null); -+ } -+ return boat; -+ // Purpur end - } - - public static enum Type implements StringRepresentable { -diff --git a/src/main/java/net/minecraft/world/item/ArmorStandItem.java b/src/main/java/net/minecraft/world/item/ArmorStandItem.java -index 1634a7d5ff06583408cf2f02f2b5f90931b1e02a..dfe8473a880cbddfc3ac6a9c97f1a500624eeb38 100644 ---- a/src/main/java/net/minecraft/world/item/ArmorStandItem.java -+++ b/src/main/java/net/minecraft/world/item/ArmorStandItem.java -@@ -58,6 +58,14 @@ public class ArmorStandItem extends Item { - return InteractionResult.FAIL; - } - // CraftBukkit end -+ // Purpur start -+ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) { -+ entityarmorstand.setCustomName(null); -+ } -+ if (world.purpurConfig.armorstandSetNameVisible) { -+ entityarmorstand.setCustomNameVisible(true); -+ } -+ // Purpur end - worldserver.addFreshEntityWithPassengers(entityarmorstand); - world.playSound((Player) null, entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F); - entityarmorstand.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer()); -diff --git a/src/main/java/net/minecraft/world/item/BoatItem.java b/src/main/java/net/minecraft/world/item/BoatItem.java -index eb74d45ad458b80cf8455297c3bc550186adaea3..ef01856c487e4ab982996e01537618233592ac32 100644 ---- a/src/main/java/net/minecraft/world/item/BoatItem.java -+++ b/src/main/java/net/minecraft/world/item/BoatItem.java -@@ -72,6 +72,11 @@ public class BoatItem extends Item { - - entityboat.setVariant(this.type); - entityboat.setYRot(user.getYRot()); -+ // Purpur start -+ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) { -+ entityboat.setCustomName(null); -+ } -+ // Purpur end - if (!world.noCollision(entityboat, entityboat.getBoundingBox())) { - return InteractionResultHolder.fail(itemstack); - } else { -diff --git a/src/main/java/net/minecraft/world/item/HangingEntityItem.java b/src/main/java/net/minecraft/world/item/HangingEntityItem.java -index 530167ce8e5bb72a418f8ec61411e38a5892fd72..35dc7546793dba34bf6debad3f214f61a8fb4f4e 100644 ---- a/src/main/java/net/minecraft/world/item/HangingEntityItem.java -+++ b/src/main/java/net/minecraft/world/item/HangingEntityItem.java -@@ -73,6 +73,11 @@ public class HangingEntityItem extends Item { - - if (!customdata.isEmpty()) { - EntityType.updateCustomEntityTag(world, entityhuman, (Entity) object, customdata); -+ // Purpur start -+ if (!world.purpurConfig.persistentDroppableEntityDisplayNames) { -+ ((Entity) object).setCustomName(null); -+ } -+ // Purpur end - } - - if (((HangingEntity) object).survives()) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 8ba5fc8813ef1cb34f7df801f6d7b2ed42b1c052..1f5cfaf07e0fd86a530b57fd0198ade2b1d0d999 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -97,8 +97,10 @@ public class PurpurWorldConfig { - } - - public float armorstandStepHeight = 0.0F; -+ public boolean armorstandSetNameVisible = true; - private void armorstandSettings() { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); -+ armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); - } - - public boolean arrowMovementResetsDespawnCounter = true; -@@ -111,6 +113,7 @@ public class PurpurWorldConfig { - public boolean disableDropsOnCrammingDeath = false; - public boolean entitiesCanUsePortals = true; - public boolean milkCuresBadOmen = true; -+ public boolean persistentDroppableEntityDisplayNames = true; - public double tridentLoyaltyVoidReturnHeight = 0.0D; - public double voidDamageHeight = -64.0D; - public double voidDamageDealt = 4.0D; -@@ -122,6 +125,7 @@ public class PurpurWorldConfig { - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); - entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); -+ persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); - voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); - voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); diff --git a/patches/server/0101-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch b/patches/server/0101-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch deleted file mode 100644 index aef93925b..000000000 --- a/patches/server/0101-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Tue, 17 Nov 2020 13:12:09 -0800 -Subject: [PATCH] Set name visible when using a Name Tag on an Armor Stand - - -diff --git a/src/main/java/net/minecraft/world/item/NameTagItem.java b/src/main/java/net/minecraft/world/item/NameTagItem.java -index 774c982f28b4f127fc3f036c19dfb47fb9ae3264..d49b60e7e643498b49c03593dc0da2f8e4459902 100644 ---- a/src/main/java/net/minecraft/world/item/NameTagItem.java -+++ b/src/main/java/net/minecraft/world/item/NameTagItem.java -@@ -23,6 +23,7 @@ public class NameTagItem extends Item { - if (!event.callEvent()) return InteractionResult.PASS; - LivingEntity newEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle(); - newEntity.setCustomName(event.getName() != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(event.getName()) : null); -+ if (user.level().purpurConfig.armorstandFixNametags && entity instanceof net.minecraft.world.entity.decoration.ArmorStand) entity.setCustomNameVisible(true); // Purpur - if (event.isPersistent() && newEntity instanceof Mob mob) { - // Paper end - Add PlayerNameEntityEvent - mob.setPersistenceRequired(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 1f5cfaf07e0fd86a530b57fd0198ade2b1d0d999..548ad445ed73c5009c93cadb0ee8e39acdbd737c 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -98,9 +98,11 @@ public class PurpurWorldConfig { - - public float armorstandStepHeight = 0.0F; - public boolean armorstandSetNameVisible = true; -+ public boolean armorstandFixNametags = false; - private void armorstandSettings() { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); - armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); -+ armorstandFixNametags = getBoolean("gameplay-mechanics.armorstand.fix-nametags", armorstandFixNametags); - } - - public boolean arrowMovementResetsDespawnCounter = true; diff --git a/patches/server/0102-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch b/patches/server/0102-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch deleted file mode 100644 index c83b3b0e5..000000000 --- a/patches/server/0102-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sun, 22 Nov 2020 22:17:53 -0800 -Subject: [PATCH] Add config for allowing Endermen to despawn even while - holding a block - -This should help to reduce the amount of dirt, gravel, grass, and etc. -that Endermen like to randomly place all over the world. - -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index cb307a9419399e33a895376a584456f084691965..052a0c168268b7e788953063f54c3769023f3c03 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -478,7 +478,7 @@ public class EnderMan extends Monster implements NeutralMob { - - @Override - public boolean requiresCustomPersistence() { -- return super.requiresCustomPersistence() || this.getCarriedBlock() != null; -+ return super.requiresCustomPersistence() || (!this.level().purpurConfig.endermanDespawnEvenWithBlock && this.getCarriedBlock() != null); // Purpur - } - - private static class EndermanFreezeWhenLookedAt extends Goal { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 548ad445ed73c5009c93cadb0ee8e39acdbd737c..2afd56fd352f7a0bd2028a2b9b238f3d1d8fe14a 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -834,6 +834,7 @@ public class PurpurWorldConfig { - public boolean endermanControllable = true; - public double endermanMaxHealth = 40.0D; - public boolean endermanAllowGriefing = true; -+ public boolean endermanDespawnEvenWithBlock = false; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -@@ -845,6 +846,7 @@ public class PurpurWorldConfig { - } - endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); - endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); -+ endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock); - } - - public boolean endermiteRidable = false; diff --git a/patches/server/0103-Add-configurable-snowball-damage.patch b/patches/server/0103-Add-configurable-snowball-damage.patch deleted file mode 100644 index 226d4c521..000000000 --- a/patches/server/0103-Add-configurable-snowball-damage.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 24 Nov 2020 05:32:02 -0600 -Subject: [PATCH] Add configurable snowball damage - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java -index 2b4d206c0d31ba38d7b2af654bd420e85145d441..f59a2903bfb8ae591a638ea5bb387caaa93ce664 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java -@@ -58,7 +58,7 @@ public class Snowball extends ThrowableItemProjectile { - protected void onHitEntity(EntityHitResult entityHitResult) { - super.onHitEntity(entityHitResult); - Entity entity = entityHitResult.getEntity(); -- int i = entity instanceof Blaze ? 3 : 0; -+ int i = entity.level().purpurConfig.snowballDamage >= 0 ? entity.level().purpurConfig.snowballDamage : entity instanceof Blaze ? 3 : 0; // Purpur - - entity.hurt(this.damageSources().thrown(this, this.getOwner()), (float) i); - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 2afd56fd352f7a0bd2028a2b9b238f3d1d8fe14a..f87abb5d0572b8d51c91dd90638e7a728c49a69a 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -383,6 +383,11 @@ public class PurpurWorldConfig { - //} - } - -+ public int snowballDamage = -1; -+ private void snowballSettings() { -+ snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); -+ } -+ - public boolean anvilAllowColors = false; - public boolean anvilColorsUseMiniMessage; - private void anvilSettings() { diff --git a/patches/server/0104-Changeable-Mob-Left-Handed-Chance.patch b/patches/server/0104-Changeable-Mob-Left-Handed-Chance.patch deleted file mode 100644 index 1fd4f031c..000000000 --- a/patches/server/0104-Changeable-Mob-Left-Handed-Chance.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Mon, 30 Nov 2020 11:40:11 -0500 -Subject: [PATCH] Changeable Mob Left Handed Chance - - -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index e7251ac940b49564c83b4b603e49c3990fc85db1..34d00acc43d2541307aa90a77a3c5d19a3057a94 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1438,7 +1438,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - RandomSource randomsource = world.getRandom(); - - this.getAttribute(Attributes.FOLLOW_RANGE).addPermanentModifier(new AttributeModifier("Random spawn bonus", randomsource.triangle(0.0D, 0.11485000000000001D), AttributeModifier.Operation.ADD_MULTIPLIED_BASE)); -- this.setLeftHanded(randomsource.nextFloat() < 0.05F); -+ this.setLeftHanded(randomsource.nextFloat() < world.getLevel().purpurConfig.entityLeftHandedChance); // Purpur - return entityData; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index f87abb5d0572b8d51c91dd90638e7a728c49a69a..4ac5d5469312b5f9e0203551baa085317189553b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -156,8 +156,10 @@ public class PurpurWorldConfig { - } - - public int entityLifeSpan = 0; -+ public float entityLeftHandedChance = 0.05f; - private void entitySettings() { - entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan); -+ entityLeftHandedChance = (float) getDouble("gameplay-mechanics.entity-left-handed-chance", entityLeftHandedChance); - } - - public boolean infinityWorksWithoutArrows = false; diff --git a/patches/server/0105-Add-boat-fall-damage-config.patch b/patches/server/0105-Add-boat-fall-damage-config.patch deleted file mode 100644 index 6282219c2..000000000 --- a/patches/server/0105-Add-boat-fall-damage-config.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 30 Nov 2020 19:36:35 -0600 -Subject: [PATCH] Add boat fall damage config - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 03b206289d103a36d19dcf3154f10ad98f976ba2..fe250c154aed8b10e33c6b916cabedb0dda3d5d6 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1189,7 +1189,16 @@ public class ServerPlayer extends Player { - if (this.isInvulnerableTo(source)) { - return false; - } else { -- if (source.is(DamageTypeTags.IS_FALL) && getRootVehicle() instanceof net.minecraft.world.entity.vehicle.AbstractMinecart && level().purpurConfig.minecartControllable && !level().purpurConfig.minecartControllableFallDamage) return false; // Purpur -+ // Purpur start -+ if (source.is(DamageTypeTags.IS_FALL)) { // Purpur -+ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.AbstractMinecart && level().purpurConfig.minecartControllable && !level().purpurConfig.minecartControllableFallDamage) { -+ return false; -+ } -+ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.Boat && !level().purpurConfig.boatsDoFallDamage) { -+ return false; -+ } -+ } -+ // Purpur end - boolean flag = this.server.isDedicatedServer() && this.isPvpAllowed() && source.is(DamageTypeTags.IS_FALL); - - if (!flag && this.spawnInvulnerableTime > 0 && !source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 4ac5d5469312b5f9e0203551baa085317189553b..8a0a018ff9119afe4ada2f30f98b260a523f2e70 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -112,6 +112,7 @@ public class PurpurWorldConfig { - - public boolean useBetterMending = false; - public boolean boatEjectPlayersOnLand = false; -+ public boolean boatsDoFallDamage = false; - public boolean disableDropsOnCrammingDeath = false; - public boolean entitiesCanUsePortals = true; - public boolean milkCuresBadOmen = true; -@@ -124,6 +125,7 @@ public class PurpurWorldConfig { - private void miscGameplayMechanicsSettings() { - useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); -+ boatsDoFallDamage = getBoolean("gameplay-mechanics.boat.do-fall-damage", boatsDoFallDamage); - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); - entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); diff --git a/patches/server/0106-Snow-Golem-rate-of-fire-config.patch b/patches/server/0106-Snow-Golem-rate-of-fire-config.patch deleted file mode 100644 index 2c258fc94..000000000 --- a/patches/server/0106-Snow-Golem-rate-of-fire-config.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Simon Gardling -Date: Tue, 1 Dec 2020 16:50:36 -0500 -Subject: [PATCH] Snow Golem rate of fire config - -The formula used to determine the amount of ticks between shots is: - ((sqrt(distanceToTarget) / snowGolemAttackDistance) / snowGolemSnowBallModifer) * (maxShootIntervalTicks - minShootIntervalTicks) + minShootIntervalTicks - -If min-shoot-interval-ticks and max-shoot-interval-ticks are both set to -0, snow golems won't shoot any snowballs. - -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index 0060414b1d5afde56372ce121e9d37a1668cd03b..ee4d4a4fe314ee9bce69c96dd65d84ed1ace0543 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -77,7 +77,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -- this.goalSelector.addGoal(1, new RangedAttackGoal(this, 1.25D, 20, 10.0F)); -+ this.goalSelector.addGoal(1, new RangedAttackGoal(this, level().purpurConfig.snowGolemAttackDistance, level().purpurConfig.snowGolemSnowBallMin, level().purpurConfig.snowGolemSnowBallMax, level().purpurConfig.snowGolemSnowBallModifier)); // Purpur - this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F)); - this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F)); - this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 8a0a018ff9119afe4ada2f30f98b260a523f2e70..51d9cdfce0cdcf2daa882fdcc75123c925396d10 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1607,6 +1607,10 @@ public class PurpurWorldConfig { - public boolean snowGolemLeaveTrailWhenRidden = false; - public double snowGolemMaxHealth = 4.0D; - public boolean snowGolemPutPumpkinBack = false; -+ public int snowGolemSnowBallMin = 20; -+ public int snowGolemSnowBallMax = 20; -+ public float snowGolemSnowBallModifier = 10.0F; -+ public double snowGolemAttackDistance = 1.25D; - private void snowGolemSettings() { - snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); - snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); -@@ -1619,6 +1623,10 @@ public class PurpurWorldConfig { - } - snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth); - snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack); -+ snowGolemSnowBallMin = getInt("mobs.snow_golem.min-shoot-interval-ticks", snowGolemSnowBallMin); -+ snowGolemSnowBallMax = getInt("mobs.snow_golem.max-shoot-interval-ticks", snowGolemSnowBallMax); -+ snowGolemSnowBallModifier = (float) getDouble("mobs.snow_golem.snow-ball-modifier", snowGolemSnowBallModifier); -+ snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance); - } - - public boolean snifferRidable = false; diff --git a/patches/server/0107-EMC-Configurable-disable-give-dropping.patch b/patches/server/0107-EMC-Configurable-disable-give-dropping.patch deleted file mode 100644 index 30a396354..000000000 --- a/patches/server/0107-EMC-Configurable-disable-give-dropping.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 14 Jan 2016 00:49:14 -0500 -Subject: [PATCH] EMC - Configurable disable give dropping - -Modified version of a patch by Aikar from EMC. Adds a config option in -purpur.yml to disable the /give command from dropping items on the -floor when a player's inventory is full. - -diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java -index 47355158e5e762540a10dc67b23092a0fc53bce3..9f1c8a62bda242781a0966fa2fc01534261423c7 100644 ---- a/src/main/java/net/minecraft/server/commands/GiveCommand.java -+++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java -@@ -92,6 +92,7 @@ public class GiveCommand { - boolean flag = entityplayer.getInventory().add(itemstack1); - ItemEntity entityitem; - -+ if (org.purpurmc.purpur.PurpurConfig.disableGiveCommandDrops) continue; // Purpur - add config option for toggling give command dropping - if (flag && itemstack1.isEmpty()) { - entityitem = entityplayer.drop(itemstack, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event - if (entityitem != null) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 6d621a93aaf94927fa6c73e649dcdb8bbbaadd2a..4d747759e2bfaebb02a875ff46159d0ae16acad6 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -209,6 +209,11 @@ public class PurpurConfig { - useAlternateKeepAlive = getBoolean("settings.use-alternate-keepalive", useAlternateKeepAlive); - } - -+ public static boolean disableGiveCommandDrops = false; -+ private static void disableGiveCommandDrops() { -+ disableGiveCommandDrops = getBoolean("settings.disable-give-dropping", disableGiveCommandDrops); -+ } -+ - public static int barrelRows = 3; - public static boolean enderChestSixRows = false; - public static boolean enderChestPermissionRows = false; diff --git a/patches/server/0108-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch b/patches/server/0108-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch deleted file mode 100644 index 527b784f4..000000000 --- a/patches/server/0108-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 5 Dec 2020 01:20:16 -0800 -Subject: [PATCH] Option for Villager Clerics to farm Nether Wart - -Adds an option so that Villagers with the Cleric profession are able to -farm Nether Wart. Reimplemented based on a feature of the carpet-extra -mod. - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -index 2ade08d1466660ee1787fa97908002ef56389712..4fa4ec34963730507253182cad1c2bf04090ad50 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -@@ -41,6 +41,7 @@ public class HarvestFarmland extends Behavior { - private long nextOkStartTime; - private int timeWorkedSoFar; - private final List validFarmlandAroundVillager = Lists.newArrayList(); -+ private boolean clericWartFarmer = false; // Purpur - - public HarvestFarmland() { - super(ImmutableMap.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT, MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT, MemoryModuleType.SECONDARY_JOB_SITE, MemoryStatus.VALUE_PRESENT)); -@@ -49,9 +50,10 @@ public class HarvestFarmland extends Behavior { - protected boolean checkExtraStartConditions(ServerLevel world, Villager entity) { - if (!world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { - return false; -- } else if (entity.getVillagerData().getProfession() != VillagerProfession.FARMER) { -+ } else if (entity.getVillagerData().getProfession() != VillagerProfession.FARMER && !(world.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC)) { // Purpur - return false; - } else { -+ if (!this.clericWartFarmer && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC) this.clericWartFarmer = true; // Purpur - BlockPos.MutableBlockPos blockposition_mutableblockposition = entity.blockPosition().mutable(); - - this.validFarmlandAroundVillager.clear(); -@@ -82,6 +84,7 @@ public class HarvestFarmland extends Behavior { - Block block = iblockdata.getBlock(); - Block block1 = world.getBlockState(pos.below()).getBlock(); - -+ if (this.clericWartFarmer) return block == Blocks.NETHER_WART && iblockdata.getValue(net.minecraft.world.level.block.NetherWartBlock.AGE) == 3 || iblockdata.isAir() && block1 == Blocks.SOUL_SAND; // Purpur - return block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata) || iblockdata.isAir() && block1 instanceof FarmBlock; - } - -@@ -107,20 +110,20 @@ public class HarvestFarmland extends Behavior { - Block block = iblockdata.getBlock(); - Block block1 = world.getBlockState(this.aboveFarmlandPos.below()).getBlock(); - -- if (block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata)) { -+ if (block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata) && !this.clericWartFarmer || this.clericWartFarmer && block == Blocks.NETHER_WART && iblockdata.getValue(net.minecraft.world.level.block.NetherWartBlock.AGE) == 3) { // Purpur - if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state - world.destroyBlock(this.aboveFarmlandPos, true, entity); - } // CraftBukkit - } - -- if (iblockdata.isAir() && block1 instanceof FarmBlock && entity.hasFarmSeeds()) { -+ if (iblockdata.isAir() && (block1 instanceof FarmBlock && !this.clericWartFarmer || this.clericWartFarmer && block1 == Blocks.SOUL_SAND) && entity.hasFarmSeeds()) { // Purpur - SimpleContainer inventorysubcontainer = entity.getInventory(); - - for (int j = 0; j < inventorysubcontainer.getContainerSize(); ++j) { - ItemStack itemstack = inventorysubcontainer.getItem(j); - boolean flag = false; - -- if (!itemstack.isEmpty() && itemstack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS)) { -+ if (!itemstack.isEmpty() && (itemstack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS) || this.clericWartFarmer && itemstack.getItem() == net.minecraft.world.item.Items.NETHER_WART)) { - Item item = itemstack.getItem(); - - if (item instanceof BlockItem) { -@@ -136,7 +139,7 @@ public class HarvestFarmland extends Behavior { - } - - if (flag) { -- world.playSound((Player) null, (double) this.aboveFarmlandPos.getX(), (double) this.aboveFarmlandPos.getY(), (double) this.aboveFarmlandPos.getZ(), SoundEvents.CROP_PLANTED, SoundSource.BLOCKS, 1.0F, 1.0F); -+ world.playSound((Player) null, (double) this.aboveFarmlandPos.getX(), (double) this.aboveFarmlandPos.getY(), (double) this.aboveFarmlandPos.getZ(), this.clericWartFarmer ? SoundEvents.NETHER_WART_PLANTED : SoundEvents.CROP_PLANTED, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - itemstack.shrink(1); - if (itemstack.isEmpty()) { - inventorysubcontainer.setItem(j, ItemStack.EMPTY); -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java b/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java -index 8508ac7de8cda3127b73e11ff4aee62502e65ead..b1544e028d5a9b84b944e1fb5a12bb163067fb54 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java -@@ -59,6 +59,12 @@ public class TradeWithVillager extends Behavior { - throwHalfStack(entity, ImmutableSet.of(Items.WHEAT), villager); - } - -+ // Purpur start -+ if (world.purpurConfig.villagerClericsFarmWarts && world.purpurConfig.villagerClericFarmersThrowWarts && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC && entity.getInventory().countItem(Items.NETHER_WART) > Items.NETHER_WART.getDefaultMaxStackSize() / 2) { -+ throwHalfStack(entity, ImmutableSet.of(Items.NETHER_WART), villager); -+ } -+ // Purpur end -+ - if (!this.trades.isEmpty() && entity.getInventory().hasAnyOf(this.trades)) { - throwHalfStack(entity, this.trades, villager); - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java -index f000a6c1e61198e6dd06ae5f084d12fdf309f50a..3091d985ba9c55d404332576320718840538722e 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java -@@ -52,8 +52,13 @@ public class VillagerGoalPackages { - } - - public static ImmutableList>> getWorkPackage(VillagerProfession profession, float speed) { -+ // Purpur start -+ return getWorkPackage(profession, speed, false); -+ } -+ public static ImmutableList>> getWorkPackage(VillagerProfession profession, float speed, boolean clericsFarmWarts) { -+ // Purpur end - WorkAtPoi workAtPoi; -- if (profession == VillagerProfession.FARMER) { -+ if (profession == VillagerProfession.FARMER || (clericsFarmWarts && profession == VillagerProfession.CLERIC)) { // Purpur - workAtPoi = new WorkAtComposter(); - } else { - workAtPoi = new WorkAtPoi(); -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java -index a0e0692d17760f440fe81d52887284c787e562db..ab9bebc07b5228dbc0d3ba4b0f7d1bbe41814c9b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java -@@ -22,6 +22,13 @@ public class SecondaryPoiSensor extends Sensor { - - @Override - protected void doTick(ServerLevel world, Villager entity) { -+ // Purpur start - make sure clerics don't wander to soul sand when the option is off -+ Brain brain = entity.getBrain(); -+ if (!world.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().getProfession() == net.minecraft.world.entity.npc.VillagerProfession.CLERIC) { -+ brain.eraseMemory(MemoryModuleType.SECONDARY_JOB_SITE); -+ return; -+ } -+ // Purpur end - ResourceKey resourceKey = world.dimension(); - BlockPos blockPos = entity.blockPosition(); - List list = Lists.newArrayList(); -@@ -38,7 +45,7 @@ public class SecondaryPoiSensor extends Sensor { - } - } - -- Brain brain = entity.getBrain(); -+ //Brain brain = entity.getBrain(); // Purpur - moved up - if (!list.isEmpty()) { - brain.setMemory(MemoryModuleType.SECONDARY_JOB_SITE, list); - } else { -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 6de74d992bd8b2845ab98d56201e7eeabd1dfc6b..f7d8f672a680cf2dfebba5677f97895e4a8c209f 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -223,7 +223,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - brain.addActivity(Activity.PLAY, VillagerGoalPackages.getPlayPackage(0.5F)); - } else { - brain.setSchedule(Schedule.VILLAGER_DEFAULT); -- brain.addActivityWithConditions(Activity.WORK, VillagerGoalPackages.getWorkPackage(villagerprofession, 0.5F), ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT))); -+ brain.addActivityWithConditions(Activity.WORK, VillagerGoalPackages.getWorkPackage(villagerprofession, 0.5F, this.level().purpurConfig.villagerClericsFarmWarts), ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT))); // Purpur - } - - brain.addActivity(Activity.CORE, VillagerGoalPackages.getCorePackage(villagerprofession, 0.5F)); -@@ -970,6 +970,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - - public boolean hasFarmSeeds() { - return this.getInventory().hasAnyMatching((itemstack) -> { -+ // Purpur start -+ if (this.level().purpurConfig.villagerClericsFarmWarts && this.getVillagerData().getProfession() == VillagerProfession.CLERIC) { -+ return itemstack.is(Items.NETHER_WART); -+ } -+ // Purpur end - return itemstack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS); - }); - } -diff --git a/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java b/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java -index 1316f4475802e17039800cc6128e1b065328beb7..d02e2d1aceac651e06a3a3698b7ac64dd30d4b12 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java -+++ b/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java -@@ -31,7 +31,7 @@ public record VillagerProfession( - public static final VillagerProfession ARMORER = register("armorer", PoiTypes.ARMORER, SoundEvents.VILLAGER_WORK_ARMORER); - public static final VillagerProfession BUTCHER = register("butcher", PoiTypes.BUTCHER, SoundEvents.VILLAGER_WORK_BUTCHER); - public static final VillagerProfession CARTOGRAPHER = register("cartographer", PoiTypes.CARTOGRAPHER, SoundEvents.VILLAGER_WORK_CARTOGRAPHER); -- public static final VillagerProfession CLERIC = register("cleric", PoiTypes.CLERIC, SoundEvents.VILLAGER_WORK_CLERIC); -+ public static final VillagerProfession CLERIC = register("cleric", PoiTypes.CLERIC, ImmutableSet.of(Items.NETHER_WART), ImmutableSet.of(Blocks.SOUL_SAND), SoundEvents.VILLAGER_WORK_CLERIC); // Purpur - public static final VillagerProfession FARMER = register( - "farmer", - PoiTypes.FARMER, -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 51d9cdfce0cdcf2daa882fdcc75123c925396d10..f20f4622871b840ba18a78bb0806028ba706f74e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1809,6 +1809,8 @@ public class PurpurWorldConfig { - public boolean villagerCanBeLeashed = false; - public boolean villagerCanBreed = true; - public int villagerBreedingTicks = 6000; -+ public boolean villagerClericsFarmWarts = false; -+ public boolean villagerClericFarmersThrowWarts = true; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -1823,6 +1825,8 @@ public class PurpurWorldConfig { - villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed); - villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed); - villagerBreedingTicks = getInt("mobs.villager.breeding-delay-ticks", villagerBreedingTicks); -+ villagerClericsFarmWarts = getBoolean("mobs.villager.clerics-farm-warts", villagerClericsFarmWarts); -+ villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts); - } - - public boolean vindicatorRidable = false; diff --git a/patches/server/0109-Toggle-for-Zombified-Piglin-death-always-counting-as.patch b/patches/server/0109-Toggle-for-Zombified-Piglin-death-always-counting-as.patch deleted file mode 100644 index 2f898ce18..000000000 --- a/patches/server/0109-Toggle-for-Zombified-Piglin-death-always-counting-as.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 5 Dec 2020 02:34:22 -0800 -Subject: [PATCH] Toggle for Zombified Piglin death always counting as player - kill when angry - -In Vanilla (as of 1.16.4), when Zombified Piglins die while angry, it will -count as a player kill regardless of whether a player has ever hit them, -meaning they will drop XP. This is abused in Zombified Piglin farms where -the player kills the entities through cramming, but they still drop XP due -to the Piglin being angry, even though the player never hit them. - -This patch adds a toggle to disable this behavior. - -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -index 75c34d9fcc4b33d30b18f1ce4c8749a068744abc..6be751e2d434982a35bbbece4f4fc4631fb3d8e0 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -146,7 +146,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - this.maybeAlertOthers(); - } - -- if (this.isAngry()) { -+ if (this.isAngry() && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur - this.lastHurtByPlayerTime = this.tickCount; - } - -@@ -201,7 +201,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - this.ticksUntilNextAlert = ZombifiedPiglin.ALERT_INTERVAL.sample(this.random); - } - -- if (entityliving instanceof Player) { -+ if (entityliving instanceof Player && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur - this.setLastHurtByPlayer((Player) entityliving); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index f20f4622871b840ba18a78bb0806028ba706f74e..d621f330f954a12635d8c87c5ff66dae7448a856 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2055,6 +2055,7 @@ public class PurpurWorldConfig { - public boolean zombifiedPiglinJockeyOnlyBaby = true; - public double zombifiedPiglinJockeyChance = 0.05D; - public boolean zombifiedPiglinJockeyTryExistingChickens = true; -+ public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = true; - private void zombifiedPiglinSettings() { - zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); - zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); -@@ -2069,5 +2070,6 @@ public class PurpurWorldConfig { - zombifiedPiglinJockeyOnlyBaby = getBoolean("mobs.zombified_piglin.jockey.only-babies", zombifiedPiglinJockeyOnlyBaby); - zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance); - zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); -+ zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry); - } - } diff --git a/patches/server/0110-Configurable-chance-for-wolves-to-spawn-rabid.patch b/patches/server/0110-Configurable-chance-for-wolves-to-spawn-rabid.patch deleted file mode 100644 index fe20c8c8d..000000000 --- a/patches/server/0110-Configurable-chance-for-wolves-to-spawn-rabid.patch +++ /dev/null @@ -1,214 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 8 Dec 2020 17:15:15 -0500 -Subject: [PATCH] Configurable chance for wolves to spawn rabid - -Configurable chance to spawn a wolf that is rabid. -Rabid wolves attack all players, mobs, and animals. - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -index 2267f8da1c27ff54b2ced59ef15eb45357b7075d..74ed226b5037f3258106f07384e14baf087be1c3 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -@@ -30,6 +30,8 @@ import net.minecraft.world.DifficultyInstance; - import net.minecraft.world.InteractionHand; - import net.minecraft.world.InteractionResult; - import net.minecraft.world.damagesource.DamageSource; -+import net.minecraft.world.effect.MobEffectInstance; -+import net.minecraft.world.effect.MobEffects; - import net.minecraft.world.entity.AgeableMob; - import net.minecraft.world.entity.Crackiness; - import net.minecraft.world.entity.Entity; -@@ -104,6 +106,37 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder RABID_PREDICATE = entity -> entity instanceof net.minecraft.server.level.ServerPlayer || entity instanceof Mob; -+ private final net.minecraft.world.entity.ai.goal.Goal PATHFINDER_VANILLA = new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR); -+ private final net.minecraft.world.entity.ai.goal.Goal PATHFINDER_RABID = new NonTameRandomTargetGoal<>(this, LivingEntity.class, false, RABID_PREDICATE); -+ private static final class AvoidRabidWolfGoal extends AvoidEntityGoal { -+ private final Wolf wolf; -+ -+ public AvoidRabidWolfGoal(Wolf wolf, float distance, double minSpeed, double maxSpeed) { -+ super(wolf, Wolf.class, distance, minSpeed, maxSpeed); -+ this.wolf = wolf; -+ } -+ -+ @Override -+ public boolean canUse() { -+ return super.canUse() && !this.wolf.isRabid() && this.toAvoid != null && this.toAvoid.isRabid(); // wolves which are not rabid run away from rabid wolves -+ } -+ -+ @Override -+ public void start() { -+ this.wolf.setTarget(null); -+ super.start(); -+ } -+ -+ @Override -+ public void tick() { -+ this.wolf.setTarget(null); -+ super.tick(); -+ } -+ } -+ // Purpur end - private static final float START_HEALTH = 8.0F; - private static final float TAME_HEALTH = 40.0F; - private static final float ARMOR_REPAIR_UNIT = 0.125F; -@@ -156,6 +189,30 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder(this, Llama.class, 24.0F, 1.5D, 1.5D)); -+ this.goalSelector.addGoal(3, new AvoidRabidWolfGoal(this, 24.0F, 1.5D, 1.5D)); // Purpur - this.goalSelector.addGoal(4, new LeapAtTargetGoal(this, 0.4F)); - this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0D, true)); - this.goalSelector.addGoal(6, new FollowOwnerGoal(this, 1.0D, 10.0F, 2.0F, false)); -@@ -176,7 +234,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder(this, Player.class, 10, true, false, this::isAngryAt)); -- this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, Wolf.PREY_SELECTOR)); -+ // this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, Wolf.PREY_SELECTOR)); // Purpur - moved to updatePathfinders() - this.targetSelector.addGoal(6, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR)); - this.targetSelector.addGoal(7, new NearestAttackableTargetGoal<>(this, AbstractSkeleton.class, false)); - this.targetSelector.addGoal(8, new ResetUniversalAngerTargetGoal<>(this, true)); -@@ -219,6 +277,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.wolfNaturalRabid; -+ this.updatePathfinders(false); -+ // Purpur end -+ - return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData); - } - -@@ -295,6 +364,11 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder -Date: Thu, 10 Dec 2020 13:43:28 -0500 -Subject: [PATCH] Configurable default collar color - -This allows for the server to set a default collar color when a wolf or cat is tamed. -Resets to RED when the value is invalid. - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index b23d6683bab3d257febb57a6c9c8be4db926af7f..27e448a38377ea3cc2e527dbe48a23d233f1ea13 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -357,6 +357,14 @@ public class Cat extends TamableAnimal implements VariantHolder -Date: Sat, 12 Dec 2020 09:10:59 -0600 -Subject: [PATCH] Phantom flames on swoop - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index 1ddccb9fa438682c2ebad7c071c7a4f8dd00b463..c15d75472d4d92baeb87a147832e17e363c360be 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -237,6 +237,7 @@ public class Phantom extends FlyingMob implements Enemy { - this.level().addParticle(ParticleTypes.MYCELIUM, this.getX() - (double) f3, this.getY() + (double) f5, this.getZ() - (double) f4, 0.0D, 0.0D, 0.0D); - } - -+ if (level().purpurConfig.phantomFlamesOnSwoop && attackPhase == AttackPhase.SWOOP) shoot(); // Purpur - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index d73268340e5201181f42084fbe47883a22d062cc..4fbd94117f356388a40d1a7f7faf75b08e6b7dbe 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1300,6 +1300,7 @@ public class PurpurWorldConfig { - public int phantomBurnInLight = 0; - public boolean phantomIgnorePlayersWithTorch = false; - public boolean phantomBurnInDaylight = true; -+ public boolean phantomFlamesOnSwoop = false; - private void phantomSettings() { - phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); - phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -@@ -1333,6 +1334,7 @@ public class PurpurWorldConfig { - phantomBurnInLight = getInt("mobs.phantom.burn-in-light", phantomBurnInLight); - phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight); - phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); -+ phantomFlamesOnSwoop = getBoolean("mobs.phantom.flames-on-swoop", phantomFlamesOnSwoop); - } - - public boolean pigRidable = false; diff --git a/patches/server/0113-Option-for-chests-to-open-even-with-a-solid-block-on.patch b/patches/server/0113-Option-for-chests-to-open-even-with-a-solid-block-on.patch deleted file mode 100644 index 5245fd9c2..000000000 --- a/patches/server/0113-Option-for-chests-to-open-even-with-a-solid-block-on.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 12 Dec 2020 14:34:18 -0800 -Subject: [PATCH] Option for chests to open even with a solid block on top - - -diff --git a/src/main/java/net/minecraft/world/level/block/ChestBlock.java b/src/main/java/net/minecraft/world/level/block/ChestBlock.java -index 8fbfd18b3caeed769396b3ffb1b1778b2f38edc0..dbfe8f5d4df244cb694b73ea8763628c5f2507a3 100644 ---- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ChestBlock.java -@@ -343,6 +343,7 @@ public class ChestBlock extends AbstractChestBlock implements - } - - public static boolean isBlockedChestByBlock(BlockGetter world, BlockPos pos) { -+ if (world instanceof Level && ((Level) world).purpurConfig.chestOpenWithBlockOnTop) return false; // Purpur - BlockPos blockposition1 = pos.above(); - - return world.getBlockState(blockposition1).isRedstoneConductor(world, blockposition1); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 4fbd94117f356388a40d1a7f7faf75b08e6b7dbe..50bf456b7e87a77e50b938488abde4cf577d1228 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -420,6 +420,11 @@ public class PurpurWorldConfig { - } - } - -+ public boolean chestOpenWithBlockOnTop = false; -+ private void chestSettings() { -+ chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); -+ } -+ - public boolean dispenserApplyCursedArmor = true; - public boolean dispenserPlaceAnvils = false; - private void dispenserSettings() { diff --git a/patches/server/0114-Implement-TPSBar.patch b/patches/server/0114-Implement-TPSBar.patch deleted file mode 100644 index 97533f4e8..000000000 --- a/patches/server/0114-Implement-TPSBar.patch +++ /dev/null @@ -1,467 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 12 Dec 2020 21:19:05 -0600 -Subject: [PATCH] Implement TPSBar - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 6af3e1e08048869ac28ab4a93e03d086872f866b..d0a81669ac20dc86e888aa34e246c251b8886ba2 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -255,6 +255,7 @@ public class Commands { - org.purpurmc.purpur.command.CreditsCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.DemoCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur -+ org.purpurmc.purpur.command.TPSBarCommand.register(this.dispatcher); // Purpur - } - - if (environment.includeIntegrated) { -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 6dd29845955b65e269a0487501330917effe7688..b68db217c8765fa029244bf2701757bd31a5db2b 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1060,6 +1060,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); -@@ -609,6 +610,7 @@ public class ServerPlayer extends Player { - }); - } - -+ if (nbt.contains("Purpur.TPSBar")) { this.tpsBar = nbt.getBoolean("Purpur.TPSBar"); } // Purpur - } - - @Override -@@ -685,6 +687,7 @@ public class ServerPlayer extends Player { - }); - } - -+ nbt.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur - } - - // CraftBukkit start - World fallback code, either respawn location or global spawn -@@ -2986,5 +2989,13 @@ public class ServerPlayer extends Player { - this.server.getPlayerList().respawn(this, toLevel, true, to, !toLevel.paperConfig().environment.disableTeleportationSuffocationCheck, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.DEATH); - } - } -+ -+ public boolean tpsBar() { -+ return this.tpsBar; -+ } -+ -+ public void tpsBar(boolean tpsBar) { -+ this.tpsBar = tpsBar; -+ } - // Purpur end - } -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 338808ba1138f62d89f3f1338a4c5068426df0e4..f2a7eba2618ea9c1acaf93c0ef8f6f5f737de6fe 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -486,6 +486,7 @@ public abstract class PlayerList { - scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam); - } - // Paper end - Configurable player collision -+ org.purpurmc.purpur.task.BossBarTask.addToAll(player); // Purpur - PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ()); - } - -@@ -597,6 +598,7 @@ public abstract class PlayerList { - } - public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer, net.kyori.adventure.text.Component leaveMessage) { - // Paper end - Fix kick event leave message not being sent -+ org.purpurmc.purpur.task.BossBarTask.removeFromAll(entityplayer.getBukkitEntity()); // Purpur - ServerLevel worldserver = entityplayer.serverLevel(); - - entityplayer.awardStat(Stats.LEAVE_GAME); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 4d747759e2bfaebb02a875ff46159d0ae16acad6..a4404782f0456a0bd05b385372ea920bd437eb35 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -182,6 +182,7 @@ public class PurpurConfig { - public static String creditsCommandOutput = "%s has been shown the end credits"; - public static String demoCommandOutput = "%s has been shown the demo screen"; - public static String pingCommandOutput = "%s's ping is %sms"; -+ public static String tpsbarCommandOutput = "Tpsbar toggled for "; - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); - afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); -@@ -192,6 +193,7 @@ public class PurpurConfig { - creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput); - demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput); - pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); -+ tpsbarCommandOutput = getString("settings.messages.tpsbar-command-output", tpsbarCommandOutput); - } - - public static String serverModName = "Purpur"; -@@ -214,6 +216,29 @@ public class PurpurConfig { - disableGiveCommandDrops = getBoolean("settings.disable-give-dropping", disableGiveCommandDrops); - } - -+ public static String commandTPSBarTitle = "TPS: MSPT: Ping: ms"; -+ public static BossBar.Overlay commandTPSBarProgressOverlay = BossBar.Overlay.NOTCHED_20; -+ public static TPSBarTask.FillMode commandTPSBarProgressFillMode = TPSBarTask.FillMode.MSPT; -+ public static BossBar.Color commandTPSBarProgressColorGood = BossBar.Color.GREEN; -+ public static BossBar.Color commandTPSBarProgressColorMedium = BossBar.Color.YELLOW; -+ public static BossBar.Color commandTPSBarProgressColorLow = BossBar.Color.RED; -+ public static String commandTPSBarTextColorGood = ""; -+ public static String commandTPSBarTextColorMedium = ""; -+ public static String commandTPSBarTextColorLow = ""; -+ public static int commandTPSBarTickInterval = 20; -+ private static void commandSettings() { -+ commandTPSBarTitle = getString("settings.command.tpsbar.title", commandTPSBarTitle); -+ commandTPSBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.tpsbar.overlay", commandTPSBarProgressOverlay.name())); -+ commandTPSBarProgressFillMode = TPSBarTask.FillMode.valueOf(getString("settings.command.tpsbar.fill-mode", commandTPSBarProgressFillMode.name())); -+ commandTPSBarProgressColorGood = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.good", commandTPSBarProgressColorGood.name())); -+ commandTPSBarProgressColorMedium = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.medium", commandTPSBarProgressColorMedium.name())); -+ commandTPSBarProgressColorLow = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.low", commandTPSBarProgressColorLow.name())); -+ commandTPSBarTextColorGood = getString("settings.command.tpsbar.text-color.good", commandTPSBarTextColorGood); -+ commandTPSBarTextColorMedium = getString("settings.command.tpsbar.text-color.medium", commandTPSBarTextColorMedium); -+ commandTPSBarTextColorLow = getString("settings.command.tpsbar.text-color.low", commandTPSBarTextColorLow); -+ commandTPSBarTickInterval = getInt("settings.command.tpsbar.tick-interval", commandTPSBarTickInterval); -+ } -+ - public static int barrelRows = 3; - public static boolean enderChestSixRows = false; - public static boolean enderChestPermissionRows = false; -diff --git a/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java b/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d8f9b044107ff7c29a83eb5378aa9f5465ba1995 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java -@@ -0,0 +1,44 @@ -+package org.purpurmc.purpur.command; -+ -+import com.mojang.brigadier.CommandDispatcher; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.minimessage.MiniMessage; -+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import net.minecraft.commands.arguments.EntityArgument; -+import net.minecraft.server.level.ServerPlayer; -+import org.purpurmc.purpur.PurpurConfig; -+import org.purpurmc.purpur.task.TPSBarTask; -+ -+import java.util.Collection; -+import java.util.Collections; -+ -+public class TPSBarCommand { -+ public static void register(CommandDispatcher dispatcher) { -+ dispatcher.register(Commands.literal("tpsbar") -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.tpsbar")) -+ .executes(context -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) -+ .then(Commands.argument("targets", EntityArgument.players()) -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.tpsbar.other")) -+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) -+ ) -+ ); -+ } -+ -+ private static int execute(CommandSourceStack sender, Collection targets) { -+ for (ServerPlayer player : targets) { -+ boolean result = TPSBarTask.instance().togglePlayer(player.getBukkitEntity()); -+ player.tpsBar(result); -+ -+ Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.tpsbarCommandOutput, -+ Placeholder.component("onoff", Component.translatable(result ? "options.on" : "options.off") -+ .color(result ? NamedTextColor.GREEN : NamedTextColor.RED)), -+ Placeholder.parsed("target", player.getGameProfile().getName())); -+ -+ sender.sendSuccess(output, false); -+ } -+ return targets.size(); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/task/BossBarTask.java b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d38b3c4a722396cc3b61a9a8ed7e39cea4ae65cb ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java -@@ -0,0 +1,109 @@ -+package org.purpurmc.purpur.task; -+ -+import net.kyori.adventure.bossbar.BossBar; -+import net.minecraft.server.level.ServerPlayer; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin; -+import org.bukkit.entity.Player; -+import org.bukkit.scheduler.BukkitRunnable; -+ -+import java.util.HashMap; -+import java.util.HashSet; -+import java.util.Iterator; -+import java.util.Map; -+import java.util.UUID; -+ -+public abstract class BossBarTask extends BukkitRunnable { -+ private final Map bossbars = new HashMap<>(); -+ private boolean started; -+ -+ abstract BossBar createBossBar(); -+ -+ abstract void updateBossBar(BossBar bossbar, Player player); -+ -+ @Override -+ public void run() { -+ Iterator> iter = bossbars.entrySet().iterator(); -+ while (iter.hasNext()) { -+ Map.Entry entry = iter.next(); -+ Player player = Bukkit.getPlayer(entry.getKey()); -+ if (player == null) { -+ iter.remove(); -+ continue; -+ } -+ updateBossBar(entry.getValue(), player); -+ } -+ } -+ -+ @Override -+ public void cancel() { -+ super.cancel(); -+ new HashSet<>(this.bossbars.keySet()).forEach(uuid -> { -+ Player player = Bukkit.getPlayer(uuid); -+ if (player != null) { -+ removePlayer(player); -+ } -+ }); -+ this.bossbars.clear(); -+ } -+ -+ public boolean removePlayer(Player player) { -+ BossBar bossbar = this.bossbars.remove(player.getUniqueId()); -+ if (bossbar != null) { -+ player.hideBossBar(bossbar); -+ return true; -+ } -+ return false; -+ } -+ -+ public void addPlayer(Player player) { -+ removePlayer(player); -+ BossBar bossbar = createBossBar(); -+ this.bossbars.put(player.getUniqueId(), bossbar); -+ this.updateBossBar(bossbar, player); -+ player.showBossBar(bossbar); -+ } -+ -+ public boolean hasPlayer(UUID uuid) { -+ return this.bossbars.containsKey(uuid); -+ } -+ -+ public boolean togglePlayer(Player player) { -+ if (removePlayer(player)) { -+ return false; -+ } -+ addPlayer(player); -+ return true; -+ } -+ -+ public void start() { -+ stop(); -+ this.runTaskTimerAsynchronously(new MinecraftInternalPlugin(), 1, 1); -+ started = true; -+ } -+ -+ public void stop() { -+ if (started) { -+ cancel(); -+ } -+ } -+ -+ public static void startAll() { -+ TPSBarTask.instance().start(); -+ } -+ -+ public static void stopAll() { -+ TPSBarTask.instance().stop(); -+ } -+ -+ public static void addToAll(ServerPlayer player) { -+ Player bukkit = player.getBukkitEntity(); -+ if (player.tpsBar()) { -+ TPSBarTask.instance().addPlayer(bukkit); -+ } -+ } -+ -+ public static void removeFromAll(Player player) { -+ TPSBarTask.instance().removePlayer(player); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java b/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8769993e7ca59da309087051a3cd38fc562c15d1 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java -@@ -0,0 +1,142 @@ -+package org.purpurmc.purpur.task; -+ -+import net.kyori.adventure.bossbar.BossBar; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.minimessage.MiniMessage; -+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -+import org.purpurmc.purpur.PurpurConfig; -+import org.bukkit.Bukkit; -+import org.bukkit.entity.Player; -+ -+public class TPSBarTask extends BossBarTask { -+ private static TPSBarTask instance; -+ private double tps = 20.0D; -+ private double mspt = 0.0D; -+ private int tick = 0; -+ -+ public static TPSBarTask instance() { -+ if (instance == null) { -+ instance = new TPSBarTask(); -+ } -+ return instance; -+ } -+ -+ @Override -+ BossBar createBossBar() { -+ return BossBar.bossBar(Component.text(""), 0.0F, instance().getBossBarColor(), PurpurConfig.commandTPSBarProgressOverlay); -+ } -+ -+ @Override -+ void updateBossBar(BossBar bossbar, Player player) { -+ bossbar.progress(getBossBarProgress()); -+ bossbar.color(getBossBarColor()); -+ bossbar.name(MiniMessage.miniMessage().deserialize(PurpurConfig.commandTPSBarTitle, -+ Placeholder.component("tps", getTPSColor()), -+ Placeholder.component("mspt", getMSPTColor()), -+ Placeholder.component("ping", getPingColor(player.getPing())) -+ )); -+ } -+ -+ @Override -+ public void run() { -+ if (++tick < PurpurConfig.commandTPSBarTickInterval) { -+ return; -+ } -+ tick = 0; -+ -+ this.tps = Math.max(Math.min(Bukkit.getTPS()[0], 20.0D), 0.0D); -+ this.mspt = Bukkit.getAverageTickTime(); -+ -+ super.run(); -+ } -+ -+ private float getBossBarProgress() { -+ if (PurpurConfig.commandTPSBarProgressFillMode == FillMode.MSPT) { -+ return Math.max(Math.min((float) mspt / 50.0F, 1.0F), 0.0F); -+ } else { -+ return Math.max(Math.min((float) tps / 20.0F, 1.0F), 0.0F); -+ } -+ } -+ -+ private BossBar.Color getBossBarColor() { -+ if (isGood(PurpurConfig.commandTPSBarProgressFillMode)) { -+ return PurpurConfig.commandTPSBarProgressColorGood; -+ } else if (isMedium(PurpurConfig.commandTPSBarProgressFillMode)) { -+ return PurpurConfig.commandTPSBarProgressColorMedium; -+ } else { -+ return PurpurConfig.commandTPSBarProgressColorLow; -+ } -+ } -+ -+ private boolean isGood(FillMode mode) { -+ return isGood(mode, 0); -+ } -+ -+ private boolean isGood(FillMode mode, int ping) { -+ if (mode == FillMode.MSPT) { -+ return mspt < 40; -+ } else if (mode == FillMode.TPS) { -+ return tps >= 19; -+ } else if (mode == FillMode.PING) { -+ return ping < 100; -+ } else { -+ return false; -+ } -+ } -+ -+ private boolean isMedium(FillMode mode) { -+ return isMedium(mode, 0); -+ } -+ -+ private boolean isMedium(FillMode mode, int ping) { -+ if (mode == FillMode.MSPT) { -+ return mspt < 50; -+ } else if (mode == FillMode.TPS) { -+ return tps >= 15; -+ } else if (mode == FillMode.PING) { -+ return ping < 200; -+ } else { -+ return false; -+ } -+ } -+ -+ private Component getTPSColor() { -+ String color; -+ if (isGood(FillMode.TPS)) { -+ color = PurpurConfig.commandTPSBarTextColorGood; -+ } else if (isMedium(FillMode.TPS)) { -+ color = PurpurConfig.commandTPSBarTextColorMedium; -+ } else { -+ color = PurpurConfig.commandTPSBarTextColorLow; -+ } -+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%.2f", tps))); -+ } -+ -+ private Component getMSPTColor() { -+ String color; -+ if (isGood(FillMode.MSPT)) { -+ color = PurpurConfig.commandTPSBarTextColorGood; -+ } else if (isMedium(FillMode.MSPT)) { -+ color = PurpurConfig.commandTPSBarTextColorMedium; -+ } else { -+ color = PurpurConfig.commandTPSBarTextColorLow; -+ } -+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%.2f", mspt))); -+ } -+ -+ private Component getPingColor(int ping) { -+ String color; -+ if (isGood(FillMode.PING, ping)) { -+ color = PurpurConfig.commandTPSBarTextColorGood; -+ } else if (isMedium(FillMode.PING, ping)) { -+ color = PurpurConfig.commandTPSBarTextColorMedium; -+ } else { -+ color = PurpurConfig.commandTPSBarTextColorLow; -+ } -+ return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%s", ping))); -+ } -+ -+ public enum FillMode { -+ TPS, MSPT, PING -+ } -+} diff --git a/patches/server/0115-Striders-give-saddle-back.patch b/patches/server/0115-Striders-give-saddle-back.patch deleted file mode 100644 index 2455ebac4..000000000 --- a/patches/server/0115-Striders-give-saddle-back.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Sun, 13 Dec 2020 20:40:57 -0500 -Subject: [PATCH] Striders give saddle back - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java -index 5f1166ccd64509a70323e2713f3ab58674d83105..741eedcd9e0e29b57d2b3caf5aef1aef18ae5118 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Strider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java -@@ -484,6 +484,19 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - public InteractionResult mobInteract(Player player, InteractionHand hand) { - boolean flag = this.isFood(player.getItemInHand(hand)); - -+ // Purpur start -+ if (level().purpurConfig.striderGiveSaddleBack && player.isSecondaryUseActive() && !flag && isSaddled() && !isVehicle()) { -+ this.steering.setSaddle(false); -+ if (!player.getAbilities().instabuild) { -+ ItemStack saddle = new ItemStack(Items.SADDLE); -+ if (!player.getInventory().add(saddle)) { -+ player.drop(saddle, false); -+ } -+ } -+ return InteractionResult.SUCCESS; -+ } -+ // Purpur end -+ - if (!flag && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) { - if (!this.level().isClientSide) { - player.startRiding(this); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 50bf456b7e87a77e50b938488abde4cf577d1228..3f83dee1fc6a847d8f56cc230a6de1223d4f3964 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1712,6 +1712,7 @@ public class PurpurWorldConfig { - public boolean striderControllable = true; - public double striderMaxHealth = 20.0D; - public int striderBreedingTicks = 6000; -+ public boolean striderGiveSaddleBack = false; - private void striderSettings() { - striderRidable = getBoolean("mobs.strider.ridable", striderRidable); - striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); -@@ -1723,6 +1724,7 @@ public class PurpurWorldConfig { - } - striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth); - striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks); -+ striderGiveSaddleBack = getBoolean("mobs.strider.give-saddle-back", striderGiveSaddleBack); - } - - public boolean tadpoleRidable = false; diff --git a/patches/server/0116-PlayerBookTooLargeEvent.patch b/patches/server/0116-PlayerBookTooLargeEvent.patch deleted file mode 100644 index dc4e5a9c7..000000000 --- a/patches/server/0116-PlayerBookTooLargeEvent.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 23 Dec 2020 00:43:59 -0600 -Subject: [PATCH] PlayerBookTooLargeEvent - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index e5df5583ef6084e59c8375c82c9909ff2d2bdc3f..b3cecec8a93bd0de1a74e693b7c103fdbc87eba2 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1183,10 +1183,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - int maxBookPageSize = io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.pageMax; - double multiplier = Math.max(0.3D, Math.min(1D, io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.totalMultiplier)); - long byteAllowed = maxBookPageSize; -+ // Purpur start -+ int slot = packet.slot(); -+ ItemStack itemstack = Inventory.isHotbarSlot(slot) || slot == Inventory.SLOT_OFFHAND ? this.player.getInventory().getItem(slot) : ItemStack.EMPTY; -+ // Purpur end - for (String testString : pageList) { - int byteLength = testString.getBytes(java.nio.charset.StandardCharsets.UTF_8).length; - if (byteLength > 256 * 4) { - ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send a book with with a page too large!"); -+ org.purpurmc.purpur.event.player.PlayerBookTooLargeEvent event = new org.purpurmc.purpur.event.player.PlayerBookTooLargeEvent(player.getBukkitEntity(), itemstack.asBukkitCopy()); if (event.shouldKickPlayer()) // Purpur - server.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause - return; - } -@@ -1210,6 +1215,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - if (byteTotal > byteAllowed) { - ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send too large of a book. Book Size: " + byteTotal + " - Allowed: "+ byteAllowed + " - Pages: " + pageList.size()); -+ org.purpurmc.purpur.event.player.PlayerBookTooLargeEvent event = new org.purpurmc.purpur.event.player.PlayerBookTooLargeEvent(player.getBukkitEntity(), itemstack.asBukkitCopy()); if (event.shouldKickPlayer()) // Purpur - server.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause - return; - } diff --git a/patches/server/0117-Full-netherite-armor-grants-fire-resistance.patch b/patches/server/0117-Full-netherite-armor-grants-fire-resistance.patch deleted file mode 100644 index b7a8b3d84..000000000 --- a/patches/server/0117-Full-netherite-armor-grants-fire-resistance.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 24 Dec 2020 11:00:15 -0600 -Subject: [PATCH] Full netherite armor grants fire resistance - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index d98f5e4323859f9eae0caac04865a78719f5befc..579a9c7d914015ef74c6147f2e17962a7aea2a78 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -381,6 +381,16 @@ public abstract class Player extends LivingEntity { - this.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 200, 0, false, false, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TURTLE_HELMET); // CraftBukkit - } - -+ // Purpur start -+ if (this.level().purpurConfig.playerNetheriteFireResistanceDuration > 0 && this.level().getGameTime() % 20 == 0) { -+ if (itemstack.is(Items.NETHERITE_HELMET) -+ && this.getItemBySlot(EquipmentSlot.CHEST).is(Items.NETHERITE_CHESTPLATE) -+ && this.getItemBySlot(EquipmentSlot.LEGS).is(Items.NETHERITE_LEGGINGS) -+ && this.getItemBySlot(EquipmentSlot.FEET).is(Items.NETHERITE_BOOTS)) { -+ this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, this.level().purpurConfig.playerNetheriteFireResistanceDuration, this.level().purpurConfig.playerNetheriteFireResistanceAmplifier, this.level().purpurConfig.playerNetheriteFireResistanceAmbient, this.level().purpurConfig.playerNetheriteFireResistanceShowParticles, this.level().purpurConfig.playerNetheriteFireResistanceShowIcon), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.NETHERITE_ARMOR); -+ } -+ } -+ // Purpur end - } - - protected ItemCooldowns createItemCooldowns() { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3f83dee1fc6a847d8f56cc230a6de1223d4f3964..66c4906cb9c3da6f111b96f0ad6be17772764125 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -295,6 +295,19 @@ public class PurpurWorldConfig { - villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate); - } - -+ public int playerNetheriteFireResistanceDuration = 0; -+ public int playerNetheriteFireResistanceAmplifier = 0; -+ public boolean playerNetheriteFireResistanceAmbient = false; -+ public boolean playerNetheriteFireResistanceShowParticles = false; -+ public boolean playerNetheriteFireResistanceShowIcon = true; -+ private void playerNetheriteFireResistance() { -+ playerNetheriteFireResistanceDuration = getInt("gameplay-mechanics.player.netherite-fire-resistance.duration", playerNetheriteFireResistanceDuration); -+ playerNetheriteFireResistanceAmplifier = getInt("gameplay-mechanics.player.netherite-fire-resistance.amplifier", playerNetheriteFireResistanceAmplifier); -+ playerNetheriteFireResistanceAmbient = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.ambient", playerNetheriteFireResistanceAmbient); -+ playerNetheriteFireResistanceShowParticles = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.show-particles", playerNetheriteFireResistanceShowParticles); -+ playerNetheriteFireResistanceShowIcon = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.show-icon", playerNetheriteFireResistanceShowIcon); -+ } -+ - public boolean idleTimeoutKick = true; - public boolean idleTimeoutTickNearbyEntities = true; - public boolean idleTimeoutCountAsSleeping = false; diff --git a/patches/server/0118-Add-mobGriefing-bypass-to-everything-affected.patch b/patches/server/0118-Add-mobGriefing-bypass-to-everything-affected.patch deleted file mode 100644 index 019668575..000000000 --- a/patches/server/0118-Add-mobGriefing-bypass-to-everything-affected.patch +++ /dev/null @@ -1,680 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 5 Jan 2021 22:21:56 -0500 -Subject: [PATCH] Add mobGriefing bypass to everything affected - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 2ea60043f3bbf6cce77799f6c74ffe1f4b226374..dc1c7c55fd13cc1a8ade803bfb1b7c385cf29132 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1831,7 +1831,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - boolean flag = false; - - if (this.dead && adversary instanceof WitherBoss) { // Paper -- if (this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (this.level().purpurConfig.witherBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - BlockPos blockposition = this.blockPosition(); - BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState(); - -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 34d00acc43d2541307aa90a77a3c5d19a3057a94..77cf0d92212d11b9036f9f9cf23b23f71f1d590d 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -748,7 +748,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - public void aiStep() { - super.aiStep(); - this.level().getProfiler().push("looting"); -- if (!this.level().isClientSide && this.canPickUpLoot() && this.isAlive() && !this.dead && this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (!this.level().isClientSide && this.canPickUpLoot() && this.isAlive() && !this.dead && (this.level().purpurConfig.entitiesPickUpLootBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { - Vec3i baseblockposition = this.getPickupReach(); - List list = this.level().getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate((double) baseblockposition.getX(), (double) baseblockposition.getY(), (double) baseblockposition.getZ())); - Iterator iterator = list.iterator(); -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -index 4fa4ec34963730507253182cad1c2bf04090ad50..8d4e206aa05b95b7bfec5d23496085cf55a3e1de 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -@@ -48,7 +48,7 @@ public class HarvestFarmland extends Behavior { - } - - protected boolean checkExtraStartConditions(ServerLevel world, Villager entity) { -- if (!world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (!world.purpurConfig.villagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - return false; - } else if (entity.getVillagerData().getProfession() != VillagerProfession.FARMER && !(world.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().getProfession() == VillagerProfession.CLERIC)) { // Purpur - return false; -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -index a85885ee51df585fa11ae9f8fcd67ff2a71c5a18..d81509e08e70ec5b2f837c9dc66b1254c86854e4 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java -@@ -32,7 +32,7 @@ public class BreakDoorGoal extends DoorInteractGoal { - - @Override - public boolean canUse() { -- return !super.canUse() ? false : (!this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.isValidDifficulty(this.mob.level().getDifficulty()) && !this.isOpen()); -+ return !super.canUse() ? false : ((!this.mob.level().purpurConfig.zombieBypassMobGriefing && !this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) ? false : this.isValidDifficulty(this.mob.level().getDifficulty()) && !this.isOpen()); // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -index 4e2c23ccdf4e4a4d65b291dbe20952bae1838bff..0da884a833f6c707fea512e826658c3bb73f7a77 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java -@@ -74,7 +74,7 @@ public class EatBlockGoal extends Goal { - - final BlockState blockState = this.level.getBlockState(blockposition); // Paper - fix wrong block state - if (EatBlockGoal.IS_TALL_GRASS.test(blockState)) { // Paper - fix wrong block state -- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, blockState.getFluidState().createLegacyBlock(), !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state -+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, blockState.getFluidState().createLegacyBlock(), !this.level.purpurConfig.sheepBypassMobGriefing && !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state // Purpur - this.level.destroyBlock(blockposition, false); - } - -@@ -83,7 +83,7 @@ public class EatBlockGoal extends Goal { - BlockPos blockposition1 = blockposition.below(); - - if (this.level.getBlockState(blockposition1).is(Blocks.GRASS_BLOCK)) { -- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state -+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !this.level.purpurConfig.sheepBypassMobGriefing && !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state // Purpur - this.level.levelEvent(2001, blockposition1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState())); - this.level.setBlock(blockposition1, Blocks.DIRT.defaultBlockState(), 2); - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -index 6634228ef002cbef67980272a26be4a75c954116..a61abba840a55fb4fbc9716a5e05eb2778068785 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -@@ -40,7 +40,7 @@ public class RemoveBlockGoal extends MoveToBlockGoal { - - @Override - public boolean canUse() { -- if (!this.removerMob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (!this.removerMob.level().purpurConfig.zombieBypassMobGriefing && !this.removerMob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - return false; - } else if (this.nextStartTick > 0) { - --this.nextStartTick; -diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java -index 0140dc8a58903bd802ea8ffb029392215e95cdf4..c246148b9851654d796f472462677a60498c7b8d 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Fox.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java -@@ -1385,7 +1385,7 @@ public class Fox extends Animal implements VariantHolder { - } - - protected void onReachedTarget() { -- if (Fox.this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (Fox.this.level().purpurConfig.foxBypassMobGriefing || Fox.this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - BlockState iblockdata = Fox.this.level().getBlockState(this.blockPos); - - if (iblockdata.is(Blocks.SWEET_BERRY_BUSH)) { -diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -index b5297b1d7223af622636a7defdb98b5bc6e6a3c9..ce424d046d7c4abd2371154b00624aa6a9ca3ae3 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -@@ -631,7 +631,7 @@ public class Rabbit extends Animal implements VariantHolder { - @Override - public boolean canUse() { - if (this.nextStartTick <= 0) { -- if (!this.rabbit.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (!this.rabbit.level().purpurConfig.rabbitBypassMobGriefing && !this.rabbit.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - return false; - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index ee4d4a4fe314ee9bce69c96dd65d84ed1ace0543..cdb6657d30d224709aec3921c5fb8380f8acd93e 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -125,7 +125,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - this.hurt(this.damageSources().melting(), 1.0F); // CraftBukkit - DamageSources.ON_FIRE -> CraftEventFactory.MELTING - } - -- if (!this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (!this.level().purpurConfig.snowGolemBypassMobGriefing && !this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - return; - } - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -index f751444603e4a1a2ef53e7232b5abfff82c316e8..0478469343c30d2b8d79bda78aef9ff1348de19b 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -@@ -603,7 +603,7 @@ public class EnderDragon extends Mob implements Enemy { - BlockState iblockdata = this.level().getBlockState(blockposition); - - if (!iblockdata.isAir() && !iblockdata.is(BlockTags.DRAGON_TRANSPARENT)) { -- if (this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !iblockdata.is(BlockTags.DRAGON_IMMUNE)) { -+ if ((this.level().purpurConfig.enderDragonBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && !iblockdata.is(BlockTags.DRAGON_IMMUNE)) { // Purpur - // CraftBukkit start - Add blocks to list rather than destroying them - // flag1 = this.level().removeBlock(blockposition, false) || flag1; - flag1 = true; -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 8d2894bb1ae70f63c8fa67de3e9f7c6a9c940f3e..2f0c44a0b97e9ad7591c5b66c2560f3e405c61c4 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -493,7 +493,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - - if (this.destroyBlocksTick > 0) { - --this.destroyBlocksTick; -- if (this.destroyBlocksTick == 0 && this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (this.destroyBlocksTick == 0 && (this.level().purpurConfig.witherBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // Purpur - boolean flag = false; - - j = Mth.floor(this.getBbWidth() / 2.0F + 1.0F); -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index 052a0c168268b7e788953063f54c3769023f3c03..de1fe3b115c1b3936b79c8900389542a8c8a2c90 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -526,7 +526,15 @@ public class EnderMan extends Monster implements NeutralMob { - @Override - public boolean canUse() { - if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur -- return this.enderman.getCarriedBlock() == null ? false : (!this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0); -+ // Purpur start -+ if (this.enderman.getCarriedBlock() == null) { -+ return false; -+ } -+ if (!this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !this.enderman.level().purpurConfig.endermanBypassMobGriefing) { -+ return false; -+ } -+ return this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0; -+ // Purpur end - } - - @Override -@@ -572,7 +580,15 @@ public class EnderMan extends Monster implements NeutralMob { - @Override - public boolean canUse() { - if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur -- return this.enderman.getCarriedBlock() != null ? false : (!this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? false : this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0); -+ // Purpur start -+ if (this.enderman.getCarriedBlock() != null) { -+ return false; -+ } -+ if (!this.enderman.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !this.enderman.level().purpurConfig.endermanBypassMobGriefing) { -+ return false; -+ } -+ return this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0; -+ // Purpur end - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Evoker.java b/src/main/java/net/minecraft/world/entity/monster/Evoker.java -index 8f0c685790aa59b7f2352c3bac6ede444d0ede22..ce2e5c16db13accb082b3f2403661c65411c7a80 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Evoker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Evoker.java -@@ -364,7 +364,7 @@ public class Evoker extends SpellcasterIllager { - return false; - } else if (Evoker.this.tickCount < this.nextAttackTickCount) { - return false; -- } else if (!Evoker.this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ } else if (!Evoker.this.level().purpurConfig.evokerBypassMobGriefing && !Evoker.this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - return false; - } else { - List list = Evoker.this.level().getNearbyEntities(Sheep.class, this.wololoTargeting, Evoker.this, Evoker.this.getBoundingBox().inflate(16.0D, 4.0D, 16.0D)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index 32d547a4430a8f524a7fc0bd1aa063bbebfaeb7f..cebe89b0868043b819fb3e9987f899926961be52 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -168,7 +168,7 @@ public class Ravager extends Raider { - this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(Mth.lerp(0.1D, d1, d0)); - } - -- if (this.horizontalCollision && this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (this.horizontalCollision && (this.level().purpurConfig.ravagerBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // Purpur - boolean flag = false; - AABB axisalignedbb = this.getBoundingBox().inflate(0.2D); - Iterator iterator = BlockPos.betweenClosed(Mth.floor(axisalignedbb.minX), Mth.floor(axisalignedbb.minY), Mth.floor(axisalignedbb.minZ), Mth.floor(axisalignedbb.maxX), Mth.floor(axisalignedbb.maxY), Mth.floor(axisalignedbb.maxZ)).iterator(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java -index 75f82922260b2c0666021e7ed42dfde401e1a9d6..a175144d5480b7af091787c6ab366fb3e8d70587 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java -@@ -191,7 +191,7 @@ public class Silverfish extends Monster { - continue; - } - // CraftBukkit end -- if (world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (world.purpurConfig.silverfishBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - world.destroyBlock(blockposition1, true, this.silverfish); - } else { - world.setBlock(blockposition1, ((InfestedBlock) block).hostStateByInfested(world.getBlockState(blockposition1)), 3); -@@ -229,7 +229,7 @@ public class Silverfish extends Monster { - } else { - RandomSource randomsource = this.mob.getRandom(); - -- if (this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && randomsource.nextInt(reducedTickDelay(10)) == 0) { -+ if ((this.mob.level().purpurConfig.silverfishBypassMobGriefing || this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && randomsource.nextInt(reducedTickDelay(10)) == 0) { // Purpur - this.selectedDirection = Direction.getRandom(randomsource); - BlockPos blockposition = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5D, this.mob.getZ()).relative(this.selectedDirection); - BlockState iblockdata = this.mob.level().getBlockState(blockposition); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index 06e0f737615c90bd733a89a731156598ccfe447f..57089ba787731ddda853dce959ba015abe135bfd 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -412,7 +412,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - - @Override - public boolean wantsToPickUp(ItemStack stack) { -- return this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack); -+ return (this.level().purpurConfig.piglinBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack); - } - - protected boolean canReplaceCurrentItem(ItemStack stack) { -diff --git a/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java b/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java -index 9d89872c5958f3e8d6c1ef4fd93f9b8b85296851..6a94c86acce5afbf1e9c8e7d664b3eb2d79ab5ab 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java -@@ -19,20 +19,20 @@ public class LargeFireball extends Fireball { - - public LargeFireball(EntityType type, Level world) { - super(type, world); -- this.isIncendiary = this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit -+ this.isIncendiary = this.level().purpurConfig.fireballsBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit // Purpur - } - - public LargeFireball(Level world, LivingEntity owner, double velocityX, double velocityY, double velocityZ, int explosionPower) { - super(EntityType.FIREBALL, owner, velocityX, velocityY, velocityZ, world); - this.explosionPower = explosionPower; -- this.isIncendiary = this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit -+ this.isIncendiary = this.level().purpurConfig.fireballsBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit // Purpur - } - - @Override - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); - if (!this.level().isClientSide) { -- boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); -+ boolean flag = this.level().purpurConfig.fireballsBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - - // CraftBukkit start - fire ExplosionPrimeEvent - ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 74c596264d4da551437bd2a23e1c70022cfc73fc..e4d4ff0ef4a0f3283aa42fe2304816cd6d9475a8 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -343,7 +343,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { - public boolean mayInteract(Level world, BlockPos pos) { - Entity entity = this.getOwner(); - -- return entity instanceof Player ? entity.mayInteract(world, pos) : entity == null || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); -+ return entity instanceof Player ? entity.mayInteract(world, pos) : entity == null || world.purpurConfig.projectilesBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); - } - - public boolean mayBreak(Level world) { -diff --git a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java -index 3a11ad32d95088a5aca713a1a6a984cc22d4fa9a..c078ccad4aabe469a9611331b415a4cef241973e 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java -@@ -27,7 +27,7 @@ public class SmallFireball extends Fireball { - super(EntityType.SMALL_FIREBALL, owner, velocityX, velocityY, velocityZ, world); - // CraftBukkit start - if (this.getOwner() != null && this.getOwner() instanceof Mob) { -- this.isIncendiary = this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); -+ this.isIncendiary = this.level().purpurConfig.fireballsBypassMobGriefing || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - } - // CraftBukkit end - } -diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java -index 98e558338b5d9fb03869d2cc21b3e90eb45b95f6..4a8fa7e5844b5cd12ef6b113f988b715c7a3ef64 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raider.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java -@@ -341,7 +341,7 @@ public abstract class Raider extends PatrollingMonster { - - @Override - public boolean canUse() { -- if (!this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items -+ if ((!this.mob.level().purpurConfig.pillagerBypassMobGriefing && !this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items // Purpur - Raid raid = this.mob.getCurrentRaid(); - - if (this.mob.hasActiveRaid() && !this.mob.getCurrentRaid().isOver() && this.mob.canBeLeader() && !ItemStack.matches(this.mob.getItemBySlot(EquipmentSlot.HEAD), Raid.getLeaderBannerInstance(this.mob.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) { -diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java -index 112d2feba5f75a2a873b595617780515945c10e4..2af4c365743b2956939335512f74e0a1d84298f7 100644 ---- a/src/main/java/net/minecraft/world/level/block/CropBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java -@@ -179,7 +179,7 @@ public class CropBlock extends BushBlock implements BonemealableBlock { - @Override - protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { - if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent -- if (entity instanceof Ravager && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit -+ if (entity instanceof Ravager && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), (!world.purpurConfig.ravagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)))) { // CraftBukkit // Purpur - world.destroyBlock(pos, true, entity); - } - -diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index dc356bd0931af9bdab9ec71e3de66e88a67375ad..99798220b6e0ad06db2ba5c9b74bfb72af185fee 100644 ---- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -111,7 +111,7 @@ public class FarmBlock extends Block { - @Override - public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { - super.fallOn(world, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage. -- if (!world.isClientSide && world.random.nextFloat() < fallDistance - 0.5F && entity instanceof LivingEntity && (entity instanceof Player || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { -+ if (!world.isClientSide && world.random.nextFloat() < fallDistance - 0.5F && entity instanceof LivingEntity && (entity instanceof Player || world.purpurConfig.farmlandBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { // Purpur - // CraftBukkit start - Interact soil - org.bukkit.event.Cancellable cancellable; - if (entity instanceof Player) { -diff --git a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java -index a6e6545402904141ffc6218a0158b0e9c67217c8..5eac1a54398dfa5571b98fb6eefca9d2bf9b2793 100644 ---- a/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PowderSnowBlock.java -@@ -80,7 +80,7 @@ public class PowderSnowBlock extends Block implements BucketPickup { - if (!world.isClientSide) { - // CraftBukkit start - if (entity.isOnFire() && entity.mayInteract(world, pos)) { -- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !(world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || entity instanceof Player))) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !((world.purpurConfig.powderSnowBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) || entity instanceof Player))) { - return; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -index c7377d04ceac3ea624117439783a443c6d6f6d08..0c732cfbd9ce50198a3f85ae8ef2263d7ae0bc1a 100644 ---- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -@@ -221,7 +221,7 @@ public class TurtleEggBlock extends Block { - } - if (entity instanceof Player) return true; - -- return world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); -+ return world.purpurConfig.turtleEggsBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); - // Purpur end - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 66c4906cb9c3da6f111b96f0ad6be17772764125..51002cc2901b432123dfc6b3c130e26b3c3486a3 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -115,8 +115,11 @@ public class PurpurWorldConfig { - public boolean boatsDoFallDamage = false; - public boolean disableDropsOnCrammingDeath = false; - public boolean entitiesCanUsePortals = true; -+ public boolean entitiesPickUpLootBypassMobGriefing = false; -+ public boolean fireballsBypassMobGriefing = false; - public boolean milkCuresBadOmen = true; - public boolean persistentDroppableEntityDisplayNames = true; -+ public boolean projectilesBypassMobGriefing = false; - public double tridentLoyaltyVoidReturnHeight = 0.0D; - public double voidDamageHeight = -64.0D; - public double voidDamageDealt = 4.0D; -@@ -128,8 +131,11 @@ public class PurpurWorldConfig { - boatsDoFallDamage = getBoolean("gameplay-mechanics.boat.do-fall-damage", boatsDoFallDamage); - disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); - entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); -+ entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); -+ fireballsBypassMobGriefing = getBoolean("gameplay-mechanics.fireballs-bypass-mob-griefing", fireballsBypassMobGriefing); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); - persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); -+ projectilesBypassMobGriefing = getBoolean("gameplay-mechanics.projectiles-bypass-mob-griefing", projectilesBypassMobGriefing); - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); - voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); - voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); -@@ -445,9 +451,11 @@ public class PurpurWorldConfig { - dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils); - } - -+ public boolean farmlandBypassMobGriefing = false; - public boolean farmlandGetsMoistFromBelow = false; - public boolean farmlandAlpha = false; - private void farmlandSettings() { -+ farmlandBypassMobGriefing = getBoolean("blocks.farmland.bypass-mob-griefing", farmlandBypassMobGriefing); - farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); - farmlandAlpha = getBoolean("blocks.farmland.use-alpha-farmland", farmlandAlpha); - } -@@ -472,6 +480,11 @@ public class PurpurWorldConfig { - lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether); - } - -+ public boolean powderSnowBypassMobGriefing = false; -+ private void powderSnowSettings() { -+ powderSnowBypassMobGriefing = getBoolean("blocks.powder_snow.bypass-mob-griefing", powderSnowBypassMobGriefing); -+ } -+ - public boolean respawnAnchorExplode = true; - public double respawnAnchorExplosionPower = 5.0D; - public boolean respawnAnchorExplosionFire = true; -@@ -501,10 +514,12 @@ public class PurpurWorldConfig { - public boolean turtleEggsBreakFromExpOrbs = false; - public boolean turtleEggsBreakFromItems = false; - public boolean turtleEggsBreakFromMinecarts = false; -+ public boolean turtleEggsBypassMobGriefing = false; - private void turtleEggSettings() { - turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs); - turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems); - turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); -+ turtleEggsBypassMobGriefing = getBoolean("blocks.turtle_egg.bypass-mob-griefing", turtleEggsBypassMobGriefing); - } - - public int waterInfiniteRequiredSources = 2; -@@ -738,6 +753,7 @@ public class PurpurWorldConfig { - public double creeperMaxHealth = 20.0D; - public double creeperChargedChance = 0.0D; - public boolean creeperAllowGriefing = true; -+ public boolean creeperBypassMobGriefing = false; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -750,6 +766,7 @@ public class PurpurWorldConfig { - creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth); - creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); - creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); -+ creeperBypassMobGriefing = getBoolean("mobs.creeper.bypass-mob-griefing", creeperBypassMobGriefing); - } - - public boolean dolphinRidable = false; -@@ -844,6 +861,7 @@ public class PurpurWorldConfig { - public double enderDragonMaxY = 320D; - public double enderDragonMaxHealth = 200.0D; - public boolean enderDragonAlwaysDropsFullExp = false; -+ public boolean enderDragonBypassMobGriefing = false; - private void enderDragonSettings() { - enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); - enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); -@@ -860,6 +878,7 @@ public class PurpurWorldConfig { - } - enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth); - enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); -+ enderDragonBypassMobGriefing = getBoolean("mobs.ender_dragon.bypass-mob-griefing", enderDragonBypassMobGriefing); - } - - public boolean endermanRidable = false; -@@ -868,6 +887,7 @@ public class PurpurWorldConfig { - public double endermanMaxHealth = 40.0D; - public boolean endermanAllowGriefing = true; - public boolean endermanDespawnEvenWithBlock = false; -+ public boolean endermanBypassMobGriefing = false; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -@@ -880,6 +900,7 @@ public class PurpurWorldConfig { - endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); - endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); - endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock); -+ endermanBypassMobGriefing = getBoolean("mobs.enderman.bypass-mob-griefing", endermanBypassMobGriefing); - } - - public boolean endermiteRidable = false; -@@ -902,6 +923,7 @@ public class PurpurWorldConfig { - public boolean evokerRidableInWater = true; - public boolean evokerControllable = true; - public double evokerMaxHealth = 24.0D; -+ public boolean evokerBypassMobGriefing = false; - private void evokerSettings() { - evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); - evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); -@@ -912,6 +934,7 @@ public class PurpurWorldConfig { - set("mobs.evoker.attributes.max_health", oldValue); - } - evokerMaxHealth = getDouble("mobs.evoker.attributes.max_health", evokerMaxHealth); -+ evokerBypassMobGriefing = getBoolean("mobs.evoker.bypass-mob-griefing", evokerBypassMobGriefing); - } - - public boolean foxRidable = false; -@@ -920,6 +943,7 @@ public class PurpurWorldConfig { - public double foxMaxHealth = 10.0D; - public boolean foxTypeChangesWithTulips = false; - public int foxBreedingTicks = 6000; -+ public boolean foxBypassMobGriefing = false; - private void foxSettings() { - foxRidable = getBoolean("mobs.fox.ridable", foxRidable); - foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); -@@ -932,6 +956,7 @@ public class PurpurWorldConfig { - foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth); - foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); - foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks); -+ foxBypassMobGriefing = getBoolean("mobs.fox.bypass-mob-griefing", foxBypassMobGriefing); - } - - public boolean frogRidable = false; -@@ -1379,6 +1404,7 @@ public class PurpurWorldConfig { - public boolean piglinRidableInWater = true; - public boolean piglinControllable = true; - public double piglinMaxHealth = 16.0D; -+ public boolean piglinBypassMobGriefing = false; - private void piglinSettings() { - piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); - piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); -@@ -1389,6 +1415,7 @@ public class PurpurWorldConfig { - set("mobs.piglin.attributes.max_health", oldValue); - } - piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth); -+ piglinBypassMobGriefing = getBoolean("mobs.piglin.bypass-mob-griefing", piglinBypassMobGriefing); - } - - public boolean piglinBruteRidable = false; -@@ -1411,6 +1438,7 @@ public class PurpurWorldConfig { - public boolean pillagerRidableInWater = true; - public boolean pillagerControllable = true; - public double pillagerMaxHealth = 24.0D; -+ public boolean pillagerBypassMobGriefing = false; - private void pillagerSettings() { - pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); - pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); -@@ -1421,6 +1449,7 @@ public class PurpurWorldConfig { - set("mobs.pillager.attributes.max_health", oldValue); - } - pillagerMaxHealth = getDouble("mobs.pillager.attributes.max_health", pillagerMaxHealth); -+ pillagerBypassMobGriefing = getBoolean("mobs.pillager.bypass-mob-griefing", pillagerBypassMobGriefing); - } - - public boolean polarBearRidable = false; -@@ -1467,6 +1496,7 @@ public class PurpurWorldConfig { - public double rabbitNaturalToast = 0.0D; - public double rabbitNaturalKiller = 0.0D; - public int rabbitBreedingTicks = 6000; -+ public boolean rabbitBypassMobGriefing = false; - private void rabbitSettings() { - rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); - rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); -@@ -1480,12 +1510,14 @@ public class PurpurWorldConfig { - rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); - rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); - rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks); -+ rabbitBypassMobGriefing = getBoolean("mobs.rabbit.bypass-mob-griefing", rabbitBypassMobGriefing); - } - - public boolean ravagerRidable = false; - public boolean ravagerRidableInWater = false; - public boolean ravagerControllable = true; - public double ravagerMaxHealth = 100.0D; -+ public boolean ravagerBypassMobGriefing = false; - private void ravagerSettings() { - ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); - ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); -@@ -1496,6 +1528,7 @@ public class PurpurWorldConfig { - set("mobs.ravager.attributes.max_health", oldValue); - } - ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth); -+ ravagerBypassMobGriefing = getBoolean("mobs.ravager.bypass-mob-griefing", ravagerBypassMobGriefing); - } - - public boolean salmonRidable = false; -@@ -1517,6 +1550,7 @@ public class PurpurWorldConfig { - public boolean sheepControllable = true; - public double sheepMaxHealth = 8.0D; - public int sheepBreedingTicks = 6000; -+ public boolean sheepBypassMobGriefing = false; - private void sheepSettings() { - sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); - sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); -@@ -1528,6 +1562,7 @@ public class PurpurWorldConfig { - } - sheepMaxHealth = getDouble("mobs.sheep.attributes.max_health", sheepMaxHealth); - sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks); -+ sheepBypassMobGriefing = getBoolean("mobs.sheep.bypass-mob-griefing", sheepBypassMobGriefing); - } - - public boolean shulkerRidable = false; -@@ -1550,6 +1585,7 @@ public class PurpurWorldConfig { - public boolean silverfishRidableInWater = true; - public boolean silverfishControllable = true; - public double silverfishMaxHealth = 8.0D; -+ public boolean silverfishBypassMobGriefing = false; - private void silverfishSettings() { - silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); - silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); -@@ -1560,6 +1596,7 @@ public class PurpurWorldConfig { - set("mobs.silverfish.attributes.max_health", oldValue); - } - silverfishMaxHealth = getDouble("mobs.silverfish.attributes.max_health", silverfishMaxHealth); -+ silverfishBypassMobGriefing = getBoolean("mobs.silverfish.bypass-mob-griefing", silverfishBypassMobGriefing); - } - - public boolean skeletonRidable = false; -@@ -1637,6 +1674,7 @@ public class PurpurWorldConfig { - public int snowGolemSnowBallMax = 20; - public float snowGolemSnowBallModifier = 10.0F; - public double snowGolemAttackDistance = 1.25D; -+ public boolean snowGolemBypassMobGriefing = false; - private void snowGolemSettings() { - snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); - snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); -@@ -1653,6 +1691,7 @@ public class PurpurWorldConfig { - snowGolemSnowBallMax = getInt("mobs.snow_golem.max-shoot-interval-ticks", snowGolemSnowBallMax); - snowGolemSnowBallModifier = (float) getDouble("mobs.snow_golem.snow-ball-modifier", snowGolemSnowBallModifier); - snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance); -+ snowGolemBypassMobGriefing = getBoolean("mobs.snow_golem.bypass-mob-griefing", snowGolemBypassMobGriefing); - } - - public boolean snifferRidable = false; -@@ -1839,6 +1878,7 @@ public class PurpurWorldConfig { - public int villagerBreedingTicks = 6000; - public boolean villagerClericsFarmWarts = false; - public boolean villagerClericFarmersThrowWarts = true; -+ public boolean villagerBypassMobGriefing = false; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -1855,6 +1895,7 @@ public class PurpurWorldConfig { - villagerBreedingTicks = getInt("mobs.villager.breeding-delay-ticks", villagerBreedingTicks); - villagerClericsFarmWarts = getBoolean("mobs.villager.clerics-farm-warts", villagerClericsFarmWarts); - villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts); -+ villagerBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerBypassMobGriefing); - } - - public boolean vindicatorRidable = false; -@@ -1927,6 +1968,7 @@ public class PurpurWorldConfig { - public double witherMaxHealth = 300.0D; - public float witherHealthRegenAmount = 1.0f; - public int witherHealthRegenDelay = 20; -+ public boolean witherBypassMobGriefing = false; - private void witherSettings() { - witherRidable = getBoolean("mobs.wither.ridable", witherRidable); - witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); -@@ -1944,6 +1986,7 @@ public class PurpurWorldConfig { - witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth); - witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount); - witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); -+ witherBypassMobGriefing = getBoolean("mobs.wither.bypass-mob-griefing", witherBypassMobGriefing); - } - - public boolean witherSkeletonRidable = false; -@@ -2015,6 +2058,7 @@ public class PurpurWorldConfig { - public double zombieJockeyChance = 0.05D; - public boolean zombieJockeyTryExistingChickens = true; - public boolean zombieAggressiveTowardsVillagerWhenLagging = true; -+ public boolean zombieBypassMobGriefing = false; - private void zombieSettings() { - zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); - zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); -@@ -2030,6 +2074,7 @@ public class PurpurWorldConfig { - zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); - zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); - zombieAggressiveTowardsVillagerWhenLagging = getBoolean("mobs.zombie.aggressive-towards-villager-when-lagging", zombieAggressiveTowardsVillagerWhenLagging); -+ zombieBypassMobGriefing = getBoolean("mobs.zombie.bypass-mob-griefing", zombieBypassMobGriefing); - } - - public boolean zombieHorseRidable = false; diff --git a/patches/server/0119-Config-to-allow-Note-Block-sounds-when-blocked.patch b/patches/server/0119-Config-to-allow-Note-Block-sounds-when-blocked.patch deleted file mode 100644 index fe5cc46f7..000000000 --- a/patches/server/0119-Config-to-allow-Note-Block-sounds-when-blocked.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Fri, 8 Jan 2021 16:07:32 -0500 -Subject: [PATCH] Config to allow Note Block sounds when blocked - -Allows for Note Blocks to ignore whether or not there's air above them to play. - -Normally, the sounds will only play when the block directly above is air. -With this patch enabled, players can place any block above the Note Block and it will still work. - -diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java -index 1d82cfe7af0dc42f88901fb0c44896771fdf8a93..43dd972b374daa1072608f3a68e812e7fb733a2b 100644 ---- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java -@@ -95,7 +95,7 @@ public class NoteBlock extends Block { - } - - private void playNote(@Nullable Entity entity, BlockState state, Level world, BlockPos pos) { -- if (((NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT)).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) { -+ if (world.purpurConfig.noteBlockIgnoreAbove || ((NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT)).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) { // Purpur - // CraftBukkit start - // org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE)); - // if (event.isCancelled()) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 51002cc2901b432123dfc6b3c130e26b3c3486a3..30a95d4b18964c6b25beb4dbec84f03effc2145b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -118,6 +118,7 @@ public class PurpurWorldConfig { - public boolean entitiesPickUpLootBypassMobGriefing = false; - public boolean fireballsBypassMobGriefing = false; - public boolean milkCuresBadOmen = true; -+ public boolean noteBlockIgnoreAbove = false; - public boolean persistentDroppableEntityDisplayNames = true; - public boolean projectilesBypassMobGriefing = false; - public double tridentLoyaltyVoidReturnHeight = 0.0D; -@@ -134,6 +135,7 @@ public class PurpurWorldConfig { - entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); - fireballsBypassMobGriefing = getBoolean("gameplay-mechanics.fireballs-bypass-mob-griefing", fireballsBypassMobGriefing); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); -+ noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove); - persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); - projectilesBypassMobGriefing = getBoolean("gameplay-mechanics.projectiles-bypass-mob-griefing", projectilesBypassMobGriefing); - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); diff --git a/patches/server/0120-Add-EntityTeleportHinderedEvent.patch b/patches/server/0120-Add-EntityTeleportHinderedEvent.patch deleted file mode 100644 index c3a3264a8..000000000 --- a/patches/server/0120-Add-EntityTeleportHinderedEvent.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 9 Jan 2021 15:27:46 +0100 -Subject: [PATCH] Add EntityTeleportHinderedEvent - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -index 7272d70c672b54dcf595beafd7a2ed33c96e35cb..d7f33c676bba279661583d908d3a58c86d853545 100644 ---- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -@@ -54,6 +54,14 @@ public class EndPortalBlock extends BaseEntityBlock { - protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { - if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (world instanceof ServerLevel && entity.canChangeDimensions() && Shapes.joinIsNotEmpty(Shapes.create(entity.getBoundingBox().move((double) (-pos.getX()), (double) (-pos.getY()), (double) (-pos.getZ()))), state.getShape(world, pos), BooleanOp.AND)) { -+ // Purpur start -+ if (entity.isPassenger() || entity.isVehicle()) { -+ if (new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, PlayerTeleportEvent.TeleportCause.END_PORTAL).callEvent()) { -+ this.entityInside(state, world, pos, entity); -+ } -+ return; -+ } -+ // Purpur end - ResourceKey resourcekey = world.getTypeKey() == LevelStem.END ? Level.OVERWORLD : Level.END; // CraftBukkit - SPIGOT-6152: send back to main overworld in custom ends - ServerLevel worldserver = ((ServerLevel) world).getServer().getLevel(resourcekey); - -diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -index a9e3078cefcae8cc4672d514a7add162590d48df..67060b7446535fc352d221d9fe3928d1d6ffcf54 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -@@ -92,6 +92,14 @@ public class NetherPortalBlock extends Block { - protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { - if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent - if (entity.canChangeDimensions()) { -+ // Purpur start -+ if (entity.isPassenger() || entity.isVehicle()) { -+ if (new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL).callEvent()) { -+ this.entityInside(state, world, pos, entity); -+ } -+ return; -+ } -+ // Purpur end - // CraftBukkit start - Entity in portal - EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); - world.getCraftServer().getPluginManager().callEvent(event); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -index 60b343edc4383c8bc450f106f483349850432fa3..fb9611866671880fc7a1a969da928b8f2ad15269 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -@@ -168,6 +168,14 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { - public static void teleportEntity(Level world, BlockPos pos, BlockState state, Entity entity, TheEndGatewayBlockEntity blockEntity) { - if (world instanceof ServerLevel worldserver && !blockEntity.isCoolingDown()) { - if (!entity.canChangeDimensions()) return; // Purpur -+ // Purpur start -+ if (world.purpurConfig.imposeTeleportRestrictionsOnGateways && (entity.isVehicle() || entity.isPassenger())) { -+ if (new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, PlayerTeleportEvent.TeleportCause.END_GATEWAY).callEvent()) { -+ teleportEntity(world, pos, state, entity, blockEntity); -+ } -+ return; -+ } -+ // Purpur end - blockEntity.teleportCooldown = 100; - BlockPos blockposition1; - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index a6268b3df9691278606501284b5504da718703c2..befe3372d5f1550b7bde3b63b5e7aef9035c5379 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -253,6 +253,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - // Paper end - - if ((!ignorePassengers && this.entity.isVehicle()) || this.entity.isRemoved()) { // Paper - Teleport passenger API -+ // Purpur start -+ if (!entity.isRemoved() && new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) -+ return teleport(location, cause); -+ // Purpur end - return false; - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index a4e4babedbf5bbf09bfbabd4f55ecd6301dae302..925b8260bb2b1c94e544d6e082ea3b02e613d224 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1443,6 +1443,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - - if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API -+ // Purpur start -+ if (new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) -+ return teleport(location, cause); -+ // Purpur end - return false; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 30a95d4b18964c6b25beb4dbec84f03effc2145b..bed0ee3cac8d2acda872f5f3fcbd2b75a6ca3a0d 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -117,6 +117,7 @@ public class PurpurWorldConfig { - public boolean entitiesCanUsePortals = true; - public boolean entitiesPickUpLootBypassMobGriefing = false; - public boolean fireballsBypassMobGriefing = false; -+ public boolean imposeTeleportRestrictionsOnGateways = false; - public boolean milkCuresBadOmen = true; - public boolean noteBlockIgnoreAbove = false; - public boolean persistentDroppableEntityDisplayNames = true; -@@ -134,6 +135,7 @@ public class PurpurWorldConfig { - entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); - entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); - fireballsBypassMobGriefing = getBoolean("gameplay-mechanics.fireballs-bypass-mob-griefing", fireballsBypassMobGriefing); -+ imposeTeleportRestrictionsOnGateways = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-gateways", imposeTeleportRestrictionsOnGateways); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); - noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove); - persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); diff --git a/patches/server/0121-Farmland-trampling-changes.patch b/patches/server/0121-Farmland-trampling-changes.patch deleted file mode 100644 index e48e6ca91..000000000 --- a/patches/server/0121-Farmland-trampling-changes.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 9 Jan 2021 16:06:40 +0100 -Subject: [PATCH] Farmland trampling changes - -This lets us choose if farmland trampling is fully disabled or only -players may trample farmland. - -This lets us choose if entities can stop trampling if they fall a -distance equal to their feather falling level, plus the extra block -necessary to trample in the first place. Feather Falling 1 requires -you to fall over 3+ blocks to trample. FF 2 requires 4+, etc. - -diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index 99798220b6e0ad06db2ba5c9b74bfb72af185fee..12a0c69f8fec30fad64cbb00af2ca1bbf0ea5153 100644 ---- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -126,12 +126,20 @@ public class FarmBlock extends Block { - } - - // Purpur start -+ if (world.purpurConfig.farmlandTramplingDisabled) return; -+ if (world.purpurConfig.farmlandTramplingOnlyPlayers && !(entity instanceof Player)) return; - if (world.purpurConfig.farmlandAlpha) { - Block block = world.getBlockState(pos.below()).getBlock(); - if (block instanceof FenceBlock || block instanceof WallBlock) { - return; - } - } -+ if (world.purpurConfig.farmlandTramplingFeatherFalling) { -+ Iterator armor = ((LivingEntity) entity).getArmorSlots().iterator(); -+ if (armor.hasNext() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) >= (int) entity.fallDistance) { -+ return; -+ } -+ } - // Purpur end - if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.DIRT.defaultBlockState())) { - return; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index bed0ee3cac8d2acda872f5f3fcbd2b75a6ca3a0d..91f204f313ee4b5a1f16416670e855d4e7177e51 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -458,10 +458,16 @@ public class PurpurWorldConfig { - public boolean farmlandBypassMobGriefing = false; - public boolean farmlandGetsMoistFromBelow = false; - public boolean farmlandAlpha = false; -+ public boolean farmlandTramplingDisabled = false; -+ public boolean farmlandTramplingOnlyPlayers = false; -+ public boolean farmlandTramplingFeatherFalling = false; - private void farmlandSettings() { - farmlandBypassMobGriefing = getBoolean("blocks.farmland.bypass-mob-griefing", farmlandBypassMobGriefing); - farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); - farmlandAlpha = getBoolean("blocks.farmland.use-alpha-farmland", farmlandAlpha); -+ farmlandTramplingDisabled = getBoolean("blocks.farmland.disable-trampling", farmlandTramplingDisabled); -+ farmlandTramplingOnlyPlayers = getBoolean("blocks.farmland.only-players-trample", farmlandTramplingOnlyPlayers); -+ farmlandTramplingFeatherFalling = getBoolean("blocks.farmland.feather-fall-distance-affects-trampling", farmlandTramplingFeatherFalling); - } - - public boolean furnaceUseLavaFromUnderneath = false; diff --git a/patches/server/0122-Movement-options-for-armor-stands.patch b/patches/server/0122-Movement-options-for-armor-stands.patch deleted file mode 100644 index 2e06519b9..000000000 --- a/patches/server/0122-Movement-options-for-armor-stands.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mariell Hoversholm -Date: Sat, 9 Jan 2021 22:22:59 +0100 -Subject: [PATCH] Movement options for armor stands - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index a93ae9de698ce97e8603deb1075e6dc5aeaab274..2f8b5646222b86fa7ef908c9796d28e034702ec7 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1936,7 +1936,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return this.isInWater() || flag; - } - -- void updateInWaterStateAndDoWaterCurrentPushing() { -+ public void updateInWaterStateAndDoWaterCurrentPushing() { // Purpur - package-private -> public - Entity entity = this.getVehicle(); - - if (entity instanceof Boat entityboat) { -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -index 8b25bb80a913cd002cdaeadf076d811172f10488..89f600edda9a1c5d1b132355fefb7eaed77c52f5 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -103,10 +103,12 @@ public class ArmorStand extends LivingEntity { - private boolean noTickPoseDirty = false; - private boolean noTickEquipmentDirty = false; - // Paper end - Allow ArmorStands not to tick -+ public boolean canMovementTick = true; // Purpur - - public ArmorStand(EntityType type, Level world) { - super(type, world); - if (world != null) this.canTick = world.paperConfig().entities.armorStands.tick; // Paper - Allow ArmorStands not to tick -+ if (world != null) this.canMovementTick = world.purpurConfig.armorstandMovement; // Purpur - this.handItems = NonNullList.withSize(2, ItemStack.EMPTY); - this.armorItems = NonNullList.withSize(4, ItemStack.EMPTY); - this.headPose = ArmorStand.DEFAULT_HEAD_POSE; -@@ -1005,4 +1007,18 @@ public class ArmorStand extends LivingEntity { - } - } - // Paper end -+ -+ // Purpur start -+ @Override -+ public void updateInWaterStateAndDoWaterCurrentPushing() { -+ if (this.level().purpurConfig.armorstandWaterMovement && -+ (this.level().purpurConfig.armorstandWaterFence || !(level().getBlockState(blockPosition().below()).getBlock() instanceof net.minecraft.world.level.block.FenceBlock))) -+ super.updateInWaterStateAndDoWaterCurrentPushing(); -+ } -+ -+ @Override -+ public void aiStep() { -+ if (this.canMovementTick && this.canMove) super.aiStep(); -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 91f204f313ee4b5a1f16416670e855d4e7177e51..c0f62102bb2147d08666013c5ca5360a5bcf8e8b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -99,10 +99,16 @@ public class PurpurWorldConfig { - public float armorstandStepHeight = 0.0F; - public boolean armorstandSetNameVisible = true; - public boolean armorstandFixNametags = false; -+ public boolean armorstandMovement = true; -+ public boolean armorstandWaterMovement = true; -+ public boolean armorstandWaterFence = true; - private void armorstandSettings() { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); - armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); - armorstandFixNametags = getBoolean("gameplay-mechanics.armorstand.fix-nametags", armorstandFixNametags); -+ armorstandMovement = getBoolean("gameplay-mechanics.armorstand.can-movement-tick", armorstandMovement); -+ armorstandWaterMovement = getBoolean("gameplay-mechanics.armorstand.can-move-in-water", armorstandWaterMovement); -+ armorstandWaterFence = getBoolean("gameplay-mechanics.armorstand.can-move-in-water-over-fence", armorstandWaterFence); - } - - public boolean arrowMovementResetsDespawnCounter = true; diff --git a/patches/server/0123-Fix-stuck-in-portals.patch b/patches/server/0123-Fix-stuck-in-portals.patch deleted file mode 100644 index 79213b490..000000000 --- a/patches/server/0123-Fix-stuck-in-portals.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 14 Jan 2021 16:48:10 -0600 -Subject: [PATCH] Fix stuck in portals - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 07d08bc8d95025fda0859c84b9ea84fe6870d004..146c2e46e0fb9a9358484a054f716d72b9750ed8 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1348,6 +1348,7 @@ public class ServerPlayer extends Player { - playerlist.sendPlayerPermissionLevel(this); - worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); - this.unsetRemoved(); -+ this.portalPos = io.papermc.paper.util.MCUtil.toBlockPosition(exit); // Purpur - - // CraftBukkit end - this.setServerLevel(worldserver); -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 2f8b5646222b86fa7ef908c9796d28e034702ec7..1ec1f023d7eee5714c94dbb6c842444f70603f40 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3217,12 +3217,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return Vec3.directionFromRotation(this.getRotationVector()); - } - -+ public BlockPos portalPos = BlockPos.ZERO; // Purpur - public void handleInsidePortal(BlockPos pos) { - if (this.isOnPortalCooldown()) { -+ if (!(level().purpurConfig.playerFixStuckPortal && this instanceof Player && !pos.equals(portalPos))) // Purpur - this.setPortalCooldown(); - } else if (level().purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer) { // Purpur - if (!this.level().isClientSide && !pos.equals(this.portalEntrancePos)) { - this.portalEntrancePos = pos.immutable(); -+ portalPos = BlockPos.ZERO; // Purpur - } - - this.isInsidePortal = true; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index c0f62102bb2147d08666013c5ca5360a5bcf8e8b..780a13db057456e49690d90c368284752bafde3f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -333,6 +333,7 @@ public class PurpurWorldConfig { - public int playerDeathExpDropMax = 100; - public boolean teleportIfOutsideBorder = false; - public boolean totemOfUndyingWorksInInventory = false; -+ public boolean playerFixStuckPortal = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -348,6 +349,7 @@ public class PurpurWorldConfig { - playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax); - teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); - totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory); -+ playerFixStuckPortal = getBoolean("gameplay-mechanics.player.fix-stuck-in-portal", playerFixStuckPortal); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0124-Toggle-for-water-sensitive-mob-damage.patch b/patches/server/0124-Toggle-for-water-sensitive-mob-damage.patch deleted file mode 100644 index ef95121ec..000000000 --- a/patches/server/0124-Toggle-for-water-sensitive-mob-damage.patch +++ /dev/null @@ -1,2344 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: YouHaveTrouble -Date: Fri, 5 Feb 2021 01:11:22 +0100 -Subject: [PATCH] Toggle for water sensitive mob damage - - -diff --git a/src/main/java/net/minecraft/world/entity/GlowSquid.java b/src/main/java/net/minecraft/world/entity/GlowSquid.java -index 4cd57672c548950cb4e0aa97af75ecca84be6823..70e3d583f7a039a5c67428ce9e8beb1922574c7b 100644 ---- a/src/main/java/net/minecraft/world/entity/GlowSquid.java -+++ b/src/main/java/net/minecraft/world/entity/GlowSquid.java -@@ -46,6 +46,11 @@ public class GlowSquid extends Squid { - return this.level().purpurConfig.glowSquidsCanFly; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.glowSquidTakeDamageFromWater; -+ } -+ - @Override - protected ParticleOptions getInkParticle() { - return ParticleTypes.GLOW_SQUID_INK; -diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index 49adf3f230fa34289a2ce09a9d829f5dbf952fc8..a7847b6ca5b203fd693337928f31a9043be163d7 100644 ---- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java -+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -277,6 +277,11 @@ public class Bat extends AmbientCreature { - this.getAttribute(Attributes.ATTACK_KNOCKBACK).setBaseValue(this.level().purpurConfig.batAttackKnockback); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.batTakeDamageFromWater; -+ } -+ - @Override - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index cbcfe8177362d9b8af97f21e716a4dce9e227465..0978f519177ce2f0991402dafb9a22c5a8686168 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -175,7 +175,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - // Paper end - Fix MC-167279 - this.lookControl = new Bee.BeeLookControl(this); - this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F); -- this.setPathfindingMalus(PathType.WATER, -1.0F); -+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - this.setPathfindingMalus(PathType.WATER_BORDER, 16.0F); - this.setPathfindingMalus(PathType.COCOA, -1.0F); - this.setPathfindingMalus(PathType.FENCE, -1.0F); -@@ -477,6 +477,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - return this.level().purpurConfig.beeBreedingTicks; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.beeTakeDamageFromWater; -+ } -+ - @Override - public int getRemainingPersistentAngerTime() { - return (Integer) this.entityData.get(Bee.DATA_REMAINING_ANGER_TIME); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 27e448a38377ea3cc2e527dbe48a23d233f1ea13..446aec4d10e614f136fe6ae4bb5a7dd0ac6d0f18 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -139,6 +139,11 @@ public class Cat extends TamableAnimal implements VariantHolder { - return this.level().purpurConfig.foxBreedingTicks; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.foxTakeDamageFromWater; -+ } -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -index 2919d055e2136a956aa038bd0bf4c1a2ff5afa2f..9c86d86a6d89585cfbdace89e66866f496da86cb 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -@@ -83,6 +83,11 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - } - // Purpur end - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.ironGolemTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - if (level().purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur -diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index 22a2328fe5159c8fed635a62334a3f1028c346a5..6cb8d85986f4d891dfbb66b83163ed23bac694f6 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -91,6 +91,11 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder { - public int getPurpurBreedTime() { - return this.level().purpurConfig.rabbitBreedingTicks; - } -+ -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.rabbitTakeDamageFromWater; -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/Salmon.java b/src/main/java/net/minecraft/world/entity/animal/Salmon.java -index 742805994f29a18af444912b10af631d2c60cacf..e101c3bf425902908c43ffa18867fb83a5e1f16e 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Salmon.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Salmon.java -@@ -30,6 +30,11 @@ public class Salmon extends AbstractSchoolingFish { - this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.salmonMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.salmonTakeDamageFromWater; -+ } -+ - @Override - public int getMaxSchoolSize() { - return 5; -diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -index c3cc949291d11ae707fa5175d666df2ee81cdcce..afec39ba3b51b121fd7ae937e7bac060ef430dfd 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -144,6 +144,11 @@ public class Sheep extends Animal implements Shearable { - return this.level().purpurConfig.sheepBreedingTicks; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.sheepTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - this.eatBlockGoal = new EatBlockGoal(this); -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index cdb6657d30d224709aec3921c5fb8380f8acd93e..9f20eae7449c670b913cc3bbe1a89254a1d8cde2 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -114,7 +114,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - - @Override - public boolean isSensitiveToWater() { -- return true; -+ return this.level().purpurConfig.snowGolemTakeDamageFromWater; // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index f0261117a4f8ae240b3b991053deaf8d6419b5b4..0d05879eadeff8731028d78d89d5d32142818ea2 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Squid.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -88,6 +88,11 @@ public class Squid extends WaterAnimal { - return this.wasTouchingWater || canFly(); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.squidTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -index 327b1805d9d4069212a8772ff189c9ab24ae1183..4ac998e9d96aed3b0ea0ec3f9dcd5fdd74c45d24 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -+++ b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -@@ -84,6 +84,11 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder - this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.tropicalFishMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.tropicalFishTakeDamageFromWater; -+ } -+ - public static String getPredefinedName(int variant) { - return "entity.minecraft.tropical_fish.predefined." + variant; - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index a577ec78b2f5bca0166277c499da4fa7988d5395..b146ac72584d998cee4279133b3b19051fbf14c9 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -114,6 +114,11 @@ public class Turtle extends Animal { - return this.level().purpurConfig.turtleBreedingTicks; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.turtleTakeDamageFromWater; -+ } -+ - public void setHomePos(BlockPos pos) { - this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos... - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -index 580bff2b4308f97acf402c9539755aee7aa8b3d8..db0d71da579752bfb8246f5fa2ec9d360f53c7a8 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -@@ -219,6 +219,11 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder getModelRotationValues() { - return this.modelRotationValues; -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 84c04603d50e190430e4e6cf2a7b613537a0c341..412b44ea2d33ef68721b91da9f550738c6c780ba 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -113,6 +113,11 @@ public class Goat extends Animal { - return this.level().purpurConfig.goatBreedingTicks; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.goatTakeDamageFromWater; -+ } -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(Goat.MEMORY_TYPES, Goat.SENSOR_TYPES); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -index 2990d50fd5209b272e0cfbd5dd633124048e8129..891ea1cca8495c08a1817096c8c4277f5311d6c7 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -@@ -42,6 +42,11 @@ public class Donkey extends AbstractChestedHorse { - return this.level().purpurConfig.donkeyBreedingTicks; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.donkeyTakeDamageFromWater; -+ } -+ - @Override - protected SoundEvent getAmbientSound() { - return SoundEvents.DONKEY_AMBIENT; -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -index 16d4278d49dad84f72c968ca36914e93d46dc5f6..e623284b353831d1a540af40e139ac16091dcbf6 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -@@ -71,6 +71,11 @@ public class Horse extends AbstractHorse implements VariantHolder { - return this.level().purpurConfig.horseBreedingTicks; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.horseTakeDamageFromWater; -+ } -+ - @Override - protected void randomizeAttributes(RandomSource random) { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)generateMaxHealth(random::nextInt)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 81d614cf14512464b376575fd2d7e7fbf93d9e03..87ec5bd632353ce364de29c5d56460551b6a4139 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -@@ -145,6 +145,11 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, Level world) { - super(type, world); - this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur -- this.setPathfindingMalus(PathType.WATER, -1.0F); -+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - this.setPathfindingMalus(PathType.LAVA, 8.0F); - this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); - this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); -@@ -153,7 +153,7 @@ public class Blaze extends Monster { - - @Override - public boolean isSensitiveToWater() { -- return true; -+ return this.level().purpurConfig.blazeTakeDamageFromWater; // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java -index 562f73dd5e617c10382c50be86ce88f4de1a4fe1..0604b7c68373ed071ac22cabd7a961161ad228f8 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java -@@ -48,6 +48,11 @@ public class CaveSpider extends Spider { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.caveSpiderMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.caveSpiderTakeDamageFromWater; -+ } -+ - @Override - public boolean doHurtTarget(Entity target) { - if (super.doHurtTarget(target)) { -diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index 98c93c46694f1e67be803a7ca0c0f55532df2e95..a9523b156eb88646ef82ee857d5f68360b12a753 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -265,6 +265,11 @@ public class Creeper extends Monster implements PowerableMob { - return super.finalizeSpawn(world, difficulty, spawnReason, entityData); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.creeperTakeDamageFromWater; -+ } -+ - @Override - protected SoundEvent getHurtSound(DamageSource source) { - return SoundEvents.CREEPER_HURT; -diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -index b02cdbaa0455319b1e8a7e777e64ff4a56590388..f037d50f26f7532f11a71790448de7a71644b6ca 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -@@ -98,6 +98,11 @@ public class Drowned extends Zombie implements RangedAttackMob { - this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.drownedSpawnReinforcements); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.drownedTakeDamageFromWater; -+ } -+ - @Override - public boolean jockeyOnlyBaby() { - return level().purpurConfig.drownedJockeyOnlyBaby; -diff --git a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -index 6152117a3e13252068e16945b4346a73a3090dda..3651a720e4ae20686a91b4420fe4879f765935e4 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java -@@ -50,6 +50,11 @@ public class ElderGuardian extends Guardian { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.elderGuardianMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.elderGuardianTakeDamageFromWater; -+ } -+ - public static AttributeSupplier.Builder createAttributes() { - return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.ATTACK_DAMAGE, 8.0D).add(Attributes.MAX_HEALTH, 80.0D); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index de1fe3b115c1b3936b79c8900389542a8c8a2c90..17b044e58d2ed33ed16e60f4fd4f63b2ee3f854d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -90,7 +90,7 @@ public class EnderMan extends Monster implements NeutralMob { - - public EnderMan(EntityType type, Level world) { - super(type, world); -- this.setPathfindingMalus(PathType.WATER, -1.0F); -+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - } - - // Purpur start -@@ -298,7 +298,7 @@ public class EnderMan extends Monster implements NeutralMob { - - @Override - public boolean isSensitiveToWater() { -- return true; -+ return this.level().purpurConfig.endermanTakeDamageFromWater; // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Endermite.java b/src/main/java/net/minecraft/world/entity/monster/Endermite.java -index 52e2588b32b56b51bdbbdf63a290b2a4a4b02c13..514354bfcd0608554fd515248975fb107eddf427 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Endermite.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Endermite.java -@@ -60,6 +60,11 @@ public class Endermite extends Monster { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.endermiteMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.endermiteTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(1, new FloatGoal(this)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Evoker.java b/src/main/java/net/minecraft/world/entity/monster/Evoker.java -index ce2e5c16db13accb082b3f2403661c65411c7a80..a3e88c252b39a78a0759623f188dbdc8aa2fcc0b 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Evoker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Evoker.java -@@ -74,6 +74,11 @@ public class Evoker extends SpellcasterIllager { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.evokerMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.evokerTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ghast.java b/src/main/java/net/minecraft/world/entity/monster/Ghast.java -index 4bad5bdce2df5f5233465b30bcd3121b1dff0874..96f7c8fb4e49e7640aaa1adb466d67fc887a2dc5 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ghast.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ghast.java -@@ -136,6 +136,11 @@ public class Ghast extends FlyingMob implements Enemy { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ghastMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.ghastTakeDamageFromWater; -+ } -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Giant.java b/src/main/java/net/minecraft/world/entity/monster/Giant.java -index 3c1217d36522b1fd3d1a099d3a12d99016f34c4b..47e403a5986f77dbb3833acb9a3ea59e5c3740c6 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Giant.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Giant.java -@@ -72,6 +72,11 @@ public class Giant extends Monster { - } - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.giantTakeDamageFromWater; -+ } -+ - @Override - protected void initAttributes() { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.giantMaxHealth); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Guardian.java b/src/main/java/net/minecraft/world/entity/monster/Guardian.java -index 7fa4e9761c6aad83848bf5e80a213689d728921d..6b0ff4ded5e8b62572d5889f0be5e3148243ed7d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Guardian.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Guardian.java -@@ -95,6 +95,11 @@ public class Guardian extends Monster { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.guardianMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.guardianTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - MoveTowardsRestrictionGoal pathfindergoalmovetowardsrestriction = new MoveTowardsRestrictionGoal(this, 1.0D); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Husk.java b/src/main/java/net/minecraft/world/entity/monster/Husk.java -index 6673c0bff3a4e3d11a09e9dc8aeb0c2418dc7f59..cb96bd5769159e6c25968673ea07cd6d107cff46 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Husk.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Husk.java -@@ -64,6 +64,11 @@ public class Husk extends Zombie { - return level().purpurConfig.huskJockeyTryExistingChickens; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.huskTakeDamageFromWater; -+ } -+ - public static boolean checkHuskSpawnRules(EntityType type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - return checkMonsterSpawnRules(type, world, spawnReason, pos, random) && (MobSpawnType.isSpawner(spawnReason) || world.canSeeSky(pos)); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -index c680e1efb73a6387aad6ecdab94f690c12451a32..e2393be574475377fd401d55ab0be9b483e705e6 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -@@ -80,6 +80,11 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.illusionerMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.illusionerTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -index 61cd97bc17802d3ab30999fc1f2b91e8b00652b2..adacdbf9fac7d1504be73e2e5a7526e8258a126d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -+++ b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -@@ -66,6 +66,11 @@ public class MagmaCube extends Slime { - return level().purpurConfig.magmaCubeAttackDamageCache; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.magmaCubeTakeDamageFromWater; -+ } -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index c15d75472d4d92baeb87a147832e17e363c360be..c52d40eb33a16e428c016a902faeb62aea0fd727 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -136,6 +136,11 @@ public class Phantom extends FlyingMob implements Enemy { - } - // Purpur end - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.phantomTakeDamageFromWater; -+ } -+ - @Override - public boolean isFlapping() { - return (this.getUniqueFlapTickOffset() + this.tickCount) % Phantom.TICKS_PER_FLAP == 0; -diff --git a/src/main/java/net/minecraft/world/entity/monster/Pillager.java b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -index 8c06e648df453fdd4eea0aa4843fada9b6375f81..a405764724d7f4b586d8510450a6258417495942 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Pillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -@@ -80,6 +80,11 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pillagerMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.pillagerTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index cebe89b0868043b819fb3e9987f899926961be52..e592b5ee3a0bfce987557defed8250682373fe65 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -96,6 +96,11 @@ public class Ravager extends Raider { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ravagerMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.ravagerTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index 1793c5f4e33fbab9d64d81bb1767b0e9b248106f..5b4ad4f64488ca5a21312caa3d13318f429401ea 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -119,6 +119,11 @@ public class Shulker extends AbstractGolem implements VariantHolder type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - BlockPos blockPos = pos; - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java -index 741eedcd9e0e29b57d2b3caf5aef1aef18ae5118..585614f7825700da28c7c832bdfc6a9eb0b78b5f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Strider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java -@@ -91,7 +91,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - super(type, world); - this.steering = new ItemBasedSteering(this.entityData, Strider.DATA_BOOST_TIME, Strider.DATA_SADDLE_ID); - this.blocksBuilding = true; -- this.setPathfindingMalus(PathType.WATER, -1.0F); -+ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - this.setPathfindingMalus(PathType.LAVA, 0.0F); - this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); - this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); -@@ -442,7 +442,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - - @Override - public boolean isSensitiveToWater() { -- return true; -+ return this.level().purpurConfig.striderTakeDamageFromWater; // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java -index ca6c688b31240863dfc5095c7b6187583cf2f6ce..d85e4baa892ebd987993bd39c895e5f1d310e30e 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vex.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java -@@ -107,6 +107,11 @@ public class Vex extends Monster implements TraceableEntity { - public void initAttributes() { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vexMaxHealth); - } -+ -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.vexTakeDamageFromWater; -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -index 61f1778d454cebaab5580179614ff48ab67b8fe6..ded53c16dfd850c9c520878bc75414ebc188ea8a 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -@@ -72,6 +72,11 @@ public class Vindicator extends AbstractIllager { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vindicatorMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.vindicatorTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java -index d99c52b4f0326421f90162d4894044394b3c49c4..51d35e7f510c76d1fc18c67dbb56707207b39e4e 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Witch.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java -@@ -77,6 +77,11 @@ public class Witch extends Raider implements RangedAttackMob { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witchMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.witchTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -index 9fd9b95cbec010dafec261b5923938c5b39cd1e6..9865cc694e6ef02543a4b04cde37be3dc285475b 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -@@ -54,6 +54,11 @@ public class WitherSkeleton extends AbstractSkeleton { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witherSkeletonMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.witherSkeletonTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -index 698076b0e958aadf9736d7753df64a73dd3c17cd..76d47ba17dd140572a0be40dfda18c24851198bb 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -@@ -102,6 +102,11 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zoglinMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.zoglinTakeDamageFromWater; -+ } -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index 3d42b2ea26217243dba96174ff0eadbcdd81a6cd..de7a74f1e5181373da8dcc639245f35f77f4f09b 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -138,6 +138,11 @@ public class Zombie extends Monster { - return level().purpurConfig.zombieJockeyTryExistingChickens; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.zombieTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index ffe2144e307acebd4a8bed043db0ee0bb6bf611c..2ec3a09135f85a5de68e77511f3f213adf08712c 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -107,6 +107,11 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieVillagerSpawnReinforcements); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.zombieVillagerTakeDamageFromWater; -+ } -+ - @Override - public boolean jockeyOnlyBaby() { - return level().purpurConfig.zombieVillagerJockeyOnlyBaby; -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -index 6be751e2d434982a35bbbece4f4fc4631fb3d8e0..bd2953448e568b1a20bcc6a889cef83b88418548 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -84,6 +84,11 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombifiedPiglinMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.zombifiedPiglinTakeDamageFromWater; -+ } -+ - @Override - public boolean jockeyOnlyBaby() { - return level().purpurConfig.zombifiedPiglinJockeyOnlyBaby; -diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index a770ae0e13c4dad296dfb8f33259408ee1531c70..9ca294d5177ec7d541433d644d2fb90d937b011c 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -117,6 +117,11 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - return this.level().purpurConfig.hoglinBreedingTicks; - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.hoglinTakeDamageFromWater; -+ } -+ - @Override - public boolean canBeLeashed(Player player) { - return !this.isLeashed(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index 57089ba787731ddda853dce959ba015abe135bfd..e5b24bd8e31ca5748185181bb6741760c86a92a1 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -116,6 +116,11 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.piglinTakeDamageFromWater; -+ } -+ - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -index 362f3fddd8090799278f4b4e58c5af5de00315f2..6c7e0f177382cb6329002dcde270f6ce51f08f9f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -@@ -84,6 +84,11 @@ public class PiglinBrute extends AbstractPiglin { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinBruteMaxHealth); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.piglinBruteTakeDamageFromWater; -+ } -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 50.0).add(Attributes.MOVEMENT_SPEED, 0.35F).add(Attributes.ATTACK_DAMAGE, 7.0); - } -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index f7d8f672a680cf2dfebba5677f97895e4a8c209f..c9cfbc8817fe62e22cb165f856ed8569668c0a60 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -189,6 +189,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - return level().purpurConfig.villagerCanBeLeashed && !this.isLeashed(); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.villagerTakeDamageFromWater; -+ } -+ - @Override - public Brain getBrain() { - return (Brain) super.getBrain(); // CraftBukkit - decompile error -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index 9d5eaaf1869a3ecb61947ab0c09af558fa1cd283..c192f4cc5fd9cb0cf40083c4297f649ab909649d 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -98,6 +98,11 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - return level().purpurConfig.wanderingTraderCanBeLeashed && !this.isLeashed(); - } - -+ @Override -+ public boolean isSensitiveToWater() { -+ return this.level().purpurConfig.wanderingTraderTakeDamageFromWater; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 780a13db057456e49690d90c368284752bafde3f..7e520532aec1dc38da84dce2dc8679d977a030ea 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -569,11 +569,13 @@ public class PurpurWorldConfig { - public boolean axolotlControllable = true; - public double axolotlMaxHealth = 14.0D; - public int axolotlBreedingTicks = 6000; -+ public boolean axolotlTakeDamageFromWater = false; - private void axolotlSettings() { - axolotlRidable = getBoolean("mobs.axolotl.ridable", axolotlRidable); - axolotlControllable = getBoolean("mobs.axolotl.controllable", axolotlControllable); - axolotlMaxHealth = getDouble("mobs.axolotl.attributes.max_health", axolotlMaxHealth); - axolotlBreedingTicks = getInt("mobs.axolotl.breeding-delay-ticks", axolotlBreedingTicks); -+ axolotlTakeDamageFromWater = getBoolean("mobs.axolotl.takes-damage-from-water", axolotlTakeDamageFromWater); - } - - public boolean batRidable = false; -@@ -588,6 +590,7 @@ public class PurpurWorldConfig { - public double batArmor = 0.0D; - public double batArmorToughness = 0.0D; - public double batAttackKnockback = 0.0D; -+ public boolean batTakeDamageFromWater = false; - private void batSettings() { - batRidable = getBoolean("mobs.bat.ridable", batRidable); - batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater); -@@ -606,6 +609,7 @@ public class PurpurWorldConfig { - batArmor = getDouble("mobs.bat.attributes.armor", batArmor); - batArmorToughness = getDouble("mobs.bat.attributes.armor_toughness", batArmorToughness); - batAttackKnockback = getDouble("mobs.bat.attributes.attack_knockback", batAttackKnockback); -+ batTakeDamageFromWater = getBoolean("mobs.bat.takes-damage-from-water", batTakeDamageFromWater); - } - - public boolean beeRidable = false; -@@ -614,6 +618,7 @@ public class PurpurWorldConfig { - public double beeMaxY = 320D; - public double beeMaxHealth = 10.0D; - public int beeBreedingTicks = 6000; -+ public boolean beeTakeDamageFromWater = false; - private void beeSettings() { - beeRidable = getBoolean("mobs.bee.ridable", beeRidable); - beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); -@@ -626,6 +631,7 @@ public class PurpurWorldConfig { - } - beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth); - beeBreedingTicks = getInt("mobs.bee.breeding-delay-ticks", beeBreedingTicks); -+ beeTakeDamageFromWater = getBoolean("mobs.bee.takes-damage-from-water", beeTakeDamageFromWater); - } - - public boolean blazeRidable = false; -@@ -633,6 +639,7 @@ public class PurpurWorldConfig { - public boolean blazeControllable = true; - public double blazeMaxY = 320D; - public double blazeMaxHealth = 20.0D; -+ public boolean blazeTakeDamageFromWater = true; - private void blazeSettings() { - blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); - blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); -@@ -644,6 +651,7 @@ public class PurpurWorldConfig { - set("mobs.blaze.attributes.max_health", oldValue); - } - blazeMaxHealth = getDouble("mobs.blaze.attributes.max_health", blazeMaxHealth); -+ blazeTakeDamageFromWater = getBoolean("mobs.blaze.takes-damage-from-water", blazeTakeDamageFromWater); - } - - public boolean camelRidableInWater = false; -@@ -674,6 +682,7 @@ public class PurpurWorldConfig { - public int catSpawnVillageScanRange = 48; - public int catBreedingTicks = 6000; - public DyeColor catDefaultCollarColor = DyeColor.RED; -+ public boolean catTakeDamageFromWater = false; - private void catSettings() { - catRidable = getBoolean("mobs.cat.ridable", catRidable); - catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); -@@ -693,12 +702,14 @@ public class PurpurWorldConfig { - } catch (IllegalArgumentException ignore) { - catDefaultCollarColor = DyeColor.RED; - } -+ catTakeDamageFromWater = getBoolean("mobs.cat.takes-damage-from-water", catTakeDamageFromWater); - } - - public boolean caveSpiderRidable = false; - public boolean caveSpiderRidableInWater = true; - public boolean caveSpiderControllable = true; - public double caveSpiderMaxHealth = 12.0D; -+ public boolean caveSpiderTakeDamageFromWater = false; - private void caveSpiderSettings() { - caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable); - caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater); -@@ -709,6 +720,7 @@ public class PurpurWorldConfig { - set("mobs.cave_spider.attributes.max_health", oldValue); - } - caveSpiderMaxHealth = getDouble("mobs.cave_spider.attributes.max_health", caveSpiderMaxHealth); -+ caveSpiderTakeDamageFromWater = getBoolean("mobs.cave_spider.takes-damage-from-water", caveSpiderTakeDamageFromWater); - } - - public boolean chickenRidable = false; -@@ -717,6 +729,7 @@ public class PurpurWorldConfig { - public double chickenMaxHealth = 4.0D; - public boolean chickenRetaliate = false; - public int chickenBreedingTicks = 6000; -+ public boolean chickenTakeDamageFromWater = false; - private void chickenSettings() { - chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); - chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); -@@ -729,11 +742,13 @@ public class PurpurWorldConfig { - chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth); - chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); - chickenBreedingTicks = getInt("mobs.chicken.breeding-delay-ticks", chickenBreedingTicks); -+ chickenTakeDamageFromWater = getBoolean("mobs.chicken.takes-damage-from-water", chickenTakeDamageFromWater); - } - - public boolean codRidable = false; - public boolean codControllable = true; - public double codMaxHealth = 3.0D; -+ public boolean codTakeDamageFromWater = false; - private void codSettings() { - codRidable = getBoolean("mobs.cod.ridable", codRidable); - codControllable = getBoolean("mobs.cod.controllable", codControllable); -@@ -743,6 +758,7 @@ public class PurpurWorldConfig { - set("mobs.cod.attributes.max_health", oldValue); - } - codMaxHealth = getDouble("mobs.cod.attributes.max_health", codMaxHealth); -+ codTakeDamageFromWater = getBoolean("mobs.cod.takes-damage-from-water", codTakeDamageFromWater); - } - - public boolean cowRidable = false; -@@ -751,6 +767,7 @@ public class PurpurWorldConfig { - public double cowMaxHealth = 10.0D; - public int cowFeedMushrooms = 0; - public int cowBreedingTicks = 6000; -+ public boolean cowTakeDamageFromWater = false; - private void cowSettings() { - cowRidable = getBoolean("mobs.cow.ridable", cowRidable); - cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); -@@ -763,6 +780,7 @@ public class PurpurWorldConfig { - cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth); - cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); - cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks); -+ cowTakeDamageFromWater = getBoolean("mobs.cow.takes-damage-from-water", cowTakeDamageFromWater); - } - - public boolean creeperRidable = false; -@@ -772,6 +790,7 @@ public class PurpurWorldConfig { - public double creeperChargedChance = 0.0D; - public boolean creeperAllowGriefing = true; - public boolean creeperBypassMobGriefing = false; -+ public boolean creeperTakeDamageFromWater = false; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -785,6 +804,7 @@ public class PurpurWorldConfig { - creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); - creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); - creeperBypassMobGriefing = getBoolean("mobs.creeper.bypass-mob-griefing", creeperBypassMobGriefing); -+ creeperTakeDamageFromWater = getBoolean("mobs.creeper.takes-damage-from-water", creeperTakeDamageFromWater); - } - - public boolean dolphinRidable = false; -@@ -794,6 +814,7 @@ public class PurpurWorldConfig { - public float dolphinSpitDamage = 2.0F; - public double dolphinMaxHealth = 10.0D; - public boolean dolphinDisableTreasureSearching = false; -+ public boolean dolphinTakeDamageFromWater = false; - private void dolphinSettings() { - dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); - dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable); -@@ -807,6 +828,7 @@ public class PurpurWorldConfig { - } - dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth); - dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching); -+ dolphinTakeDamageFromWater = getBoolean("mobs.dolphin.takes-damage-from-water", dolphinTakeDamageFromWater); - } - - public boolean donkeyRidableInWater = false; -@@ -817,6 +839,7 @@ public class PurpurWorldConfig { - public double donkeyMovementSpeedMin = 0.175D; - public double donkeyMovementSpeedMax = 0.175D; - public int donkeyBreedingTicks = 6000; -+ public boolean donkeyTakeDamageFromWater = false; - private void donkeySettings() { - donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); - if (PurpurConfig.version < 10) { -@@ -833,6 +856,7 @@ public class PurpurWorldConfig { - donkeyMovementSpeedMin = getDouble("mobs.donkey.attributes.movement_speed.min", donkeyMovementSpeedMin); - donkeyMovementSpeedMax = getDouble("mobs.donkey.attributes.movement_speed.max", donkeyMovementSpeedMax); - donkeyBreedingTicks = getInt("mobs.donkey.breeding-delay-ticks", donkeyBreedingTicks); -+ donkeyTakeDamageFromWater = getBoolean("mobs.donkey.takes-damage-from-water", donkeyTakeDamageFromWater); - } - - public boolean drownedRidable = false; -@@ -843,6 +867,7 @@ public class PurpurWorldConfig { - public boolean drownedJockeyOnlyBaby = true; - public double drownedJockeyChance = 0.05D; - public boolean drownedJockeyTryExistingChickens = true; -+ public boolean drownedTakeDamageFromWater = false; - private void drownedSettings() { - drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); - drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); -@@ -857,11 +882,13 @@ public class PurpurWorldConfig { - drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby); - drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance); - drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens); -+ drownedTakeDamageFromWater = getBoolean("mobs.drowned.takes-damage-from-water", drownedTakeDamageFromWater); - } - - public boolean elderGuardianRidable = false; - public boolean elderGuardianControllable = true; - public double elderGuardianMaxHealth = 80.0D; -+ public boolean elderGuardianTakeDamageFromWater = false; - private void elderGuardianSettings() { - elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable); - elderGuardianControllable = getBoolean("mobs.elder_guardian.controllable", elderGuardianControllable); -@@ -871,6 +898,7 @@ public class PurpurWorldConfig { - set("mobs.elder_guardian.attributes.max_health", oldValue); - } - elderGuardianMaxHealth = getDouble("mobs.elder_guardian.attributes.max_health", elderGuardianMaxHealth); -+ elderGuardianTakeDamageFromWater = getBoolean("mobs.elder_guardian.takes-damage-from-water", elderGuardianTakeDamageFromWater); - } - - public boolean enderDragonRidable = false; -@@ -880,6 +908,7 @@ public class PurpurWorldConfig { - public double enderDragonMaxHealth = 200.0D; - public boolean enderDragonAlwaysDropsFullExp = false; - public boolean enderDragonBypassMobGriefing = false; -+ public boolean enderDragonTakeDamageFromWater = false; - private void enderDragonSettings() { - enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); - enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); -@@ -897,6 +926,7 @@ public class PurpurWorldConfig { - enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth); - enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); - enderDragonBypassMobGriefing = getBoolean("mobs.ender_dragon.bypass-mob-griefing", enderDragonBypassMobGriefing); -+ enderDragonTakeDamageFromWater = getBoolean("mobs.ender_dragon.takes-damage-from-water", enderDragonTakeDamageFromWater); - } - - public boolean endermanRidable = false; -@@ -906,6 +936,7 @@ public class PurpurWorldConfig { - public boolean endermanAllowGriefing = true; - public boolean endermanDespawnEvenWithBlock = false; - public boolean endermanBypassMobGriefing = false; -+ public boolean endermanTakeDamageFromWater = true; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -@@ -919,12 +950,14 @@ public class PurpurWorldConfig { - endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); - endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock); - endermanBypassMobGriefing = getBoolean("mobs.enderman.bypass-mob-griefing", endermanBypassMobGriefing); -+ endermanTakeDamageFromWater = getBoolean("mobs.enderman.takes-damage-from-water", endermanTakeDamageFromWater); - } - - public boolean endermiteRidable = false; - public boolean endermiteRidableInWater = true; - public boolean endermiteControllable = true; - public double endermiteMaxHealth = 8.0D; -+ public boolean endermiteTakeDamageFromWater = false; - private void endermiteSettings() { - endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable); - endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater); -@@ -935,6 +968,7 @@ public class PurpurWorldConfig { - set("mobs.endermite.attributes.max_health", oldValue); - } - endermiteMaxHealth = getDouble("mobs.endermite.attributes.max_health", endermiteMaxHealth); -+ endermiteTakeDamageFromWater = getBoolean("mobs.endermite.takes-damage-from-water", endermiteTakeDamageFromWater); - } - - public boolean evokerRidable = false; -@@ -942,6 +976,7 @@ public class PurpurWorldConfig { - public boolean evokerControllable = true; - public double evokerMaxHealth = 24.0D; - public boolean evokerBypassMobGriefing = false; -+ public boolean evokerTakeDamageFromWater = false; - private void evokerSettings() { - evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); - evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); -@@ -953,6 +988,7 @@ public class PurpurWorldConfig { - } - evokerMaxHealth = getDouble("mobs.evoker.attributes.max_health", evokerMaxHealth); - evokerBypassMobGriefing = getBoolean("mobs.evoker.bypass-mob-griefing", evokerBypassMobGriefing); -+ evokerTakeDamageFromWater = getBoolean("mobs.evoker.takes-damage-from-water", evokerTakeDamageFromWater); - } - - public boolean foxRidable = false; -@@ -962,6 +998,7 @@ public class PurpurWorldConfig { - public boolean foxTypeChangesWithTulips = false; - public int foxBreedingTicks = 6000; - public boolean foxBypassMobGriefing = false; -+ public boolean foxTakeDamageFromWater = false; - private void foxSettings() { - foxRidable = getBoolean("mobs.fox.ridable", foxRidable); - foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); -@@ -975,6 +1012,7 @@ public class PurpurWorldConfig { - foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); - foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks); - foxBypassMobGriefing = getBoolean("mobs.fox.bypass-mob-griefing", foxBypassMobGriefing); -+ foxTakeDamageFromWater = getBoolean("mobs.fox.takes-damage-from-water", foxTakeDamageFromWater); - } - - public boolean frogRidable = false; -@@ -995,6 +1033,7 @@ public class PurpurWorldConfig { - public boolean ghastControllable = true; - public double ghastMaxY = 320D; - public double ghastMaxHealth = 10.0D; -+ public boolean ghastTakeDamageFromWater = false; - private void ghastSettings() { - ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); - ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater); -@@ -1006,6 +1045,7 @@ public class PurpurWorldConfig { - set("mobs.ghast.attributes.max_health", oldValue); - } - ghastMaxHealth = getDouble("mobs.ghast.attributes.max_health", ghastMaxHealth); -+ ghastTakeDamageFromWater = getBoolean("mobs.ghast.takes-damage-from-water", ghastTakeDamageFromWater); - } - - public boolean giantRidable = false; -@@ -1018,6 +1058,7 @@ public class PurpurWorldConfig { - public float giantJumpHeight = 1.0F; - public boolean giantHaveAI = false; - public boolean giantHaveHostileAI = false; -+ public boolean giantTakeDamageFromWater = false; - private void giantSettings() { - giantRidable = getBoolean("mobs.giant.ridable", giantRidable); - giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater); -@@ -1038,17 +1079,20 @@ public class PurpurWorldConfig { - giantJumpHeight = (float) getDouble("mobs.giant.jump-height", giantJumpHeight); - giantHaveAI = getBoolean("mobs.giant.have-ai", giantHaveAI); - giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI); -+ giantTakeDamageFromWater = getBoolean("mobs.giant.takes-damage-from-water", giantTakeDamageFromWater); - } - - public boolean glowSquidRidable = false; - public boolean glowSquidControllable = true; - public double glowSquidMaxHealth = 10.0D; - public boolean glowSquidsCanFly = false; -+ public boolean glowSquidTakeDamageFromWater = false; - private void glowSquidSettings() { - glowSquidRidable = getBoolean("mobs.glow_squid.ridable", glowSquidRidable); - glowSquidControllable = getBoolean("mobs.glow_squid.controllable", glowSquidControllable); - glowSquidMaxHealth = getDouble("mobs.glow_squid.attributes.max_health", glowSquidMaxHealth); - glowSquidsCanFly = getBoolean("mobs.glow_squid.can-fly", glowSquidsCanFly); -+ glowSquidTakeDamageFromWater = getBoolean("mobs.glow_squid.takes-damage-from-water", glowSquidTakeDamageFromWater); - } - - public boolean goatRidable = false; -@@ -1056,17 +1100,20 @@ public class PurpurWorldConfig { - public boolean goatControllable = true; - public double goatMaxHealth = 10.0D; - public int goatBreedingTicks = 6000; -+ public boolean goatTakeDamageFromWater = false; - private void goatSettings() { - goatRidable = getBoolean("mobs.goat.ridable", goatRidable); - goatRidableInWater = getBoolean("mobs.goat.ridable-in-water", goatRidableInWater); - goatControllable = getBoolean("mobs.goat.controllable", goatControllable); - goatMaxHealth = getDouble("mobs.goat.attributes.max_health", goatMaxHealth); - goatBreedingTicks = getInt("mobs.goat.breeding-delay-ticks", goatBreedingTicks); -+ goatTakeDamageFromWater = getBoolean("mobs.goat.takes-damage-from-water", goatTakeDamageFromWater); - } - - public boolean guardianRidable = false; - public boolean guardianControllable = true; - public double guardianMaxHealth = 30.0D; -+ public boolean guardianTakeDamageFromWater = false; - private void guardianSettings() { - guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable); - guardianControllable = getBoolean("mobs.guardian.controllable", guardianControllable); -@@ -1076,6 +1123,7 @@ public class PurpurWorldConfig { - set("mobs.guardian.attributes.max_health", oldValue); - } - guardianMaxHealth = getDouble("mobs.guardian.attributes.max_health", guardianMaxHealth); -+ guardianTakeDamageFromWater = getBoolean("mobs.guardian.takes-damage-from-water", guardianTakeDamageFromWater); - } - - public boolean hoglinRidable = false; -@@ -1083,6 +1131,7 @@ public class PurpurWorldConfig { - public boolean hoglinControllable = true; - public double hoglinMaxHealth = 40.0D; - public int hoglinBreedingTicks = 6000; -+ public boolean hoglinTakeDamageFromWater = false; - private void hoglinSettings() { - hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); - hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); -@@ -1094,6 +1143,7 @@ public class PurpurWorldConfig { - } - hoglinMaxHealth = getDouble("mobs.hoglin.attributes.max_health", hoglinMaxHealth); - hoglinBreedingTicks = getInt("mobs.hoglin.breeding-delay-ticks", hoglinBreedingTicks); -+ hoglinTakeDamageFromWater = getBoolean("mobs.hoglin.takes-damage-from-water", hoglinTakeDamageFromWater); - } - - public boolean horseRidableInWater = false; -@@ -1104,6 +1154,7 @@ public class PurpurWorldConfig { - public double horseMovementSpeedMin = 0.1125D; - public double horseMovementSpeedMax = 0.3375D; - public int horseBreedingTicks = 6000; -+ public boolean horseTakeDamageFromWater = false; - private void horseSettings() { - horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); - if (PurpurConfig.version < 10) { -@@ -1120,6 +1171,7 @@ public class PurpurWorldConfig { - horseMovementSpeedMin = getDouble("mobs.horse.attributes.movement_speed.min", horseMovementSpeedMin); - horseMovementSpeedMax = getDouble("mobs.horse.attributes.movement_speed.max", horseMovementSpeedMax); - horseBreedingTicks = getInt("mobs.horse.breeding-delay-ticks", horseBreedingTicks); -+ horseTakeDamageFromWater = getBoolean("mobs.horse.takes-damage-from-water", horseTakeDamageFromWater); - } - - public boolean huskRidable = false; -@@ -1130,6 +1182,7 @@ public class PurpurWorldConfig { - public boolean huskJockeyOnlyBaby = true; - public double huskJockeyChance = 0.05D; - public boolean huskJockeyTryExistingChickens = true; -+ public boolean huskTakeDamageFromWater = false; - private void huskSettings() { - huskRidable = getBoolean("mobs.husk.ridable", huskRidable); - huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); -@@ -1144,6 +1197,7 @@ public class PurpurWorldConfig { - huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby); - huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance); - huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens); -+ huskTakeDamageFromWater = getBoolean("mobs.husk.takes-damage-from-water", huskTakeDamageFromWater); - } - - public boolean illusionerRidable = false; -@@ -1152,6 +1206,7 @@ public class PurpurWorldConfig { - public double illusionerMovementSpeed = 0.5D; - public double illusionerFollowRange = 18.0D; - public double illusionerMaxHealth = 32.0D; -+ public boolean illusionerTakeDamageFromWater = false; - private void illusionerSettings() { - illusionerRidable = getBoolean("mobs.illusioner.ridable", illusionerRidable); - illusionerRidableInWater = getBoolean("mobs.illusioner.ridable-in-water", illusionerRidableInWater); -@@ -1168,6 +1223,7 @@ public class PurpurWorldConfig { - set("mobs.illusioner.attributes.max_health", oldValue); - } - illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max_health", illusionerMaxHealth); -+ illusionerTakeDamageFromWater = getBoolean("mobs.illusioner.takes-damage-from-water", illusionerTakeDamageFromWater); - } - - public boolean ironGolemRidable = false; -@@ -1175,6 +1231,7 @@ public class PurpurWorldConfig { - public boolean ironGolemControllable = true; - public boolean ironGolemCanSwim = false; - public double ironGolemMaxHealth = 100.0D; -+ public boolean ironGolemTakeDamageFromWater = false; - private void ironGolemSettings() { - ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); - ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); -@@ -1186,6 +1243,7 @@ public class PurpurWorldConfig { - set("mobs.iron_golem.attributes.max_health", oldValue); - } - ironGolemMaxHealth = getDouble("mobs.iron_golem.attributes.max_health", ironGolemMaxHealth); -+ ironGolemTakeDamageFromWater = getBoolean("mobs.iron_golem.takes-damage-from-water", ironGolemTakeDamageFromWater); - } - - public boolean llamaRidable = false; -@@ -1198,6 +1256,7 @@ public class PurpurWorldConfig { - public double llamaMovementSpeedMin = 0.175D; - public double llamaMovementSpeedMax = 0.175D; - public int llamaBreedingTicks = 6000; -+ public boolean llamaTakeDamageFromWater = false; - private void llamaSettings() { - llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); - llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); -@@ -1216,6 +1275,7 @@ public class PurpurWorldConfig { - llamaMovementSpeedMin = getDouble("mobs.llama.attributes.movement_speed.min", llamaMovementSpeedMin); - llamaMovementSpeedMax = getDouble("mobs.llama.attributes.movement_speed.max", llamaMovementSpeedMax); - llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks); -+ llamaTakeDamageFromWater = getBoolean("mobs.llama.takes-damage-from-water", llamaTakeDamageFromWater); - } - - public boolean magmaCubeRidable = false; -@@ -1225,6 +1285,7 @@ public class PurpurWorldConfig { - public String magmaCubeAttackDamage = "size"; - public Map magmaCubeMaxHealthCache = new HashMap<>(); - public Map magmaCubeAttackDamageCache = new HashMap<>(); -+ public boolean magmaCubeTakeDamageFromWater = false; - private void magmaCubeSettings() { - magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable); - magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater); -@@ -1238,6 +1299,7 @@ public class PurpurWorldConfig { - magmaCubeAttackDamage = getString("mobs.magma_cube.attributes.attack_damage", magmaCubeAttackDamage); - magmaCubeMaxHealthCache.clear(); - magmaCubeAttackDamageCache.clear(); -+ magmaCubeTakeDamageFromWater = getBoolean("mobs.magma_cube.takes-damage-from-water", magmaCubeTakeDamageFromWater); - } - - public boolean mooshroomRidable = false; -@@ -1245,6 +1307,7 @@ public class PurpurWorldConfig { - public boolean mooshroomControllable = true; - public double mooshroomMaxHealth = 10.0D; - public int mooshroomBreedingTicks = 6000; -+ public boolean mooshroomTakeDamageFromWater = false; - private void mooshroomSettings() { - mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); - mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); -@@ -1256,6 +1319,7 @@ public class PurpurWorldConfig { - } - mooshroomMaxHealth = getDouble("mobs.mooshroom.attributes.max_health", mooshroomMaxHealth); - mooshroomBreedingTicks = getInt("mobs.mooshroom.breeding-delay-ticks", mooshroomBreedingTicks); -+ mooshroomTakeDamageFromWater = getBoolean("mobs.mooshroom.takes-damage-from-water", mooshroomTakeDamageFromWater); - } - - public boolean muleRidableInWater = false; -@@ -1266,6 +1330,7 @@ public class PurpurWorldConfig { - public double muleMovementSpeedMin = 0.175D; - public double muleMovementSpeedMax = 0.175D; - public int muleBreedingTicks = 6000; -+ public boolean muleTakeDamageFromWater = false; - private void muleSettings() { - muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); - if (PurpurConfig.version < 10) { -@@ -1282,6 +1347,7 @@ public class PurpurWorldConfig { - muleMovementSpeedMin = getDouble("mobs.mule.attributes.movement_speed.min", muleMovementSpeedMin); - muleMovementSpeedMax = getDouble("mobs.mule.attributes.movement_speed.max", muleMovementSpeedMax); - muleBreedingTicks = getInt("mobs.mule.breeding-delay-ticks", muleBreedingTicks); -+ muleTakeDamageFromWater = getBoolean("mobs.mule.takes-damage-from-water", muleTakeDamageFromWater); - } - - public boolean ocelotRidable = false; -@@ -1289,6 +1355,7 @@ public class PurpurWorldConfig { - public boolean ocelotControllable = true; - public double ocelotMaxHealth = 10.0D; - public int ocelotBreedingTicks = 6000; -+ public boolean ocelotTakeDamageFromWater = false; - private void ocelotSettings() { - ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); - ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); -@@ -1300,6 +1367,7 @@ public class PurpurWorldConfig { - } - ocelotMaxHealth = getDouble("mobs.ocelot.attributes.max_health", ocelotMaxHealth); - ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks); -+ ocelotTakeDamageFromWater = getBoolean("mobs.ocelot.takes-damage-from-water", ocelotTakeDamageFromWater); - } - - public boolean pandaRidable = false; -@@ -1307,6 +1375,7 @@ public class PurpurWorldConfig { - public boolean pandaControllable = true; - public double pandaMaxHealth = 20.0D; - public int pandaBreedingTicks = 6000; -+ public boolean pandaTakeDamageFromWater = false; - private void pandaSettings() { - pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); - pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); -@@ -1318,6 +1387,7 @@ public class PurpurWorldConfig { - } - pandaMaxHealth = getDouble("mobs.panda.attributes.max_health", pandaMaxHealth); - pandaBreedingTicks = getInt("mobs.panda.breeding-delay-ticks", pandaBreedingTicks); -+ pandaTakeDamageFromWater = getBoolean("mobs.panda.takes-damage-from-water", pandaTakeDamageFromWater); - } - - public boolean parrotRidable = false; -@@ -1325,6 +1395,7 @@ public class PurpurWorldConfig { - public boolean parrotControllable = true; - public double parrotMaxY = 320D; - public double parrotMaxHealth = 6.0D; -+ public boolean parrotTakeDamageFromWater = false; - private void parrotSettings() { - parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); - parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); -@@ -1336,6 +1407,7 @@ public class PurpurWorldConfig { - set("mobs.parrot.attributes.max_health", oldValue); - } - parrotMaxHealth = getDouble("mobs.parrot.attributes.max_health", parrotMaxHealth); -+ parrotTakeDamageFromWater = getBoolean("mobs.parrot.takes-damage-from-water", parrotTakeDamageFromWater); - } - - public boolean phantomRidable = false; -@@ -1362,6 +1434,7 @@ public class PurpurWorldConfig { - public boolean phantomIgnorePlayersWithTorch = false; - public boolean phantomBurnInDaylight = true; - public boolean phantomFlamesOnSwoop = false; -+ public boolean phantomTakeDamageFromWater = false; - private void phantomSettings() { - phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); - phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -@@ -1396,6 +1469,7 @@ public class PurpurWorldConfig { - phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight); - phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); - phantomFlamesOnSwoop = getBoolean("mobs.phantom.flames-on-swoop", phantomFlamesOnSwoop); -+ phantomTakeDamageFromWater = getBoolean("mobs.phantom.takes-damage-from-water", phantomTakeDamageFromWater); - } - - public boolean pigRidable = false; -@@ -1404,6 +1478,7 @@ public class PurpurWorldConfig { - public double pigMaxHealth = 10.0D; - public boolean pigGiveSaddleBack = false; - public int pigBreedingTicks = 6000; -+ public boolean pigTakeDamageFromWater = false; - private void pigSettings() { - pigRidable = getBoolean("mobs.pig.ridable", pigRidable); - pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); -@@ -1416,6 +1491,7 @@ public class PurpurWorldConfig { - pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth); - pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); - pigBreedingTicks = getInt("mobs.pig.breeding-delay-ticks", pigBreedingTicks); -+ pigTakeDamageFromWater = getBoolean("mobs.pig.takes-damage-from-water", pigTakeDamageFromWater); - } - - public boolean piglinRidable = false; -@@ -1423,6 +1499,7 @@ public class PurpurWorldConfig { - public boolean piglinControllable = true; - public double piglinMaxHealth = 16.0D; - public boolean piglinBypassMobGriefing = false; -+ public boolean piglinTakeDamageFromWater = false; - private void piglinSettings() { - piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); - piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); -@@ -1434,12 +1511,14 @@ public class PurpurWorldConfig { - } - piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth); - piglinBypassMobGriefing = getBoolean("mobs.piglin.bypass-mob-griefing", piglinBypassMobGriefing); -+ piglinTakeDamageFromWater = getBoolean("mobs.piglin.takes-damage-from-water", piglinTakeDamageFromWater); - } - - public boolean piglinBruteRidable = false; - public boolean piglinBruteRidableInWater = true; - public boolean piglinBruteControllable = true; - public double piglinBruteMaxHealth = 50.0D; -+ public boolean piglinBruteTakeDamageFromWater = false; - private void piglinBruteSettings() { - piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable); - piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater); -@@ -1450,6 +1529,7 @@ public class PurpurWorldConfig { - set("mobs.piglin_brute.attributes.max_health", oldValue); - } - piglinBruteMaxHealth = getDouble("mobs.piglin_brute.attributes.max_health", piglinBruteMaxHealth); -+ piglinBruteTakeDamageFromWater = getBoolean("mobs.piglin_brute.takes-damage-from-water", piglinBruteTakeDamageFromWater); - } - - public boolean pillagerRidable = false; -@@ -1457,6 +1537,7 @@ public class PurpurWorldConfig { - public boolean pillagerControllable = true; - public double pillagerMaxHealth = 24.0D; - public boolean pillagerBypassMobGriefing = false; -+ public boolean pillagerTakeDamageFromWater = false; - private void pillagerSettings() { - pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); - pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); -@@ -1468,6 +1549,7 @@ public class PurpurWorldConfig { - } - pillagerMaxHealth = getDouble("mobs.pillager.attributes.max_health", pillagerMaxHealth); - pillagerBypassMobGriefing = getBoolean("mobs.pillager.bypass-mob-griefing", pillagerBypassMobGriefing); -+ pillagerTakeDamageFromWater = getBoolean("mobs.pillager.takes-damage-from-water", pillagerTakeDamageFromWater); - } - - public boolean polarBearRidable = false; -@@ -1477,6 +1559,7 @@ public class PurpurWorldConfig { - public String polarBearBreedableItemString = ""; - public Item polarBearBreedableItem = null; - public int polarBearBreedingTicks = 6000; -+ public boolean polarBearTakeDamageFromWater = false; - private void polarBearSettings() { - polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); - polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); -@@ -1491,11 +1574,13 @@ public class PurpurWorldConfig { - Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(polarBearBreedableItemString)); - if (item != Items.AIR) polarBearBreedableItem = item; - polarBearBreedingTicks = getInt("mobs.polar_bear.breeding-delay-ticks", polarBearBreedingTicks); -+ polarBearTakeDamageFromWater = getBoolean("mobs.polar_bear.takes-damage-from-water", polarBearTakeDamageFromWater); - } - - public boolean pufferfishRidable = false; - public boolean pufferfishControllable = true; - public double pufferfishMaxHealth = 3.0D; -+ public boolean pufferfishTakeDamageFromWater = false; - private void pufferfishSettings() { - pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable); - pufferfishControllable = getBoolean("mobs.pufferfish.controllable", pufferfishControllable); -@@ -1505,6 +1590,7 @@ public class PurpurWorldConfig { - set("mobs.pufferfish.attributes.max_health", oldValue); - } - pufferfishMaxHealth = getDouble("mobs.pufferfish.attributes.max_health", pufferfishMaxHealth); -+ pufferfishTakeDamageFromWater = getBoolean("mobs.pufferfish.takes-damage-from-water", pufferfishTakeDamageFromWater); - } - - public boolean rabbitRidable = false; -@@ -1515,6 +1601,7 @@ public class PurpurWorldConfig { - public double rabbitNaturalKiller = 0.0D; - public int rabbitBreedingTicks = 6000; - public boolean rabbitBypassMobGriefing = false; -+ public boolean rabbitTakeDamageFromWater = false; - private void rabbitSettings() { - rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); - rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); -@@ -1529,6 +1616,7 @@ public class PurpurWorldConfig { - rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); - rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks); - rabbitBypassMobGriefing = getBoolean("mobs.rabbit.bypass-mob-griefing", rabbitBypassMobGriefing); -+ rabbitTakeDamageFromWater = getBoolean("mobs.rabbit.takes-damage-from-water", rabbitTakeDamageFromWater); - } - - public boolean ravagerRidable = false; -@@ -1536,6 +1624,7 @@ public class PurpurWorldConfig { - public boolean ravagerControllable = true; - public double ravagerMaxHealth = 100.0D; - public boolean ravagerBypassMobGriefing = false; -+ public boolean ravagerTakeDamageFromWater = false; - private void ravagerSettings() { - ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); - ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); -@@ -1547,11 +1636,13 @@ public class PurpurWorldConfig { - } - ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth); - ravagerBypassMobGriefing = getBoolean("mobs.ravager.bypass-mob-griefing", ravagerBypassMobGriefing); -+ ravagerTakeDamageFromWater = getBoolean("mobs.ravager.takes-damage-from-water", ravagerTakeDamageFromWater); - } - - public boolean salmonRidable = false; - public boolean salmonControllable = true; - public double salmonMaxHealth = 3.0D; -+ public boolean salmonTakeDamageFromWater = false; - private void salmonSettings() { - salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable); - salmonControllable = getBoolean("mobs.salmon.controllable", salmonControllable); -@@ -1561,6 +1652,7 @@ public class PurpurWorldConfig { - set("mobs.salmon.attributes.max_health", oldValue); - } - salmonMaxHealth = getDouble("mobs.salmon.attributes.max_health", salmonMaxHealth); -+ salmonTakeDamageFromWater = getBoolean("mobs.salmon.takes-damage-from-water", salmonTakeDamageFromWater); - } - - public boolean sheepRidable = false; -@@ -1569,6 +1661,7 @@ public class PurpurWorldConfig { - public double sheepMaxHealth = 8.0D; - public int sheepBreedingTicks = 6000; - public boolean sheepBypassMobGriefing = false; -+ public boolean sheepTakeDamageFromWater = false; - private void sheepSettings() { - sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); - sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); -@@ -1581,12 +1674,14 @@ public class PurpurWorldConfig { - sheepMaxHealth = getDouble("mobs.sheep.attributes.max_health", sheepMaxHealth); - sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks); - sheepBypassMobGriefing = getBoolean("mobs.sheep.bypass-mob-griefing", sheepBypassMobGriefing); -+ sheepTakeDamageFromWater = getBoolean("mobs.sheep.takes-damage-from-water", sheepTakeDamageFromWater); - } - - public boolean shulkerRidable = false; - public boolean shulkerRidableInWater = true; - public boolean shulkerControllable = true; - public double shulkerMaxHealth = 30.0D; -+ public boolean shulkerTakeDamageFromWater = false; - private void shulkerSettings() { - shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); - shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); -@@ -1597,6 +1692,7 @@ public class PurpurWorldConfig { - set("mobs.shulker.attributes.max_health", oldValue); - } - shulkerMaxHealth = getDouble("mobs.shulker.attributes.max_health", shulkerMaxHealth); -+ shulkerTakeDamageFromWater = getBoolean("mobs.shulker.takes-damage-from-water", shulkerTakeDamageFromWater); - } - - public boolean silverfishRidable = false; -@@ -1604,6 +1700,7 @@ public class PurpurWorldConfig { - public boolean silverfishControllable = true; - public double silverfishMaxHealth = 8.0D; - public boolean silverfishBypassMobGriefing = false; -+ public boolean silverfishTakeDamageFromWater = false; - private void silverfishSettings() { - silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); - silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); -@@ -1615,12 +1712,14 @@ public class PurpurWorldConfig { - } - silverfishMaxHealth = getDouble("mobs.silverfish.attributes.max_health", silverfishMaxHealth); - silverfishBypassMobGriefing = getBoolean("mobs.silverfish.bypass-mob-griefing", silverfishBypassMobGriefing); -+ silverfishTakeDamageFromWater = getBoolean("mobs.silverfish.takes-damage-from-water", silverfishTakeDamageFromWater); - } - - public boolean skeletonRidable = false; - public boolean skeletonRidableInWater = true; - public boolean skeletonControllable = true; - public double skeletonMaxHealth = 20.0D; -+ public boolean skeletonTakeDamageFromWater = false; - private void skeletonSettings() { - skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); - skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); -@@ -1631,6 +1730,7 @@ public class PurpurWorldConfig { - set("mobs.skeleton.attributes.max_health", oldValue); - } - skeletonMaxHealth = getDouble("mobs.skeleton.attributes.max_health", skeletonMaxHealth); -+ skeletonTakeDamageFromWater = getBoolean("mobs.skeleton.takes-damage-from-water", skeletonTakeDamageFromWater); - } - - public boolean skeletonHorseRidable = false; -@@ -1642,6 +1742,7 @@ public class PurpurWorldConfig { - public double skeletonHorseJumpStrengthMax = 1.0D; - public double skeletonHorseMovementSpeedMin = 0.2D; - public double skeletonHorseMovementSpeedMax = 0.2D; -+ public boolean skeletonHorseTakeDamageFromWater = false; - private void skeletonHorseSettings() { - skeletonHorseRidable = getBoolean("mobs.skeleton_horse.ridable", skeletonHorseRidable); - skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater); -@@ -1658,6 +1759,7 @@ public class PurpurWorldConfig { - skeletonHorseJumpStrengthMax = getDouble("mobs.skeleton_horse.attributes.jump_strength.max", skeletonHorseJumpStrengthMax); - skeletonHorseMovementSpeedMin = getDouble("mobs.skeleton_horse.attributes.movement_speed.min", skeletonHorseMovementSpeedMin); - skeletonHorseMovementSpeedMax = getDouble("mobs.skeleton_horse.attributes.movement_speed.max", skeletonHorseMovementSpeedMax); -+ skeletonHorseTakeDamageFromWater = getBoolean("mobs.skeleton_horse.takes-damage-from-water", skeletonHorseTakeDamageFromWater); - } - - public boolean slimeRidable = false; -@@ -1667,6 +1769,7 @@ public class PurpurWorldConfig { - public String slimeAttackDamage = "size"; - public Map slimeMaxHealthCache = new HashMap<>(); - public Map slimeAttackDamageCache = new HashMap<>(); -+ public boolean slimeTakeDamageFromWater = false; - private void slimeSettings() { - slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable); - slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater); -@@ -1680,6 +1783,7 @@ public class PurpurWorldConfig { - slimeAttackDamage = getString("mobs.slime.attributes.attack_damage", slimeAttackDamage); - slimeMaxHealthCache.clear(); - slimeAttackDamageCache.clear(); -+ slimeTakeDamageFromWater = getBoolean("mobs.slime.takes-damage-from-water", slimeTakeDamageFromWater); - } - - public boolean snowGolemRidable = false; -@@ -1693,6 +1797,7 @@ public class PurpurWorldConfig { - public float snowGolemSnowBallModifier = 10.0F; - public double snowGolemAttackDistance = 1.25D; - public boolean snowGolemBypassMobGriefing = false; -+ public boolean snowGolemTakeDamageFromWater = true; - private void snowGolemSettings() { - snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); - snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); -@@ -1710,6 +1815,7 @@ public class PurpurWorldConfig { - snowGolemSnowBallModifier = (float) getDouble("mobs.snow_golem.snow-ball-modifier", snowGolemSnowBallModifier); - snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance); - snowGolemBypassMobGriefing = getBoolean("mobs.snow_golem.bypass-mob-griefing", snowGolemBypassMobGriefing); -+ snowGolemTakeDamageFromWater = getBoolean("mobs.snow_golem.takes-damage-from-water", snowGolemTakeDamageFromWater); - } - - public boolean snifferRidable = false; -@@ -1731,6 +1837,7 @@ public class PurpurWorldConfig { - public boolean squidImmuneToEAR = true; - public double squidOffsetWaterCheck = 0.0D; - public boolean squidsCanFly = false; -+ public boolean squidTakeDamageFromWater = false; - private void squidSettings() { - squidRidable = getBoolean("mobs.squid.ridable", squidRidable); - squidControllable = getBoolean("mobs.squid.controllable", squidControllable); -@@ -1743,12 +1850,14 @@ public class PurpurWorldConfig { - squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); - squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); - squidsCanFly = getBoolean("mobs.squid.can-fly", squidsCanFly); -+ squidTakeDamageFromWater = getBoolean("mobs.squid.takes-damage-from-water", squidTakeDamageFromWater); - } - - public boolean spiderRidable = false; - public boolean spiderRidableInWater = false; - public boolean spiderControllable = true; - public double spiderMaxHealth = 16.0D; -+ public boolean spiderTakeDamageFromWater = false; - private void spiderSettings() { - spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable); - spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater); -@@ -1759,12 +1868,14 @@ public class PurpurWorldConfig { - set("mobs.spider.attributes.max_health", oldValue); - } - spiderMaxHealth = getDouble("mobs.spider.attributes.max_health", spiderMaxHealth); -+ spiderTakeDamageFromWater = getBoolean("mobs.spider.takes-damage-from-water", spiderTakeDamageFromWater); - } - - public boolean strayRidable = false; - public boolean strayRidableInWater = true; - public boolean strayControllable = true; - public double strayMaxHealth = 20.0D; -+ public boolean strayTakeDamageFromWater = false; - private void straySettings() { - strayRidable = getBoolean("mobs.stray.ridable", strayRidable); - strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater); -@@ -1775,6 +1886,7 @@ public class PurpurWorldConfig { - set("mobs.stray.attributes.max_health", oldValue); - } - strayMaxHealth = getDouble("mobs.stray.attributes.max_health", strayMaxHealth); -+ strayTakeDamageFromWater = getBoolean("mobs.stray.takes-damage-from-water", strayTakeDamageFromWater); - } - - public boolean striderRidable = false; -@@ -1783,6 +1895,7 @@ public class PurpurWorldConfig { - public double striderMaxHealth = 20.0D; - public int striderBreedingTicks = 6000; - public boolean striderGiveSaddleBack = false; -+ public boolean striderTakeDamageFromWater = true; - private void striderSettings() { - striderRidable = getBoolean("mobs.strider.ridable", striderRidable); - striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); -@@ -1795,6 +1908,7 @@ public class PurpurWorldConfig { - striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth); - striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks); - striderGiveSaddleBack = getBoolean("mobs.strider.give-saddle-back", striderGiveSaddleBack); -+ striderTakeDamageFromWater = getBoolean("mobs.strider.takes-damage-from-water", striderTakeDamageFromWater); - } - - public boolean tadpoleRidable = false; -@@ -1816,6 +1930,7 @@ public class PurpurWorldConfig { - public double traderLlamaMovementSpeedMin = 0.175D; - public double traderLlamaMovementSpeedMax = 0.175D; - public int traderLlamaBreedingTicks = 6000; -+ public boolean traderLlamaTakeDamageFromWater = false; - private void traderLlamaSettings() { - traderLlamaRidable = getBoolean("mobs.trader_llama.ridable", traderLlamaRidable); - traderLlamaRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", traderLlamaRidableInWater); -@@ -1834,11 +1949,13 @@ public class PurpurWorldConfig { - traderLlamaMovementSpeedMin = getDouble("mobs.trader_llama.attributes.movement_speed.min", traderLlamaMovementSpeedMin); - traderLlamaMovementSpeedMax = getDouble("mobs.trader_llama.attributes.movement_speed.max", traderLlamaMovementSpeedMax); - traderLlamaBreedingTicks = getInt("mobs.trader_llama.breeding-delay-ticks", traderLlamaBreedingTicks); -+ traderLlamaTakeDamageFromWater = getBoolean("mobs.trader_llama.takes-damage-from-water", traderLlamaTakeDamageFromWater); - } - - public boolean tropicalFishRidable = false; - public boolean tropicalFishControllable = true; - public double tropicalFishMaxHealth = 3.0D; -+ public boolean tropicalFishTakeDamageFromWater = false; - private void tropicalFishSettings() { - tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable); - tropicalFishControllable = getBoolean("mobs.tropical_fish.controllable", tropicalFishControllable); -@@ -1848,6 +1965,7 @@ public class PurpurWorldConfig { - set("mobs.tropical_fish.attributes.max_health", oldValue); - } - tropicalFishMaxHealth = getDouble("mobs.tropical_fish.attributes.max_health", tropicalFishMaxHealth); -+ tropicalFishTakeDamageFromWater = getBoolean("mobs.tropical_fish.takes-damage-from-water", tropicalFishTakeDamageFromWater); - } - - public boolean turtleRidable = false; -@@ -1855,6 +1973,7 @@ public class PurpurWorldConfig { - public boolean turtleControllable = true; - public double turtleMaxHealth = 30.0D; - public int turtleBreedingTicks = 6000; -+ public boolean turtleTakeDamageFromWater = false; - private void turtleSettings() { - turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); - turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); -@@ -1866,6 +1985,7 @@ public class PurpurWorldConfig { - } - turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth); - turtleBreedingTicks = getInt("mobs.turtle.breeding-delay-ticks", turtleBreedingTicks); -+ turtleTakeDamageFromWater = getBoolean("mobs.turtle.takes-damage-from-water", turtleTakeDamageFromWater); - } - - public boolean vexRidable = false; -@@ -1873,6 +1993,7 @@ public class PurpurWorldConfig { - public boolean vexControllable = true; - public double vexMaxY = 320D; - public double vexMaxHealth = 14.0D; -+ public boolean vexTakeDamageFromWater = false; - private void vexSettings() { - vexRidable = getBoolean("mobs.vex.ridable", vexRidable); - vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater); -@@ -1884,6 +2005,7 @@ public class PurpurWorldConfig { - set("mobs.vex.attributes.max_health", oldValue); - } - vexMaxHealth = getDouble("mobs.vex.attributes.max_health", vexMaxHealth); -+ vexTakeDamageFromWater = getBoolean("mobs.vex.takes-damage-from-water", vexTakeDamageFromWater); - } - - public boolean villagerRidable = false; -@@ -1897,6 +2019,7 @@ public class PurpurWorldConfig { - public boolean villagerClericsFarmWarts = false; - public boolean villagerClericFarmersThrowWarts = true; - public boolean villagerBypassMobGriefing = false; -+ public boolean villagerTakeDamageFromWater = false; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -1914,6 +2037,7 @@ public class PurpurWorldConfig { - villagerClericsFarmWarts = getBoolean("mobs.villager.clerics-farm-warts", villagerClericsFarmWarts); - villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts); - villagerBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerBypassMobGriefing); -+ villagerTakeDamageFromWater = getBoolean("mobs.villager.takes-damage-from-water", villagerTakeDamageFromWater); - } - - public boolean vindicatorRidable = false; -@@ -1921,6 +2045,7 @@ public class PurpurWorldConfig { - public boolean vindicatorControllable = true; - public double vindicatorMaxHealth = 24.0D; - public double vindicatorJohnnySpawnChance = 0D; -+ public boolean vindicatorTakeDamageFromWater = false; - private void vindicatorSettings() { - vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); - vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); -@@ -1932,6 +2057,7 @@ public class PurpurWorldConfig { - } - vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth); - vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance); -+ vindicatorTakeDamageFromWater = getBoolean("mobs.vindicator.takes-damage-from-water", vindicatorTakeDamageFromWater); - } - - public boolean wanderingTraderRidable = false; -@@ -1940,6 +2066,7 @@ public class PurpurWorldConfig { - public double wanderingTraderMaxHealth = 20.0D; - public boolean wanderingTraderFollowEmeraldBlock = false; - public boolean wanderingTraderCanBeLeashed = false; -+ public boolean wanderingTraderTakeDamageFromWater = false; - private void wanderingTraderSettings() { - wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); - wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); -@@ -1952,6 +2079,7 @@ public class PurpurWorldConfig { - wanderingTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", wanderingTraderMaxHealth); - wanderingTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", wanderingTraderFollowEmeraldBlock); - wanderingTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", wanderingTraderCanBeLeashed); -+ wanderingTraderTakeDamageFromWater = getBoolean("mobs.wandering_trader.takes-damage-from-water", wanderingTraderTakeDamageFromWater); - } - - public boolean wardenRidable = false; -@@ -1967,6 +2095,7 @@ public class PurpurWorldConfig { - public boolean witchRidableInWater = true; - public boolean witchControllable = true; - public double witchMaxHealth = 26.0D; -+ public boolean witchTakeDamageFromWater = false; - private void witchSettings() { - witchRidable = getBoolean("mobs.witch.ridable", witchRidable); - witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater); -@@ -1977,6 +2106,7 @@ public class PurpurWorldConfig { - set("mobs.witch.attributes.max_health", oldValue); - } - witchMaxHealth = getDouble("mobs.witch.attributes.max_health", witchMaxHealth); -+ witchTakeDamageFromWater = getBoolean("mobs.witch.takes-damage-from-water", witchTakeDamageFromWater); - } - - public boolean witherRidable = false; -@@ -1987,6 +2117,7 @@ public class PurpurWorldConfig { - public float witherHealthRegenAmount = 1.0f; - public int witherHealthRegenDelay = 20; - public boolean witherBypassMobGriefing = false; -+ public boolean witherTakeDamageFromWater = false; - private void witherSettings() { - witherRidable = getBoolean("mobs.wither.ridable", witherRidable); - witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); -@@ -2005,12 +2136,14 @@ public class PurpurWorldConfig { - witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount); - witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); - witherBypassMobGriefing = getBoolean("mobs.wither.bypass-mob-griefing", witherBypassMobGriefing); -+ witherTakeDamageFromWater = getBoolean("mobs.wither.takes-damage-from-water", witherTakeDamageFromWater); - } - - public boolean witherSkeletonRidable = false; - public boolean witherSkeletonRidableInWater = true; - public boolean witherSkeletonControllable = true; - public double witherSkeletonMaxHealth = 20.0D; -+ public boolean witherSkeletonTakeDamageFromWater = false; - private void witherSkeletonSettings() { - witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable); - witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater); -@@ -2021,6 +2154,7 @@ public class PurpurWorldConfig { - set("mobs.wither_skeleton.attributes.max_health", oldValue); - } - witherSkeletonMaxHealth = getDouble("mobs.wither_skeleton.attributes.max_health", witherSkeletonMaxHealth); -+ witherSkeletonTakeDamageFromWater = getBoolean("mobs.wither_skeleton.takes-damage-from-water", witherSkeletonTakeDamageFromWater); - } - - public boolean wolfRidable = false; -@@ -2031,6 +2165,7 @@ public class PurpurWorldConfig { - public boolean wolfMilkCuresRabies = true; - public double wolfNaturalRabid = 0.0D; - public int wolfBreedingTicks = 6000; -+ public boolean wolfTakeDamageFromWater = false; - private void wolfSettings() { - wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); - wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); -@@ -2049,12 +2184,14 @@ public class PurpurWorldConfig { - wolfMilkCuresRabies = getBoolean("mobs.wolf.milk-cures-rabid-wolves", wolfMilkCuresRabies); - wolfNaturalRabid = getDouble("mobs.wolf.spawn-rabid-chance", wolfNaturalRabid); - wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks); -+ wolfTakeDamageFromWater = getBoolean("mobs.wolf.takes-damage-from-water", wolfTakeDamageFromWater); - } - - public boolean zoglinRidable = false; - public boolean zoglinRidableInWater = true; - public boolean zoglinControllable = true; - public double zoglinMaxHealth = 40.0D; -+ public boolean zoglinTakeDamageFromWater = false; - private void zoglinSettings() { - zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable); - zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater); -@@ -2065,6 +2202,7 @@ public class PurpurWorldConfig { - set("mobs.zoglin.attributes.max_health", oldValue); - } - zoglinMaxHealth = getDouble("mobs.zoglin.attributes.max_health", zoglinMaxHealth); -+ zoglinTakeDamageFromWater = getBoolean("mobs.zoglin.takes-damage-from-water", zoglinTakeDamageFromWater); - } - - public boolean zombieRidable = false; -@@ -2077,6 +2215,7 @@ public class PurpurWorldConfig { - public boolean zombieJockeyTryExistingChickens = true; - public boolean zombieAggressiveTowardsVillagerWhenLagging = true; - public boolean zombieBypassMobGriefing = false; -+ public boolean zombieTakeDamageFromWater = false; - private void zombieSettings() { - zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); - zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); -@@ -2093,6 +2232,7 @@ public class PurpurWorldConfig { - zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); - zombieAggressiveTowardsVillagerWhenLagging = getBoolean("mobs.zombie.aggressive-towards-villager-when-lagging", zombieAggressiveTowardsVillagerWhenLagging); - zombieBypassMobGriefing = getBoolean("mobs.zombie.bypass-mob-griefing", zombieBypassMobGriefing); -+ zombieTakeDamageFromWater = getBoolean("mobs.zombie.takes-damage-from-water", zombieTakeDamageFromWater); - } - - public boolean zombieHorseRidable = false; -@@ -2105,6 +2245,7 @@ public class PurpurWorldConfig { - public double zombieHorseMovementSpeedMin = 0.2D; - public double zombieHorseMovementSpeedMax = 0.2D; - public double zombieHorseSpawnChance = 0.0D; -+ public boolean zombieHorseTakeDamageFromWater = false; - private void zombieHorseSettings() { - zombieHorseRidable = getBoolean("mobs.zombie_horse.ridable", zombieHorseRidable); - zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); -@@ -2122,6 +2263,7 @@ public class PurpurWorldConfig { - zombieHorseMovementSpeedMin = getDouble("mobs.zombie_horse.attributes.movement_speed.min", zombieHorseMovementSpeedMin); - zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax); - zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); -+ zombieHorseTakeDamageFromWater = getBoolean("mobs.zombie_horse.takes-damage-from-water", zombieHorseTakeDamageFromWater); - } - - public boolean zombieVillagerRidable = false; -@@ -2132,6 +2274,7 @@ public class PurpurWorldConfig { - public boolean zombieVillagerJockeyOnlyBaby = true; - public double zombieVillagerJockeyChance = 0.05D; - public boolean zombieVillagerJockeyTryExistingChickens = true; -+ public boolean zombieVillagerTakeDamageFromWater = false; - private void zombieVillagerSettings() { - zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); - zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); -@@ -2146,6 +2289,7 @@ public class PurpurWorldConfig { - zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby); - zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance); - zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens); -+ zombieVillagerTakeDamageFromWater = getBoolean("mobs.zombie_villager.takes-damage-from-water", zombieVillagerTakeDamageFromWater); - } - - public boolean zombifiedPiglinRidable = false; -@@ -2157,6 +2301,7 @@ public class PurpurWorldConfig { - public double zombifiedPiglinJockeyChance = 0.05D; - public boolean zombifiedPiglinJockeyTryExistingChickens = true; - public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = true; -+ public boolean zombifiedPiglinTakeDamageFromWater = false; - private void zombifiedPiglinSettings() { - zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); - zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); -@@ -2172,5 +2317,6 @@ public class PurpurWorldConfig { - zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance); - zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); - zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry); -+ zombifiedPiglinTakeDamageFromWater = getBoolean("mobs.zombified_piglin.takes-damage-from-water", zombifiedPiglinTakeDamageFromWater); - } - } diff --git a/patches/server/0125-Config-to-always-tame-in-Creative.patch b/patches/server/0125-Config-to-always-tame-in-Creative.patch deleted file mode 100644 index 42de81d83..000000000 --- a/patches/server/0125-Config-to-always-tame-in-Creative.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 9 Feb 2021 21:23:37 -0500 -Subject: [PATCH] Config to always tame in Creative - -Adds a configuration option that ensures a player in Creative always tames a tameable entity. -This essentially allows Creative mode players to tame animals on their first try. - -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java -index b0944fa1f3849dd24cd010fa0a6638f5fd7179d1..d409ae987088df3d47192128401d7491aaabc87c 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java -@@ -67,7 +67,7 @@ public class RunAroundLikeCrazyGoal extends Goal { - int i = this.horse.getTemper(); - int j = this.horse.getMaxTemper(); - -- if (j > 0 && this.horse.getRandom().nextInt(j) < i && !CraftEventFactory.callEntityTameEvent(this.horse, ((CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent -+ if ((this.horse.level().purpurConfig.alwaysTameInCreative && entityhuman.hasInfiniteMaterials()) || (j > 0 && this.horse.getRandom().nextInt(j) < i && !CraftEventFactory.callEntityTameEvent(this.horse, ((CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled())) { // CraftBukkit - fire EntityTameEvent // Purpur - this.horse.tameWithName(entityhuman); - return; - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 446aec4d10e614f136fe6ae4bb5a7dd0ac6d0f18..17aaeb734a5c1b16bd7771c909958f3acc956b7a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -522,7 +522,7 @@ public class Cat extends TamableAnimal implements VariantHolder -Date: Sat, 13 Feb 2021 09:28:56 -0500 -Subject: [PATCH] End crystal explosion options - - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -index 2bac39e5ba09e08d23d2a4be37f7fe0da0ce71a6..8c6ce06a1845832c8b0de654657788d2daf6b71b 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -@@ -49,6 +49,22 @@ public class EndCrystal extends Entity { - this.setPos(x, y, z); - } - -+ public boolean shouldExplode() { -+ return showsBottom() ? level().purpurConfig.basedEndCrystalExplode : level().purpurConfig.baselessEndCrystalExplode; -+ } -+ -+ public float getExplosionPower() { -+ return (float) (showsBottom() ? level().purpurConfig.basedEndCrystalExplosionPower : level().purpurConfig.baselessEndCrystalExplosionPower); -+ } -+ -+ public boolean hasExplosionFire() { -+ return showsBottom() ? level().purpurConfig.basedEndCrystalExplosionFire : level().purpurConfig.baselessEndCrystalExplosionFire; -+ } -+ -+ public Level.ExplosionInteraction getExplosionEffect() { -+ return showsBottom() ? level().purpurConfig.basedEndCrystalExplosionEffect : level().purpurConfig.baselessEndCrystalExplosionEffect; -+ } -+ - @Override - protected Entity.MovementEmission getMovementEmission() { - return Entity.MovementEmission.NONE; -@@ -170,16 +186,18 @@ public class EndCrystal extends Entity { - } - // CraftBukkit end - if (!source.is(DamageTypeTags.IS_EXPLOSION)) { -+ if (shouldExplode()) {// Purpur - DamageSource damagesource1 = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null; - - // CraftBukkit start -- ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false); -+ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, getExplosionPower(), hasExplosionFire()); // Purpur - if (event.isCancelled()) { - return false; - } - - this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause -- this.level().explode(this, damagesource1, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); -+ this.level().explode(this, damagesource1, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), getExplosionEffect()); // Purpur -+ } else this.unsetRemoved(); // Purpur - } else { - this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 75c9c93f808b624370a2820a93f625a599093b5c..9de44dd59e69d709490290cf07b7c75889ac8387 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -465,6 +465,43 @@ public class PurpurWorldConfig { - dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils); - } - -+ public boolean baselessEndCrystalExplode = true; -+ public double baselessEndCrystalExplosionPower = 6.0D; -+ public boolean baselessEndCrystalExplosionFire = false; -+ public net.minecraft.world.level.Level.ExplosionInteraction baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ public boolean basedEndCrystalExplode = true; -+ public double basedEndCrystalExplosionPower = 6.0D; -+ public boolean basedEndCrystalExplosionFire = false; -+ public net.minecraft.world.level.Level.ExplosionInteraction basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ private void endCrystalSettings() { -+ if (PurpurConfig.version < 31) { -+ if ("DESTROY".equals(getString("blocks.end-crystal.baseless.explosion-effect", baselessEndCrystalExplosionEffect.name()))) { -+ set("blocks.end-crystal.baseless.explosion-effect", "BLOCK"); -+ } -+ if ("DESTROY".equals(getString("blocks.end-crystal.base.explosion-effect", basedEndCrystalExplosionEffect.name()))) { -+ set("blocks.end-crystal.base.explosion-effect", "BLOCK"); -+ } -+ } -+ baselessEndCrystalExplode = getBoolean("blocks.end-crystal.baseless.explode", baselessEndCrystalExplode); -+ baselessEndCrystalExplosionPower = getDouble("blocks.end-crystal.baseless.explosion-power", baselessEndCrystalExplosionPower); -+ baselessEndCrystalExplosionFire = getBoolean("blocks.end-crystal.baseless.explosion-fire", baselessEndCrystalExplosionFire); -+ try { -+ baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.end-crystal.baseless.explosion-effect", baselessEndCrystalExplosionEffect.name())); -+ } catch (IllegalArgumentException e) { -+ log(Level.SEVERE, "Unknown value for `blocks.end-crystal.baseless.explosion-effect`! Using default of `BLOCK`"); -+ baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ } -+ basedEndCrystalExplode = getBoolean("blocks.end-crystal.base.explode", basedEndCrystalExplode); -+ basedEndCrystalExplosionPower = getDouble("blocks.end-crystal.base.explosion-power", basedEndCrystalExplosionPower); -+ basedEndCrystalExplosionFire = getBoolean("blocks.end-crystal.base.explosion-fire", basedEndCrystalExplosionFire); -+ try { -+ basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.end-crystal.base.explosion-effect", basedEndCrystalExplosionEffect.name())); -+ } catch (IllegalArgumentException e) { -+ log(Level.SEVERE, "Unknown value for `blocks.end-crystal.base.explosion-effect`! Using default of `BLOCK`"); -+ basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ } -+ } -+ - public boolean farmlandBypassMobGriefing = false; - public boolean farmlandGetsMoistFromBelow = false; - public boolean farmlandAlpha = false; diff --git a/patches/server/0127-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch b/patches/server/0127-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch deleted file mode 100644 index 8e440c4a0..000000000 --- a/patches/server/0127-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Sat, 20 Feb 2021 14:47:08 -0800 -Subject: [PATCH] Configs for if Wither/Ender Dragon can ride vehicles - - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -index bf657ed6a27ce5da5621a3e14b0bf41ea0c4c8c9..3da1f7a6e443954e4976dd59391ea19b9c903cf7 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -@@ -1188,6 +1188,7 @@ public class EnderDragon extends Mob implements Enemy { - - @Override - protected boolean canRide(Entity entity) { -+ if (this.level().purpurConfig.enderDragonCanRideVehicles) return this.boardingCooldown <= 0; // Purpur - return false; - } - -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 948e5747d8d280695dd903a29b9c9f9dae9a44c1..6752a0039fac041e9bdd25327cdf20d3f1922bd6 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -730,6 +730,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - - @Override - protected boolean canRide(Entity entity) { -+ if (this.level().purpurConfig.witherCanRideVehicles) return this.boardingCooldown <= 0; // Purpur - return false; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 9de44dd59e69d709490290cf07b7c75889ac8387..d56aa23ea97e6cd7e1b5824fc46d1b6c0ee23a2d 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -948,6 +948,7 @@ public class PurpurWorldConfig { - public boolean enderDragonAlwaysDropsFullExp = false; - public boolean enderDragonBypassMobGriefing = false; - public boolean enderDragonTakeDamageFromWater = false; -+ public boolean enderDragonCanRideVehicles = false; - private void enderDragonSettings() { - enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); - enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); -@@ -966,6 +967,7 @@ public class PurpurWorldConfig { - enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); - enderDragonBypassMobGriefing = getBoolean("mobs.ender_dragon.bypass-mob-griefing", enderDragonBypassMobGriefing); - enderDragonTakeDamageFromWater = getBoolean("mobs.ender_dragon.takes-damage-from-water", enderDragonTakeDamageFromWater); -+ enderDragonCanRideVehicles = getBoolean("mobs.ender_dragon.can-ride-vehicles", enderDragonCanRideVehicles); - } - - public boolean endermanRidable = false; -@@ -2157,6 +2159,7 @@ public class PurpurWorldConfig { - public int witherHealthRegenDelay = 20; - public boolean witherBypassMobGriefing = false; - public boolean witherTakeDamageFromWater = false; -+ public boolean witherCanRideVehicles = false; - private void witherSettings() { - witherRidable = getBoolean("mobs.wither.ridable", witherRidable); - witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); -@@ -2176,6 +2179,7 @@ public class PurpurWorldConfig { - witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); - witherBypassMobGriefing = getBoolean("mobs.wither.bypass-mob-griefing", witherBypassMobGriefing); - witherTakeDamageFromWater = getBoolean("mobs.wither.takes-damage-from-water", witherTakeDamageFromWater); -+ witherCanRideVehicles = getBoolean("mobs.wither.can-ride-vehicles", witherCanRideVehicles); - } - - public boolean witherSkeletonRidable = false; diff --git a/patches/server/0128-Dont-run-with-scissors.patch b/patches/server/0128-Dont-run-with-scissors.patch deleted file mode 100644 index 0ab792c43..000000000 --- a/patches/server/0128-Dont-run-with-scissors.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: JustDoom -Date: Fri, 5 Mar 2021 14:23:16 -0500 -Subject: [PATCH] Dont run with scissors! - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index b3cecec8a93bd0de1a74e693b7c103fdbc87eba2..cc3728902da9e10df2bb0e3edbb765bffd51d808 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1657,6 +1657,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.player.resetCurrentImpulseContext(); - } - -+ // Purpur Start -+ if (this.player.level().purpurConfig.dontRunWithScissors && this.player.isSprinting() && !(this.player.level().purpurConfig.ignoreScissorsInWater && this.player.isInWater()) && !(this.player.level().purpurConfig.ignoreScissorsInLava && this.player.isInLava()) && (isScissor(this.player.getItemInHand(InteractionHand.MAIN_HAND)) || isScissor(this.player.getItemInHand(InteractionHand.OFF_HAND))) && (int) (Math.random() * 10) == 0) { -+ this.player.hurt(this.player.damageSources().scissors(), (float) this.player.level().purpurConfig.scissorsRunningDamage); -+ if (!org.purpurmc.purpur.PurpurConfig.dontRunWithScissors.isBlank()) this.player.sendActionBarMessage(org.purpurmc.purpur.PurpurConfig.dontRunWithScissors); -+ } -+ // Purpur End -+ - this.player.checkMovementStatistics(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5); - this.lastGoodX = this.player.getX(); - this.lastGoodY = this.player.getY(); -@@ -1696,6 +1703,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - return false; - } - // Paper end - optimise out extra getCubes -+ -+ // Purpur start -+ public boolean isScissor(ItemStack stack) { -+ if (!stack.is(Items.SHEARS)) return false; -+ net.minecraft.world.item.component.CustomModelData customModelData = stack.get(net.minecraft.core.component.DataComponents.CUSTOM_MODEL_DATA); -+ return customModelData == null || customModelData.value() == 0; -+ } -+ // Purpur end -+ - private boolean isPlayerCollidingWithAnythingNew(LevelReader world, AABB box, double newX, double newY, double newZ) { - AABB axisalignedbb1 = this.player.getBoundingBox().move(newX - this.player.getX(), newY - this.player.getY(), newZ - this.player.getZ()); - Iterable iterable = world.getCollisions(this.player, axisalignedbb1.deflate(9.999999747378752E-6D)); -diff --git a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -index 99a7e9eb75231c15bd8bb24fbb4e296bc9fdedff..a375d40ec6365ba8704ba3ece22dd5b2de9857b5 100644 ---- a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -+++ b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -@@ -98,6 +98,11 @@ public class CombatTracker { - Component component = ComponentUtils.wrapInSquareBrackets(Component.translatable(string + ".link")).withStyle(INTENTIONAL_GAME_DESIGN_STYLE); - return Component.translatable(string + ".message", this.mob.getDisplayName(), component); - } else { -+ // Purpur start -+ if (damageSource.isScissors()) { -+ return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgRunWithScissors, this.mob); -+ } -+ // Purpur end - return damageSource.getLocalizedDeathMessage(this.mob); - } - } -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -index ff1df6360cb4d9da8717687344bdea2a44b6fc2a..894668c96ac36e737910a25cf89651236246200c 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -@@ -29,6 +29,7 @@ public class DamageSource { - private boolean withSweep = false; - private boolean melting = false; - private boolean poison = false; -+ private boolean scissors = false; // Purpur - @Nullable - private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API - -@@ -59,6 +60,17 @@ public class DamageSource { - return this.poison; - } - -+ // Purpur start -+ public DamageSource scissors() { -+ this.scissors = true; -+ return this; -+ } -+ -+ public boolean isScissors() { -+ return this.scissors; -+ } -+ // Purpur end -+ - // Paper start - fix DamageSource API - public @Nullable Entity getCustomEventDamager() { - return (this.customEventDamager != null) ? this.customEventDamager : this.directEntity; -@@ -101,6 +113,7 @@ public class DamageSource { - damageSource.withSweep = this.isSweep(); - damageSource.poison = this.isPoison(); - damageSource.melting = this.isMelting(); -+ damageSource.scissors = this.isScissors(); // Purpur - return damageSource; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSources.java b/src/main/java/net/minecraft/world/damagesource/DamageSources.java -index a1c53f04c2dd505e6af72e512e111d7994786035..13b596a1e06fa66396c43a6c72659d4342bf6549 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSources.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSources.java -@@ -44,11 +44,13 @@ public class DamageSources { - // CraftBukkit start - private final DamageSource melting; - private final DamageSource poison; -+ private final DamageSource scissors; // Purpur - - public DamageSources(RegistryAccess registryManager) { - this.damageTypes = registryManager.registryOrThrow(Registries.DAMAGE_TYPE); - this.melting = this.source(DamageTypes.ON_FIRE).melting(); - this.poison = this.source(DamageTypes.MAGIC).poison(); -+ this.scissors = this.source(DamageTypes.MAGIC).scissors(); // Purpur - // CraftBukkit end - this.inFire = this.source(DamageTypes.IN_FIRE); - this.lightningBolt = this.source(DamageTypes.LIGHTNING_BOLT); -@@ -97,6 +99,12 @@ public class DamageSources { - } - // CraftBukkit end - -+ // Purpur start -+ public DamageSource scissors() { -+ return this.scissors; -+ } -+ // Purpur end -+ - public DamageSource inFire() { - return this.inFire; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index a4404782f0456a0bd05b385372ea920bd437eb35..0587b0c7f34ae90f0d06f29d58fafbcf5b80ff13 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -183,6 +183,7 @@ public class PurpurConfig { - public static String demoCommandOutput = "%s has been shown the demo screen"; - public static String pingCommandOutput = "%s's ping is %sms"; - public static String tpsbarCommandOutput = "Tpsbar toggled for "; -+ public static String dontRunWithScissors = "Don't run with scissors!"; - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); - afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); -@@ -194,6 +195,12 @@ public class PurpurConfig { - demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput); - pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); - tpsbarCommandOutput = getString("settings.messages.tpsbar-command-output", tpsbarCommandOutput); -+ dontRunWithScissors = getString("settings.messages.dont-run-with-scissors", dontRunWithScissors); -+ } -+ -+ public static String deathMsgRunWithScissors = " slipped and fell on their shears"; -+ private static void deathMessages() { -+ deathMsgRunWithScissors = getString("settings.messages.death-message.run-with-scissors", deathMsgRunWithScissors); - } - - public static String serverModName = "Purpur"; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index d56aa23ea97e6cd7e1b5824fc46d1b6c0ee23a2d..3f07fa6eec5efb308d6ec10ddb036c4774031a32 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -197,6 +197,10 @@ public class PurpurWorldConfig { - public List itemImmuneToExplosion = new ArrayList<>(); - public List itemImmuneToFire = new ArrayList<>(); - public List itemImmuneToLightning = new ArrayList<>(); -+ public boolean dontRunWithScissors = false; -+ public boolean ignoreScissorsInWater = false; -+ public boolean ignoreScissorsInLava = false; -+ public double scissorsRunningDamage = 1D; - private void itemSettings() { - itemImmuneToCactus.clear(); - getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { -@@ -234,6 +238,10 @@ public class PurpurWorldConfig { - Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(key.toString())); - if (item != Items.AIR) itemImmuneToLightning.add(item); - }); -+ dontRunWithScissors = getBoolean("gameplay-mechanics.item.shears.damage-if-sprinting", dontRunWithScissors); -+ ignoreScissorsInWater = getBoolean("gameplay-mechanics.item.shears.ignore-in-water", ignoreScissorsInWater); -+ ignoreScissorsInLava = getBoolean("gameplay-mechanics.item.shears.ignore-in-lava", ignoreScissorsInLava); -+ scissorsRunningDamage = getDouble("gameplay-mechanics.item.shears.sprinting-damage", scissorsRunningDamage); - } - - public double minecartMaxSpeed = 0.4D; diff --git a/patches/server/0129-One-Punch-Man.patch b/patches/server/0129-One-Punch-Man.patch deleted file mode 100644 index 51461e170..000000000 --- a/patches/server/0129-One-Punch-Man.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Fourmisain <8464472+Fourmisain@users.noreply.github.com> -Date: Fri, 5 Mar 2021 17:42:35 -0500 -Subject: [PATCH] One Punch Man! - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index dc1c7c55fd13cc1a8ade803bfb1b7c385cf29132..523052af43aa86982d2ded0cc0882d34bac24da7 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2382,6 +2382,21 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - } - -+ // Purpur start -+ if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player player && damagesource.getEntity().level().purpurConfig.creativeOnePunch) { -+ if (player.isCreative()) { -+ double attackDamage; -+ net.minecraft.world.item.component.ItemAttributeModifiers itemattributemodifiers = player.getMainHandItem().getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, net.minecraft.world.item.component.ItemAttributeModifiers.EMPTY); -+ -+ attackDamage = itemattributemodifiers.compute(player.getAttributeBaseValue(Attributes.ATTACK_DAMAGE), EquipmentSlot.MAINHAND); -+ -+ if (attackDamage == 1.0D) { -+ this.setHealth(0); -+ } -+ } -+ } -+ // Purpur end -+ - if (f > 0 || !human) { - if (human) { - // PAIL: Be sure to drag all this code from the EntityHuman subclass each update. -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3f07fa6eec5efb308d6ec10ddb036c4774031a32..5f01c0d1277e1aa910208a3b9308c427b6e22cdb 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -344,6 +344,7 @@ public class PurpurWorldConfig { - public boolean teleportIfOutsideBorder = false; - public boolean totemOfUndyingWorksInInventory = false; - public boolean playerFixStuckPortal = false; -+ public boolean creativeOnePunch = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -360,6 +361,7 @@ public class PurpurWorldConfig { - teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); - totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory); - playerFixStuckPortal = getBoolean("gameplay-mechanics.player.fix-stuck-in-portal", playerFixStuckPortal); -+ creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0130-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch b/patches/server/0130-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch deleted file mode 100644 index 4248c4ebc..000000000 --- a/patches/server/0130-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Sun, 7 Mar 2021 19:08:16 -0500 -Subject: [PATCH] Configurable Ender Pearl cooldown, damage, and Endermite RNG - -- Survival and Creative Cooldown speed -- Damage dealt on pearl usage -- Endermite spawn chance - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -index 1fb1e729d6879568d8b4943071fa940325b2e5b0..b61d659dc48f795c7f2d62044c245e342cd322e5 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -@@ -71,7 +71,7 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { - Bukkit.getPluginManager().callEvent(teleEvent); - - if (!teleEvent.isCancelled() && entityplayer.connection.isAcceptingMessages()) { -- if (this.random.nextFloat() < 0.05F && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { -+ if (this.random.nextFloat() < this.level().purpurConfig.enderPearlEndermiteChance && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { // Purpur - Endermite entityendermite = (Endermite) EntityType.ENDERMITE.create(this.level()); - - if (entityendermite != null) { -@@ -86,7 +86,7 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { - - entityplayer.connection.teleport(teleEvent.getTo()); - entity.resetFallDistance(); -- entity.hurt(this.damageSources().fall().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API -+ entity.hurt(this.damageSources().fall().customEventDamager(this), this.level().purpurConfig.enderPearlDamage); // CraftBukkit // Paper - fix DamageSource API // Purpur - } - // CraftBukkit end - this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_TELEPORT, SoundSource.PLAYERS); -diff --git a/src/main/java/net/minecraft/world/item/EnderpearlItem.java b/src/main/java/net/minecraft/world/item/EnderpearlItem.java -index 20a91d798d31a71b3c05efa2cc5bda55494e26cc..fc62754f93bd11a10c28b8b7b116e9fff70a5c7b 100644 ---- a/src/main/java/net/minecraft/world/item/EnderpearlItem.java -+++ b/src/main/java/net/minecraft/world/item/EnderpearlItem.java -@@ -36,7 +36,7 @@ public class EnderpearlItem extends Item { - - world.playSound((Player) null, user.getX(), user.getY(), user.getZ(), SoundEvents.ENDER_PEARL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (net.minecraft.world.entity.Entity.SHARED_RANDOM.nextFloat() * 0.4F + 0.8F)); - user.awardStat(Stats.ITEM_USED.get(this)); -- user.getCooldowns().addCooldown(this, 20); -+ user.getCooldowns().addCooldown(this, user.getAbilities().instabuild ? world.purpurConfig.enderPearlCooldownCreative : world.purpurConfig.enderPearlCooldown); // Purpur - } else { - // Paper end - PlayerLaunchProjectileEvent - if (user instanceof net.minecraft.server.level.ServerPlayer) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 5f01c0d1277e1aa910208a3b9308c427b6e22cdb..a71ce1e255bbb469d3c0a20853450130589af326 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -201,6 +201,10 @@ public class PurpurWorldConfig { - public boolean ignoreScissorsInWater = false; - public boolean ignoreScissorsInLava = false; - public double scissorsRunningDamage = 1D; -+ public float enderPearlDamage = 5.0F; -+ public int enderPearlCooldown = 20; -+ public int enderPearlCooldownCreative = 20; -+ public float enderPearlEndermiteChance = 0.05F; - private void itemSettings() { - itemImmuneToCactus.clear(); - getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { -@@ -242,6 +246,10 @@ public class PurpurWorldConfig { - ignoreScissorsInWater = getBoolean("gameplay-mechanics.item.shears.ignore-in-water", ignoreScissorsInWater); - ignoreScissorsInLava = getBoolean("gameplay-mechanics.item.shears.ignore-in-lava", ignoreScissorsInLava); - scissorsRunningDamage = getDouble("gameplay-mechanics.item.shears.sprinting-damage", scissorsRunningDamage); -+ enderPearlDamage = (float) getDouble("gameplay-mechanics.item.ender-pearl.damage", enderPearlDamage); -+ enderPearlCooldown = getInt("gameplay-mechanics.item.ender-pearl.cooldown", enderPearlCooldown); -+ enderPearlCooldownCreative = getInt("gameplay-mechanics.item.ender-pearl.creative-cooldown", enderPearlCooldownCreative); -+ enderPearlEndermiteChance = (float) getDouble("gameplay-mechanics.item.ender-pearl.endermite-spawn-chance", enderPearlEndermiteChance); - } - - public double minecartMaxSpeed = 0.4D; diff --git a/patches/server/0131-Config-to-ignore-nearby-mobs-when-sleeping.patch b/patches/server/0131-Config-to-ignore-nearby-mobs-when-sleeping.patch deleted file mode 100644 index 29cc238c3..000000000 --- a/patches/server/0131-Config-to-ignore-nearby-mobs-when-sleeping.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Mon, 8 Mar 2021 16:46:54 -0500 -Subject: [PATCH] Config to ignore nearby mobs when sleeping - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 146c2e46e0fb9a9358484a054f716d72b9750ed8..c9458551b1da419f484e9dce6b3fba8d79c2de79 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1505,7 +1505,7 @@ public class ServerPlayer extends Player { - return entitymonster.isPreventingPlayerRest(this); - }); - -- if (!list.isEmpty()) { -+ if (!this.level().purpurConfig.playerSleepNearMonsters && !list.isEmpty()) { // Purpur - return Either.left(Player.BedSleepingProblem.NOT_SAFE); - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index a71ce1e255bbb469d3c0a20853450130589af326..afcde828b7f39affd26cf3a52b744e0b37140694 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -353,6 +353,7 @@ public class PurpurWorldConfig { - public boolean totemOfUndyingWorksInInventory = false; - public boolean playerFixStuckPortal = false; - public boolean creativeOnePunch = false; -+ public boolean playerSleepNearMonsters = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -370,6 +371,7 @@ public class PurpurWorldConfig { - totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory); - playerFixStuckPortal = getBoolean("gameplay-mechanics.player.fix-stuck-in-portal", playerFixStuckPortal); - creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); -+ playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0132-Add-back-player-spawned-endermite-API.patch b/patches/server/0132-Add-back-player-spawned-endermite-API.patch deleted file mode 100644 index 33e1c6a57..000000000 --- a/patches/server/0132-Add-back-player-spawned-endermite-API.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 9 Mar 2021 16:10:39 -0500 -Subject: [PATCH] Add back player spawned endermite API - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Endermite.java b/src/main/java/net/minecraft/world/entity/monster/Endermite.java -index 514354bfcd0608554fd515248975fb107eddf427..c5fcefc6810c2127d6a0a48f95c50c2e15a4dd52 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Endermite.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Endermite.java -@@ -32,6 +32,7 @@ public class Endermite extends Monster { - - private static final int MAX_LIFE = 2400; - public int life; -+ private boolean isPlayerSpawned; // Purpur - - public Endermite(EntityType type, Level world) { - super(type, world); -@@ -65,6 +66,14 @@ public class Endermite extends Monster { - return this.level().purpurConfig.endermiteTakeDamageFromWater; - } - -+ public boolean isPlayerSpawned() { -+ return this.isPlayerSpawned; -+ } -+ -+ public void setPlayerSpawned(boolean playerSpawned) { -+ this.isPlayerSpawned = playerSpawned; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(1, new FloatGoal(this)); -@@ -112,12 +121,14 @@ public class Endermite extends Monster { - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - this.life = nbt.getInt("Lifetime"); -+ this.isPlayerSpawned = nbt.getBoolean("PlayerSpawned"); // Purpur - } - - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); - nbt.putInt("Lifetime", this.life); -+ nbt.putBoolean("PlayerSpawned", this.isPlayerSpawned); // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -index b61d659dc48f795c7f2d62044c245e342cd322e5..d9761d8fe746e925a7a32dfc15eb8045c6150fe5 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -@@ -75,6 +75,7 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { - Endermite entityendermite = (Endermite) EntityType.ENDERMITE.create(this.level()); - - if (entityendermite != null) { -+ entityendermite.setPlayerSpawned(true); // Purpur - entityendermite.moveTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); - this.level().addFreshEntity(entityendermite, CreatureSpawnEvent.SpawnReason.ENDER_PEARL); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java -index d657fd2c507a5b215aeab0a5f3e9c2ee892a27c8..985e9ec21c60a1f47973bd5fc53b96a6f9b7d04a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java -@@ -21,12 +21,12 @@ public class CraftEndermite extends CraftMonster implements Endermite { - - @Override - public boolean isPlayerSpawned() { -- return false; -+ return getHandle().isPlayerSpawned(); // Purpur - } - - @Override - public void setPlayerSpawned(boolean playerSpawned) { -- // Nop -+ getHandle().setPlayerSpawned(playerSpawned); // Purpur - } - // Paper start - @Override diff --git a/patches/server/0133-Config-Enderman-aggressiveness-towards-Endermites.patch b/patches/server/0133-Config-Enderman-aggressiveness-towards-Endermites.patch deleted file mode 100644 index 0ef7d7bfe..000000000 --- a/patches/server/0133-Config-Enderman-aggressiveness-towards-Endermites.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 9 Mar 2021 16:10:39 -0500 -Subject: [PATCH] Config Enderman aggressiveness towards Endermites - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index 17b044e58d2ed33ed16e60f4fd4f63b2ee3f854d..4821aec304399c64cbcff741334567a08b840c0a 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -129,7 +129,7 @@ public class EnderMan extends Monster implements NeutralMob { - this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt)); - this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); -- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, true, false)); -+ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, 10, true, false, (entityliving) -> entityliving.level().purpurConfig.endermanAggroEndermites && entityliving instanceof Endermite endermite && (!entityliving.level().purpurConfig.endermanAggroEndermitesOnlyIfPlayerSpawned || endermite.isPlayerSpawned()))); // Purpur - this.targetSelector.addGoal(4, new ResetUniversalAngerTargetGoal<>(this, false)); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index afcde828b7f39affd26cf3a52b744e0b37140694..3736b6a5be1c4eea48416c48822675e394b821f1 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -998,6 +998,8 @@ public class PurpurWorldConfig { - public boolean endermanDespawnEvenWithBlock = false; - public boolean endermanBypassMobGriefing = false; - public boolean endermanTakeDamageFromWater = true; -+ public boolean endermanAggroEndermites = true; -+ public boolean endermanAggroEndermitesOnlyIfPlayerSpawned = false; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -@@ -1007,11 +1009,17 @@ public class PurpurWorldConfig { - set("mobs.enderman.attributes.max-health", null); - set("mobs.enderman.attributes.max_health", oldValue); - } -+ if (PurpurConfig.version < 15) { -+ // remove old option -+ set("mobs.enderman.aggressive-towards-spawned-endermites", null); -+ } - endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); - endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); - endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock); - endermanBypassMobGriefing = getBoolean("mobs.enderman.bypass-mob-griefing", endermanBypassMobGriefing); - endermanTakeDamageFromWater = getBoolean("mobs.enderman.takes-damage-from-water", endermanTakeDamageFromWater); -+ endermanAggroEndermites = getBoolean("mobs.enderman.aggressive-towards-endermites", endermanAggroEndermites); -+ endermanAggroEndermitesOnlyIfPlayerSpawned = getBoolean("mobs.enderman.aggressive-towards-endermites-only-spawned-by-player-thrown-ender-pearls", endermanAggroEndermitesOnlyIfPlayerSpawned); - } - - public boolean endermiteRidable = false; diff --git a/patches/server/0134-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch b/patches/server/0134-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch deleted file mode 100644 index 3fc172e84..000000000 --- a/patches/server/0134-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 9 Mar 2021 16:16:01 -0500 -Subject: [PATCH] Config to ignore Dragon Head wearers and stare aggro - -Prevents Enderman from becoming aggresive towards players that are wearing a Dragon Head. -Adds functionality to a useless item! - -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index 4821aec304399c64cbcff741334567a08b840c0a..b361c6b4ca17b9d466555037235a5660caa5c9bd 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -266,7 +266,7 @@ public class EnderMan extends Monster implements NeutralMob { - // Paper end - EndermanAttackPlayerEvent - ItemStack itemstack = (ItemStack) player.getInventory().armor.get(3); - -- if (itemstack.is(Blocks.CARVED_PUMPKIN.asItem())) { -+ if (this.level().purpurConfig.endermanDisableStareAggro || itemstack.is(Blocks.CARVED_PUMPKIN.asItem()) || (this.level().purpurConfig.endermanIgnorePlayerDragonHead && itemstack.is(net.minecraft.world.item.Items.DRAGON_HEAD))) { // Purpur - return false; - } else { - Vec3 vec3d = player.getViewVector(1.0F).normalize(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3736b6a5be1c4eea48416c48822675e394b821f1..e3e0a5c0f241e7fe1fdd2be1bd1afe7752628b9e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1000,6 +1000,8 @@ public class PurpurWorldConfig { - public boolean endermanTakeDamageFromWater = true; - public boolean endermanAggroEndermites = true; - public boolean endermanAggroEndermitesOnlyIfPlayerSpawned = false; -+ public boolean endermanIgnorePlayerDragonHead = false; -+ public boolean endermanDisableStareAggro = false; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -@@ -1020,6 +1022,8 @@ public class PurpurWorldConfig { - endermanTakeDamageFromWater = getBoolean("mobs.enderman.takes-damage-from-water", endermanTakeDamageFromWater); - endermanAggroEndermites = getBoolean("mobs.enderman.aggressive-towards-endermites", endermanAggroEndermites); - endermanAggroEndermitesOnlyIfPlayerSpawned = getBoolean("mobs.enderman.aggressive-towards-endermites-only-spawned-by-player-thrown-ender-pearls", endermanAggroEndermitesOnlyIfPlayerSpawned); -+ endermanIgnorePlayerDragonHead = getBoolean("mobs.enderman.ignore-players-wearing-dragon-head", endermanIgnorePlayerDragonHead); -+ endermanDisableStareAggro = getBoolean("mobs.enderman.disable-player-stare-aggression", endermanDisableStareAggro); - } - - public boolean endermiteRidable = false; diff --git a/patches/server/0135-Tick-fluids-config.patch b/patches/server/0135-Tick-fluids-config.patch deleted file mode 100644 index 4a067efd0..000000000 --- a/patches/server/0135-Tick-fluids-config.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 15 Mar 2021 03:52:17 -0500 -Subject: [PATCH] Tick fluids config - - -diff --git a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java -index 84623c632d8c2f0fa7ec939c711316d757117d23..1851035b9fdcc076442d0699567a3b020e6425d6 100644 ---- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java -@@ -137,7 +137,7 @@ public class LiquidBlock extends Block implements BucketPickup { - - @Override - protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) { -- if (this.shouldSpreadLiquid(world, pos, state)) { -+ if (world.purpurConfig.tickFluids && this.shouldSpreadLiquid(world, pos, state)) { // Purpur - world.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper - Configurable speed for water flowing over lava - } - -@@ -165,7 +165,7 @@ public class LiquidBlock extends Block implements BucketPickup { - - @Override - protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { -- if (state.getFluidState().isSource() || neighborState.getFluidState().isSource()) { -+ if (world.getMinecraftWorld().purpurConfig.tickFluids && state.getFluidState().isSource() || neighborState.getFluidState().isSource()) { // Purpur - world.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(world)); - } - -@@ -174,7 +174,7 @@ public class LiquidBlock extends Block implements BucketPickup { - - @Override - protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { -- if (this.shouldSpreadLiquid(world, pos, state)) { -+ if (world.purpurConfig.tickFluids && this.shouldSpreadLiquid(world, pos, state)) { // Purpur - world.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(world, pos)); // Paper - Configurable speed for water flowing over lava - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e3e0a5c0f241e7fe1fdd2be1bd1afe7752628b9e..6756564f9b03bc822485b4199bf46c50069eea65 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -129,6 +129,7 @@ public class PurpurWorldConfig { - public boolean noteBlockIgnoreAbove = false; - public boolean persistentDroppableEntityDisplayNames = true; - public boolean projectilesBypassMobGriefing = false; -+ public boolean tickFluids = true; - public double tridentLoyaltyVoidReturnHeight = 0.0D; - public double voidDamageHeight = -64.0D; - public double voidDamageDealt = 4.0D; -@@ -148,6 +149,7 @@ public class PurpurWorldConfig { - noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove); - persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); - projectilesBypassMobGriefing = getBoolean("gameplay-mechanics.projectiles-bypass-mob-griefing", projectilesBypassMobGriefing); -+ tickFluids = getBoolean("gameplay-mechanics.tick-fluids", tickFluids); - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); - voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); - voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); diff --git a/patches/server/0136-Config-to-disable-Llama-caravans.patch b/patches/server/0136-Config-to-disable-Llama-caravans.patch deleted file mode 100644 index 3600b1e45..000000000 --- a/patches/server/0136-Config-to-disable-Llama-caravans.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Wed, 17 Mar 2021 10:12:53 -0400 -Subject: [PATCH] Config to disable Llama caravans - -Disables the mechanic where llamas follow leashed llamas. - -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -index eb0faf58fa1a408f294fc62120b140def97f998d..0f4f546cd0eda4bd82b47446ae23ac32da8a9556 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -@@ -22,7 +22,7 @@ public class LlamaFollowCaravanGoal extends Goal { - - @Override - public boolean canUse() { -- if (!this.llama.shouldJoinCaravan) return false; // Purpur -+ if (!this.llama.level().purpurConfig.llamaJoinCaravans || !this.llama.shouldJoinCaravan) return false; // Purpur - if (!this.llama.isLeashed() && !this.llama.inCaravan()) { - List list = this.llama.level().getEntities(this.llama, this.llama.getBoundingBox().inflate(9.0, 4.0, 9.0), entity -> { - EntityType entityType = entity.getType(); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 87ec5bd632353ce364de29c5d56460551b6a4139..12ff4091674f7efb3e324df0df2d798dcbc46027 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -@@ -481,7 +481,7 @@ public class Llama extends AbstractChestedHorse implements VariantHolder -Date: Tue, 16 Mar 2021 19:50:58 -0400 -Subject: [PATCH] Config to make Creepers explode on death - -Creepers exploded after being killed in the alpha days. This brings that back. - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index a9523b156eb88646ef82ee857d5f68360b12a753..af6f2fd2f2f48b8057cfb0462a0e72a86a1f83e3 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -65,6 +65,7 @@ public class Creeper extends Monster implements PowerableMob { - private int spacebarCharge = 0; - private int prevSpacebarCharge = 0; - private int powerToggleDelay = 0; -+ private boolean exploding = false; - // Purpur end - - public Creeper(EntityType type, Level world) { -@@ -270,6 +271,14 @@ public class Creeper extends Monster implements PowerableMob { - return this.level().purpurConfig.creeperTakeDamageFromWater; - } - -+ @Override -+ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource damagesource) { -+ if (!exploding && this.level().purpurConfig.creeperExplodeWhenKilled && damagesource.getEntity() instanceof net.minecraft.server.level.ServerPlayer) { -+ this.explodeCreeper(); -+ } -+ return super.dropAllDeathLoot(damagesource); -+ } -+ - @Override - protected SoundEvent getHurtSound(DamageSource source) { - return SoundEvents.CREEPER_HURT; -@@ -358,6 +367,7 @@ public class Creeper extends Monster implements PowerableMob { - } - - public void explodeCreeper() { -+ this.exploding = true; // Purpur - if (!this.level().isClientSide) { - float f = this.isPowered() ? 2.0F : 1.0F; - -@@ -376,7 +386,7 @@ public class Creeper extends Monster implements PowerableMob { - } - // CraftBukkit end - } -- -+ this.exploding = false; // Purpur - } - - private void spawnLingeringCloud() { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3045fff19b9f9c35ed1b2e14894f6b5aa8442817..3a730b7d187ba043fc8f3f0ca7412ec44e352fba 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -852,6 +852,7 @@ public class PurpurWorldConfig { - public boolean creeperAllowGriefing = true; - public boolean creeperBypassMobGriefing = false; - public boolean creeperTakeDamageFromWater = false; -+ public boolean creeperExplodeWhenKilled = false; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -866,6 +867,7 @@ public class PurpurWorldConfig { - creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); - creeperBypassMobGriefing = getBoolean("mobs.creeper.bypass-mob-griefing", creeperBypassMobGriefing); - creeperTakeDamageFromWater = getBoolean("mobs.creeper.takes-damage-from-water", creeperTakeDamageFromWater); -+ creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled); - } - - public boolean dolphinRidable = false; diff --git a/patches/server/0138-Configurable-ravager-griefable-blocks-list.patch b/patches/server/0138-Configurable-ravager-griefable-blocks-list.patch deleted file mode 100644 index e4e120f7a..000000000 --- a/patches/server/0138-Configurable-ravager-griefable-blocks-list.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 17 Mar 2021 14:54:43 -0500 -Subject: [PATCH] Configurable ravager griefable blocks list - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index e592b5ee3a0bfce987557defed8250682373fe65..ea9714b561d2cccad3ce012a118d200100ccd1e8 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -183,7 +183,7 @@ public class Ravager extends Raider { - BlockState iblockdata = this.level().getBlockState(blockposition); - Block block = iblockdata.getBlock(); - -- if (block instanceof LeavesBlock) { -+ if (this.level().purpurConfig.ravagerGriefableBlocks.contains(block)) { // Purpur - // CraftBukkit start - if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state - continue; -diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java -index 2af4c365743b2956939335512f74e0a1d84298f7..a69e7e8da81bd13578d230cc1e3f0f900817cbfd 100644 ---- a/src/main/java/net/minecraft/world/level/block/CropBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java -@@ -179,7 +179,7 @@ public class CropBlock extends BushBlock implements BonemealableBlock { - @Override - protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { - if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent -- if (entity instanceof Ravager && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), (!world.purpurConfig.ravagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)))) { // CraftBukkit // Purpur -+ if (entity instanceof Ravager && world.purpurConfig.ravagerGriefableBlocks.contains(world.getBlockState(pos).getBlock()) && CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), (!world.purpurConfig.ravagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)))) { // CraftBukkit // Purpur - world.destroyBlock(pos, true, entity); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3a730b7d187ba043fc8f3f0ca7412ec44e352fba..9ec5bae4a4caee44d84dd77b8be6b5c4b4b05b3e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1704,6 +1704,7 @@ public class PurpurWorldConfig { - public double ravagerMaxHealth = 100.0D; - public boolean ravagerBypassMobGriefing = false; - public boolean ravagerTakeDamageFromWater = false; -+ public List ravagerGriefableBlocks = new ArrayList<>(); - private void ravagerSettings() { - ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); - ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); -@@ -1716,6 +1717,23 @@ public class PurpurWorldConfig { - ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth); - ravagerBypassMobGriefing = getBoolean("mobs.ravager.bypass-mob-griefing", ravagerBypassMobGriefing); - ravagerTakeDamageFromWater = getBoolean("mobs.ravager.takes-damage-from-water", ravagerTakeDamageFromWater); -+ getList("mobs.ravager.griefable-blocks", new ArrayList(){{ -+ add("minecraft:oak_leaves"); -+ add("minecraft:spruce_leaves"); -+ add("minecraft:birch_leaves"); -+ add("minecraft:jungle_leaves"); -+ add("minecraft:acacia_leaves"); -+ add("minecraft:dark_oak_leaves"); -+ add("minecraft:beetroots"); -+ add("minecraft:carrots"); -+ add("minecraft:potatoes"); -+ add("minecraft:wheat"); -+ }}).forEach(key -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(key.toString())); -+ if (!block.defaultBlockState().isAir()) { -+ ravagerGriefableBlocks.add(block); -+ } -+ }); - } - - public boolean salmonRidable = false; diff --git a/patches/server/0139-Sneak-to-bulk-process-composter.patch b/patches/server/0139-Sneak-to-bulk-process-composter.patch deleted file mode 100644 index 3260a1417..000000000 --- a/patches/server/0139-Sneak-to-bulk-process-composter.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 7 May 2023 22:26:59 -0700 -Subject: [PATCH] Sneak to bulk process composter - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 5cedce1f432f6b809b25269242a16477682c824f..61ff2f6c09251da8c34fd653020cd4d3b46a4371 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -573,7 +573,7 @@ public class ServerPlayerGameMode { - ItemStack itemstack1 = stack.copy(); - InteractionResult enuminteractionresult; - -- if (!flag1) { -+ if (!flag1 || (player.level().purpurConfig.composterBulkProcess && iblockdata.is(Blocks.COMPOSTER))) { // Purpur - ItemInteractionResult iteminteractionresult = iblockdata.useItemOn(player.getItemInHand(hand), world, player, hand, hitResult); - - if (iteminteractionresult.consumesAction()) { -diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -index d3d12f9114173f4971f95d7ef895a4374705bd3f..f34159f8d6c51af2341bf49db0d6d6f0417919cf 100644 ---- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java -@@ -237,18 +237,27 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - int i = (Integer) state.getValue(ComposterBlock.LEVEL); - - if (i < 8 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) { -- if (i < 7 && !world.isClientSide) { -- BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack); -- // Paper start - handle cancelled events -- if (iblockdata1 == null) { -- return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; -- } -- // Paper end -- -- world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0); -- player.awardStat(Stats.ITEM_USED.get(stack.getItem())); -- stack.consume(1, player); -+ // Purpur start - sneak to bulk process composter -+ BlockState newState = process(i, player, state, world, pos, stack); -+ if (newState == null) { -+ return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; - } -+ if (world.purpurConfig.composterBulkProcess && player.isShiftKeyDown() && newState != state) { -+ BlockState oldState; -+ int oldCount, newCount, oldLevel, newLevel; -+ do { -+ oldState = newState; -+ oldCount = stack.getCount(); -+ oldLevel = oldState.getValue(ComposterBlock.LEVEL); -+ newState = process(oldLevel, player, oldState, world, pos, stack); -+ if (newState == null) { -+ return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; -+ } -+ newCount = stack.getCount(); -+ newLevel = newState.getValue(ComposterBlock.LEVEL); -+ } while (newCount > 0 && (newCount != oldCount || newLevel != oldLevel || newState != oldState)); -+ } -+ // Purpur end - - return ItemInteractionResult.sidedSuccess(world.isClientSide); - } else { -@@ -256,6 +265,25 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { - } - } - -+ // Purpur start - sneak to bulk process composter -+ private static @Nullable BlockState process(int level, Player player, BlockState state, Level world, BlockPos pos, ItemStack stack) { -+ if (level < 7 && !world.isClientSide) { -+ BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack); -+ // Paper start - handle cancelled events -+ if (iblockdata1 == null) { -+ return null; -+ } -+ // Paper end -+ -+ world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0); -+ player.awardStat(Stats.ITEM_USED.get(stack.getItem())); -+ stack.consume(1, player); -+ return iblockdata1; -+ } -+ return state; -+ } -+ // Purpur end -+ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { - int i = (Integer) state.getValue(ComposterBlock.LEVEL); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 9ec5bae4a4caee44d84dd77b8be6b5c4b4b05b3e..3b9973bbe7e752e906e152f9ddde5e7a1546988b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -480,6 +480,11 @@ public class PurpurWorldConfig { - chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); - } - -+ public boolean composterBulkProcess = false; -+ private void composterSettings() { -+ composterBulkProcess = getBoolean("blocks.composter.sneak-to-bulk-process", composterBulkProcess); -+ } -+ - public boolean dispenserApplyCursedArmor = true; - public boolean dispenserPlaceAnvils = false; - private void dispenserSettings() { diff --git a/patches/server/0140-Config-for-skipping-night.patch b/patches/server/0140-Config-for-skipping-night.patch deleted file mode 100644 index a0874bf67..000000000 --- a/patches/server/0140-Config-for-skipping-night.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Thu, 18 Mar 2021 06:22:40 -0400 -Subject: [PATCH] Config for skipping night - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index aef5157d183b69903fd215a5ce30c0705ba8fa3e..bcdef2c9bb116409445a4ef65c5e407c1003a55d 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -846,7 +846,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); - long j; - -- if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) { -+ if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) { - // CraftBukkit start - j = this.levelData.getDayTime() + 24000L; - TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (j - j % 24000L) - this.getDayTime()); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3b9973bbe7e752e906e152f9ddde5e7a1546988b..94f0eea598ee9908dd58efd7f4d5f6841bc9a003 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -356,6 +356,7 @@ public class PurpurWorldConfig { - public boolean playerFixStuckPortal = false; - public boolean creativeOnePunch = false; - public boolean playerSleepNearMonsters = false; -+ public boolean playersSkipNight = true; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -374,6 +375,7 @@ public class PurpurWorldConfig { - playerFixStuckPortal = getBoolean("gameplay-mechanics.player.fix-stuck-in-portal", playerFixStuckPortal); - creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); - playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters); -+ playersSkipNight = getBoolean("gameplay-mechanics.player.can-skip-night", playersSkipNight); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0141-Add-config-for-villager-trading.patch b/patches/server/0141-Add-config-for-villager-trading.patch deleted file mode 100644 index 2a72a25f9..000000000 --- a/patches/server/0141-Add-config-for-villager-trading.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Thu, 18 Mar 2021 07:23:27 -0400 -Subject: [PATCH] Add config for villager trading - - -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index c9cfbc8817fe62e22cb165f856ed8569668c0a60..a7c85c9efd13145cc061a3a0076b44a7af9812b9 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -371,7 +371,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - return tryRide(player, hand, InteractionResult.sidedSuccess(this.level().isClientSide)); // Purpur - } else { - if (level().purpurConfig.villagerRidable && itemstack.isEmpty()) return tryRide(player, hand); // Purpur -- if (!this.level().isClientSide && !this.offers.isEmpty()) { -+ if (this.level().purpurConfig.villagerAllowTrading && !this.offers.isEmpty()) { - this.startTrading(player); - } - -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index c192f4cc5fd9cb0cf40083c4297f649ab909649d..0d11200ab580cc306602c29c61f7619565d8261d 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -154,7 +154,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - return tryRide(player, hand, InteractionResult.sidedSuccess(this.level().isClientSide)); // Purpur - } else { - if (level().purpurConfig.wanderingTraderRidable && itemstack.isEmpty()) return tryRide(player, hand); // Purpur -- if (!this.level().isClientSide) { -+ if (this.level().purpurConfig.wanderingTraderAllowTrading) { - this.setTradingPlayer(player); - this.openTradingScreen(player, this.getDisplayName(), 1); - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 94f0eea598ee9908dd58efd7f4d5f6841bc9a003..9ad20a137f6cf35776e0e9cafe03c0dd475501b0 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2124,6 +2124,7 @@ public class PurpurWorldConfig { - public boolean villagerClericFarmersThrowWarts = true; - public boolean villagerBypassMobGriefing = false; - public boolean villagerTakeDamageFromWater = false; -+ public boolean villagerAllowTrading = true; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -2142,6 +2143,7 @@ public class PurpurWorldConfig { - villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts); - villagerBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerBypassMobGriefing); - villagerTakeDamageFromWater = getBoolean("mobs.villager.takes-damage-from-water", villagerTakeDamageFromWater); -+ villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading); - } - - public boolean vindicatorRidable = false; -@@ -2171,6 +2173,7 @@ public class PurpurWorldConfig { - public boolean wanderingTraderFollowEmeraldBlock = false; - public boolean wanderingTraderCanBeLeashed = false; - public boolean wanderingTraderTakeDamageFromWater = false; -+ public boolean wanderingTraderAllowTrading = true; - private void wanderingTraderSettings() { - wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); - wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); -@@ -2184,6 +2187,7 @@ public class PurpurWorldConfig { - wanderingTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", wanderingTraderFollowEmeraldBlock); - wanderingTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", wanderingTraderCanBeLeashed); - wanderingTraderTakeDamageFromWater = getBoolean("mobs.wandering_trader.takes-damage-from-water", wanderingTraderTakeDamageFromWater); -+ wanderingTraderAllowTrading = getBoolean("mobs.wandering_trader.allow-trading", wanderingTraderAllowTrading); - } - - public boolean wardenRidable = false; diff --git a/patches/server/0143-Drowning-Settings.patch b/patches/server/0143-Drowning-Settings.patch deleted file mode 100644 index 76bd7109d..000000000 --- a/patches/server/0143-Drowning-Settings.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Sun, 21 Mar 2021 15:26:52 -0400 -Subject: [PATCH] Drowning Settings - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 1ec1f023d7eee5714c94dbb6c842444f70603f40..5f19cc285efac25b56a29242b41c2823020f170e 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3452,7 +3452,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public int getMaxAirSupply() { -- return this.maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() -+ return this.level == null? this.maxAirTicks : this.level().purpurConfig.drowningAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() // Purpur - } - - public int getAirSupply() { -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 523052af43aa86982d2ded0cc0882d34bac24da7..aca2bd27da4d5bc754d7e98e45eb468170d17408 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -452,7 +452,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - - if (flag1) { - this.setAirSupply(this.decreaseAirSupply(this.getAirSupply())); -- if (this.getAirSupply() == -20) { -+ if (this.getAirSupply() == -this.level().purpurConfig.drowningDamageInterval) { // Purpur - this.setAirSupply(0); - Vec3 vec3d = this.getDeltaMovement(); - -@@ -464,7 +464,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.level().addParticle(ParticleTypes.BUBBLE, this.getX() + d2, this.getY() + d3, this.getZ() + d4, vec3d.x, vec3d.y, vec3d.z); - } - -- this.hurt(this.damageSources().drown(), 2.0F); -+ this.hurt(this.damageSources().drown(), (float) this.level().purpurConfig.damageFromDrowning); // Purpur - } - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 9ad20a137f6cf35776e0e9cafe03c0dd475501b0..76e26e67ba5bc56af28aae17ccd1da9b609e4947 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -164,6 +164,15 @@ public class PurpurWorldConfig { - nighttimeTicks = getInt("gameplay-mechanics.daylight-cycle-ticks.nighttime", nighttimeTicks); - } - -+ public int drowningAirTicks = 300; -+ public int drowningDamageInterval = 20; -+ public double damageFromDrowning = 2.0F; -+ private void drowningSettings() { -+ drowningAirTicks = getInt("gameplay-mechanics.drowning.air-ticks", drowningAirTicks); -+ drowningDamageInterval = getInt("gameplay-mechanics.drowning.ticks-per-damage", drowningDamageInterval); -+ damageFromDrowning = getDouble("gameplay-mechanics.drowning.damage-from-drowning", damageFromDrowning); -+ } -+ - public int elytraDamagePerSecond = 1; - public double elytraDamageMultiplyBySpeed = 0; - public boolean elytraIgnoreUnbreaking = false; diff --git a/patches/server/0144-Break-individual-slabs-when-sneaking.patch b/patches/server/0144-Break-individual-slabs-when-sneaking.patch deleted file mode 100644 index c62491c48..000000000 --- a/patches/server/0144-Break-individual-slabs-when-sneaking.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 23 Mar 2021 19:38:53 -0500 -Subject: [PATCH] Break individual slabs when sneaking - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 61ff2f6c09251da8c34fd653020cd4d3b46a4371..a810eaa7dc319f5ea69b239190ae91838bfad4ec 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -400,6 +400,7 @@ public class ServerPlayerGameMode { - } else {capturedBlockEntity = true;} // Paper - Send block entities after destroy prediction - return false; - } -+ if (this.player.level().purpurConfig.slabHalfBreak && this.player.isShiftKeyDown() && iblockdata.getBlock() instanceof net.minecraft.world.level.block.SlabBlock && ((net.minecraft.world.level.block.SlabBlock) iblockdata.getBlock()).halfBreak(iblockdata, pos, this.player)) return true; // Purpur - } - // CraftBukkit end - -diff --git a/src/main/java/net/minecraft/world/level/block/SlabBlock.java b/src/main/java/net/minecraft/world/level/block/SlabBlock.java -index fa29eb15934b3dad171d27c21d99b2451cfe553b..ba4aa69425d796d306791ea193f9c6b21a065f0b 100644 ---- a/src/main/java/net/minecraft/world/level/block/SlabBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SlabBlock.java -@@ -138,4 +138,25 @@ public class SlabBlock extends Block implements SimpleWaterloggedBlock { - return false; - } - } -+ -+ // Purpur start -+ public boolean halfBreak(BlockState state, BlockPos pos, net.minecraft.server.level.ServerPlayer player) { -+ if (state.getValue(SlabBlock.TYPE) != SlabType.DOUBLE) { -+ return false; -+ } -+ net.minecraft.world.phys.HitResult result = player.getRayTrace(16, net.minecraft.world.level.ClipContext.Fluid.NONE); -+ if (result.getType() != net.minecraft.world.phys.HitResult.Type.BLOCK) { -+ return false; -+ } -+ double hitY = result.getLocation().y(); -+ int blockY = org.bukkit.util.NumberConversions.floor(hitY); -+ player.level().setBlock(pos, state.setValue(SlabBlock.TYPE, (hitY - blockY > 0.5 || blockY - pos.getY() == 1) ? SlabType.BOTTOM : SlabType.TOP), 3); -+ if (!player.getAbilities().instabuild) { -+ net.minecraft.world.entity.item.ItemEntity item = new net.minecraft.world.entity.item.ItemEntity(player.level(), pos.getX(), pos.getY(), pos.getZ(), new ItemStack(asItem())); -+ item.setDefaultPickUpDelay(); -+ player.level().addFreshEntity(item); -+ } -+ return true; -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 76e26e67ba5bc56af28aae17ccd1da9b609e4947..c84cd3ebe3b95505a832e612c993e106d4cc1067 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -601,6 +601,11 @@ public class PurpurWorldConfig { - } - } - -+ public boolean slabHalfBreak = false; -+ private void slabSettings() { -+ slabHalfBreak = getBoolean("blocks.slab.break-individual-slabs-when-sneaking", slabHalfBreak); -+ } -+ - public boolean spawnerDeactivateByRedstone = false; - private void spawnerSettings() { - spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); diff --git a/patches/server/0145-Config-to-disable-hostile-mob-spawn-on-ice.patch b/patches/server/0145-Config-to-disable-hostile-mob-spawn-on-ice.patch deleted file mode 100644 index 16d1fd82b..000000000 --- a/patches/server/0145-Config-to-disable-hostile-mob-spawn-on-ice.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 23 Mar 2021 15:40:45 -0400 -Subject: [PATCH] Config to disable hostile mob spawn on ice - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java -index 759839e912c54598b257ad738481364940f88a18..e60e6b3e5ae5a468cfe649ed2222412f3bc8b268 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Monster.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Monster.java -@@ -88,6 +88,14 @@ public abstract class Monster extends PathfinderMob implements Enemy { - } - - public static boolean isDarkEnoughToSpawn(ServerLevelAccessor world, BlockPos pos, RandomSource random) { -+ // Purpur start -+ if (!world.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce || !world.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce) { -+ net.minecraft.world.level.block.state.BlockState spawnBlock = world.getBlockState(pos.below()); -+ if ((!world.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.PACKED_ICE)) || (!world.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.BLUE_ICE))) { -+ return false; -+ } -+ } -+ // Purpur end - if (world.getBrightness(LightLayer.SKY, pos) > random.nextInt(32)) { - return false; - } else { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index c84cd3ebe3b95505a832e612c993e106d4cc1067..afac6d1da8604a2d6c6b015227db77617914867e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -566,6 +566,13 @@ public class PurpurWorldConfig { - furnaceUseLavaFromUnderneath = getBoolean("blocks.furnace.use-lava-from-underneath", furnaceUseLavaFromUnderneath); - } - -+ public boolean mobsSpawnOnPackedIce = true; -+ public boolean mobsSpawnOnBlueIce = true; -+ private void iceSettings() { -+ mobsSpawnOnPackedIce = getBoolean("blocks.packed_ice.allow-mob-spawns", mobsSpawnOnPackedIce); -+ mobsSpawnOnBlueIce = getBoolean("blocks.blue_ice.allow-mob-spawns", mobsSpawnOnBlueIce); -+ } -+ - public int lavaInfiniteRequiredSources = 2; - public int lavaSpeedNether = 10; - public int lavaSpeedNotNether = 30; diff --git a/patches/server/0146-Config-to-show-Armor-Stand-arms-on-spawn.patch b/patches/server/0146-Config-to-show-Armor-Stand-arms-on-spawn.patch deleted file mode 100644 index 6908249a2..000000000 --- a/patches/server/0146-Config-to-show-Armor-Stand-arms-on-spawn.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 23 Mar 2021 22:42:20 -0400 -Subject: [PATCH] Config to show Armor Stand arms on spawn - - -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -index 89f600edda9a1c5d1b132355fefb7eaed77c52f5..6697cd8a632becd72ee132007a61d1221e817abf 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -117,6 +117,7 @@ public class ArmorStand extends LivingEntity { - this.rightArmPose = ArmorStand.DEFAULT_RIGHT_ARM_POSE; - this.leftLegPose = ArmorStand.DEFAULT_LEFT_LEG_POSE; - this.rightLegPose = ArmorStand.DEFAULT_RIGHT_LEG_POSE; -+ this.setShowArms(world != null && world.purpurConfig.armorstandPlaceWithArms); // Purpur - } - - public ArmorStand(Level world, double x, double y, double z) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index afac6d1da8604a2d6c6b015227db77617914867e..4c9479029b659baa53377fde1dd7117d5e1bfc15 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -102,6 +102,7 @@ public class PurpurWorldConfig { - public boolean armorstandMovement = true; - public boolean armorstandWaterMovement = true; - public boolean armorstandWaterFence = true; -+ public boolean armorstandPlaceWithArms = false; - private void armorstandSettings() { - armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); - armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); -@@ -109,6 +110,7 @@ public class PurpurWorldConfig { - armorstandMovement = getBoolean("gameplay-mechanics.armorstand.can-movement-tick", armorstandMovement); - armorstandWaterMovement = getBoolean("gameplay-mechanics.armorstand.can-move-in-water", armorstandWaterMovement); - armorstandWaterFence = getBoolean("gameplay-mechanics.armorstand.can-move-in-water-over-fence", armorstandWaterFence); -+ armorstandPlaceWithArms = getBoolean("gameplay-mechanics.armorstand.place-with-arms-visible", armorstandPlaceWithArms); - } - - public boolean arrowMovementResetsDespawnCounter = true; diff --git a/patches/server/0147-Option-to-make-doors-require-redstone.patch b/patches/server/0147-Option-to-make-doors-require-redstone.patch deleted file mode 100644 index 739f0b0e7..000000000 --- a/patches/server/0147-Option-to-make-doors-require-redstone.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 24 Mar 2021 04:40:11 -0500 -Subject: [PATCH] Option to make doors require redstone - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java b/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java -index 736f46d552d558bf0edd9a86601b5fbb6940815b..cf039181dfe0ddb3ccda44064a5d8a2f6c5c432c 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java -@@ -57,7 +57,7 @@ public class InteractWithDoor { - - if (iblockdata.is(BlockTags.WOODEN_DOORS, (blockbase_blockdata) -> { - return blockbase_blockdata.getBlock() instanceof DoorBlock; -- })) { -+ }) && !DoorBlock.requiresRedstone(entityliving.level(), iblockdata, blockposition)) { // Purpur - DoorBlock blockdoor = (DoorBlock) iblockdata.getBlock(); - - if (!blockdoor.isOpen(iblockdata)) { -@@ -79,7 +79,7 @@ public class InteractWithDoor { - - if (iblockdata1.is(BlockTags.WOODEN_DOORS, (blockbase_blockdata) -> { - return blockbase_blockdata.getBlock() instanceof DoorBlock; -- })) { -+ }) && !DoorBlock.requiresRedstone(entityliving.level(), iblockdata, blockposition1)) { // Purpur - DoorBlock blockdoor1 = (DoorBlock) iblockdata1.getBlock(); - - if (!blockdoor1.isOpen(iblockdata1)) { -@@ -122,7 +122,7 @@ public class InteractWithDoor { - - if (!iblockdata.is(BlockTags.WOODEN_DOORS, (blockbase_blockdata) -> { - return blockbase_blockdata.getBlock() instanceof DoorBlock; -- })) { -+ }) || DoorBlock.requiresRedstone(entity.level(), iblockdata, blockposition)) { // Purpur - iterator.remove(); - } else { - DoorBlock blockdoor = (DoorBlock) iblockdata.getBlock(); -diff --git a/src/main/java/net/minecraft/world/level/block/DoorBlock.java b/src/main/java/net/minecraft/world/level/block/DoorBlock.java -index 42d43b7a7e3b7c53cc80b8706c130e660f2c72da..96199441202ad929ad0274574704635c538a93c7 100644 ---- a/src/main/java/net/minecraft/world/level/block/DoorBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DoorBlock.java -@@ -198,6 +198,7 @@ public class DoorBlock extends Block { - protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { - if (!this.type.canOpenByHand()) { - return InteractionResult.PASS; -+ } else if (requiresRedstone(world, state, pos)) { return InteractionResult.CONSUME; // Purpur - } else { - state = (BlockState) state.cycle(DoorBlock.OPEN); - world.setBlock(pos, state, 10); -@@ -299,4 +300,18 @@ public class DoorBlock extends Block { - flag = false; - return flag; - } -+ -+ // Purpur start -+ public static boolean requiresRedstone(Level level, BlockState state, BlockPos pos) { -+ if (level.purpurConfig.doorRequiresRedstone.contains(state.getBlock())) { -+ // force update client -+ BlockPos otherPos = pos.relative(state.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN); -+ BlockState otherState = level.getBlockState(otherPos); -+ level.sendBlockUpdated(pos, state, state, 3); -+ level.sendBlockUpdated(otherPos, otherState, otherState, 3); -+ return true; -+ } -+ return false; -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 4c9479029b659baa53377fde1dd7117d5e1bfc15..3464f0c8d019c4675c2df7c83e0a77cb3eec16e0 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -505,6 +505,16 @@ public class PurpurWorldConfig { - dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils); - } - -+ public List doorRequiresRedstone = new ArrayList<>(); -+ private void doorSettings() { -+ getList("blocks.door.requires-redstone", new ArrayList()).forEach(key -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(key.toString())); -+ if (!block.defaultBlockState().isAir()) { -+ doorRequiresRedstone.add(block); -+ } -+ }); -+ } -+ - public boolean baselessEndCrystalExplode = true; - public double baselessEndCrystalExplosionPower = 6.0D; - public boolean baselessEndCrystalExplosionFire = false; diff --git a/patches/server/0148-Config-to-allow-for-unsafe-enchants.patch b/patches/server/0148-Config-to-allow-for-unsafe-enchants.patch deleted file mode 100644 index 7e350835a..000000000 --- a/patches/server/0148-Config-to-allow-for-unsafe-enchants.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Wed, 24 Mar 2021 17:59:54 -0400 -Subject: [PATCH] Config to allow for unsafe enchants - - -diff --git a/src/main/java/net/minecraft/server/commands/EnchantCommand.java b/src/main/java/net/minecraft/server/commands/EnchantCommand.java -index 84f1ba6275f04624f46ccd772924b5e075e7b205..bfb455fb74f0a9645212f90acb54f68d1c7d9772 100644 ---- a/src/main/java/net/minecraft/server/commands/EnchantCommand.java -+++ b/src/main/java/net/minecraft/server/commands/EnchantCommand.java -@@ -70,7 +70,7 @@ public class EnchantCommand { - - private static int enchant(CommandSourceStack source, Collection targets, Holder enchantment, int level) throws CommandSyntaxException { - Enchantment enchantment2 = enchantment.value(); -- if (level > enchantment2.getMaxLevel()) { -+ if (!org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchantCommand && level > enchantment2.getMaxLevel()) { // Purpur - throw ERROR_LEVEL_TOO_HIGH.create(level, enchantment2.getMaxLevel()); - } else { - int i = 0; -@@ -81,7 +81,7 @@ public class EnchantCommand { - ItemStack itemStack = livingEntity.getMainHandItem(); - if (!itemStack.isEmpty()) { - if (enchantment2.canEnchant(itemStack) -- && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(itemStack).keySet(), enchantment2)) { -+ && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(itemStack).keySet(), enchantment2) || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchantCommand && !itemStack.hasEnchantment(enchantment2))) { // Purpur - itemStack.enchant(enchantment2, level); - i++; - } else if (targets.size() == 1) { -diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index 5cadd69bcae33b1de58806fcf40533850d976154..17067510990f575bf638f6a95ed0d964f6e94dc5 100644 ---- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -@@ -228,7 +228,8 @@ public class AnvilMenu extends ItemCombinerMenu { - int i2 = entry.getIntValue(); - - i2 = l1 == i2 ? i2 + 1 : Math.max(i2, l1); -- boolean flag3 = enchantment.canEnchant(itemstack); -+ boolean flag3 = canDoUnsafeEnchants || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants && org.purpurmc.purpur.PurpurConfig.allowInapplicableEnchants) || enchantment.canEnchant(itemstack); // Purpur -+ boolean flag4 = true; // Purpur - - if (this.player.getAbilities().instabuild || itemstack.is(Items.ENCHANTED_BOOK)) { - flag3 = true; -@@ -240,16 +241,20 @@ public class AnvilMenu extends ItemCombinerMenu { - Holder holder1 = (Holder) iterator1.next(); - - if (!holder1.equals(holder) && !enchantment.isCompatibleWith((Enchantment) holder1.value())) { -- flag3 = canDoUnsafeEnchants; // Purpur -+ flag4 = canDoUnsafeEnchants || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants && org.purpurmc.purpur.PurpurConfig.allowIncompatibleEnchants); // Purpur flag3 -> flag4 -+ if (!flag4 && org.purpurmc.purpur.PurpurConfig.replaceIncompatibleEnchants) { -+ iterator1.remove(); -+ flag4 = true; -+ } - ++i; - } - } - -- if (!flag3) { -+ if (!flag3 || !flag4) { // Purpur - flag2 = true; - } else { - flag1 = true; -- if (i2 > enchantment.getMaxLevel()) { -+ if ((!org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants || !org.purpurmc.purpur.PurpurConfig.allowHigherEnchantsLevels) && i2 > enchantment.getMaxLevel()) { // Purpur - i2 = enchantment.getMaxLevel(); - } - -@@ -374,7 +379,7 @@ public class AnvilMenu extends ItemCombinerMenu { - this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client - this.broadcastChanges(); - // Purpur start -- if (canDoUnsafeEnchants && itemstack1 != ItemStack.EMPTY) { -+ if ((canDoUnsafeEnchants || org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchants) && itemstack1 != ItemStack.EMPTY) { - ((ServerPlayer) player).connection.send(new ClientboundContainerSetSlotPacket(containerId, incrementStateId(), 2, itemstack1)); - ((ServerPlayer) player).connection.send(new ClientboundContainerSetDataPacket(containerId, 0, cost.get())); - } -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 4e5315c93e99dd3c1c27f48cdec9bd5a2cc70ec5..1b829ad61a25ef1e18adefe291d91fdb7401956d 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -1226,6 +1226,16 @@ public final class ItemStack implements DataComponentHolder { - return !((ItemEnchantments) this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY)).isEmpty(); - } - -+ // Purpur start -+ public boolean hasEnchantment(Enchantment enchantment) { -+ if (isEnchanted()) { -+ ItemEnchantments enchantments = this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); -+ return new net.minecraft.advancements.critereon.EnchantmentPredicate(enchantment, net.minecraft.advancements.critereon.MinMaxBounds.Ints.atLeast(1)).containedIn(enchantments); -+ } -+ return false; -+ } -+ // Purpur end -+ - public ItemEnchantments getEnchantments() { - return (ItemEnchantments) this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index c60d0d1861fd24b74bfa93228357f27d524f4ce7..25b0eeb09f20601e8517f3dc413a72a3b05ac983 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -285,14 +285,34 @@ public class PurpurConfig { - - public static boolean allowInfinityMending = false; - public static boolean allowCrossbowInfinity = true; -+ public static boolean allowUnsafeEnchants = false; -+ public static boolean allowInapplicableEnchants = true; -+ public static boolean allowIncompatibleEnchants = true; -+ public static boolean allowHigherEnchantsLevels = true; -+ public static boolean allowUnsafeEnchantCommand = false; -+ public static boolean replaceIncompatibleEnchants = false; - private static void enchantmentSettings() { - if (version < 5) { - boolean oldValue = getBoolean("settings.enchantment.allow-infinite-and-mending-together", false); - set("settings.enchantment.allow-infinity-and-mending-together", oldValue); - set("settings.enchantment.allow-infinite-and-mending-together", null); - } -+ if (version < 30) { -+ boolean oldValue = getBoolean("settings.enchantment.allow-unsafe-enchants", false); -+ set("settings.enchantment.anvil.allow-unsafe-enchants", oldValue); -+ set("settings.enchantment.anvil.allow-inapplicable-enchants", true); -+ set("settings.enchantment.anvil.allow-incompatible-enchants", true); -+ set("settings.enchantment.anvil.allow-higher-enchants-levels", true); -+ set("settings.enchantment.allow-unsafe-enchants", null); -+ } - allowInfinityMending = getBoolean("settings.enchantment.allow-infinity-and-mending-together", allowInfinityMending); - allowCrossbowInfinity = getBoolean("settings.enchantment.allow-infinity-on-crossbow", allowCrossbowInfinity); -+ allowUnsafeEnchants = getBoolean("settings.enchantment.anvil.allow-unsafe-enchants", allowUnsafeEnchants); -+ allowInapplicableEnchants = getBoolean("settings.enchantment.anvil.allow-inapplicable-enchants", allowInapplicableEnchants); -+ allowIncompatibleEnchants = getBoolean("settings.enchantment.anvil.allow-incompatible-enchants", allowIncompatibleEnchants); -+ allowHigherEnchantsLevels = getBoolean("settings.enchantment.anvil.allow-higher-enchants-levels", allowHigherEnchantsLevels); -+ allowUnsafeEnchantCommand = getBoolean("settings.enchantment.allow-unsafe-enchant-command", allowUnsafeEnchants); // allowUnsafeEnchants as default for backwards compatability -+ replaceIncompatibleEnchants = getBoolean("settings.enchantment.anvil.replace-incompatible-enchants", replaceIncompatibleEnchants); - } - - public static boolean endermanShortHeight = false; diff --git a/patches/server/0149-Configurable-sponge-absorption.patch b/patches/server/0149-Configurable-sponge-absorption.patch deleted file mode 100644 index 3c506fc31..000000000 --- a/patches/server/0149-Configurable-sponge-absorption.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Wed, 24 Mar 2021 20:30:37 -0400 -Subject: [PATCH] Configurable sponge absorption - -Allows the total area and radius of water blocks the sponge can absorb to be changed. - -Co-authored by: granny - -diff --git a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java -index 902825ec9ea05f4418b45f56a008d73f217bd178..a676ccfa6b02e8986df6f6a2e04cbb06b3edd0ff 100644 ---- a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java -@@ -58,7 +58,7 @@ public class SpongeBlock extends Block { - - private boolean removeWaterBreadthFirstSearch(Level world, BlockPos pos) { - BlockStateListPopulator blockList = new BlockStateListPopulator(world); // CraftBukkit - Use BlockStateListPopulator -- BlockPos.breadthFirstTraversal(pos, 6, 65, (blockposition1, consumer) -> { -+ BlockPos.breadthFirstTraversal(pos, world.purpurConfig.spongeAbsorptionRadius, world.purpurConfig.spongeAbsorptionArea, (blockposition1, consumer) -> { // Purpur - Direction[] aenumdirection = SpongeBlock.ALL_DIRECTIONS; - int i = aenumdirection.length; - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3464f0c8d019c4675c2df7c83e0a77cb3eec16e0..d7cfb2ab82953799d0ff13fcdcb115ca2fa20450 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -630,6 +630,13 @@ public class PurpurWorldConfig { - spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); - } - -+ public int spongeAbsorptionArea = 65; -+ public int spongeAbsorptionRadius = 6; -+ private void spongeSettings() { -+ spongeAbsorptionArea = getInt("blocks.sponge.absorption.area", spongeAbsorptionArea); -+ spongeAbsorptionRadius = getInt("blocks.sponge.absorption.radius", spongeAbsorptionRadius); -+ } -+ - public boolean turtleEggsBreakFromExpOrbs = false; - public boolean turtleEggsBreakFromItems = false; - public boolean turtleEggsBreakFromMinecarts = false; diff --git a/patches/server/0150-Projectile-offset-config.patch b/patches/server/0150-Projectile-offset-config.patch deleted file mode 100644 index bf73e8d3c..000000000 --- a/patches/server/0150-Projectile-offset-config.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: YouHaveTrouble -Date: Thu, 25 Mar 2021 01:56:38 +0100 -Subject: [PATCH] Projectile offset config - - -diff --git a/src/main/java/net/minecraft/world/item/BowItem.java b/src/main/java/net/minecraft/world/item/BowItem.java -index abe6da2d70e8080461f70014757c1e1b5878bbf7..8bca38ec152f9612298bf6b3e10e7e0566ec3b78 100644 ---- a/src/main/java/net/minecraft/world/item/BowItem.java -+++ b/src/main/java/net/minecraft/world/item/BowItem.java -@@ -31,7 +31,7 @@ public class BowItem extends ProjectileWeaponItem { - if (!((double)f < 0.1)) { - List list = draw(stack, itemStack, player); - if (!world.isClientSide() && !list.isEmpty()) { -- this.shoot(world, player, player.getUsedItemHand(), stack, list, f * 3.0F, 1.0F, f == 1.0F, null); -+ this.shoot(world, player, player.getUsedItemHand(), stack, list, f * 3.0F, (float) world.purpurConfig.bowProjectileOffset, f == 1.0F, null); // Purpur - } - - world.playSound( -diff --git a/src/main/java/net/minecraft/world/item/CrossbowItem.java b/src/main/java/net/minecraft/world/item/CrossbowItem.java -index d2bb5c84e1895f28afed03d1868a79338e4f3e58..78f124f5204e4af9318ca3eeced6b1e3353b210f 100644 ---- a/src/main/java/net/minecraft/world/item/CrossbowItem.java -+++ b/src/main/java/net/minecraft/world/item/CrossbowItem.java -@@ -60,7 +60,7 @@ public class CrossbowItem extends ProjectileWeaponItem { - ItemStack itemStack = user.getItemInHand(hand); - ChargedProjectiles chargedProjectiles = itemStack.get(DataComponents.CHARGED_PROJECTILES); - if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { -- this.performShooting(world, user, hand, itemStack, getShootingPower(chargedProjectiles), 1.0F, null); -+ this.performShooting(world, user, hand, itemStack, getShootingPower(chargedProjectiles), (float) world.purpurConfig.crossbowProjectileOffset, null); // Purpur - return InteractionResultHolder.consume(itemStack); - } else if (!user.getProjectile(itemStack).isEmpty()) { - this.startSoundPlayed = false; -diff --git a/src/main/java/net/minecraft/world/item/EggItem.java b/src/main/java/net/minecraft/world/item/EggItem.java -index 4ebd634cff286b10868e26eeb3ecf34abdcab22e..7dc811335caa46870d1d895899a1e6c21980382d 100644 ---- a/src/main/java/net/minecraft/world/item/EggItem.java -+++ b/src/main/java/net/minecraft/world/item/EggItem.java -@@ -27,7 +27,7 @@ public class EggItem extends Item implements ProjectileItem { - ThrownEgg entityegg = new ThrownEgg(world, user); - - entityegg.setItem(itemstack); -- entityegg.shootFromRotation(user, user.getXRot(), user.getYRot(), 0.0F, 1.5F, 1.0F); -+ entityegg.shootFromRotation(user, user.getXRot(), user.getYRot(), 0.0F, 1.5F, (float) world.purpurConfig.eggProjectileOffset); // Purpur - // Paper start - PlayerLaunchProjectileEvent - com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entityegg.getBukkitEntity()); - if (event.callEvent() && world.addFreshEntity(entityegg)) { -diff --git a/src/main/java/net/minecraft/world/item/EnderpearlItem.java b/src/main/java/net/minecraft/world/item/EnderpearlItem.java -index fc62754f93bd11a10c28b8b7b116e9fff70a5c7b..11b04455f09d8bfdf44499bb8359dc715c2daffd 100644 ---- a/src/main/java/net/minecraft/world/item/EnderpearlItem.java -+++ b/src/main/java/net/minecraft/world/item/EnderpearlItem.java -@@ -24,7 +24,7 @@ public class EnderpearlItem extends Item { - ThrownEnderpearl entityenderpearl = new ThrownEnderpearl(world, user); - - entityenderpearl.setItem(itemstack); -- entityenderpearl.shootFromRotation(user, user.getXRot(), user.getYRot(), 0.0F, 1.5F, 1.0F); -+ entityenderpearl.shootFromRotation(user, user.getXRot(), user.getYRot(), 0.0F, 1.5F, (float) world.purpurConfig.enderPearlProjectileOffset); // Purpur - // Paper start - PlayerLaunchProjectileEvent - com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entityenderpearl.getBukkitEntity()); - if (event.callEvent() && world.addFreshEntity(entityenderpearl)) { -diff --git a/src/main/java/net/minecraft/world/item/SnowballItem.java b/src/main/java/net/minecraft/world/item/SnowballItem.java -index 32b170551a2f5bdc88d29f4d03750bfe3974e71b..a41fb0dd26af367fc2470a7913a84d864bc505f7 100644 ---- a/src/main/java/net/minecraft/world/item/SnowballItem.java -+++ b/src/main/java/net/minecraft/world/item/SnowballItem.java -@@ -28,7 +28,7 @@ public class SnowballItem extends Item implements ProjectileItem { - Snowball entitysnowball = new Snowball(world, user); - - entitysnowball.setItem(itemstack); -- entitysnowball.shootFromRotation(user, user.getXRot(), user.getYRot(), 0.0F, 1.5F, 1.0F); -+ entitysnowball.shootFromRotation(user, user.getXRot(), user.getYRot(), 0.0F, 1.5F, (float) world.purpurConfig.snowballProjectileOffset); // Purpur - // Paper start - PlayerLaunchProjectileEvent - com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitysnowball.getBukkitEntity()); - if (event.callEvent() && world.addFreshEntity(entitysnowball)) { -diff --git a/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java b/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java -index 369955746f4b51f69fa01103e3771dd74fc6c8f0..e6edd3a0fa2578900cdbe8bd588219dc3fd3af5f 100644 ---- a/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java -+++ b/src/main/java/net/minecraft/world/item/ThrowablePotionItem.java -@@ -21,7 +21,7 @@ public class ThrowablePotionItem extends PotionItem implements ProjectileItem { - if (!world.isClientSide) { - ThrownPotion thrownPotion = new ThrownPotion(world, user); - thrownPotion.setItem(itemStack); -- thrownPotion.shootFromRotation(user, user.getXRot(), user.getYRot(), -20.0F, 0.5F, 1.0F); -+ thrownPotion.shootFromRotation(user, user.getXRot(), user.getYRot(), -20.0F, 0.5F, (float) world.purpurConfig.throwablePotionProjectileOffset); // Purpur - // Paper start - PlayerLaunchProjectileEvent - com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) user.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) thrownPotion.getBukkitEntity()); - if (event.callEvent() && world.addFreshEntity(thrownPotion)) { -diff --git a/src/main/java/net/minecraft/world/item/TridentItem.java b/src/main/java/net/minecraft/world/item/TridentItem.java -index b094f4ec513194e10442156d8f7f2205da2384ac..85dc79b9b969fa0cbf6964cb26bac139fa55710a 100644 ---- a/src/main/java/net/minecraft/world/item/TridentItem.java -+++ b/src/main/java/net/minecraft/world/item/TridentItem.java -@@ -76,7 +76,7 @@ public class TridentItem extends Item implements ProjectileItem { - if (k == 0) { - ThrownTrident entitythrowntrident = new ThrownTrident(world, entityhuman, stack); - -- entitythrowntrident.shootFromRotation(entityhuman, entityhuman.getXRot(), entityhuman.getYRot(), 0.0F, 2.5F + (float) k * 0.5F, 1.0F); -+ entitythrowntrident.shootFromRotation(entityhuman, entityhuman.getXRot(), entityhuman.getYRot(), 0.0F, 2.5F + (float) k * 0.5F, (float) world.purpurConfig.tridentProjectileOffset); // Purpur - if (entityhuman.hasInfiniteMaterials()) { - entitythrowntrident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index d7cfb2ab82953799d0ff13fcdcb115ca2fa20450..3550147e9c80964dc1bf4007e4280de4a3b39d78 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -455,6 +455,23 @@ public class PurpurWorldConfig { - //} - } - -+ public double bowProjectileOffset = 1.0D; -+ public double crossbowProjectileOffset = 1.0D; -+ public double eggProjectileOffset = 1.0D; -+ public double enderPearlProjectileOffset = 1.0D; -+ public double throwablePotionProjectileOffset = 1.0D; -+ public double tridentProjectileOffset = 1.0D; -+ public double snowballProjectileOffset = 1.0D; -+ private void projectileOffsetSettings() { -+ bowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.bow", bowProjectileOffset); -+ crossbowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.crossbow", crossbowProjectileOffset); -+ eggProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.egg", eggProjectileOffset); -+ enderPearlProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.ender-pearl", enderPearlProjectileOffset); -+ throwablePotionProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.throwable-potion", throwablePotionProjectileOffset); -+ tridentProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.trident", tridentProjectileOffset); -+ snowballProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.snowball", snowballProjectileOffset); -+ } -+ - public int snowballDamage = -1; - private void snowballSettings() { - snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); diff --git a/patches/server/0151-Config-for-powered-rail-activation-distance.patch b/patches/server/0151-Config-for-powered-rail-activation-distance.patch deleted file mode 100644 index a92753919..000000000 --- a/patches/server/0151-Config-for-powered-rail-activation-distance.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Thu, 25 Mar 2021 18:10:03 -0400 -Subject: [PATCH] Config for powered rail activation distance - - -diff --git a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java -index 9603d8c84ff483030dc08e82d3579b89e5c1f6e9..8fc65c32a3c6e6842a76b36f45e1b1c23abbc480 100644 ---- a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java -@@ -30,7 +30,7 @@ public class PoweredRailBlock extends BaseRailBlock { - } - - protected boolean findPoweredRailSignal(Level world, BlockPos pos, BlockState state, boolean flag, int distance) { -- if (distance >= 8) { -+ if (distance >= world.purpurConfig.railActivationRange) { // Purpur - return false; - } else { - int j = pos.getX(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3550147e9c80964dc1bf4007e4280de4a3b39d78..57ac8480bc6bb324366bbdd30718eb5df6a7d69b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -616,6 +616,11 @@ public class PurpurWorldConfig { - powderSnowBypassMobGriefing = getBoolean("blocks.powder_snow.bypass-mob-griefing", powderSnowBypassMobGriefing); - } - -+ public int railActivationRange = 8; -+ private void railSettings() { -+ railActivationRange = getInt("blocks.powered-rail.activation-range", railActivationRange); -+ } -+ - public boolean respawnAnchorExplode = true; - public double respawnAnchorExplosionPower = 5.0D; - public boolean respawnAnchorExplosionFire = true; diff --git a/patches/server/0152-Piglin-portal-spawn-modifier.patch b/patches/server/0152-Piglin-portal-spawn-modifier.patch deleted file mode 100644 index 1ef7cd6e3..000000000 --- a/patches/server/0152-Piglin-portal-spawn-modifier.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 13 Apr 2021 11:19:35 -0500 -Subject: [PATCH] Piglin portal spawn modifier - -Allows changing the modifier for the piglin spawn chance from a portal block -based on the world difficulty. - -For example, with the default vanilla value of 2000 there is a 2 out of 2000 chance -for a piglin to spawn in a portal block each tick in normal mode. - -Equation: random.nextInt(modifier) < difficulty - -Difficulties: -0 - peaceful -1 - easy -2 - normal -3 - hard - -diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -index 67060b7446535fc352d221d9fe3928d1d6ffcf54..8d5e841d8cc69bf09a9f1b6248633a72ce5fe1d7 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -@@ -60,7 +60,7 @@ public class NetherPortalBlock extends Block { - - @Override - protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { -- if (world.spigotConfig.enableZombiePigmenPortalSpawns && world.dimensionType().natural() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && random.nextInt(2000) < world.getDifficulty().getId()) { // Spigot -+ if (world.spigotConfig.enableZombiePigmenPortalSpawns && world.dimensionType().natural() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && random.nextInt(world.purpurConfig.piglinPortalSpawnModifier) < world.getDifficulty().getId()) { // Spigot // Purpur - while (world.getBlockState(pos).is((Block) this)) { - pos = pos.below(); - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 57ac8480bc6bb324366bbdd30718eb5df6a7d69b..518973f15f10d68039675dfcedfbeb5d2324a989 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1648,6 +1648,7 @@ public class PurpurWorldConfig { - public double piglinMaxHealth = 16.0D; - public boolean piglinBypassMobGriefing = false; - public boolean piglinTakeDamageFromWater = false; -+ public int piglinPortalSpawnModifier = 2000; - private void piglinSettings() { - piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); - piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); -@@ -1660,6 +1661,7 @@ public class PurpurWorldConfig { - piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth); - piglinBypassMobGriefing = getBoolean("mobs.piglin.bypass-mob-griefing", piglinBypassMobGriefing); - piglinTakeDamageFromWater = getBoolean("mobs.piglin.takes-damage-from-water", piglinTakeDamageFromWater); -+ piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier); - } - - public boolean piglinBruteRidable = false; diff --git a/patches/server/0153-Config-to-change-max-number-of-bees.patch b/patches/server/0153-Config-to-change-max-number-of-bees.patch deleted file mode 100644 index 2a7554450..000000000 --- a/patches/server/0153-Config-to-change-max-number-of-bees.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Thu, 29 Apr 2021 19:37:48 +0200 -Subject: [PATCH] Config to change max number of bees - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -index 7b263fab4f0014400b3b8e7e33db32f9a125f6ba..f52823146944d333f2d050e90261b570ba66f5dd 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -59,7 +59,7 @@ public class BeehiveBlockEntity extends BlockEntity { - private final List stored = Lists.newArrayList(); - @Nullable - public BlockPos savedFlowerPos; -- public int maxBees = 3; // CraftBukkit - allow setting max amount of bees a hive can hold -+ public int maxBees = org.purpurmc.purpur.PurpurConfig.beeInsideBeeHive; // CraftBukkit - allow setting max amount of bees a hive can hold // Purpur - - public BeehiveBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.BEEHIVE, pos, state); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 25b0eeb09f20601e8517f3dc413a72a3b05ac983..80dfed685a84c15d8e667272e0ec91e0f1349296 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -250,6 +250,7 @@ public class PurpurConfig { - public static boolean enderChestSixRows = false; - public static boolean enderChestPermissionRows = false; - public static boolean cryingObsidianValidForPortalFrame = false; -+ public static int beeInsideBeeHive = 3; - private static void blockSettings() { - if (version < 3) { - boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); -@@ -281,6 +282,7 @@ public class PurpurConfig { - org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); - enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); - cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame); -+ beeInsideBeeHive = getInt("settings.blocks.beehive.max-bees-inside", beeInsideBeeHive); - } - - public static boolean allowInfinityMending = false; diff --git a/patches/server/0154-Config-for-wither-explosion-radius.patch b/patches/server/0154-Config-for-wither-explosion-radius.patch deleted file mode 100644 index 6b368ede8..000000000 --- a/patches/server/0154-Config-for-wither-explosion-radius.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Thu, 29 Apr 2021 14:39:07 -0400 -Subject: [PATCH] Config for wither explosion radius - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -index c753f715710ec4bb8337e035ac5a4c11371a84a0..a60d7f7baab005afc532ecec7aa22c53db4f51e0 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java -@@ -99,7 +99,7 @@ public class WitherSkull extends AbstractHurtingProjectile { - if (!this.level().isClientSide) { - // CraftBukkit start - // this.level().explode(this, this.getX(), this.getY(), this.getZ(), 1.0F, false, World.a.MOB); -- ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 1.0F, false); -+ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), this.level().purpurConfig.witherExplosionRadius, false); // Purpur - this.level().getCraftServer().getPluginManager().callEvent(event); - - if (!event.isCancelled()) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 518973f15f10d68039675dfcedfbeb5d2324a989..3a298515545972bb06a2f214aa35fb579bbac3de 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2291,6 +2291,7 @@ public class PurpurWorldConfig { - public boolean witherBypassMobGriefing = false; - public boolean witherTakeDamageFromWater = false; - public boolean witherCanRideVehicles = false; -+ public float witherExplosionRadius = 1.0F; - private void witherSettings() { - witherRidable = getBoolean("mobs.wither.ridable", witherRidable); - witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); -@@ -2311,6 +2312,7 @@ public class PurpurWorldConfig { - witherBypassMobGriefing = getBoolean("mobs.wither.bypass-mob-griefing", witherBypassMobGriefing); - witherTakeDamageFromWater = getBoolean("mobs.wither.takes-damage-from-water", witherTakeDamageFromWater); - witherCanRideVehicles = getBoolean("mobs.wither.can-ride-vehicles", witherCanRideVehicles); -+ witherExplosionRadius = (float) getDouble("mobs.wither.explosion-radius", witherExplosionRadius); - } - - public boolean witherSkeletonRidable = false; diff --git a/patches/server/0155-Gamemode-extra-permissions.patch b/patches/server/0155-Gamemode-extra-permissions.patch deleted file mode 100644 index 8c95cf26c..000000000 --- a/patches/server/0155-Gamemode-extra-permissions.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 30 Apr 2021 13:39:39 -0500 -Subject: [PATCH] Gamemode extra permissions - - -diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index edb94e5601acc38994dac20a167b145de778d426..7475aaac2673729091eabc741c8ebb561aeec8f1 100644 ---- a/src/main/java/net/minecraft/commands/CommandSourceStack.java -+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java -@@ -230,6 +230,19 @@ public class CommandSourceStack implements ExecutionCommandSource").replacement(bukkitPermission).build()))); -+ } -+ return false; -+ } -+ // Purpur end -+ - public Vec3 getPosition() { - return this.worldPosition; - } -diff --git a/src/main/java/net/minecraft/server/commands/GameModeCommand.java b/src/main/java/net/minecraft/server/commands/GameModeCommand.java -index d1da3600dc07107309b20ebe6e7c0c4da0e8de76..244b4719c689f153fa36381a60acc280bb0bd9b3 100644 ---- a/src/main/java/net/minecraft/server/commands/GameModeCommand.java -+++ b/src/main/java/net/minecraft/server/commands/GameModeCommand.java -@@ -57,6 +57,18 @@ public class GameModeCommand { - } - - private static int setMode(CommandContext context, Collection targets, GameType gameMode) { -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.commandGamemodeRequiresPermission) { -+ String gamemode = gameMode.getName(); -+ CommandSourceStack sender = context.getSource(); -+ if (!sender.testPermission(2, "minecraft.command.gamemode." + gamemode)) { -+ return 0; -+ } -+ if (sender.getEntity() instanceof ServerPlayer player && (targets.size() > 1 || !targets.contains(player)) && !sender.testPermission(2, "minecraft.command.gamemode." + gamemode + ".other")) { -+ return 0; -+ } -+ } -+ // Purpur end - int i = 0; - - for (ServerPlayer serverPlayer : targets) { -diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java -index 52649f82351ab4f675c3cc3cd6640956b0f76b91..eb51c88c7a0658190d3a8bfd5d18dca79d85fba0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java -@@ -23,7 +23,15 @@ public final class CommandPermissions { - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "kick", "Allows the user to kick players", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "stop", "Allows the user to stop the server", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "list", "Allows the user to list all online players", PermissionDefault.OP, commands); -- DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "gamemode", "Allows the user to change the gamemode of another player", PermissionDefault.OP, commands); -+ // Purpur start -+ Permission gamemodeVanilla = DefaultPermissions.registerPermission(PREFIX + "gamemode", "Allows the user to change the gamemode", PermissionDefault.OP, commands); -+ for (net.minecraft.world.level.GameType gametype : net.minecraft.world.level.GameType.values()) { -+ Permission gamemodeSelf = DefaultPermissions.registerPermission(PREFIX + "gamemode." + gametype.getName(), "Allows the user to set " + gametype.getName() + " gamemode for self", PermissionDefault.OP); -+ Permission gamemodeOther = DefaultPermissions.registerPermission(PREFIX + "gamemode." + gametype.getName() + ".other", "Allows the user to set " + gametype.getName() + " gamemode for other players", PermissionDefault.OP); -+ gamemodeSelf.addParent(gamemodeOther, true); -+ gamemodeVanilla.addParent(gamemodeSelf, true); -+ } -+ // Purpur end - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "experience", "Allows the user to give themselves or others arbitrary values of experience", PermissionDefault.OP, commands); // Paper - wrong permission; redirects are de-redirected and the root literal name is used, so xp -> experience - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "defaultgamemode", "Allows the user to change the default gamemode of the server", PermissionDefault.OP, commands); - DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "seed", "Allows the user to view the seed of the world", PermissionDefault.OP, commands); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 80dfed685a84c15d8e667272e0ec91e0f1349296..8a28fc51baa9ff014d50acc91c05dcd1975b6081 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -233,6 +233,7 @@ public class PurpurConfig { - public static String commandTPSBarTextColorMedium = ""; - public static String commandTPSBarTextColorLow = ""; - public static int commandTPSBarTickInterval = 20; -+ public static boolean commandGamemodeRequiresPermission = false; - private static void commandSettings() { - commandTPSBarTitle = getString("settings.command.tpsbar.title", commandTPSBarTitle); - commandTPSBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.tpsbar.overlay", commandTPSBarProgressOverlay.name())); -@@ -244,6 +245,7 @@ public class PurpurConfig { - commandTPSBarTextColorMedium = getString("settings.command.tpsbar.text-color.medium", commandTPSBarTextColorMedium); - commandTPSBarTextColorLow = getString("settings.command.tpsbar.text-color.low", commandTPSBarTextColorLow); - commandTPSBarTickInterval = getInt("settings.command.tpsbar.tick-interval", commandTPSBarTickInterval); -+ commandGamemodeRequiresPermission = getBoolean("settings.command.gamemode.requires-specific-permission", commandGamemodeRequiresPermission); - } - - public static int barrelRows = 3; diff --git a/patches/server/0156-Configurable-piston-push-limit.patch b/patches/server/0156-Configurable-piston-push-limit.patch deleted file mode 100644 index 4b3ade3fc..000000000 --- a/patches/server/0156-Configurable-piston-push-limit.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Sun, 2 May 2021 23:14:54 +0200 -Subject: [PATCH] Configurable piston push limit - - -diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java b/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java -index 205e223c356634bd6bc6bd58c6f0b7fda61a6f5f..bea05cb928d540a2f19b51bb7352d032b2dd69cd 100644 ---- a/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java -+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonStructureResolver.java -@@ -81,7 +81,7 @@ public class PistonStructureResolver { - return true; - } else { - int i = 1; -- if (i + this.toPush.size() > 12) { -+ if (i + this.toPush.size() > this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - return false; - } else { - while (isSticky(blockState)) { -@@ -95,7 +95,7 @@ public class PistonStructureResolver { - break; - } - -- if (++i + this.toPush.size() > 12) { -+ if (++i + this.toPush.size() > this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - return false; - } - } -@@ -140,7 +140,7 @@ public class PistonStructureResolver { - return true; - } - -- if (this.toPush.size() >= 12) { -+ if (this.toPush.size() >= this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - return false; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 3a298515545972bb06a2f214aa35fb579bbac3de..046c11b359125851d48f97505b0a823f01635cff 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -611,6 +611,11 @@ public class PurpurWorldConfig { - lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether); - } - -+ public int pistonBlockPushLimit = 12; -+ private void pistonSettings() { -+ pistonBlockPushLimit = getInt("blocks.piston.block-push-limit", pistonBlockPushLimit); -+ } -+ - public boolean powderSnowBypassMobGriefing = false; - private void powderSnowSettings() { - powderSnowBypassMobGriefing = getBoolean("blocks.powder_snow.bypass-mob-griefing", powderSnowBypassMobGriefing); diff --git a/patches/server/0157-Configurable-broadcast-settings.patch b/patches/server/0157-Configurable-broadcast-settings.patch deleted file mode 100644 index 84652faba..000000000 --- a/patches/server/0157-Configurable-broadcast-settings.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Mon, 3 May 2021 01:33:14 +0200 -Subject: [PATCH] Configurable broadcast settings - - -diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java -index 94893039363b5fe2d7d0622d0592bce2c867b1c3..ef520d1dd00ae9473c1f34e2df4d8b064fe4d6ea 100644 ---- a/src/main/java/net/minecraft/server/PlayerAdvancements.java -+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java -@@ -250,6 +250,7 @@ public class PlayerAdvancements { - advancement.value().display().ifPresent((advancementdisplay) -> { - // Paper start - Add Adventure message to PlayerAdvancementDoneEvent - if (event.message() != null && this.player.level().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) { -+ if (org.purpurmc.purpur.PurpurConfig.advancementOnlyBroadcastToAffectedPlayer) this.player.sendMessage(message); else // Purpur - this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false); - // Paper end - } -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index c9458551b1da419f484e9dce6b3fba8d79c2de79..2b10087cf34be4c36d8596d0263d68476bb1a521 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1089,6 +1089,7 @@ public class ServerPlayer extends Player { - })); - PlayerTeam scoreboardteam = this.getTeam(); - -+ if (org.purpurmc.purpur.PurpurConfig.deathMessageOnlyBroadcastToAffectedPlayer) this.sendSystemMessage(ichatbasecomponent); else // Purpur - if (scoreboardteam != null && scoreboardteam.getDeathMessageVisibility() != Team.Visibility.ALWAYS) { - if (scoreboardteam.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) { - this.server.getPlayerList().broadcastSystemToTeam(this, ichatbasecomponent); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 8a28fc51baa9ff014d50acc91c05dcd1975b6081..608acf6a75062fd6ac663a89b8a828fee7e6a773 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -203,6 +203,18 @@ public class PurpurConfig { - deathMsgRunWithScissors = getString("settings.messages.death-message.run-with-scissors", deathMsgRunWithScissors); - } - -+ public static boolean advancementOnlyBroadcastToAffectedPlayer = false; -+ public static boolean deathMessageOnlyBroadcastToAffectedPlayer = false; -+ private static void broadcastSettings() { -+ if (version < 13) { -+ boolean oldValue = getBoolean("settings.advancement.only-broadcast-to-affected-player", false); -+ set("settings.broadcasts.advancement.only-broadcast-to-affected-player", oldValue); -+ set("settings.advancement.only-broadcast-to-affected-player", null); -+ } -+ advancementOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.advancement.only-broadcast-to-affected-player", advancementOnlyBroadcastToAffectedPlayer); -+ deathMessageOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.death.only-broadcast-to-affected-player", deathMessageOnlyBroadcastToAffectedPlayer); -+ } -+ - public static String serverModName = "Purpur"; - private static void serverModName() { - serverModName = getString("settings.server-mod-name", serverModName); diff --git a/patches/server/0158-Configurable-mob-blindness.patch b/patches/server/0158-Configurable-mob-blindness.patch deleted file mode 100644 index b8a5ec65c..000000000 --- a/patches/server/0158-Configurable-mob-blindness.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 11 May 2021 21:00:53 -0400 -Subject: [PATCH] Configurable mob blindness - -Ported from https://github.com/raltsmc/mobblindness - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index aca2bd27da4d5bc754d7e98e45eb468170d17408..ce0d043f8839bb6b7fa2f6e1e721a26ffe33f77c 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1067,6 +1067,17 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL) || entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD) || entitytypes == EntityType.PIGLIN && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.PIGLIN_BRUTE && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) { - d0 *= 0.5D; - } -+ -+ // Purpur start -+ if (entity instanceof LivingEntity entityliving) { -+ if (entityliving.hasEffect(MobEffects.BLINDNESS)) { -+ int amplifier = entityliving.getEffect(MobEffects.BLINDNESS).getAmplifier(); -+ for (int i = 0; i < amplifier; i++) { -+ d0 *= this.level().purpurConfig.mobsBlindnessMultiplier; -+ } -+ } -+ } -+ // Purpur end - } - - return d0; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 046c11b359125851d48f97505b0a823f01635cff..bc6d8925d1124a138af8918146764ed2bc7b9f27 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -132,6 +132,7 @@ public class PurpurWorldConfig { - public boolean persistentDroppableEntityDisplayNames = true; - public boolean projectilesBypassMobGriefing = false; - public boolean tickFluids = true; -+ public double mobsBlindnessMultiplier = 1; - public double tridentLoyaltyVoidReturnHeight = 0.0D; - public double voidDamageHeight = -64.0D; - public double voidDamageDealt = 4.0D; -@@ -152,6 +153,7 @@ public class PurpurWorldConfig { - persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); - projectilesBypassMobGriefing = getBoolean("gameplay-mechanics.projectiles-bypass-mob-griefing", projectilesBypassMobGriefing); - tickFluids = getBoolean("gameplay-mechanics.tick-fluids", tickFluids); -+ mobsBlindnessMultiplier = getDouble("gameplay-mechanics.entity-blindness-multiplier", mobsBlindnessMultiplier); - tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); - voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); - voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); diff --git a/patches/server/0159-Hide-hidden-players-from-entity-selector.patch b/patches/server/0159-Hide-hidden-players-from-entity-selector.patch deleted file mode 100644 index a013b2ecc..000000000 --- a/patches/server/0159-Hide-hidden-players-from-entity-selector.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 13 May 2021 16:18:29 -0500 -Subject: [PATCH] Hide hidden players from entity selector - - -diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java -index 676a1499747b071515479130875157263d3a8352..fc1bba350030c076405711716e9830f8ae7f3953 100644 ---- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java -+++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java -@@ -200,10 +200,10 @@ public class EntitySelector { - - if (this.playerName != null) { - entityplayer = source.getServer().getPlayerList().getPlayerByName(this.playerName); -- return (List) (entityplayer == null ? Collections.emptyList() : Lists.newArrayList(new ServerPlayer[]{entityplayer})); -+ return entityplayer == null || !canSee(source, entityplayer) ? Collections.emptyList() : Lists.newArrayList(entityplayer); // Purpur - } else if (this.entityUUID != null) { - entityplayer = source.getServer().getPlayerList().getPlayer(this.entityUUID); -- return (List) (entityplayer == null ? Collections.emptyList() : Lists.newArrayList(new ServerPlayer[]{entityplayer})); -+ return entityplayer == null || !canSee(source, entityplayer) ? Collections.emptyList() : Lists.newArrayList(entityplayer); // Purpur - } else { - Vec3 vec3d = (Vec3) this.position.apply(source.getPosition()); - Predicate predicate = this.getPredicate(vec3d); -@@ -215,7 +215,7 @@ public class EntitySelector { - ServerPlayer entityplayer1 = (ServerPlayer) entity; - - if (predicate.test(entityplayer1)) { -- return Lists.newArrayList(new ServerPlayer[]{entityplayer1}); -+ return !canSee(source, entityplayer1) ? Collections.emptyList() : Lists.newArrayList(entityplayer1); // Purpur - } - } - -@@ -226,6 +226,7 @@ public class EntitySelector { - - if (this.isWorldLimited()) { - object = source.getLevel().getPlayers(predicate, i); -+ ((List) object).removeIf(entityplayer3 -> !canSee(source, (ServerPlayer) entityplayer3)); // Purpur - } else { - object = Lists.newArrayList(); - Iterator iterator = source.getServer().getPlayerList().getPlayers().iterator(); -@@ -233,7 +234,7 @@ public class EntitySelector { - while (iterator.hasNext()) { - ServerPlayer entityplayer2 = (ServerPlayer) iterator.next(); - -- if (predicate.test(entityplayer2)) { -+ if (predicate.test(entityplayer2) && canSee(source, entityplayer2)) { // Purpur - ((List) object).add(entityplayer2); - if (((List) object).size() >= i) { - return (List) object; -@@ -278,4 +279,10 @@ public class EntitySelector { - public static Component joinNames(List entities) { - return ComponentUtils.formatList(entities, Entity::getDisplayName); - } -+ -+ // Purpur start -+ private boolean canSee(CommandSourceStack sender, ServerPlayer target) { -+ return !org.purpurmc.purpur.PurpurConfig.hideHiddenPlayersFromEntitySelector || !(sender.getEntity() instanceof ServerPlayer player) || player.getBukkitEntity().canSee(target.getBukkitEntity()); -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 608acf6a75062fd6ac663a89b8a828fee7e6a773..6b94bc901a6394434da3fd7c4737b87916c69908 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -246,6 +246,7 @@ public class PurpurConfig { - public static String commandTPSBarTextColorLow = ""; - public static int commandTPSBarTickInterval = 20; - public static boolean commandGamemodeRequiresPermission = false; -+ public static boolean hideHiddenPlayersFromEntitySelector = false; - private static void commandSettings() { - commandTPSBarTitle = getString("settings.command.tpsbar.title", commandTPSBarTitle); - commandTPSBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.tpsbar.overlay", commandTPSBarProgressOverlay.name())); -@@ -258,6 +259,7 @@ public class PurpurConfig { - commandTPSBarTextColorLow = getString("settings.command.tpsbar.text-color.low", commandTPSBarTextColorLow); - commandTPSBarTickInterval = getInt("settings.command.tpsbar.tick-interval", commandTPSBarTickInterval); - commandGamemodeRequiresPermission = getBoolean("settings.command.gamemode.requires-specific-permission", commandGamemodeRequiresPermission); -+ hideHiddenPlayersFromEntitySelector = getBoolean("settings.command.hide-hidden-players-from-entity-selector", hideHiddenPlayersFromEntitySelector); - } - - public static int barrelRows = 3; diff --git a/patches/server/0160-Config-for-health-to-impact-Creeper-explosion-radius.patch b/patches/server/0160-Config-for-health-to-impact-Creeper-explosion-radius.patch deleted file mode 100644 index 48baffaa1..000000000 --- a/patches/server/0160-Config-for-health-to-impact-Creeper-explosion-radius.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Thu, 29 Apr 2021 20:28:18 -0400 -Subject: [PATCH] Config for health to impact Creeper explosion radius - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index af6f2fd2f2f48b8057cfb0462a0e72a86a1f83e3..039ae2b694800e0bcd9844be85ad29a001ce52c0 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -370,9 +370,10 @@ public class Creeper extends Monster implements PowerableMob { - this.exploding = true; // Purpur - if (!this.level().isClientSide) { - float f = this.isPowered() ? 2.0F : 1.0F; -+ float multiplier = this.level().purpurConfig.creeperHealthRadius ? this.getHealth() / this.getMaxHealth() : 1; // Purpur - - // CraftBukkit start -- ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, this.explosionRadius * f, false); -+ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, (this.explosionRadius * f) * multiplier, false); // Purpur - if (!event.isCancelled()) { - // CraftBukkit end - this.dead = true; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index bc6d8925d1124a138af8918146764ed2bc7b9f27..77af32b0e98aaf49add6ca97ff00c6024bcc2cfd 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -929,6 +929,7 @@ public class PurpurWorldConfig { - public boolean creeperBypassMobGriefing = false; - public boolean creeperTakeDamageFromWater = false; - public boolean creeperExplodeWhenKilled = false; -+ public boolean creeperHealthRadius = false; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -944,6 +945,7 @@ public class PurpurWorldConfig { - creeperBypassMobGriefing = getBoolean("mobs.creeper.bypass-mob-griefing", creeperBypassMobGriefing); - creeperTakeDamageFromWater = getBoolean("mobs.creeper.takes-damage-from-water", creeperTakeDamageFromWater); - creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled); -+ creeperHealthRadius = getBoolean("mobs.creeper.health-impacts-explosion", creeperHealthRadius); - } - - public boolean dolphinRidable = false; diff --git a/patches/server/0161-Iron-golem-calm-anger-options.patch b/patches/server/0161-Iron-golem-calm-anger-options.patch deleted file mode 100644 index 3a31b700a..000000000 --- a/patches/server/0161-Iron-golem-calm-anger-options.patch +++ /dev/null @@ -1,145 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 13 May 2021 21:22:51 -0500 -Subject: [PATCH] Iron golem calm anger options - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -index 9c86d86a6d89585cfbdace89e66866f496da86cb..fa81b12fc38a20b8ec39155259fb75c18ff9f0ae 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -@@ -91,6 +91,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - @Override - protected void registerGoals() { - if (level().purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur -+ if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0D, true)); - this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9D, 32.0F)); -@@ -307,6 +308,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - - this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f1); - itemstack.consume(1, player); -+ if (this.level().purpurConfig.ironGolemHealCalm && isAngry() && getHealth() == getMaxHealth()) stopBeingAngry(); // Purpur - return InteractionResult.sidedSuccess(this.level().isClientSide); - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 77af32b0e98aaf49add6ca97ff00c6024bcc2cfd..0e8829422bd7239523c80048be1aa8c3a17480b1 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1387,6 +1387,8 @@ public class PurpurWorldConfig { - public boolean ironGolemCanSwim = false; - public double ironGolemMaxHealth = 100.0D; - public boolean ironGolemTakeDamageFromWater = false; -+ public boolean ironGolemPoppyCalm = false; -+ public boolean ironGolemHealCalm = false; - private void ironGolemSettings() { - ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); - ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); -@@ -1399,6 +1401,8 @@ public class PurpurWorldConfig { - } - ironGolemMaxHealth = getDouble("mobs.iron_golem.attributes.max_health", ironGolemMaxHealth); - ironGolemTakeDamageFromWater = getBoolean("mobs.iron_golem.takes-damage-from-water", ironGolemTakeDamageFromWater); -+ ironGolemPoppyCalm = getBoolean("mobs.iron_golem.poppy-calms-anger", ironGolemPoppyCalm); -+ ironGolemHealCalm = getBoolean("mobs.iron_golem.healing-calms-anger", ironGolemHealCalm); - } - - public boolean llamaRidable = false; -diff --git a/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java b/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9660716f4162a4441c6e1b0baddef8f5086566c5 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java -@@ -0,0 +1,91 @@ -+package org.purpurmc.purpur.entity.ai; -+ -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.ai.goal.Goal; -+import net.minecraft.world.entity.animal.IronGolem; -+import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.level.block.Blocks; -+ -+import java.util.EnumSet; -+import java.util.UUID; -+ -+public class ReceiveFlower extends Goal { -+ private final IronGolem irongolem; -+ private ServerPlayer target; -+ private int cooldown; -+ -+ public ReceiveFlower(IronGolem entity) { -+ this.irongolem = entity; -+ setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK)); -+ } -+ -+ @Override -+ public boolean canUse() { -+ if (this.irongolem.getOfferFlowerTick() > 0) { -+ return false; -+ } -+ if (!this.irongolem.isAngry()) { -+ return false; -+ } -+ UUID uuid = this.irongolem.getPersistentAngerTarget(); -+ if (uuid == null) { -+ return false; -+ } -+ Entity target = ((ServerLevel) this.irongolem.level()).getEntity(uuid); -+ if (!(target instanceof ServerPlayer player)) { -+ return false; -+ } -+ InteractionHand hand = getPoppyHand(player); -+ if (hand == null) { -+ return false; -+ } -+ removeFlower(player, hand); -+ this.target = player; -+ return true; -+ } -+ -+ @Override -+ public boolean canContinueToUse() { -+ return this.cooldown > 0; -+ } -+ -+ @Override -+ public void start() { -+ this.cooldown = 100; -+ this.irongolem.stopBeingAngry(); -+ this.irongolem.offerFlower(true); -+ } -+ -+ @Override -+ public void stop() { -+ this.irongolem.offerFlower(false); -+ this.target = null; -+ } -+ -+ @Override -+ public void tick() { -+ this.irongolem.getLookControl().setLookAt(this.target, 30.0F, 30.0F); -+ --this.cooldown; -+ } -+ -+ private InteractionHand getPoppyHand(ServerPlayer player) { -+ if (isPoppy(player.getMainHandItem())) { -+ return InteractionHand.MAIN_HAND; -+ } -+ if (isPoppy(player.getOffhandItem())) { -+ return InteractionHand.OFF_HAND; -+ } -+ return null; -+ } -+ -+ private void removeFlower(ServerPlayer player, InteractionHand hand) { -+ player.setItemInHand(hand, ItemStack.EMPTY); -+ } -+ -+ private boolean isPoppy(ItemStack item) { -+ return item.getItem() == Blocks.POPPY.asItem(); -+ } -+} diff --git a/patches/server/0162-Breedable-parrots.patch b/patches/server/0162-Breedable-parrots.patch deleted file mode 100644 index d017c922c..000000000 --- a/patches/server/0162-Breedable-parrots.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 13 May 2021 22:17:50 -0500 -Subject: [PATCH] Breedable parrots - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Parrot.java b/src/main/java/net/minecraft/world/entity/animal/Parrot.java -index 490d7f8ac402f50a2f2f90ca032169784a402c0f..65be3dd9bc6994cac828ed45b74a577b65b7118a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Parrot.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Parrot.java -@@ -221,6 +221,7 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { -@@ -365,13 +367,13 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder -Date: Fri, 14 May 2021 21:22:57 +0100 -Subject: [PATCH] Configurable powered rail boost modifier - - -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -index 97172e9c53c381d451111227feb4d1fa19d38ad8..e7a1ce585c9e552e6f9ce9acd26fdfe5c43e0b5d 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecart.java -@@ -673,7 +673,7 @@ public abstract class AbstractMinecart extends VehicleEntity { - if (d18 > 0.01D) { - double d20 = 0.06D; - -- this.setDeltaMovement(vec3d4.add(vec3d4.x / d18 * 0.06D, 0.0D, vec3d4.z / d18 * 0.06D)); -+ this.setDeltaMovement(vec3d4.add(vec3d4.x / d18 * this.level().purpurConfig.poweredRailBoostModifier, 0.0D, vec3d4.z / d18 * this.level().purpurConfig.poweredRailBoostModifier)); // Purpur - } else { - Vec3 vec3d5 = this.getDeltaMovement(); - double d21 = vec3d5.x; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 77f8952da7ee8476b685e6aef1f8e2441bca068e..c283a8aec6dfea3f9b84d47cf6abf568be2a73da 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -275,6 +275,7 @@ public class PurpurWorldConfig { - public boolean minecartControllableFallDamage = true; - public double minecartControllableBaseSpeed = 0.1D; - public Map minecartControllableBlockSpeeds = new HashMap<>(); -+ public double poweredRailBoostModifier = 0.06; - private void minecartSettings() { - if (PurpurConfig.version < 12) { - boolean oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.place-anywhere", minecartPlaceAnywhere); -@@ -327,6 +328,7 @@ public class PurpurWorldConfig { - set("gameplay-mechanics.minecart.controllable.block-speed.grass_block", 0.3D); - set("gameplay-mechanics.minecart.controllable.block-speed.stone", 0.5D); - } -+ poweredRailBoostModifier = getDouble("gameplay-mechanics.minecart.powered-rail.boost-modifier", poweredRailBoostModifier); - } - - public boolean catSpawning; diff --git a/patches/server/0164-Add-config-change-multiplier-critical-damage-value.patch b/patches/server/0164-Add-config-change-multiplier-critical-damage-value.patch deleted file mode 100644 index 885fc1f18..000000000 --- a/patches/server/0164-Add-config-change-multiplier-critical-damage-value.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Mon, 17 May 2021 02:40:13 +0200 -Subject: [PATCH] Add config change multiplier critical damage value - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 579a9c7d914015ef74c6147f2e17962a7aea2a78..bc994bbc4c7b66e6365739acb896aaa81fbcbd7e 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1332,7 +1332,7 @@ public abstract class Player extends LivingEntity { - - flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits - if (flag2) { -- f *= 1.5F; -+ f *= this.level().purpurConfig.playerCriticalDamageMultiplier; // Purpur - } - - f += f1; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index c283a8aec6dfea3f9b84d47cf6abf568be2a73da..a7d95013005c895676dbe8cc10f12dbcf689b29c 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -372,6 +372,7 @@ public class PurpurWorldConfig { - public boolean creativeOnePunch = false; - public boolean playerSleepNearMonsters = false; - public boolean playersSkipNight = true; -+ public double playerCriticalDamageMultiplier = 1.5D; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -391,6 +392,7 @@ public class PurpurWorldConfig { - creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); - playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters); - playersSkipNight = getBoolean("gameplay-mechanics.player.can-skip-night", playersSkipNight); -+ playerCriticalDamageMultiplier = getDouble("gameplay-mechanics.player.critical-damage-multiplier", playerCriticalDamageMultiplier); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0165-Option-to-disable-dragon-egg-teleporting.patch b/patches/server/0165-Option-to-disable-dragon-egg-teleporting.patch deleted file mode 100644 index 591f3c374..000000000 --- a/patches/server/0165-Option-to-disable-dragon-egg-teleporting.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 17 May 2021 04:46:23 -0500 -Subject: [PATCH] Option to disable dragon egg teleporting - - -diff --git a/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java b/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java -index fbe15cdd5b9bca2ab4b1e871abbbdbff49ade8a4..23d113842bf774bdc74e0dffcc97b642bc8684f1 100644 ---- a/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DragonEggBlock.java -@@ -48,8 +48,8 @@ public class DragonEggBlock extends FallingBlock { - } - - private void teleport(BlockState state, Level world, BlockPos pos) { -+ if (!world.purpurConfig.dragonEggTeleport) return; // Purpur - WorldBorder worldborder = world.getWorldBorder(); -- - for (int i = 0; i < 1000; ++i) { - BlockPos blockposition1 = pos.offset(world.random.nextInt(16) - world.random.nextInt(16), world.random.nextInt(8) - world.random.nextInt(8), world.random.nextInt(16) - world.random.nextInt(16)); - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index a7d95013005c895676dbe8cc10f12dbcf689b29c..9c9fea719a90e49147b6c2ae342a1437ea8b9be3 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -538,6 +538,11 @@ public class PurpurWorldConfig { - }); - } - -+ public boolean dragonEggTeleport = true; -+ private void dragonEggSettings() { -+ dragonEggTeleport = getBoolean("blocks.dragon_egg.teleport", dragonEggTeleport); -+ } -+ - public boolean baselessEndCrystalExplode = true; - public double baselessEndCrystalExplosionPower = 6.0D; - public boolean baselessEndCrystalExplosionFire = false; diff --git a/patches/server/0166-Config-for-unverified-username-message.patch b/patches/server/0166-Config-for-unverified-username-message.patch deleted file mode 100644 index ae1572f3d..000000000 --- a/patches/server/0166-Config-for-unverified-username-message.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Wed, 19 May 2021 15:33:43 -0400 -Subject: [PATCH] Config for unverified username message - - -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index b656741eb68adeb04bf995f1045902cb6bd5f2e7..3b4fadb37eafb2f7b0ce4d6b276d2fdaa8287521 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -315,7 +315,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!"); - ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(s1)); // Spigot - } else { -- ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username")); -+ ServerLoginPacketListenerImpl.this.disconnect(org.purpurmc.purpur.PurpurConfig.unverifiedUsername.equals("default") ? Component.translatable("multiplayer.disconnect.unverified_username") : io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.unverifiedUsername))); // Purpur - ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", s1); - } - } catch (AuthenticationUnavailableException authenticationunavailableexception) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 6b94bc901a6394434da3fd7c4737b87916c69908..1b2fdefed6b01719211b29119b6beb1baa77b497 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -184,6 +184,7 @@ public class PurpurConfig { - public static String pingCommandOutput = "%s's ping is %sms"; - public static String tpsbarCommandOutput = "Tpsbar toggled for "; - public static String dontRunWithScissors = "Don't run with scissors!"; -+ public static String unverifiedUsername = "default"; - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); - afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); -@@ -196,6 +197,7 @@ public class PurpurConfig { - pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); - tpsbarCommandOutput = getString("settings.messages.tpsbar-command-output", tpsbarCommandOutput); - dontRunWithScissors = getString("settings.messages.dont-run-with-scissors", dontRunWithScissors); -+ unverifiedUsername = getString("settings.messages.unverified-username", unverifiedUsername); - } - - public static String deathMsgRunWithScissors = " slipped and fell on their shears"; diff --git a/patches/server/0167-Make-anvil-cumulative-cost-configurable.patch b/patches/server/0167-Make-anvil-cumulative-cost-configurable.patch deleted file mode 100644 index 5f3b4e7da..000000000 --- a/patches/server/0167-Make-anvil-cumulative-cost-configurable.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Fri, 21 May 2021 16:58:45 +0200 -Subject: [PATCH] Make anvil cumulative cost configurable - - -diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -index 17067510990f575bf638f6a95ed0d964f6e94dc5..2747f04e657154362af55eef1dd50455e02af371 100644 ---- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java -@@ -391,7 +391,7 @@ public class AnvilMenu extends ItemCombinerMenu { - } - - public static int calculateIncreasedRepairCost(int cost) { -- return (int) Math.min((long) cost * 2L + 1L, 2147483647L); -+ return org.purpurmc.purpur.PurpurConfig.anvilCumulativeCost ? (int) Math.min((long) cost * 2L + 1L, 2147483647L) : 0; - } - - public boolean setItemName(String newItemName) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 1b2fdefed6b01719211b29119b6beb1baa77b497..b10e0de76f618c545294873038ce29ee0c486d24 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -269,6 +269,7 @@ public class PurpurConfig { - public static boolean enderChestPermissionRows = false; - public static boolean cryingObsidianValidForPortalFrame = false; - public static int beeInsideBeeHive = 3; -+ public static boolean anvilCumulativeCost = true; - private static void blockSettings() { - if (version < 3) { - boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); -@@ -301,6 +302,7 @@ public class PurpurConfig { - enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); - cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame); - beeInsideBeeHive = getInt("settings.blocks.beehive.max-bees-inside", beeInsideBeeHive); -+ anvilCumulativeCost = getBoolean("settings.blocks.anvil.cumulative-cost", anvilCumulativeCost); - } - - public static boolean allowInfinityMending = false; diff --git a/patches/server/0168-Bee-can-work-when-raining-or-at-night.patch b/patches/server/0168-Bee-can-work-when-raining-or-at-night.patch deleted file mode 100644 index e5f375fc3..000000000 --- a/patches/server/0168-Bee-can-work-when-raining-or-at-night.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Thu, 27 May 2021 06:46:30 +0200 -Subject: [PATCH] Bee can work when raining or at night - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 0978f519177ce2f0991402dafb9a22c5a8686168..91c013f7ab58f570d0ebe2773932fcdb49344b3c 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -395,7 +395,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - - boolean wantsToEnterHive() { - if (this.stayOutOfHiveCountdown <= 0 && !this.beePollinateGoal.isPollinating() && !this.hasStung() && this.getTarget() == null) { -- boolean flag = this.isTiredOfLookingForNectar() || this.level().isRaining() || this.level().isNight() || this.hasNectar(); -+ boolean flag = this.isTiredOfLookingForNectar() || (this.level().isRaining() && !this.level().purpurConfig.beeCanWorkInRain) || (this.level().isNight() && !this.level().purpurConfig.beeCanWorkAtNight) || this.hasNectar(); // Purpur - - return flag && !this.isHiveNearFire(); - } else { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -index f52823146944d333f2d050e90261b570ba66f5dd..d8efb00c325448d566c59418fe22268c6eb4cfce 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -212,7 +212,7 @@ public class BeehiveBlockEntity extends BlockEntity { - } - - private static boolean releaseOccupant(Level world, BlockPos blockposition, BlockState iblockdata, BeehiveBlockEntity.Occupant tileentitybeehive_c, @Nullable List list, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, @Nullable BlockPos blockposition1, boolean force) { -- if (!force && (world.isNight() || world.isRaining()) && tileentitybeehive_releasestatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) { -+ if (!force && ((world.isNight() && !world.purpurConfig.beeCanWorkAtNight) || (world.isRaining() && !world.purpurConfig.beeCanWorkInRain)) && tileentitybeehive_releasestatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) { // Purpur - // CraftBukkit end - return false; - } else { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 9c9fea719a90e49147b6c2ae342a1437ea8b9be3..b3d24e076aef331f26ed5035f2015680f4a5c732 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -765,6 +765,8 @@ public class PurpurWorldConfig { - public double beeMaxHealth = 10.0D; - public int beeBreedingTicks = 6000; - public boolean beeTakeDamageFromWater = false; -+ public boolean beeCanWorkAtNight = false; -+ public boolean beeCanWorkInRain = false; - private void beeSettings() { - beeRidable = getBoolean("mobs.bee.ridable", beeRidable); - beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); -@@ -778,6 +780,8 @@ public class PurpurWorldConfig { - beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth); - beeBreedingTicks = getInt("mobs.bee.breeding-delay-ticks", beeBreedingTicks); - beeTakeDamageFromWater = getBoolean("mobs.bee.takes-damage-from-water", beeTakeDamageFromWater); -+ beeCanWorkAtNight = getBoolean("mobs.bee.can-work-at-night", beeCanWorkAtNight); -+ beeCanWorkInRain = getBoolean("mobs.bee.can-work-in-rain", beeCanWorkInRain); - } - - public boolean blazeRidable = false; diff --git a/patches/server/0169-API-for-any-mob-to-burn-daylight.patch b/patches/server/0169-API-for-any-mob-to-burn-daylight.patch deleted file mode 100644 index c3a524598..000000000 --- a/patches/server/0169-API-for-any-mob-to-burn-daylight.patch +++ /dev/null @@ -1,382 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Tue, 25 May 2021 16:31:09 -0400 -Subject: [PATCH] API for any mob to burn daylight - -Co-authored by: Encode42 - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 5f19cc285efac25b56a29242b41c2823020f170e..2d1fc8734f440c284710c71abc6789e8185ec909 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -562,6 +562,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return true; - } - -+ // Purpur start - copied from Mob -+ public boolean isSunBurnTick() { -+ if (this.level().isDay() && !this.level().isClientSide) { -+ float f = this.getLightLevelDependentMagicValue(); -+ BlockPos blockposition = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ()); -+ boolean flag = this.isInWaterRainOrBubble() || this.isInPowderSnow || this.wasInPowderSnow; -+ -+ if (f > 0.5F && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && !flag && this.level().canSeeSky(blockposition)) { -+ return true; -+ } -+ } -+ -+ return false; -+ } -+ - public final boolean hardCollides() { - return this.hardCollides; - } -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index ce0d043f8839bb6b7fa2f6e1e721a26ffe33f77c..54a612dd2fcdf6972f7580fbd814f461df07b7f6 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -274,6 +274,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper - public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event - public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API -+ protected boolean shouldBurnInDay = false; public boolean shouldBurnInDay() { return this.shouldBurnInDay; } public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } // Purpur - - @Override - public float getBukkitYaw() { -@@ -842,6 +843,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> { - nbt.put("Brain", nbtbase); - }); -+ nbt.putBoolean("Purpur.ShouldBurnInDay", shouldBurnInDay); // Purpur - } - - @Override -@@ -929,6 +931,11 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.brain = this.makeBrain(new Dynamic(NbtOps.INSTANCE, nbt.get("Brain"))); - } - -+ // Purpur start -+ if (nbt.contains("Purpur.ShouldBurnInDay")) { -+ shouldBurnInDay = nbt.getBoolean("Purpur.ShouldBurnInDay"); -+ } -+ // Purpur end - } - - // CraftBukkit start -@@ -3573,6 +3580,27 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.hurt(this.damageSources().drown(), 1.0F); - } - -+ // Purpur start - copied from Zombie -+ if (this.isAlive()) { -+ boolean flag = this.shouldBurnInDay() && this.isSunBurnTick(); -+ if (flag) { -+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); -+ if (!itemstack.isEmpty()) { -+ if (itemstack.isDamageableItem()) { -+ itemstack.setDamageValue(itemstack.getDamageValue() + this.random.nextInt(2)); -+ if (itemstack.getDamageValue() >= itemstack.getMaxDamage()) { -+ this.broadcastBreakEvent(EquipmentSlot.HEAD); -+ this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY); -+ } -+ } -+ flag = false; -+ } -+ if (flag) { -+ this.igniteForSeconds(8); -+ } -+ } -+ } -+ // Purpur end - } - - public boolean isSensitiveToWater() { -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 77cf0d92212d11b9036f9f9cf23b23f71f1d590d..ee98efa69d67cd22eb5722cf68f3b7063e2595c8 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1881,17 +1881,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti - } - - public boolean isSunBurnTick() { -- if (this.level().isDay() && !this.level().isClientSide) { -- float f = this.getLightLevelDependentMagicValue(); -- BlockPos blockposition = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ()); -- boolean flag = this.isInWaterRainOrBubble() || this.isInPowderSnow || this.wasInPowderSnow; -- -- if (f > 0.5F && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && !flag && this.level().canSeeSky(blockposition)) { -- return true; -- } -- } -- -- return false; -+ return super.isSunBurnTick(); - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -index 8f71739a4b23bc53994f1cbff8500b6bad288a42..919767affe2ede755cf83398436fbf1581ad508f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -65,6 +65,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - protected AbstractSkeleton(EntityType type, Level world) { - super(type, world); - this.reassessWeaponGoal(); -+ this.setShouldBurnInDay(true); // Purpur - } - - @Override -@@ -95,35 +96,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - abstract SoundEvent getStepSound(); - - // Paper start - shouldBurnInDay API -- private boolean shouldBurnInDay = true; -+ // private boolean shouldBurnInDay = true; // Purpur - moved to LivingEntity - keep methods for ABI compatibility - public boolean shouldBurnInDay() { return shouldBurnInDay; } - public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } - // Paper end - shouldBurnInDay API - - @Override - public void aiStep() { -- boolean flag = shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API -- -- if (flag) { -- ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); -- -- if (!itemstack.isEmpty()) { -- if (itemstack.isDamageableItem()) { -- itemstack.setDamageValue(itemstack.getDamageValue() + this.random.nextInt(2)); -- if (itemstack.getDamageValue() >= itemstack.getMaxDamage()) { -- this.broadcastBreakEvent(EquipmentSlot.HEAD); -- this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY); -- } -- } -- -- flag = false; -- } -- -- if (flag) { -- this.igniteForSeconds(8); -- } -- } -- -+ // Purpur start - implemented in LivingEntity - super.aiStep(); - } - -@@ -238,7 +218,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - this.reassessWeaponGoal(); - // Paper start - shouldBurnInDay API - if (nbt.contains("Paper.ShouldBurnInDay")) { -- this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); -+ // this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); // Purpur - implemented in LivingEntity - } - // Paper end - shouldBurnInDay API - } -@@ -247,7 +227,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); -- nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); -+ // nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - implemented in LivingEntity - } - // Paper end - shouldBurnInDay API - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Husk.java b/src/main/java/net/minecraft/world/entity/monster/Husk.java -index cb96bd5769159e6c25968673ea07cd6d107cff46..440c90feeae3a55c98e2011ecb27c28d58f11e6e 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Husk.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Husk.java -@@ -20,6 +20,7 @@ public class Husk extends Zombie { - - public Husk(EntityType type, Level world) { - super(type, world); -+ this.setShouldBurnInDay(false); // Purpur - } - - // Purpur start -@@ -75,7 +76,7 @@ public class Husk extends Zombie { - - @Override - public boolean isSunSensitive() { -- return false; -+ return this.shouldBurnInDay; // Purpur - moved to LivingEntity - keep methods for ABI compatibility - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index c52d40eb33a16e428c016a902faeb62aea0fd727..bebc6f9f7e49e9dd34fa295d9ce3e8397feb280c 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -59,6 +59,7 @@ public class Phantom extends FlyingMob implements Enemy { - this.xpReward = 5; - this.moveControl = new Phantom.PhantomMoveControl(this); - this.lookControl = new Phantom.PhantomLookControl(this, this); -+ this.setShouldBurnInDay(true); // Purpur - } - - // Purpur start -@@ -247,15 +248,7 @@ public class Phantom extends FlyingMob implements Enemy { - - @Override - public void aiStep() { -- // Purpur start -- boolean burnFromDaylight = this.shouldBurnInDay && this.isSunBurnTick() && this.level().purpurConfig.phantomBurnInDaylight; -- boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight; -- if (this.isAlive() && (burnFromDaylight || burnFromLightSource)) { // Paper - shouldBurnInDay API -- // Purpur end -- if (getRider() == null || !this.isControllable()) // Purpur -- this.igniteForSeconds(8); -- } -- -+ // Purpur - moved down to shouldBurnInDay() - super.aiStep(); - } - -@@ -283,7 +276,7 @@ public class Phantom extends FlyingMob implements Enemy { - if (nbt.hasUUID("Paper.SpawningEntity")) { - this.spawningEntity = nbt.getUUID("Paper.SpawningEntity"); - } -- if (nbt.contains("Paper.ShouldBurnInDay")) { -+ if (false && nbt.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); - } - // Paper end -@@ -300,7 +293,7 @@ public class Phantom extends FlyingMob implements Enemy { - if (this.spawningEntity != null) { - nbt.putUUID("Paper.SpawningEntity", this.spawningEntity); - } -- nbt.putBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); -+ // nbt.putBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); // Purpur - implemented in LivingEntity - // Paper end - } - -@@ -356,8 +349,15 @@ public class Phantom extends FlyingMob implements Enemy { - return this.spawningEntity; - } - public void setSpawningEntity(java.util.UUID entity) { this.spawningEntity = entity; } -- private boolean shouldBurnInDay = true; -- public boolean shouldBurnInDay() { return shouldBurnInDay; } -+ -+ // private boolean shouldBurnInDay = true; // Purpur - moved to LivingEntity - keep methods for ABI compatibility -+ // Purpur start -+ public boolean shouldBurnInDay() { -+ boolean burnFromDaylight = this.shouldBurnInDay && this.level().purpurConfig.phantomBurnInDaylight; -+ boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight; -+ return burnFromDaylight || burnFromLightSource; -+ } -+ // Purpur End - public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } - // Paper end - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index de7a74f1e5181373da8dcc639245f35f77f4f09b..53f7659aed2378b36f1923a0208c7f86048eb85b 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -93,11 +93,12 @@ public class Zombie extends Monster { - private int inWaterTime; - public int conversionTime; - private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field -- private boolean shouldBurnInDay = true; // Paper - Add more Zombie API -+ // private boolean shouldBurnInDay = true; // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - - public Zombie(EntityType type, Level world) { - super(type, world); - this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(world.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(type, world.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty -+ this.setShouldBurnInDay(true); // Purpur - } - - public Zombie(Level world) { -@@ -293,30 +294,7 @@ public class Zombie extends Monster { - - @Override - public void aiStep() { -- if (this.isAlive()) { -- boolean flag = this.isSunSensitive() && this.isSunBurnTick(); -- -- if (flag) { -- ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); -- -- if (!itemstack.isEmpty()) { -- if (itemstack.isDamageableItem()) { -- itemstack.setDamageValue(itemstack.getDamageValue() + this.random.nextInt(2)); -- if (itemstack.getDamageValue() >= itemstack.getMaxDamage()) { -- this.broadcastBreakEvent(EquipmentSlot.HEAD); -- this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY); -- } -- } -- -- flag = false; -- } -- -- if (flag) { -- this.igniteForSeconds(8); -- } -- } -- } -- -+ // Purpur - implemented in LivingEntity - super.aiStep(); - } - -@@ -354,6 +332,7 @@ public class Zombie extends Monster { - - } - -+ public boolean shouldBurnInDay() { return isSunSensitive(); } // Purpur - for ABI compatibility - public boolean isSunSensitive() { - return this.shouldBurnInDay; // Paper - Add more Zombie API - } -@@ -477,7 +456,7 @@ public class Zombie extends Monster { - nbt.putBoolean("CanBreakDoors", this.canBreakDoors()); - nbt.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1); - nbt.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1); -- nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API -+ // nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - } - - @Override -@@ -491,7 +470,7 @@ public class Zombie extends Monster { - } - // Paper start - Add more Zombie API - if (nbt.contains("Paper.ShouldBurnInDay")) { -- this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); -+ // this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); // Purpur - implemented in LivingEntity - } - // Paper end - Add more Zombie API - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index befe3372d5f1550b7bde3b63b5e7aef9035c5379..3c674ecd3b80501047b4593e8872034287defd2e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -84,6 +84,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - this.entityType = CraftEntityType.minecraftToBukkit(entity.getType()); - } - -+ @Override -+ public boolean isInDaylight() { -+ return getHandle().isSunBurnTick(); -+ } -+ - public static CraftEntity getEntity(CraftServer server, T entity) { - Preconditions.checkArgument(entity != null, "Unknown entity"); - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 11bd76d79bbfff68734d8ee1095f21c5c50e7bde..1a8a76aa31bd1d1670be6e9cada162c540084cf9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -1180,5 +1180,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - if (slot == null) return; - getHandle().broadcastBreakEvent(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot)); - } -+ -+ @Override -+ public boolean shouldBurnInDay() { -+ return getHandle().shouldBurnInDay(); -+ } -+ -+ @Override -+ public void setShouldBurnInDay(boolean shouldBurnInDay) { -+ getHandle().setShouldBurnInDay(shouldBurnInDay); -+ } - // Purpur end - } diff --git a/patches/server/0170-Config-MobEffect-by-world.patch b/patches/server/0170-Config-MobEffect-by-world.patch deleted file mode 100644 index 5b850adcc..000000000 --- a/patches/server/0170-Config-MobEffect-by-world.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Sat, 23 Sep 2023 03:59:15 -0700 -Subject: [PATCH] Config MobEffect by world - - -diff --git a/src/main/java/net/minecraft/world/effect/HungerMobEffect.java b/src/main/java/net/minecraft/world/effect/HungerMobEffect.java -index a476b56ed98d0a1afc6a396ce29424df78f24ada..5119ff3414fbd9a1ae0a8db0fd15bd3c57c8e148 100644 ---- a/src/main/java/net/minecraft/world/effect/HungerMobEffect.java -+++ b/src/main/java/net/minecraft/world/effect/HungerMobEffect.java -@@ -12,7 +12,7 @@ class HungerMobEffect extends MobEffect { - @Override - public boolean applyEffectTick(LivingEntity entity, int amplifier) { - if (entity instanceof Player entityhuman) { -- entityhuman.causeFoodExhaustion(0.005F * (float) (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent -+ entityhuman.causeFoodExhaustion(entity.level().purpurConfig.humanHungerExhaustionAmount * (float) (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent // Purpur - } - - return true; -diff --git a/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java b/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java -index 3e7a703632251e0a5234259e3702b58b332e5ef0..f2cc43fbccb5d2ba012b350268065c2cfe014faf 100644 ---- a/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java -+++ b/src/main/java/net/minecraft/world/effect/PoisonMobEffect.java -@@ -10,8 +10,8 @@ class PoisonMobEffect extends MobEffect { - - @Override - public boolean applyEffectTick(LivingEntity entity, int amplifier) { -- if (entity.getHealth() > 1.0F) { -- entity.hurt(entity.damageSources().poison(), 1.0F); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON -+ if (entity.getHealth() > entity.level().purpurConfig.entityMinimalHealthPoison) { // Purpur -+ entity.hurt(entity.damageSources().poison(), entity.level().purpurConfig.entityPoisonDegenerationAmount); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON // Purpur - } - - return true; -diff --git a/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java b/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java -index 4dba3e813e054951cbfbe0b323c1f5d973469cc0..426f61d55b9692cf085368df4e4df6f6997aa420 100644 ---- a/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java -+++ b/src/main/java/net/minecraft/world/effect/RegenerationMobEffect.java -@@ -11,7 +11,7 @@ class RegenerationMobEffect extends MobEffect { - @Override - public boolean applyEffectTick(LivingEntity entity, int amplifier) { - if (entity.getHealth() < entity.getMaxHealth()) { -- entity.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit -+ entity.heal(entity.level().purpurConfig.entityHealthRegenAmount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit // Purpur - } - - return true; -diff --git a/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java b/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java -index 7b415dca88f50dc472fe4be96e5ef0996f117913..2bb872f29350d15db46b32c686aef78fc1b6fa29 100644 ---- a/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java -+++ b/src/main/java/net/minecraft/world/effect/SaturationMobEffect.java -@@ -20,7 +20,7 @@ class SaturationMobEffect extends InstantenousMobEffect { - int oldFoodLevel = entityhuman.getFoodData().foodLevel; - org.bukkit.event.entity.FoodLevelChangeEvent event = CraftEventFactory.callFoodLevelChangeEvent(entityhuman, amplifier + 1 + oldFoodLevel); - if (!event.isCancelled()) { -- entityhuman.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 1.0F); -+ entityhuman.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, entity.level().purpurConfig.humanSaturationRegenAmount); // Purpur - } - - ((CraftPlayer) entityhuman.getBukkitEntity()).sendHealthUpdate(); -diff --git a/src/main/java/net/minecraft/world/effect/WitherMobEffect.java b/src/main/java/net/minecraft/world/effect/WitherMobEffect.java -index f43bf280999ff3860cc702def50cc62b131eb1bd..66d9e99a351f5fc6cf58be3bee4397d92c932d64 100644 ---- a/src/main/java/net/minecraft/world/effect/WitherMobEffect.java -+++ b/src/main/java/net/minecraft/world/effect/WitherMobEffect.java -@@ -9,7 +9,7 @@ class WitherMobEffect extends MobEffect { - - @Override - public boolean applyEffectTick(LivingEntity entity, int amplifier) { -- entity.hurt(entity.damageSources().wither(), 1.0F); -+ entity.hurt(entity.damageSources().wither(), entity.level().purpurConfig.entityWitherDegenerationAmount); // Purpur - return true; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b3d24e076aef331f26ed5035f2015680f4a5c732..e22dc10989d83642c4714aef97fbbd4a82d68c11 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -331,6 +331,21 @@ public class PurpurWorldConfig { - poweredRailBoostModifier = getDouble("gameplay-mechanics.minecart.powered-rail.boost-modifier", poweredRailBoostModifier); - } - -+ public float entityHealthRegenAmount = 1.0F; -+ public float entityMinimalHealthPoison = 1.0F; -+ public float entityPoisonDegenerationAmount = 1.0F; -+ public float entityWitherDegenerationAmount = 1.0F; -+ public float humanHungerExhaustionAmount = 0.005F; -+ public float humanSaturationRegenAmount = 1.0F; -+ private void mobEffectSettings() { -+ entityHealthRegenAmount = (float) getDouble("gameplay-mechanics.mob-effects.health-regen-amount", entityHealthRegenAmount); -+ entityMinimalHealthPoison = (float) getDouble("gameplay-mechanics.mob-effects.minimal-health-poison-amount", entityMinimalHealthPoison); -+ entityPoisonDegenerationAmount = (float) getDouble("gameplay-mechanics.mob-effects.poison-degeneration-amount", entityPoisonDegenerationAmount); -+ entityWitherDegenerationAmount = (float) getDouble("gameplay-mechanics.mob-effects.wither-degeneration-amount", entityWitherDegenerationAmount); -+ humanHungerExhaustionAmount = (float) getDouble("gameplay-mechanics.mob-effects.hunger-exhaustion-amount", humanHungerExhaustionAmount); -+ humanSaturationRegenAmount = (float) getDouble("gameplay-mechanics.mob-effects.saturation-regen-amount", humanSaturationRegenAmount); -+ } -+ - public boolean catSpawning; - public boolean patrolSpawning; - public boolean phantomSpawning; diff --git a/patches/server/0171-Beacon-Activation-Range-Configurable.patch b/patches/server/0171-Beacon-Activation-Range-Configurable.patch deleted file mode 100644 index 317654aee..000000000 --- a/patches/server/0171-Beacon-Activation-Range-Configurable.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Wed, 2 Jun 2021 02:45:47 +0200 -Subject: [PATCH] Beacon Activation Range Configurable - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index a6ffbbc1b5021564864e42c0756342352c2b8290..2b9cc89a2e71b523c90bbfa987b0f8352efff95a 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -92,6 +92,16 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - - public double getEffectRange() { - if (this.effectRange < 0) { -+ // Purpur Start -+ if (this.level != null) { -+ switch (this.levels) { -+ case 1: return this.level.purpurConfig.beaconLevelOne; -+ case 2: return this.level.purpurConfig.beaconLevelTwo; -+ case 3: return this.level.purpurConfig.beaconLevelThree; -+ case 4: return this.level.purpurConfig.beaconLevelFour; -+ } -+ } -+ // Purpur End - return this.levels * 10 + 10; - } else { - return effectRange; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e22dc10989d83642c4714aef97fbbd4a82d68c11..c27e8ad0e401499105ed3db2ef7b73a6fda8fb37 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -505,6 +505,17 @@ public class PurpurWorldConfig { - anvilColorsUseMiniMessage = getBoolean("blocks.anvil.use-mini-message", anvilColorsUseMiniMessage); - } - -+ public int beaconLevelOne = 20; -+ public int beaconLevelTwo = 30; -+ public int beaconLevelThree = 40; -+ public int beaconLevelFour = 50; -+ private void beaconSettings() { -+ beaconLevelOne = getInt("blocks.beacon.effect-range.level-1", beaconLevelOne); -+ beaconLevelTwo = getInt("blocks.beacon.effect-range.level-2", beaconLevelTwo); -+ beaconLevelThree = getInt("blocks.beacon.effect-range.level-3", beaconLevelThree); -+ beaconLevelFour = getInt("blocks.beacon.effect-range.level-4", beaconLevelFour); -+ } -+ - public boolean bedExplode = true; - public double bedExplosionPower = 5.0D; - public boolean bedExplosionFire = true; diff --git a/patches/server/0172-Make-lightning-rod-range-configurable.patch b/patches/server/0172-Make-lightning-rod-range-configurable.patch deleted file mode 100644 index 1b3474b59..000000000 --- a/patches/server/0172-Make-lightning-rod-range-configurable.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Wed, 23 Jun 2021 13:36:20 +0200 -Subject: [PATCH] Make lightning rod range configurable - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index bcdef2c9bb116409445a4ef65c5e407c1003a55d..1dc58b41d3963c2adc58e79cd6db7e146ac049ad 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1182,7 +1182,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - return holder.is(PoiTypes.LIGHTNING_ROD); - }, (blockposition1) -> { - return blockposition1.getY() == this.getHeight(Heightmap.Types.WORLD_SURFACE, blockposition1.getX(), blockposition1.getZ()) - 1; -- }, pos, 128, PoiManager.Occupancy.ANY); -+ }, pos, org.purpurmc.purpur.PurpurConfig.lightningRodRange, PoiManager.Occupancy.ANY); - - return optional.map((blockposition1) -> { - return blockposition1.above(1); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index b10e0de76f618c545294873038ce29ee0c486d24..f3f8ca5f2b391860b2134e06784819aa0e78321e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -270,6 +270,7 @@ public class PurpurConfig { - public static boolean cryingObsidianValidForPortalFrame = false; - public static int beeInsideBeeHive = 3; - public static boolean anvilCumulativeCost = true; -+ public static int lightningRodRange = 128; - private static void blockSettings() { - if (version < 3) { - boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); -@@ -303,6 +304,7 @@ public class PurpurConfig { - cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame); - beeInsideBeeHive = getInt("settings.blocks.beehive.max-bees-inside", beeInsideBeeHive); - anvilCumulativeCost = getBoolean("settings.blocks.anvil.cumulative-cost", anvilCumulativeCost); -+ lightningRodRange = getInt("settings.blocks.lightning_rod.range", lightningRodRange); - } - - public static boolean allowInfinityMending = false; diff --git a/patches/server/0173-Burp-delay-burp-after-eating-food-fills-hunger-bar-c.patch b/patches/server/0173-Burp-delay-burp-after-eating-food-fills-hunger-bar-c.patch deleted file mode 100644 index 969b2d855..000000000 --- a/patches/server/0173-Burp-delay-burp-after-eating-food-fills-hunger-bar-c.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 24 Jun 2021 21:19:30 -0500 -Subject: [PATCH] Burp delay, burp after eating food fills hunger bar - completely - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index bc994bbc4c7b66e6365739acb896aaa81fbcbd7e..ea3252a70c68f3c228417d8ed6d19d5669abb5fb 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -196,6 +196,7 @@ public abstract class Player extends LivingEntity { - public boolean affectsSpawning = true; // Paper - Affects Spawning API - public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage - public int sixRowEnderchestSlotCount = -1; // Purpur -+ public int burpDelay = 0; // Purpur - - // CraftBukkit start - public boolean fauxSleeping; -@@ -271,6 +272,12 @@ public abstract class Player extends LivingEntity { - - @Override - public void tick() { -+ // Purpur start -+ if (this.burpDelay > 0 && --this.burpDelay == 0) { -+ this.level().playSound(null, getX(), getY(), getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 1.0F, this.level().random.nextFloat() * 0.1F + 0.9F); -+ } -+ // Purpur end -+ - this.noPhysics = this.isSpectator(); - if (this.isSpectator()) { - this.setOnGround(false); -@@ -2362,7 +2369,7 @@ public abstract class Player extends LivingEntity { - public ItemStack eat(Level world, ItemStack stack) { - this.getFoodData().eat(stack); - this.awardStat(Stats.ITEM_USED.get(stack.getItem())); -- world.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); -+ // world.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F); // Purpur - moved to tick() - if (this instanceof ServerPlayer) { - CriteriaTriggers.CONSUME_ITEM.trigger((ServerPlayer) this, stack); - } -diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java -index b89860d451d92ddda64b7e4144542b7fc5fd86f0..08a6cca64ddd49826a0bbddd7711187c73bb4997 100644 ---- a/src/main/java/net/minecraft/world/food/FoodData.java -+++ b/src/main/java/net/minecraft/world/food/FoodData.java -@@ -38,7 +38,9 @@ public class FoodData { - } - - public void eat(int food, float saturationModifier) { -+ int oldValue = this.foodLevel; // Purpur - this.add(food, FoodConstants.saturationByModifier(food, saturationModifier)); -+ if (this.entityhuman.level().purpurConfig.playerBurpWhenFull && this.foodLevel == 20 && oldValue < 20) this.entityhuman.burpDelay = this.entityhuman.level().purpurConfig.playerBurpDelay; // Purpur - } - - public void eat(ItemStack stack) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index c27e8ad0e401499105ed3db2ef7b73a6fda8fb37..1c2aec3ddbe6d9dd0ae9ce4d074092ed0555d711 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -388,6 +388,8 @@ public class PurpurWorldConfig { - public boolean playerSleepNearMonsters = false; - public boolean playersSkipNight = true; - public double playerCriticalDamageMultiplier = 1.5D; -+ public int playerBurpDelay = 10; -+ public boolean playerBurpWhenFull = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -408,6 +410,8 @@ public class PurpurWorldConfig { - playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters); - playersSkipNight = getBoolean("gameplay-mechanics.player.can-skip-night", playersSkipNight); - playerCriticalDamageMultiplier = getDouble("gameplay-mechanics.player.critical-damage-multiplier", playerCriticalDamageMultiplier); -+ playerBurpDelay = getInt("gameplay-mechanics.player.burp-delay", playerBurpDelay); -+ playerBurpWhenFull = getBoolean("gameplay-mechanics.player.burp-when-full", playerBurpWhenFull); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0174-Allow-player-join-full-server-by-permission.patch b/patches/server/0174-Allow-player-join-full-server-by-permission.patch deleted file mode 100644 index 6b634e729..000000000 --- a/patches/server/0174-Allow-player-join-full-server-by-permission.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Thu, 24 Jun 2021 02:28:32 +0200 -Subject: [PATCH] Allow player join full server by permission - - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index f2a7eba2618ea9c1acaf93c0ef8f6f5f737de6fe..d20a7a79e27db1092ff78910df5d45982971cc3e 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -754,7 +754,7 @@ public abstract class PlayerList { - event.disallow(PlayerLoginEvent.Result.KICK_BANNED, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure - } else { - // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile) ? IChatBaseComponent.translatable("multiplayer.disconnect.server_full") : null; -- if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile)) { -+ if (this.players.size() >= this.maxPlayers && !(player.hasPermission("purpur.joinfullserver") || this.canBypassPlayerLimit(gameprofile))) { // Purpur - event.disallow(PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure - } - } diff --git a/patches/server/0175-Add-portal-permission-bypass.patch b/patches/server/0175-Add-portal-permission-bypass.patch deleted file mode 100644 index 7d5cd2bd7..000000000 --- a/patches/server/0175-Add-portal-permission-bypass.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 7 Dec 2023 14:53:48 -0800 -Subject: [PATCH] Add portal permission bypass - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index ea3252a70c68f3c228417d8ed6d19d5669abb5fb..458c14d4f298137ef1a333368644568a2c8a0b09 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -197,6 +197,7 @@ public abstract class Player extends LivingEntity { - public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage - public int sixRowEnderchestSlotCount = -1; // Purpur - public int burpDelay = 0; // Purpur -+ public boolean canPortalInstant = false; // Purpur - - // CraftBukkit start - public boolean fauxSleeping; -@@ -488,7 +489,7 @@ public abstract class Player extends LivingEntity { - - @Override - public int getPortalWaitTime() { -- return Math.max(1, this.level().getGameRules().getInt(this.abilities.invulnerable ? GameRules.RULE_PLAYERS_NETHER_PORTAL_CREATIVE_DELAY : GameRules.RULE_PLAYERS_NETHER_PORTAL_DEFAULT_DELAY)); -+ return Math.max(1, canPortalInstant ? 1 : this.level().getGameRules().getInt(this.abilities.invulnerable ? GameRules.RULE_PLAYERS_NETHER_PORTAL_CREATIVE_DELAY : GameRules.RULE_PLAYERS_NETHER_PORTAL_DEFAULT_DELAY)); - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 41f3cdec7deabf34358b8087df77169f85a5b919..90265b6f2acd43713b61e277799dd31311b6b7e2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -265,6 +265,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { - @Override - public void recalculatePermissions() { - this.perm.recalculatePermissions(); -+ getHandle().canPortalInstant = hasPermission("purpur.portal.instant"); // Purpur - } - - @Override diff --git a/patches/server/0176-Shulker-spawn-from-bullet-options.patch b/patches/server/0176-Shulker-spawn-from-bullet-options.patch deleted file mode 100644 index 7776673b5..000000000 --- a/patches/server/0176-Shulker-spawn-from-bullet-options.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 25 Jun 2021 19:48:21 -0500 -Subject: [PATCH] Shulker spawn from bullet options - -(0 - 1) / 5.0 = -0.2 (can never happen because self is included in count) -(1 - 1) / 5.0 = 0.0 1.0 - 0.0 = 1.0 100% (just self) -(2 - 1) / 5.0 = 0.2 1.0 - 0.2 = 0.8 80% (1 other shulker) -(3 - 1) / 5.0 = 0.4 1.0 - 0.4 = 0.6 60% (2 other shulkers) -(4 - 1) / 5.0 = 0.6 1.0 - 0.6 = 0.4 40% (3 other shulkers) -(5 - 1) / 5.0 = 0.8 1.0 - 0.8 = 0.2 20% (4 other shulkers) -(6 - 1) / 5.0 = 1.0 1.0 - 1.0 = 0.0 0% (5 other shulkers) -(7 - 1) / 5.0 = 1.2 1.0 - 1.2 = -0.2 0% (6 other shulkers) - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index 5b4ad4f64488ca5a21312caa3d13318f429401ea..73063abbd051f1d044a8b2c0530cc8d2a96a6331 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -504,12 +504,21 @@ public class Shulker extends AbstractGolem implements VariantHolder= f) { -+ if ((!this.level().purpurConfig.shulkerSpawnFromBulletRequireOpenLid || !this.isClosed()) && this.teleportSomewhere()) { -+ // Purpur start -+ float chance = this.level().purpurConfig.shulkerSpawnFromBulletBaseChance; -+ if (!this.level().purpurConfig.shulkerSpawnFromBulletNearbyEquation.isBlank()) { -+ int nearby = this.level().getEntities((EntityTypeTest) EntityType.SHULKER, axisalignedbb.inflate(this.level().purpurConfig.shulkerSpawnFromBulletNearbyRange), Entity::isAlive).size(); -+ try { -+ chance -= ((Number) scriptEngine.eval("let nearby = " + nearby + "; " + this.level().purpurConfig.shulkerSpawnFromBulletNearbyEquation)).floatValue(); -+ } catch (javax.script.ScriptException e) { -+ e.printStackTrace(); -+ chance -= (nearby - 1) / 5.0F; -+ } -+ } -+ if (this.level().random.nextFloat() <= chance) { - Shulker entityshulker = (Shulker) EntityType.SHULKER.create(this.level()); -+ // Purpur end - - if (entityshulker != null) { - entityshulker.setVariant(this.getVariant()); -@@ -621,7 +630,7 @@ public class Shulker extends AbstractGolem implements VariantHolder getVariant() { -- return Optional.ofNullable(this.getColor()); -+ return Optional.ofNullable(this.level().purpurConfig.shulkerSpawnFromBulletRandomColor ? DyeColor.random(this.level().random) : this.getColor()); // Purpur - } - - @Nullable -diff --git a/src/main/java/net/minecraft/world/item/DyeColor.java b/src/main/java/net/minecraft/world/item/DyeColor.java -index 2202798612cad53aff28c499b8909a7292a37ad5..5ed2b7d15686fc9aa6dc7c03c337433cb3ee2cbd 100644 ---- a/src/main/java/net/minecraft/world/item/DyeColor.java -+++ b/src/main/java/net/minecraft/world/item/DyeColor.java -@@ -105,4 +105,10 @@ public enum DyeColor implements StringRepresentable { - public String getSerializedName() { - return this.name; - } -+ -+ // Purpur start -+ public static DyeColor random(net.minecraft.util.RandomSource random) { -+ return values()[random.nextInt(values().length)]; -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 1c2aec3ddbe6d9dd0ae9ce4d074092ed0555d711..444ae36042e5d5bf2bd3ba7348882304825b5f06 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1908,6 +1908,11 @@ public class PurpurWorldConfig { - public boolean shulkerControllable = true; - public double shulkerMaxHealth = 30.0D; - public boolean shulkerTakeDamageFromWater = false; -+ public float shulkerSpawnFromBulletBaseChance = 1.0F; -+ public boolean shulkerSpawnFromBulletRequireOpenLid = true; -+ public double shulkerSpawnFromBulletNearbyRange = 8.0D; -+ public String shulkerSpawnFromBulletNearbyEquation = "(nearby - 1) / 5.0"; -+ public boolean shulkerSpawnFromBulletRandomColor = false; - private void shulkerSettings() { - shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); - shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); -@@ -1919,6 +1924,11 @@ public class PurpurWorldConfig { - } - shulkerMaxHealth = getDouble("mobs.shulker.attributes.max_health", shulkerMaxHealth); - shulkerTakeDamageFromWater = getBoolean("mobs.shulker.takes-damage-from-water", shulkerTakeDamageFromWater); -+ shulkerSpawnFromBulletBaseChance = (float) getDouble("mobs.shulker.spawn-from-bullet.base-chance", shulkerSpawnFromBulletBaseChance); -+ shulkerSpawnFromBulletRequireOpenLid = getBoolean("mobs.shulker.spawn-from-bullet.require-open-lid", shulkerSpawnFromBulletRequireOpenLid); -+ shulkerSpawnFromBulletNearbyRange = getDouble("mobs.shulker.spawn-from-bullet.nearby-range", shulkerSpawnFromBulletNearbyRange); -+ shulkerSpawnFromBulletNearbyEquation = getString("mobs.shulker.spawn-from-bullet.nearby-equation", shulkerSpawnFromBulletNearbyEquation); -+ shulkerSpawnFromBulletRandomColor = getBoolean("mobs.shulker.spawn-from-bullet.random-color", shulkerSpawnFromBulletRandomColor); - } - - public boolean silverfishRidable = false; diff --git a/patches/server/0177-Eating-glow-berries-adds-glow-effect.patch b/patches/server/0177-Eating-glow-berries-adds-glow-effect.patch deleted file mode 100644 index c5288146e..000000000 --- a/patches/server/0177-Eating-glow-berries-adds-glow-effect.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 28 Jun 2021 14:07:35 -0500 -Subject: [PATCH] Eating glow berries adds glow effect - - -diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java -index 6467358f5fdf4cd4f7c1e2cc65c834a9da39596a..42b322879629afb2d2fc64a215f010f5d5ce9e02 100644 ---- a/src/main/java/net/minecraft/world/item/Items.java -+++ b/src/main/java/net/minecraft/world/item/Items.java -@@ -1909,7 +1909,7 @@ public class Items { - "sweet_berries", new ItemNameBlockItem(Blocks.SWEET_BERRY_BUSH, new Item.Properties().food(Foods.SWEET_BERRIES)) - ); - public static final Item GLOW_BERRIES = registerItem( -- "glow_berries", new ItemNameBlockItem(Blocks.CAVE_VINES, new Item.Properties().food(Foods.GLOW_BERRIES)) -+ "glow_berries", new org.purpurmc.purpur.item.GlowBerryItem(Blocks.CAVE_VINES, new Item.Properties().food(Foods.GLOW_BERRIES)) // Purpur - ); - public static final Item CAMPFIRE = registerBlock(Blocks.CAMPFIRE, settings -> settings.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY)); - public static final Item SOUL_CAMPFIRE = registerBlock( -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 444ae36042e5d5bf2bd3ba7348882304825b5f06..75903da7236f6f57c4978d33cd8ac15a4f7d7a62 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -220,6 +220,7 @@ public class PurpurWorldConfig { - public int enderPearlCooldown = 20; - public int enderPearlCooldownCreative = 20; - public float enderPearlEndermiteChance = 0.05F; -+ public int glowBerriesEatGlowDuration = 0; - private void itemSettings() { - itemImmuneToCactus.clear(); - getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { -@@ -265,6 +266,7 @@ public class PurpurWorldConfig { - enderPearlCooldown = getInt("gameplay-mechanics.item.ender-pearl.cooldown", enderPearlCooldown); - enderPearlCooldownCreative = getInt("gameplay-mechanics.item.ender-pearl.creative-cooldown", enderPearlCooldownCreative); - enderPearlEndermiteChance = (float) getDouble("gameplay-mechanics.item.ender-pearl.endermite-spawn-chance", enderPearlEndermiteChance); -+ glowBerriesEatGlowDuration = getInt("gameplay-mechanics.item.glow_berries.eat-glow-duration", glowBerriesEatGlowDuration); - } - - public double minecartMaxSpeed = 0.4D; -diff --git a/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java b/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7f526883495b3222746de3d0442e9e4fb5107036 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java -@@ -0,0 +1,26 @@ -+package org.purpurmc.purpur.item; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.effect.MobEffectInstance; -+import net.minecraft.world.effect.MobEffects; -+import net.minecraft.world.entity.LivingEntity; -+import net.minecraft.world.item.ItemNameBlockItem; -+import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.Block; -+import org.bukkit.event.entity.EntityPotionEffectEvent; -+ -+public class GlowBerryItem extends ItemNameBlockItem { -+ public GlowBerryItem(Block block, Properties settings) { -+ super(block, settings); -+ } -+ -+ @Override -+ public ItemStack finishUsingItem(ItemStack stack, Level world, LivingEntity user) { -+ ItemStack result = super.finishUsingItem(stack, world, user); -+ if (world.purpurConfig.glowBerriesEatGlowDuration > 0 && user instanceof ServerPlayer player) { -+ player.addEffect(new MobEffectInstance(MobEffects.GLOWING, world.purpurConfig.glowBerriesEatGlowDuration), EntityPotionEffectEvent.Cause.FOOD); -+ } -+ return result; -+ } -+} diff --git a/patches/server/0178-Option-to-make-drowned-break-doors.patch b/patches/server/0178-Option-to-make-drowned-break-doors.patch deleted file mode 100644 index 48af70fc1..000000000 --- a/patches/server/0178-Option-to-make-drowned-break-doors.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Fri, 25 Jun 2021 13:56:15 +0200 -Subject: [PATCH] Option to make drowned break doors - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -index f037d50f26f7532f11a71790448de7a71644b6ca..2547ac49721e2840da2845076d5e62a1465a4ea3 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -@@ -29,6 +29,7 @@ import net.minecraft.world.entity.ai.goal.MoveToBlockGoal; - import net.minecraft.world.entity.ai.goal.RandomStrollGoal; - import net.minecraft.world.entity.ai.goal.RangedAttackGoal; - import net.minecraft.world.entity.ai.goal.ZombieAttackGoal; -+import net.minecraft.world.entity.ai.goal.MoveThroughVillageGoal; - import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; - import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; - import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -@@ -125,6 +126,7 @@ public class Drowned extends Zombie implements RangedAttackMob { - this.goalSelector.addGoal(2, new Drowned.DrownedAttackGoal(this, 1.0D, false)); - this.goalSelector.addGoal(5, new Drowned.DrownedGoToBeachGoal(this, 1.0D)); - this.goalSelector.addGoal(6, new Drowned.DrownedSwimUpGoal(this, 1.0D, this.level().getSeaLevel())); -+ if (level().purpurConfig.drownedBreakDoors) this.goalSelector.addGoal(6, new MoveThroughVillageGoal(this, 1.0D, true, 4, this::canBreakDoors)); - this.goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0D)); - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Drowned.class})).setAlertOthers(ZombifiedPiglin.class)); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::okTarget)); -@@ -174,7 +176,7 @@ public class Drowned extends Zombie implements RangedAttackMob { - - @Override - public boolean supportsBreakDoorGoal() { -- return false; -+ return level().purpurConfig.drownedBreakDoors ? true : false; - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 75903da7236f6f57c4978d33cd8ac15a4f7d7a62..b3a999c8ecaaf9e0dae83d0fe10f9f927f592b58 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1054,6 +1054,7 @@ public class PurpurWorldConfig { - public double drownedJockeyChance = 0.05D; - public boolean drownedJockeyTryExistingChickens = true; - public boolean drownedTakeDamageFromWater = false; -+ public boolean drownedBreakDoors = false; - private void drownedSettings() { - drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); - drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); -@@ -1069,6 +1070,7 @@ public class PurpurWorldConfig { - drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance); - drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens); - drownedTakeDamageFromWater = getBoolean("mobs.drowned.takes-damage-from-water", drownedTakeDamageFromWater); -+ drownedBreakDoors = getBoolean("mobs.drowned.can-break-doors", drownedBreakDoors); - } - - public boolean elderGuardianRidable = false; diff --git a/patches/server/0179-Configurable-hunger-starvation-damage.patch b/patches/server/0179-Configurable-hunger-starvation-damage.patch deleted file mode 100644 index 0d9d7df22..000000000 --- a/patches/server/0179-Configurable-hunger-starvation-damage.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 29 Jun 2021 23:44:36 -0400 -Subject: [PATCH] Configurable hunger starvation damage - - -diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java -index 08a6cca64ddd49826a0bbddd7711187c73bb4997..dd72d6a79139ff33f26a32b71283ce0b8d084ecc 100644 ---- a/src/main/java/net/minecraft/world/food/FoodData.java -+++ b/src/main/java/net/minecraft/world/food/FoodData.java -@@ -107,7 +107,7 @@ public class FoodData { - ++this.tickTimer; - if (this.tickTimer >= this.starvationRate) { // CraftBukkit - add regen rate manipulation - if (player.getHealth() > 10.0F || enumdifficulty == Difficulty.HARD || player.getHealth() > 1.0F && enumdifficulty == Difficulty.NORMAL) { -- player.hurt(player.damageSources().starve(), 1.0F); -+ player.hurt(player.damageSources().starve(), player.level().purpurConfig.hungerStarvationDamage); // Purpur - } - - this.tickTimer = 0; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b3a999c8ecaaf9e0dae83d0fe10f9f927f592b58..a9a2b09b985e3e4eb69d4ae16dfd40f46be936d6 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2567,4 +2567,9 @@ public class PurpurWorldConfig { - zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry); - zombifiedPiglinTakeDamageFromWater = getBoolean("mobs.zombified_piglin.takes-damage-from-water", zombifiedPiglinTakeDamageFromWater); - } -+ -+ public float hungerStarvationDamage = 1.0F; -+ private void hungerSettings() { -+ hungerStarvationDamage = (float) getDouble("hunger.starvation-damage", hungerStarvationDamage); -+ } - } diff --git a/patches/server/0181-Add-uptime-command.patch b/patches/server/0181-Add-uptime-command.patch deleted file mode 100644 index 5f0236123..000000000 --- a/patches/server/0181-Add-uptime-command.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 1 Jul 2021 15:48:02 -0500 -Subject: [PATCH] Add uptime command - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index d0a81669ac20dc86e888aa34e246c251b8886ba2..26c9254cef922a78deac3053f93c60037f19d31f 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -255,6 +255,7 @@ public class Commands { - org.purpurmc.purpur.command.CreditsCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.DemoCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur -+ org.purpurmc.purpur.command.UptimeCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.TPSBarCommand.register(this.dispatcher); // Purpur - } - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index b68db217c8765fa029244bf2701757bd31a5db2b..6d84eb68e3160f772d6832513df2bc4db87b594e 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -300,6 +300,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); - public int autosavePeriod; - public Commands vanillaCommandDispatcher; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index f3f8ca5f2b391860b2134e06784819aa0e78321e..16239aafded82b4f19f97ae5fd87c53b55a5ef53 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -184,6 +184,7 @@ public class PurpurConfig { - public static String pingCommandOutput = "%s's ping is %sms"; - public static String tpsbarCommandOutput = "Tpsbar toggled for "; - public static String dontRunWithScissors = "Don't run with scissors!"; -+ public static String uptimeCommandOutput = "Server uptime is "; - public static String unverifiedUsername = "default"; - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); -@@ -197,6 +198,7 @@ public class PurpurConfig { - pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); - tpsbarCommandOutput = getString("settings.messages.tpsbar-command-output", tpsbarCommandOutput); - dontRunWithScissors = getString("settings.messages.dont-run-with-scissors", dontRunWithScissors); -+ uptimeCommandOutput = getString("settings.messages.uptime-command-output", uptimeCommandOutput); - unverifiedUsername = getString("settings.messages.unverified-username", unverifiedUsername); - } - -@@ -249,6 +251,15 @@ public class PurpurConfig { - public static int commandTPSBarTickInterval = 20; - public static boolean commandGamemodeRequiresPermission = false; - public static boolean hideHiddenPlayersFromEntitySelector = false; -+ public static String uptimeFormat = ""; -+ public static String uptimeDay = "%02d day, "; -+ public static String uptimeDays = "%02d days, "; -+ public static String uptimeHour = "%02d hour, "; -+ public static String uptimeHours = "%02d hours, "; -+ public static String uptimeMinute = "%02d minute, and "; -+ public static String uptimeMinutes = "%02d minutes, and "; -+ public static String uptimeSecond = "%02d second"; -+ public static String uptimeSeconds = "%02d seconds"; - private static void commandSettings() { - commandTPSBarTitle = getString("settings.command.tpsbar.title", commandTPSBarTitle); - commandTPSBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.tpsbar.overlay", commandTPSBarProgressOverlay.name())); -@@ -262,6 +273,15 @@ public class PurpurConfig { - commandTPSBarTickInterval = getInt("settings.command.tpsbar.tick-interval", commandTPSBarTickInterval); - commandGamemodeRequiresPermission = getBoolean("settings.command.gamemode.requires-specific-permission", commandGamemodeRequiresPermission); - hideHiddenPlayersFromEntitySelector = getBoolean("settings.command.hide-hidden-players-from-entity-selector", hideHiddenPlayersFromEntitySelector); -+ uptimeFormat = getString("settings.command.uptime.format", uptimeFormat); -+ uptimeDay = getString("settings.command.uptime.day", uptimeDay); -+ uptimeDays = getString("settings.command.uptime.days", uptimeDays); -+ uptimeHour = getString("settings.command.uptime.hour", uptimeHour); -+ uptimeHours = getString("settings.command.uptime.hours", uptimeHours); -+ uptimeMinute = getString("settings.command.uptime.minute", uptimeMinute); -+ uptimeMinutes = getString("settings.command.uptime.minutes", uptimeMinutes); -+ uptimeSecond = getString("settings.command.uptime.second", uptimeSecond); -+ uptimeSeconds = getString("settings.command.uptime.seconds", uptimeSeconds); - } - - public static int barrelRows = 3; -diff --git a/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java b/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4bb475099bcf8f05d5f1474e7fbf29c57c2c40cd ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java -@@ -0,0 +1,55 @@ -+package org.purpurmc.purpur.command; -+ -+import com.mojang.brigadier.CommandDispatcher; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.minimessage.MiniMessage; -+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import net.minecraft.server.MinecraftServer; -+import org.purpurmc.purpur.PurpurConfig; -+ -+import java.util.concurrent.TimeUnit; -+import java.util.function.Function; -+ -+public class UptimeCommand { -+ public static void register(CommandDispatcher dispatcher) { -+ dispatcher.register(Commands.literal("uptime") -+ .requires((listener) -> listener.hasPermission(2, "bukkit.command.uptime")) -+ .executes((context) -> execute(context.getSource())) -+ ); -+ } -+ -+ private static int execute(CommandSourceStack sender) { -+ Data data = new Data(); -+ -+ data.format = PurpurConfig.uptimeFormat; -+ data.hide = true; -+ data.millis = System.currentTimeMillis() - MinecraftServer.startTimeMillis; -+ -+ process(data, "", PurpurConfig.uptimeDay, PurpurConfig.uptimeDays, TimeUnit.DAYS, TimeUnit.MILLISECONDS::toDays); -+ process(data, "", PurpurConfig.uptimeHour, PurpurConfig.uptimeHours, TimeUnit.HOURS, TimeUnit.MILLISECONDS::toHours); -+ process(data, "", PurpurConfig.uptimeMinute, PurpurConfig.uptimeMinutes, TimeUnit.MINUTES, TimeUnit.MILLISECONDS::toMinutes); -+ data.hide = false; // never hide seconds -+ process(data, "", PurpurConfig.uptimeSecond, PurpurConfig.uptimeSeconds, TimeUnit.SECONDS, TimeUnit.MILLISECONDS::toSeconds); -+ -+ Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.uptimeCommandOutput, Placeholder.unparsed("uptime", data.format)); -+ sender.sendSuccess(output, false); -+ return 1; -+ } -+ -+ private static void process(Data data, String replace, String singular, String plural, TimeUnit unit, Function func) { -+ if (data.format.contains(replace)) { -+ long val = func.apply(data.millis); -+ if (data.hide) data.hide = val == 0; -+ if (!data.hide) data.millis -= unit.toMillis(val); -+ data.format = data.format.replace(replace, data.hide ? "" : String.format(val == 1 ? singular : plural, val)); -+ } -+ } -+ -+ private static class Data { -+ String format; -+ boolean hide; -+ long millis; -+ } -+} diff --git a/patches/server/0182-Tool-actionable-options.patch b/patches/server/0182-Tool-actionable-options.patch deleted file mode 100644 index 869604642..000000000 --- a/patches/server/0182-Tool-actionable-options.patch +++ /dev/null @@ -1,597 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 2 Jul 2021 20:54:29 -0500 -Subject: [PATCH] Tool actionable options - - -diff --git a/src/main/java/net/minecraft/world/item/AxeItem.java b/src/main/java/net/minecraft/world/item/AxeItem.java -index 9fd2d97ff0e05578a3e6a0b86dc1974691845c5d..58343722399404530d497648155dbc254d6a865a 100644 ---- a/src/main/java/net/minecraft/world/item/AxeItem.java -+++ b/src/main/java/net/minecraft/world/item/AxeItem.java -@@ -56,13 +56,15 @@ public class AxeItem extends DiggerItem { - Level level = context.getLevel(); - BlockPos blockPos = context.getClickedPos(); - Player player = context.getPlayer(); -- Optional optional = this.evaluateNewBlockState(level, blockPos, player, level.getBlockState(blockPos)); -+ Optional optional = this.evaluateActionable(level, blockPos, player, level.getBlockState(blockPos)); // Purpur - if (optional.isEmpty()) { - return InteractionResult.PASS; - } else { -+ org.purpurmc.purpur.tool.Actionable actionable = optional.get(); // Purpur -+ BlockState state = actionable.into().withPropertiesOf(level.getBlockState(blockPos)); // Purpur - ItemStack itemStack = context.getItemInHand(); - // Paper start - EntityChangeBlockEvent -- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, optional.get())) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, state)) { // Purpur - return InteractionResult.PASS; - } - // Paper end -@@ -70,32 +72,41 @@ public class AxeItem extends DiggerItem { - CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack); - } - -- level.setBlock(blockPos, optional.get(), 11); -- level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, optional.get())); -+ // Purpur start -+ level.setBlock(blockPos, state, 11); -+ actionable.drops().forEach((drop, chance) -> { -+ if (level.random.nextDouble() < chance) { -+ Block.popResourceFromFace(level, blockPos, context.getClickedFace(), new ItemStack(drop)); -+ } -+ }); -+ level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, state)); -+ // Purpur end - if (player != null) { - itemStack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(context.getHand())); - } - -- return InteractionResult.sidedSuccess(level.isClientSide); -+ return InteractionResult.SUCCESS; // Purpur - force arm swing - } - } - -- private Optional evaluateNewBlockState(Level world, BlockPos pos, @Nullable Player player, BlockState state) { -- Optional optional = this.getStripped(state); -+ private Optional evaluateActionable(Level world, BlockPos pos, @Nullable Player player, BlockState state) { // Purpur -+ Optional optional = Optional.ofNullable(world.purpurConfig.axeStrippables.get(state.getBlock())); // Purpur - if (optional.isPresent()) { -- world.playSound(player, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F); -+ world.playSound(STRIPPABLES.containsKey(state.getBlock()) ? player : null, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound - return optional; - } else { -- Optional optional2 = WeatheringCopper.getPrevious(state); -+ Optional optional2 = Optional.ofNullable(world.purpurConfig.axeWeatherables.get(state.getBlock())); // Purpur - if (optional2.isPresent()) { -- world.playSound(player, pos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F); -+ world.playSound(WeatheringCopper.getPrevious(state).isPresent() ? player : null, pos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound - world.levelEvent(player, 3005, pos, 0); - return optional2; - } else { -- Optional optional3 = Optional.ofNullable(HoneycombItem.WAX_OFF_BY_BLOCK.get().get(state.getBlock())) -- .map(block -> block.withPropertiesOf(state)); -+ // Purpur start -+ Optional optional3 = Optional.ofNullable(world.purpurConfig.axeWaxables.get(state.getBlock())); -+ // .map(block -> block.withPropertiesOf(state)); -+ // Purpur end - if (optional3.isPresent()) { -- world.playSound(player, pos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F); -+ world.playSound(HoneycombItem.WAX_OFF_BY_BLOCK.get().containsKey(state.getBlock()) ? player : null, pos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound - world.levelEvent(player, 3004, pos, 0); - return optional3; - } else { -diff --git a/src/main/java/net/minecraft/world/item/HoeItem.java b/src/main/java/net/minecraft/world/item/HoeItem.java -index 06497b5141e611cc7a1b6030a7b9c54b5c4eda06..28df1b3230762e52b5458ac93a85c9a5d41eb6a6 100644 ---- a/src/main/java/net/minecraft/world/item/HoeItem.java -+++ b/src/main/java/net/minecraft/world/item/HoeItem.java -@@ -46,15 +46,23 @@ public class HoeItem extends DiggerItem { - public InteractionResult useOn(UseOnContext context) { - Level level = context.getLevel(); - BlockPos blockPos = context.getClickedPos(); -- Pair, Consumer> pair = TILLABLES.get(level.getBlockState(blockPos).getBlock()); -- if (pair == null) { -- return InteractionResult.PASS; -- } else { -- Predicate predicate = pair.getFirst(); -- Consumer consumer = pair.getSecond(); -+ // Purpur start -+ Block clickedBlock = level.getBlockState(blockPos).getBlock(); -+ var tillable = level.purpurConfig.hoeTillables.get(clickedBlock); -+ if (tillable == null) { return InteractionResult.PASS; } else { -+ Predicate predicate = tillable.condition().predicate(); -+ Consumer consumer = (ctx) -> { -+ level.setBlock(blockPos, tillable.into().defaultBlockState(), 11); -+ tillable.drops().forEach((drop, chance) -> { -+ if (level.random.nextDouble() < chance) { -+ Block.popResourceFromFace(level, blockPos, ctx.getClickedFace(), new ItemStack(drop)); -+ } -+ }); -+ }; -+ // Purpur end - if (predicate.test(context)) { - Player player = context.getPlayer(); -- level.playSound(player, blockPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F); -+ if (!TILLABLES.containsKey(clickedBlock)) level.playSound(null, blockPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound - if (!level.isClientSide) { - consumer.accept(context); - if (player != null) { -@@ -62,7 +70,7 @@ public class HoeItem extends DiggerItem { - } - } - -- return InteractionResult.sidedSuccess(level.isClientSide); -+ return InteractionResult.SUCCESS; // Purpur - force arm swing - } else { - return InteractionResult.PASS; - } -diff --git a/src/main/java/net/minecraft/world/item/ShovelItem.java b/src/main/java/net/minecraft/world/item/ShovelItem.java -index 24f6a158e4759aac3be8da4cf5e0d40bd295355b..6b7dbb570f8a698c87c6bce992d84d87b55176e6 100644 ---- a/src/main/java/net/minecraft/world/item/ShovelItem.java -+++ b/src/main/java/net/minecraft/world/item/ShovelItem.java -@@ -47,9 +47,12 @@ public class ShovelItem extends DiggerItem { - BlockState blockState2 = FLATTENABLES.get(blockState.getBlock()); - BlockState blockState3 = null; - Runnable afterAction = null; // Paper -- if (blockState2 != null && level.getBlockState(blockPos.above()).isAir()) { -- afterAction = () -> level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper -- blockState3 = blockState2; -+ // Purpur start -+ var flattenable = level.purpurConfig.shovelFlattenables.get(blockState.getBlock()); -+ if (flattenable != null && level.getBlockState(blockPos.above()).isAir()) { -+ afterAction = () -> {if (!FLATTENABLES.containsKey(blockState.getBlock())) level.playSound(null, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F);}; // Paper -+ blockState3 = flattenable.into().defaultBlockState(); -+ // Purpur end - } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { - afterAction = () -> { // Paper - if (!level.isClientSide()) { -@@ -76,7 +79,7 @@ public class ShovelItem extends DiggerItem { - } - } - -- return InteractionResult.sidedSuccess(level.isClientSide); -+ return InteractionResult.SUCCESS; // Purpur - force arm swing - } else { - return InteractionResult.PASS; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index a9a2b09b985e3e4eb69d4ae16dfd40f46be936d6..e653a0cf4a4350d0faac21fab7681863fe2c75e0 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -504,6 +504,280 @@ public class PurpurWorldConfig { - snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); - } - -+ public Map axeStrippables = new HashMap<>(); -+ public Map axeWaxables = new HashMap<>(); -+ public Map axeWeatherables = new HashMap<>(); -+ public Map hoeTillables = new HashMap<>(); -+ public Map shovelFlattenables = new HashMap<>(); -+ private void toolSettings() { -+ axeStrippables.clear(); -+ axeWaxables.clear(); -+ axeWeatherables.clear(); -+ hoeTillables.clear(); -+ shovelFlattenables.clear(); -+ if (PurpurConfig.version < 18) { -+ ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + ".tools.hoe.tilling"); -+ if (section != null) { -+ PurpurConfig.config.set("world-settings." + worldName + ".tools.hoe.tillables", section); -+ PurpurConfig.config.set("world-settings." + worldName + ".tools.hoe.tilling", null); -+ } -+ section = PurpurConfig.config.getConfigurationSection("world-settings.default.tools.hoe.tilling"); -+ if (section != null) { -+ PurpurConfig.config.set("world-settings.default.tools.hoe.tillables", section); -+ PurpurConfig.config.set("world-settings.default.tools.hoe.tilling", null); -+ } -+ } -+ if (PurpurConfig.version < 29) { -+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:mangrove_log", Map.of("into", "minecraft:stripped_mangrove_log", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:mangrove_wood", Map.of("into", "minecraft:stripped_mangrove_wood", "drops", new HashMap())); -+ } -+ if (PurpurConfig.version < 32) { -+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:cherry_log", Map.of("into", "minecraft:stripped_cherry_log", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:cherry_wood", Map.of("into", "minecraft:stripped_cherry_wood", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:bamboo_block", Map.of("into", "minecraft:stripped_bamboo_block", "drops", new HashMap())); -+ } -+ if (PurpurConfig.version < 33) { -+ getList("gameplay-mechanics.shovel-turns-block-to-grass-path", new ArrayList(){{ -+ add("minecraft:coarse_dirt"); -+ add("minecraft:dirt"); -+ add("minecraft:grass_block"); -+ add("minecraft:mycelium"); -+ add("minecraft:podzol"); -+ add("minecraft:rooted_dirt"); -+ }}).forEach(key -> { -+ PurpurConfig.config.set("world-settings.default.tools.shovel.flattenables." + key.toString(), Map.of("into", "minecraft:dirt_path", "drops", new HashMap())); -+ }); -+ set("gameplay-mechanics.shovel-turns-block-to-grass-path", null); -+ } -+ if (PurpurConfig.version < 34) { -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_chiseled_copper", Map.of("into", "minecraft:oxidized_chiseled_copper", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_door", Map.of("into", "minecraft:oxidized_copper_door", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_trapdoor", Map.of("into", "minecraft:oxidized_copper_trapdoor", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_grate", Map.of("into", "minecraft:oxidized_copper_grate", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_bulb", Map.of("into", "minecraft:oxidized_copper_bulb", "drops", new HashMap())); -+ -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap())); -+ PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap())); -+ } -+ getMap("tools.axe.strippables", Map.ofEntries( -+ Map.entry("minecraft:oak_wood", Map.of("into", "minecraft:stripped_oak_wood", "drops", new HashMap())), -+ Map.entry("minecraft:oak_log", Map.of("into", "minecraft:stripped_oak_log", "drops", new HashMap())), -+ Map.entry("minecraft:dark_oak_wood", Map.of("into", "minecraft:stripped_dark_oak_wood", "drops", new HashMap())), -+ Map.entry("minecraft:dark_oak_log", Map.of("into", "minecraft:stripped_dark_oak_log", "drops", new HashMap())), -+ Map.entry("minecraft:acacia_wood", Map.of("into", "minecraft:stripped_acacia_wood", "drops", new HashMap())), -+ Map.entry("minecraft:acacia_log", Map.of("into", "minecraft:stripped_acacia_log", "drops", new HashMap())), -+ Map.entry("minecraft:birch_wood", Map.of("into", "minecraft:stripped_birch_wood", "drops", new HashMap())), -+ Map.entry("minecraft:birch_log", Map.of("into", "minecraft:stripped_birch_log", "drops", new HashMap())), -+ Map.entry("minecraft:jungle_wood", Map.of("into", "minecraft:stripped_jungle_wood", "drops", new HashMap())), -+ Map.entry("minecraft:jungle_log", Map.of("into", "minecraft:stripped_jungle_log", "drops", new HashMap())), -+ Map.entry("minecraft:spruce_wood", Map.of("into", "minecraft:stripped_spruce_wood", "drops", new HashMap())), -+ Map.entry("minecraft:spruce_log", Map.of("into", "minecraft:stripped_spruce_log", "drops", new HashMap())), -+ Map.entry("minecraft:mangrove_wood", Map.of("into", "minecraft:stripped_mangrove_wood", "drops", new HashMap())), -+ Map.entry("minecraft:mangrove_log", Map.of("into", "minecraft:stripped_mangrove_log", "drops", new HashMap())), -+ Map.entry("minecraft:cherry_log", Map.of("into", "minecraft:stripped_cherry_log", "drops", new HashMap())), -+ Map.entry("minecraft:cherry_wood", Map.of("into", "minecraft:stripped_cherry_wood", "drops", new HashMap())), -+ Map.entry("minecraft:bamboo_block", Map.of("into", "minecraft:stripped_bamboo_block", "drops", new HashMap())), -+ Map.entry("minecraft:warped_stem", Map.of("into", "minecraft:stripped_warped_stem", "drops", new HashMap())), -+ Map.entry("minecraft:warped_hyphae", Map.of("into", "minecraft:stripped_warped_hyphae", "drops", new HashMap())), -+ Map.entry("minecraft:crimson_stem", Map.of("into", "minecraft:stripped_crimson_stem", "drops", new HashMap())), -+ Map.entry("minecraft:crimson_hyphae", Map.of("into", "minecraft:stripped_crimson_hyphae", "drops", new HashMap()))) -+ ).forEach((blockId, obj) -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockId)); -+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.strippables`: " + blockId); return; } -+ if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.strippables." + blockId + "`"); return; } -+ String intoId = (String) map.get("into"); -+ Block into = BuiltInRegistries.BLOCK.get(new ResourceLocation(intoId)); -+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.strippables." + blockId + ".into`: " + intoId); return; } -+ Object dropsObj = map.get("drops"); -+ if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.strippables." + blockId + ".drops`"); return; } -+ Map drops = new HashMap<>(); -+ dropsMap.forEach((itemId, chance) -> { -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(itemId.toString())); -+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.strippables." + blockId + ".drops`: " + itemId); return; } -+ drops.put(item, (double) chance); -+ }); -+ axeStrippables.put(block, new Strippable(into, drops)); -+ }); -+ getMap("tools.axe.waxables", Map.ofEntries( -+ Map.entry("minecraft:waxed_copper_block", Map.of("into", "minecraft:copper_block", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_copper", Map.of("into", "minecraft:exposed_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_copper", Map.of("into", "minecraft:weathered_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_copper", Map.of("into", "minecraft:oxidized_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_cut_copper", Map.of("into", "minecraft:cut_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_cut_copper", Map.of("into", "minecraft:exposed_cut_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_cut_copper", Map.of("into", "minecraft:weathered_cut_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_cut_copper", Map.of("into", "minecraft:oxidized_cut_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_cut_copper_slab", Map.of("into", "minecraft:cut_copper_slab", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_cut_copper_slab", Map.of("into", "minecraft:exposed_cut_copper_slab", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_cut_copper_slab", Map.of("into", "minecraft:weathered_cut_copper_slab", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_cut_copper_slab", Map.of("into", "minecraft:oxidized_cut_copper_slab", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_cut_copper_stairs", Map.of("into", "minecraft:cut_copper_stairs", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_cut_copper_stairs", Map.of("into", "minecraft:exposed_cut_copper_stairs", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_cut_copper_stairs", Map.of("into", "minecraft:oxidized_cut_copper_stairs", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_chiseled_copper", Map.of("into", "minecraft:oxidized_chiseled_copper", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_copper_door", Map.of("into", "minecraft:oxidized_copper_door", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_copper_trapdoor", Map.of("into", "minecraft:oxidized_copper_trapdoor", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_copper_grate", Map.of("into", "minecraft:oxidized_copper_grate", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_exposed_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_weathered_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap())), -+ Map.entry("minecraft:waxed_oxidized_copper_bulb", Map.of("into", "minecraft:oxidized_copper_bulb", "drops", new HashMap()))) -+ ).forEach((blockId, obj) -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockId)); -+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.waxables`: " + blockId); return; } -+ if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.waxables." + blockId + "`"); return; } -+ String intoId = (String) map.get("into"); -+ Block into = BuiltInRegistries.BLOCK.get(new ResourceLocation(intoId)); -+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.waxables." + blockId + ".into`: " + intoId); return; } -+ Object dropsObj = map.get("drops"); -+ if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.waxables." + blockId + ".drops`"); return; } -+ Map drops = new HashMap<>(); -+ dropsMap.forEach((itemId, chance) -> { -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(itemId.toString())); -+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.waxables." + blockId + ".drops`: " + itemId); return; } -+ drops.put(item, (double) chance); -+ }); -+ axeWaxables.put(block, new Waxable(into, drops)); -+ }); -+ getMap("tools.axe.weatherables", Map.ofEntries( -+ Map.entry("minecraft:exposed_copper", Map.of("into", "minecraft:copper_block", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_copper", Map.of("into", "minecraft:exposed_copper", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_copper", Map.of("into", "minecraft:weathered_copper", "drops", new HashMap())), -+ Map.entry("minecraft:exposed_cut_copper", Map.of("into", "minecraft:cut_copper", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_cut_copper", Map.of("into", "minecraft:exposed_cut_copper", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_cut_copper", Map.of("into", "minecraft:weathered_cut_copper", "drops", new HashMap())), -+ Map.entry("minecraft:exposed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap())), -+ Map.entry("minecraft:exposed_cut_copper_slab", Map.of("into", "minecraft:cut_copper_slab", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_cut_copper_slab", Map.of("into", "minecraft:exposed_cut_copper_slab", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_cut_copper_slab", Map.of("into", "minecraft:weathered_cut_copper_slab", "drops", new HashMap())), -+ Map.entry("minecraft:exposed_cut_copper_stairs", Map.of("into", "minecraft:cut_copper_stairs", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_cut_copper_stairs", Map.of("into", "minecraft:exposed_cut_copper_stairs", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap())), -+ Map.entry("minecraft:exposed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap())), -+ Map.entry("minecraft:exposed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap())), -+ Map.entry("minecraft:exposed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap())), -+ Map.entry("minecraft:exposed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap())), -+ Map.entry("minecraft:weathered_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap())), -+ Map.entry("minecraft:oxidized_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap()))) -+ ).forEach((blockId, obj) -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockId)); -+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.weatherables`: " + blockId); return; } -+ if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.weatherables." + blockId + "`"); return; } -+ String intoId = (String) map.get("into"); -+ Block into = BuiltInRegistries.BLOCK.get(new ResourceLocation(intoId)); -+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.weatherables." + blockId + ".into`: " + intoId); return; } -+ Object dropsObj = map.get("drops"); -+ if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.weatherables." + blockId + ".drops`"); return; } -+ Map drops = new HashMap<>(); -+ dropsMap.forEach((itemId, chance) -> { -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(itemId.toString())); -+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.weatherables." + blockId + ".drops`: " + itemId); return; } -+ drops.put(item, (double) chance); -+ }); -+ axeWeatherables.put(block, new Weatherable(into, drops)); -+ }); -+ getMap("tools.hoe.tillables", Map.ofEntries( -+ Map.entry("minecraft:grass_block", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap())), -+ Map.entry("minecraft:dirt_path", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap())), -+ Map.entry("minecraft:dirt", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap())), -+ Map.entry("minecraft:coarse_dirt", Map.of("condition", "air_above", "into", "minecraft:dirt", "drops", new HashMap())), -+ Map.entry("minecraft:rooted_dirt", Map.of("condition", "always", "into", "minecraft:dirt", "drops", Map.of("minecraft:hanging_roots", 1.0D)))) -+ ).forEach((blockId, obj) -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockId)); -+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.hoe.tillables`: " + blockId); return; } -+ if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.hoe.tillables." + blockId + "`"); return; } -+ String conditionId = (String) map.get("condition"); -+ Tillable.Condition condition = Tillable.Condition.get(conditionId); -+ if (condition == null) { PurpurConfig.log(Level.SEVERE, "Invalid condition for `tools.hoe.tillables." + blockId + ".condition`: " + conditionId); return; } -+ String intoId = (String) map.get("into"); -+ Block into = BuiltInRegistries.BLOCK.get(new ResourceLocation(intoId)); -+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.hoe.tillables." + blockId + ".into`: " + intoId); return; } -+ Object dropsObj = map.get("drops"); -+ if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.hoe.tillables." + blockId + ".drops`"); return; } -+ Map drops = new HashMap<>(); -+ dropsMap.forEach((itemId, chance) -> { -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(itemId.toString())); -+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.hoe.tillables." + blockId + ".drops`: " + itemId); return; } -+ drops.put(item, (double) chance); -+ }); -+ hoeTillables.put(block, new Tillable(condition, into, drops)); -+ }); -+ getMap("tools.shovel.flattenables", Map.ofEntries( -+ Map.entry("minecraft:grass_block", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), -+ Map.entry("minecraft:dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), -+ Map.entry("minecraft:podzol", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), -+ Map.entry("minecraft:coarse_dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), -+ Map.entry("minecraft:mycelium", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), -+ Map.entry("minecraft:rooted_dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap()))) -+ ).forEach((blockId, obj) -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockId)); -+ if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.shovel.flattenables`: " + blockId); return; } -+ if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.shovel.flattenables." + blockId + "`"); return; } -+ String intoId = (String) map.get("into"); -+ Block into = BuiltInRegistries.BLOCK.get(new ResourceLocation(intoId)); -+ if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.shovel.flattenables." + blockId + ".into`: " + intoId); return; } -+ Object dropsObj = map.get("drops"); -+ if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.shovel.flattenables." + blockId + ".drops`"); return; } -+ Map drops = new HashMap<>(); -+ dropsMap.forEach((itemId, chance) -> { -+ Item item = BuiltInRegistries.ITEM.get(new ResourceLocation(itemId.toString())); -+ if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.shovel.flattenables." + blockId + ".drops`: " + itemId); return; } -+ drops.put(item, (double) chance); -+ }); -+ shovelFlattenables.put(block, new Flattenable(into, drops)); -+ }); -+ } -+ - public boolean anvilAllowColors = false; - public boolean anvilColorsUseMiniMessage; - private void anvilSettings() { -diff --git a/src/main/java/org/purpurmc/purpur/tool/Actionable.java b/src/main/java/org/purpurmc/purpur/tool/Actionable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e18c37f06730da9d3055d5215e813b1477c1e70e ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/tool/Actionable.java -@@ -0,0 +1,24 @@ -+package org.purpurmc.purpur.tool; -+ -+import net.minecraft.world.item.Item; -+import net.minecraft.world.level.block.Block; -+ -+import java.util.Map; -+ -+public abstract class Actionable { -+ private final Block into; -+ private final Map drops; -+ -+ public Actionable(Block into, Map drops) { -+ this.into = into; -+ this.drops = drops; -+ } -+ -+ public Block into() { -+ return into; -+ } -+ -+ public Map drops() { -+ return drops; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/tool/Flattenable.java b/src/main/java/org/purpurmc/purpur/tool/Flattenable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..345d4ee4ff0b78bd1050959711a4f5d16a5e8aee ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/tool/Flattenable.java -@@ -0,0 +1,12 @@ -+package org.purpurmc.purpur.tool; -+ -+import net.minecraft.world.item.Item; -+import net.minecraft.world.level.block.Block; -+ -+import java.util.Map; -+ -+public class Flattenable extends Actionable { -+ public Flattenable(Block into, Map drops) { -+ super(into, drops); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/tool/Strippable.java b/src/main/java/org/purpurmc/purpur/tool/Strippable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bf5402214f41af9c09bd6c5c4f45d330516d742e ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/tool/Strippable.java -@@ -0,0 +1,12 @@ -+package org.purpurmc.purpur.tool; -+ -+import net.minecraft.world.item.Item; -+import net.minecraft.world.level.block.Block; -+ -+import java.util.Map; -+ -+public class Strippable extends Actionable { -+ public Strippable(Block into, Map drops) { -+ super(into, drops); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/tool/Tillable.java b/src/main/java/org/purpurmc/purpur/tool/Tillable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..715f6dd44480347eebced43c11bc364e05727498 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/tool/Tillable.java -@@ -0,0 +1,50 @@ -+package org.purpurmc.purpur.tool; -+ -+import net.minecraft.world.item.HoeItem; -+import net.minecraft.world.item.Item; -+import net.minecraft.world.item.context.UseOnContext; -+import net.minecraft.world.level.block.Block; -+ -+import java.util.HashMap; -+import java.util.Map; -+import java.util.function.Predicate; -+ -+public class Tillable extends Actionable { -+ private final Condition condition; -+ -+ public Tillable(Condition condition, Block into, Map drops) { -+ super(into, drops); -+ this.condition = condition; -+ } -+ -+ public Condition condition() { -+ return condition; -+ } -+ -+ public enum Condition { -+ AIR_ABOVE(HoeItem::onlyIfAirAbove), -+ ALWAYS((useOnContext) -> true); -+ -+ private final Predicate predicate; -+ -+ Condition(Predicate predicate) { -+ this.predicate = predicate; -+ } -+ -+ public Predicate predicate() { -+ return predicate; -+ } -+ -+ private static final Map BY_NAME = new HashMap<>(); -+ -+ static { -+ for (Condition condition : values()) { -+ BY_NAME.put(condition.name(), condition); -+ } -+ } -+ -+ public static Condition get(String name) { -+ return BY_NAME.get(name.toUpperCase(java.util.Locale.ROOT)); -+ } -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/tool/Waxable.java b/src/main/java/org/purpurmc/purpur/tool/Waxable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..64adb13b29b6757dcf227a55588da70ecabe083f ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/tool/Waxable.java -@@ -0,0 +1,12 @@ -+package org.purpurmc.purpur.tool; -+ -+import net.minecraft.world.item.Item; -+import net.minecraft.world.level.block.Block; -+ -+import java.util.Map; -+ -+public class Waxable extends Actionable { -+ public Waxable(Block into, Map drops) { -+ super(into, drops); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/tool/Weatherable.java b/src/main/java/org/purpurmc/purpur/tool/Weatherable.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b7586f494528f30eb0da82420d3bcf5b83a1a902 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/tool/Weatherable.java -@@ -0,0 +1,12 @@ -+package org.purpurmc.purpur.tool; -+ -+import net.minecraft.world.item.Item; -+import net.minecraft.world.level.block.Block; -+ -+import java.util.Map; -+ -+public class Weatherable extends Actionable { -+ public Weatherable(Block into, Map drops) { -+ super(into, drops); -+ } -+} diff --git a/patches/server/0183-Store-placer-on-Block-when-placed.patch b/patches/server/0183-Store-placer-on-Block-when-placed.patch deleted file mode 100644 index eaf73e694..000000000 --- a/patches/server/0183-Store-placer-on-Block-when-placed.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Jul 2021 18:40:32 -0500 -Subject: [PATCH] Store placer on Block when placed - - -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 1b829ad61a25ef1e18adefe291d91fdb7401956d..f93cb39c2664b74066bd9ac352137c11e612e5f9 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -475,6 +475,7 @@ public final class ItemStack implements DataComponentHolder { - world.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710 - for (BlockState blockstate : blocks) { - blockstate.update(true, false); -+ ((CraftBlock) blockstate.getBlock()).getNMS().getBlock().forgetPlacer(); // Purpur - } - world.preventPoiUpdated = false; - -@@ -506,6 +507,7 @@ public final class ItemStack implements DataComponentHolder { - if (!(block.getBlock() instanceof BaseEntityBlock)) { // Containers get placed automatically - block.onPlace(world, newblockposition, oldBlock, true, context); // Paper - pass context - } -+ block.getBlock().forgetPlacer(); // Purpur - - world.notifyAndUpdatePhysics(newblockposition, null, oldBlock, block, world.getBlockState(newblockposition), updateFlag, 512); // send null chunk as chunk.k() returns false by this point - } -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index cf8b8c8efd1c9c81eb5f02d75bd75875eb66771f..6f7e90d406b088fee0eb254f8042bd404d8f36fa 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -438,7 +438,17 @@ public class Block extends BlockBehaviour implements ItemLike { - } // Paper - fix drops not preventing stats/food exhaustion - } - -- public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {} -+ // Purpur start -+ @Nullable protected LivingEntity placer = null; -+ -+ public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) { -+ this.placer = placer; -+ } -+ -+ public void forgetPlacer() { -+ this.placer = null; -+ } -+ // Purpur end - - public boolean isPossibleToRespawnInThis(BlockState state) { - return !state.isSolid() && !state.liquid(); diff --git a/patches/server/0184-Summoner-API.patch b/patches/server/0184-Summoner-API.patch deleted file mode 100644 index a269522e4..000000000 --- a/patches/server/0184-Summoner-API.patch +++ /dev/null @@ -1,255 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Jul 2021 18:40:58 -0500 -Subject: [PATCH] Summoner API - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -index fa81b12fc38a20b8ec39155259fb75c18ff9f0ae..8b08476457a6ead1a3c3e2ab35d08a8e0625c43e 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -@@ -56,6 +56,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - private int remainingPersistentAngerTime; - @Nullable - private UUID persistentAngerTarget; -+ @Nullable private UUID summoner; // Purpur - - public IronGolem(EntityType type, Level world) { - super(type, world); -@@ -88,6 +89,15 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - return this.level().purpurConfig.ironGolemTakeDamageFromWater; - } - -+ @Nullable -+ public UUID getSummoner() { -+ return summoner; -+ } -+ -+ public void setSummoner(@Nullable UUID summoner) { -+ this.summoner = summoner; -+ } -+ - @Override - protected void registerGoals() { - if (level().purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur -@@ -165,6 +175,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); - nbt.putBoolean("PlayerCreated", this.isPlayerCreated()); -+ if (getSummoner() != null) nbt.putUUID("Purpur.Summoner", getSummoner()); // Purpur - this.addPersistentAngerSaveData(nbt); - } - -@@ -172,6 +183,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - this.setPlayerCreated(nbt.getBoolean("PlayerCreated")); -+ if (nbt.contains("Purpur.Summoner")) setSummoner(nbt.getUUID("Purpur.Summoner")); // Purpur - this.readPersistentAngerSaveData(this.level(), nbt); - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index 9f20eae7449c670b913cc3bbe1a89254a1d8cde2..8f2348a7fe830a85985ce2b19cb2a9159bca711f 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -47,6 +47,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - - private static final EntityDataAccessor DATA_PUMPKIN_ID = SynchedEntityData.defineId(SnowGolem.class, EntityDataSerializers.BYTE); - private static final byte PUMPKIN_FLAG = 16; -+ @Nullable private java.util.UUID summoner; // Purpur - - public SnowGolem(EntityType type, Level world) { - super(type, world); -@@ -74,6 +75,15 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.snowGolemMaxHealth); - } - -+ @Nullable -+ public java.util.UUID getSummoner() { -+ return summoner; -+ } -+ -+ public void setSummoner(@Nullable java.util.UUID summoner) { -+ this.summoner = summoner; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -@@ -101,6 +111,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); - nbt.putBoolean("Pumpkin", this.hasPumpkin()); -+ if (getSummoner() != null) nbt.putUUID("Purpur.Summoner", getSummoner()); // Purpur - } - - @Override -@@ -109,6 +120,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - if (nbt.contains("Pumpkin")) { - this.setPumpkin(nbt.getBoolean("Pumpkin")); - } -+ if (nbt.contains("Purpur.Summoner")) setSummoner(nbt.getUUID("Purpur.Summoner")); // Purpur - - } - -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 6752a0039fac041e9bdd25327cdf20d3f1922bd6..01d193d2584b62897687bd088fb590de8a4ab279 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -88,6 +88,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - return !entityliving.getType().is(EntityTypeTags.WITHER_FRIENDS) && entityliving.attackable(); - }; - private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0D).selector(WitherBoss.LIVING_ENTITY_SELECTOR); -+ @Nullable private java.util.UUID summoner; // Purpur - private int shootCooldown = 0; // Purpur - // Paper start - private boolean canPortal = false; -@@ -126,6 +127,15 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - return this.level().purpurConfig.witherTakeDamageFromWater; - } - -+ @Nullable -+ public java.util.UUID getSummoner() { -+ return summoner; -+ } -+ -+ public void setSummoner(@Nullable java.util.UUID summoner) { -+ this.summoner = summoner; -+ } -+ - @Override - protected PathNavigation createNavigation(Level world) { - FlyingPathNavigation navigationflying = new FlyingPathNavigation(this, world); -@@ -260,6 +270,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); - nbt.putInt("Invul", this.getInvulnerableTicks()); -+ if (getSummoner() != null) nbt.putUUID("Purpur.Summoner", getSummoner()); // Purpur - } - - @Override -@@ -269,6 +280,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - if (this.hasCustomName()) { - this.bossEvent.setName(this.getDisplayName()); - } -+ if (nbt.contains("Purpur.Summoner")) setSummoner(nbt.getUUID("Purpur.Summoner")); // Purpur - - } - -diff --git a/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java b/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java -index 655f51902e5d24643d41c4ec981743543c0890a5..e6a299eeda5d18274fa3b1fb542b217a074c1d83 100644 ---- a/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CarvedPumpkinBlock.java -@@ -71,7 +71,7 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock { - SnowGolem entitysnowman = (SnowGolem) EntityType.SNOW_GOLEM.create(world); - - if (entitysnowman != null) { -- CarvedPumpkinBlock.spawnGolemInWorld(world, shapedetector_shapedetectorcollection, entitysnowman, shapedetector_shapedetectorcollection.getBlock(0, 2, 0).getPos()); -+ CarvedPumpkinBlock.spawnGolemInWorld(world, shapedetector_shapedetectorcollection, entitysnowman, shapedetector_shapedetectorcollection.getBlock(0, 2, 0).getPos(), this.placer); // Purpur - } - } else { - BlockPattern.BlockPatternMatch shapedetector_shapedetectorcollection1 = this.getOrCreateIronGolemFull().find(world, pos); -@@ -81,7 +81,7 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock { - - if (entityirongolem != null) { - entityirongolem.setPlayerCreated(true); -- CarvedPumpkinBlock.spawnGolemInWorld(world, shapedetector_shapedetectorcollection1, entityirongolem, shapedetector_shapedetectorcollection1.getBlock(1, 2, 0).getPos()); -+ CarvedPumpkinBlock.spawnGolemInWorld(world, shapedetector_shapedetectorcollection1, entityirongolem, shapedetector_shapedetectorcollection1.getBlock(1, 2, 0).getPos(), this.placer); // Purpur - } - } - } -@@ -89,6 +89,16 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock { - } - - private static void spawnGolemInWorld(Level world, BlockPattern.BlockPatternMatch patternResult, Entity entity, BlockPos pos) { -+ // Purpur start -+ spawnGolemInWorld(world, patternResult, entity, pos, null); -+ } -+ private static void spawnGolemInWorld(Level world, BlockPattern.BlockPatternMatch patternResult, Entity entity, BlockPos pos, net.minecraft.world.entity.LivingEntity placer) { -+ if (entity instanceof SnowGolem snowGolem) { -+ snowGolem.setSummoner(placer == null ? null : placer.getUUID()); -+ } else if (entity instanceof IronGolem ironGolem) { -+ ironGolem.setSummoner(placer == null ? null : placer.getUUID()); -+ } -+ // Purpur end - // clearPatternBlocks(world, shapedetector_shapedetectorcollection); // CraftBukkit - moved down - entity.moveTo((double) pos.getX() + 0.5D, (double) pos.getY() + 0.05D, (double) pos.getZ() + 0.5D, 0.0F, 0.0F); - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java b/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java -index bbf59b2577812e74ffd45f694b83a42e043273c0..5cb06959aeaceeb98cfee34b1df804e6642f305f 100644 ---- a/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java -@@ -79,6 +79,7 @@ public class WitherSkullBlock extends SkullBlock { - entitywither.moveTo((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.55D, (double) blockposition1.getZ() + 0.5D, shapedetector_shapedetectorcollection.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F, 0.0F); - entitywither.yBodyRot = shapedetector_shapedetectorcollection.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F; - entitywither.makeInvulnerable(); -+ entitywither.setSummoner(iblockdata.getBlock().placer == null ? null : iblockdata.getBlock().placer.getUUID()); // Purpur - // CraftBukkit start - if (!world.addFreshEntity(entitywither, SpawnReason.BUILD_WITHER)) { - return; -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java -index 63cae1a2e95d8da17c45c4404a8dd0ca6a413c39..966587c2788b5c93be83259ddc962a89cde7cbaa 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java -@@ -27,4 +27,17 @@ public class CraftIronGolem extends CraftGolem implements IronGolem { - public void setPlayerCreated(boolean playerCreated) { - this.getHandle().setPlayerCreated(playerCreated); - } -+ -+ // Purpur start -+ @Override -+ @org.jetbrains.annotations.Nullable -+ public java.util.UUID getSummoner() { -+ return getHandle().getSummoner(); -+ } -+ -+ @Override -+ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) { -+ getHandle().setSummoner(summoner); -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java -index 4ce2373ff71c3c1b8951646e057587a3ab09e145..4f7f6cf6ca24406570d2d29dc63dc89401119961 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java -@@ -28,4 +28,17 @@ public class CraftSnowman extends CraftGolem implements Snowman, com.destroystok - public String toString() { - return "CraftSnowman"; - } -+ -+ // Purpur start -+ @Override -+ @org.jetbrains.annotations.Nullable -+ public java.util.UUID getSummoner() { -+ return getHandle().getSummoner(); -+ } -+ -+ @Override -+ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) { -+ getHandle().setSummoner(summoner); -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java -index 7a8ce6956db56061af93ba9761f5d1057a90bc49..6d286b23806666f7b00ac88c5922144649f8a041 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java -@@ -99,4 +99,17 @@ public class CraftWither extends CraftMonster implements Wither, com.destroystok - this.getHandle().makeInvulnerable(); - } - // Paper end -+ -+ // Purpur start -+ @Override -+ @org.jetbrains.annotations.Nullable -+ public java.util.UUID getSummoner() { -+ return getHandle().getSummoner(); -+ } -+ -+ @Override -+ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) { -+ getHandle().setSummoner(summoner); -+ } -+ // Purpur end - } diff --git a/patches/server/0185-Customizable-sleeping-actionbar-messages.patch b/patches/server/0185-Customizable-sleeping-actionbar-messages.patch deleted file mode 100644 index 2834d4aee..000000000 --- a/patches/server/0185-Customizable-sleeping-actionbar-messages.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 3 Jul 2021 21:52:15 -0500 -Subject: [PATCH] Customizable sleeping actionbar messages - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 1dc58b41d3963c2adc58e79cd6db7e146ac049ad..83ec2e31d81d6209953252a3780552c3cf110c68 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1231,11 +1231,27 @@ public class ServerLevel extends Level implements WorldGenLevel { - if (this.canSleepThroughNights()) { - if (!this.getServer().isSingleplayer() || this.getServer().isPublished()) { - int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); -- MutableComponent ichatmutablecomponent; -+ Component ichatmutablecomponent; - - if (this.sleepStatus.areEnoughSleeping(i)) { -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.isBlank()) { -+ return; -+ } -+ if (!org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.equalsIgnoreCase("default")) { -+ ichatmutablecomponent = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepSkippingNight)); -+ } else - ichatmutablecomponent = Component.translatable("sleep.skipping_night"); - } else { -+ if (org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.isBlank()) { -+ return; -+ } -+ if (!org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.equalsIgnoreCase("default")) { -+ ichatmutablecomponent = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent, -+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("count", Integer.toString(this.sleepStatus.amountSleeping())), -+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("total", Integer.toString(this.sleepStatus.sleepersNeeded(i))))); -+ } else -+ // Purpur end - ichatmutablecomponent = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(i)); - } - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 2b10087cf34be4c36d8596d0263d68476bb1a521..7bb82c9b652a509c2bf1a43ed82a5da709fb2cb2 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1546,7 +1546,19 @@ public class ServerPlayer extends Player { - }); - - if (!this.serverLevel().canSleepThroughNights()) { -- this.displayClientMessage(Component.translatable("sleep.not_possible"), true); -+ // Purpur start -+ Component clientMessage; -+ if (org.purpurmc.purpur.PurpurConfig.sleepNotPossible.isBlank()) { -+ clientMessage = null; -+ } else if (!org.purpurmc.purpur.PurpurConfig.sleepNotPossible.equalsIgnoreCase("default")) { -+ clientMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepNotPossible)); -+ } else { -+ clientMessage = Component.translatable("sleep.not_possible"); -+ } -+ if (clientMessage != null) { -+ this.displayClientMessage(clientMessage, true); -+ } -+ // Purpur end - } - - ((ServerLevel) this.level()).updateSleepingPlayerList(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 16239aafded82b4f19f97ae5fd87c53b55a5ef53..e4188163e7a9dda878e72ae84a1b5cb28c23510d 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -186,6 +186,9 @@ public class PurpurConfig { - public static String dontRunWithScissors = "Don't run with scissors!"; - public static String uptimeCommandOutput = "Server uptime is "; - public static String unverifiedUsername = "default"; -+ public static String sleepSkippingNight = "default"; -+ public static String sleepingPlayersPercent = "default"; -+ public static String sleepNotPossible = "default"; - private static void messages() { - cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); - afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); -@@ -200,6 +203,9 @@ public class PurpurConfig { - dontRunWithScissors = getString("settings.messages.dont-run-with-scissors", dontRunWithScissors); - uptimeCommandOutput = getString("settings.messages.uptime-command-output", uptimeCommandOutput); - unverifiedUsername = getString("settings.messages.unverified-username", unverifiedUsername); -+ sleepSkippingNight = getString("settings.messages.sleep-skipping-night", sleepSkippingNight); -+ sleepingPlayersPercent = getString("settings.messages.sleeping-players-percent", sleepingPlayersPercent); -+ sleepNotPossible = getString("settings.messages.sleep-not-possible", sleepNotPossible); - } - - public static String deathMsgRunWithScissors = " slipped and fell on their shears"; diff --git a/patches/server/0186-option-to-disable-shulker-box-items-from-dropping-co.patch b/patches/server/0186-option-to-disable-shulker-box-items-from-dropping-co.patch deleted file mode 100644 index d14d88490..000000000 --- a/patches/server/0186-option-to-disable-shulker-box-items-from-dropping-co.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 5 Jul 2021 20:23:08 -0500 -Subject: [PATCH] option to disable shulker box items from dropping contents - when destroyed - - -diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index 3253361d91e2a2e68d354eaf3dd3e3cd486e191d..2649188930653610b8aaaeb18797c80879cd572a 100644 ---- a/src/main/java/net/minecraft/world/item/BlockItem.java -+++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -260,6 +260,7 @@ public class BlockItem extends Item { - ItemContainerContents itemcontainercontents = (ItemContainerContents) entity.getItem().set(DataComponents.CONTAINER, ItemContainerContents.EMPTY); - - if (itemcontainercontents != null) { -+ if (entity.level().purpurConfig.shulkerBoxItemDropContentsWhenDestroyed && entity.getItem().is(Items.SHULKER_BOX)) // Purpur - ItemUtils.onContainerDestroyed(entity, itemcontainercontents.nonEmptyItemsCopy()); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e653a0cf4a4350d0faac21fab7681863fe2c75e0..2a05ee4d6d609fb0ab1837d2add45ffba68603fe 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -221,6 +221,7 @@ public class PurpurWorldConfig { - public int enderPearlCooldownCreative = 20; - public float enderPearlEndermiteChance = 0.05F; - public int glowBerriesEatGlowDuration = 0; -+ public boolean shulkerBoxItemDropContentsWhenDestroyed = true; - private void itemSettings() { - itemImmuneToCactus.clear(); - getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { -@@ -267,6 +268,7 @@ public class PurpurWorldConfig { - enderPearlCooldownCreative = getInt("gameplay-mechanics.item.ender-pearl.creative-cooldown", enderPearlCooldownCreative); - enderPearlEndermiteChance = (float) getDouble("gameplay-mechanics.item.ender-pearl.endermite-spawn-chance", enderPearlEndermiteChance); - glowBerriesEatGlowDuration = getInt("gameplay-mechanics.item.glow_berries.eat-glow-duration", glowBerriesEatGlowDuration); -+ shulkerBoxItemDropContentsWhenDestroyed = getBoolean("gameplay-mechanics.item.shulker_box.drop-contents-when-destroyed", shulkerBoxItemDropContentsWhenDestroyed); - } - - public double minecartMaxSpeed = 0.4D; diff --git a/patches/server/0187-Big-dripleaf-tilt-delay.patch b/patches/server/0187-Big-dripleaf-tilt-delay.patch deleted file mode 100644 index 5161c5006..000000000 --- a/patches/server/0187-Big-dripleaf-tilt-delay.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 16 Jul 2021 22:47:29 -0500 -Subject: [PATCH] Big dripleaf tilt delay - -Makes the tilt delays configurable. There are only 3 types of tilts used by this setting. When an entity steps on a -big_dripleaf with no tilt it will immediately change to an UNSTABLE tilt. Each change after that is on a tick timer: - -UNSTABLE: big_dripleaf with UNSTABLE tilt will change to PARTIAL tilt after 10 ticks -PARTIAL: big_dripleaf with PARTIAL tilt will change to FULL tilt after 10 ticks -UNSTABLE: big_dripleaf with FULL tilt will change back to no tilt after 100 ticks - -diff --git a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java -index 8240c32d676a88aa23dcd052ee0136767e54fb0d..372c4ab9d390d5afd98947f21c79aae06b15064d 100644 ---- a/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BigDripleafBlock.java -@@ -244,7 +244,7 @@ public class BigDripleafBlock extends HorizontalDirectionalBlock implements Bone - BigDripleafBlock.playTiltSound(world, blockposition, soundeffect); - } - -- int i = BigDripleafBlock.DELAY_UNTIL_NEXT_TILT_STATE.getInt(tilt); -+ int i = world.purpurConfig.bigDripleafTiltDelay.getOrDefault(tilt, -1); // Purpur - - if (i != -1) { - world.scheduleTick(blockposition, (Block) this, i); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 2a05ee4d6d609fb0ab1837d2add45ffba68603fe..220787aa0d3d144d2fa4296463af3c6b9ed0cf00 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -819,6 +819,22 @@ public class PurpurWorldConfig { - } - } - -+ public Map bigDripleafTiltDelay = new HashMap<>(); -+ private void bigDripleafSettings() { -+ bigDripleafTiltDelay.clear(); -+ getMap("blocks.big_dripleaf.tilt-delay", Map.ofEntries( -+ Map.entry("UNSTABLE", 10), -+ Map.entry("PARTIAL", 10), -+ Map.entry("FULL", 100)) -+ ).forEach((tilt, delay) -> { -+ try { -+ bigDripleafTiltDelay.put(Tilt.valueOf(tilt), (int) delay); -+ } catch (IllegalArgumentException e) { -+ PurpurConfig.log(Level.SEVERE, "Invalid big_dripleaf tilt key: " + tilt); -+ } -+ }); -+ } -+ - public boolean chestOpenWithBlockOnTop = false; - private void chestSettings() { - chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); diff --git a/patches/server/0188-Player-ridable-in-water-option.patch b/patches/server/0188-Player-ridable-in-water-option.patch deleted file mode 100644 index 08cdecfce..000000000 --- a/patches/server/0188-Player-ridable-in-water-option.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 17 Jul 2021 15:55:14 -0500 -Subject: [PATCH] Player ridable in water option - - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 458c14d4f298137ef1a333368644568a2c8a0b09..0460bdb52ce6b29cf57ef8f2d7f430e761c82d85 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -2073,6 +2073,13 @@ public abstract class Player extends LivingEntity { - return slot != EquipmentSlot.BODY; - } - -+ // Purpur start -+ @Override -+ public boolean dismountsUnderwater() { -+ return !level().purpurConfig.playerRidableInWater; -+ } -+ // Purpur end -+ - public boolean setEntityOnShoulder(CompoundTag entityNbt) { - if (!this.isPassenger() && this.onGround() && !this.isInWater() && !this.isInPowderSnow) { - if (this.getShoulderEntityLeft().isEmpty()) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 220787aa0d3d144d2fa4296463af3c6b9ed0cf00..ee356e3174791f3c54abb8ddbf30694a3e9a87dc 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -394,6 +394,7 @@ public class PurpurWorldConfig { - public double playerCriticalDamageMultiplier = 1.5D; - public int playerBurpDelay = 10; - public boolean playerBurpWhenFull = false; -+ public boolean playerRidableInWater = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -416,6 +417,7 @@ public class PurpurWorldConfig { - playerCriticalDamageMultiplier = getDouble("gameplay-mechanics.player.critical-damage-multiplier", playerCriticalDamageMultiplier); - playerBurpDelay = getInt("gameplay-mechanics.player.burp-delay", playerBurpDelay); - playerBurpWhenFull = getBoolean("gameplay-mechanics.player.burp-when-full", playerBurpWhenFull); -+ playerRidableInWater = getBoolean("gameplay-mechanics.player.ridable-in-water", playerRidableInWater); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0189-Config-to-disable-Enderman-teleport-on-projectile-hi.patch b/patches/server/0189-Config-to-disable-Enderman-teleport-on-projectile-hi.patch deleted file mode 100644 index 645ac77ce..000000000 --- a/patches/server/0189-Config-to-disable-Enderman-teleport-on-projectile-hi.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Mon, 19 Jul 2021 19:28:17 -0400 -Subject: [PATCH] Config to disable Enderman teleport on projectile hit - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index b361c6b4ca17b9d466555037235a5660caa5c9bd..21a570d09ad3e19e6c709ff1152db7d204648122 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -434,6 +434,7 @@ public class EnderMan extends Monster implements NeutralMob { - } else { - flag1 = flag && this.hurtWithCleanWater(source, (ThrownPotion) source.getDirectEntity(), amount); - -+ if (!flag1 && this.level().purpurConfig.endermanIgnoreProjectiles) return super.hurt(source, amount); // Purpur - if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent - for (int i = 0; i < 64; ++i) { - if (this.teleport()) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ee356e3174791f3c54abb8ddbf30694a3e9a87dc..ae67aa6cf66e64d5e7506c0ca7193a9ba8a986ce 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1425,6 +1425,7 @@ public class PurpurWorldConfig { - public boolean endermanAggroEndermitesOnlyIfPlayerSpawned = false; - public boolean endermanIgnorePlayerDragonHead = false; - public boolean endermanDisableStareAggro = false; -+ public boolean endermanIgnoreProjectiles = false; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -@@ -1447,6 +1448,7 @@ public class PurpurWorldConfig { - endermanAggroEndermitesOnlyIfPlayerSpawned = getBoolean("mobs.enderman.aggressive-towards-endermites-only-spawned-by-player-thrown-ender-pearls", endermanAggroEndermitesOnlyIfPlayerSpawned); - endermanIgnorePlayerDragonHead = getBoolean("mobs.enderman.ignore-players-wearing-dragon-head", endermanIgnorePlayerDragonHead); - endermanDisableStareAggro = getBoolean("mobs.enderman.disable-player-stare-aggression", endermanDisableStareAggro); -+ endermanIgnoreProjectiles = getBoolean("mobs.enderman.ignore-projectiles", endermanIgnoreProjectiles); - } - - public boolean endermiteRidable = false; diff --git a/patches/server/0190-Add-compass-command.patch b/patches/server/0190-Add-compass-command.patch deleted file mode 100644 index a7c9fd136..000000000 --- a/patches/server/0190-Add-compass-command.patch +++ /dev/null @@ -1,248 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 24 Jul 2021 00:07:31 -0500 -Subject: [PATCH] Add compass command - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 26c9254cef922a78deac3053f93c60037f19d31f..67ec90a2a05269a5912b3c8e64d6d4162a8c6ca2 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -257,6 +257,7 @@ public class Commands { - org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.UptimeCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.TPSBarCommand.register(this.dispatcher); // Purpur -+ org.purpurmc.purpur.command.CompassCommand.register(this.dispatcher); // Purpur - } - - if (environment.includeIntegrated) { -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 7bb82c9b652a509c2bf1a43ed82a5da709fb2cb2..e9d9cb47221075447aac66dd30ce6e8f08962cf5 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -300,6 +300,7 @@ public class ServerPlayer extends Player { - public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event - public boolean purpurClient = false; // Purpur - private boolean tpsBar = false; // Purpur -+ private boolean compassBar = false; // Purpur - - // Paper start - replace player chunk loader - private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); -@@ -611,6 +612,7 @@ public class ServerPlayer extends Player { - } - - if (nbt.contains("Purpur.TPSBar")) { this.tpsBar = nbt.getBoolean("Purpur.TPSBar"); } // Purpur -+ if (nbt.contains("Purpur.CompassBar")) { this.compassBar = nbt.getBoolean("Purpur.CompassBar"); } // Purpur - } - - @Override -@@ -688,6 +690,7 @@ public class ServerPlayer extends Player { - } - - nbt.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur -+ nbt.putBoolean("Purpur.CompassBar", this.compassBar); // Purpur - } - - // CraftBukkit start - World fallback code, either respawn location or global spawn -@@ -3011,5 +3014,13 @@ public class ServerPlayer extends Player { - public void tpsBar(boolean tpsBar) { - this.tpsBar = tpsBar; - } -+ -+ public boolean compassBar() { -+ return this.compassBar; -+ } -+ -+ public void compassBar(boolean compassBar) { -+ this.compassBar = compassBar; -+ } - // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index e4188163e7a9dda878e72ae84a1b5cb28c23510d..b56afa30c04350b5e9ca4ea2d33f9e7c58559380 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -255,6 +255,11 @@ public class PurpurConfig { - public static String commandTPSBarTextColorMedium = ""; - public static String commandTPSBarTextColorLow = ""; - public static int commandTPSBarTickInterval = 20; -+ public static String commandCompassBarTitle = "S \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 W \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 N \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 E \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 S \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 W \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 N \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 E \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 "; -+ public static BossBar.Overlay commandCompassBarProgressOverlay = BossBar.Overlay.PROGRESS; -+ public static BossBar.Color commandCompassBarProgressColor = BossBar.Color.BLUE; -+ public static float commandCompassBarProgressPercent = 1.0F; -+ public static int commandCompassBarTickInterval = 5; - public static boolean commandGamemodeRequiresPermission = false; - public static boolean hideHiddenPlayersFromEntitySelector = false; - public static String uptimeFormat = ""; -@@ -277,6 +282,13 @@ public class PurpurConfig { - commandTPSBarTextColorMedium = getString("settings.command.tpsbar.text-color.medium", commandTPSBarTextColorMedium); - commandTPSBarTextColorLow = getString("settings.command.tpsbar.text-color.low", commandTPSBarTextColorLow); - commandTPSBarTickInterval = getInt("settings.command.tpsbar.tick-interval", commandTPSBarTickInterval); -+ -+ commandCompassBarTitle = getString("settings.command.compass.title", commandCompassBarTitle); -+ commandCompassBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.compass.overlay", commandCompassBarProgressOverlay.name())); -+ commandCompassBarProgressColor = BossBar.Color.valueOf(getString("settings.command.compass.progress-color", commandCompassBarProgressColor.name())); -+ commandCompassBarProgressPercent = (float) getDouble("settings.command.compass.percent", commandCompassBarProgressPercent); -+ commandCompassBarTickInterval = getInt("settings.command.compass.tick-interval", commandCompassBarTickInterval); -+ - commandGamemodeRequiresPermission = getBoolean("settings.command.gamemode.requires-specific-permission", commandGamemodeRequiresPermission); - hideHiddenPlayersFromEntitySelector = getBoolean("settings.command.hide-hidden-players-from-entity-selector", hideHiddenPlayersFromEntitySelector); - uptimeFormat = getString("settings.command.uptime.format", uptimeFormat); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ae67aa6cf66e64d5e7506c0ca7193a9ba8a986ce..963540e5c3eb6dfbb78b089bba013ef348c8487f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -222,6 +222,7 @@ public class PurpurWorldConfig { - public float enderPearlEndermiteChance = 0.05F; - public int glowBerriesEatGlowDuration = 0; - public boolean shulkerBoxItemDropContentsWhenDestroyed = true; -+ public boolean compassItemShowsBossBar = false; - private void itemSettings() { - itemImmuneToCactus.clear(); - getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { -@@ -269,6 +270,7 @@ public class PurpurWorldConfig { - enderPearlEndermiteChance = (float) getDouble("gameplay-mechanics.item.ender-pearl.endermite-spawn-chance", enderPearlEndermiteChance); - glowBerriesEatGlowDuration = getInt("gameplay-mechanics.item.glow_berries.eat-glow-duration", glowBerriesEatGlowDuration); - shulkerBoxItemDropContentsWhenDestroyed = getBoolean("gameplay-mechanics.item.shulker_box.drop-contents-when-destroyed", shulkerBoxItemDropContentsWhenDestroyed); -+ compassItemShowsBossBar = getBoolean("gameplay-mechanics.item.compass.holding-shows-bossbar", compassItemShowsBossBar); - } - - public double minecartMaxSpeed = 0.4D; -diff --git a/src/main/java/org/purpurmc/purpur/command/CompassCommand.java b/src/main/java/org/purpurmc/purpur/command/CompassCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..79b8490832d2a0cc7846ddcb091cb6bcac74ea45 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/CompassCommand.java -@@ -0,0 +1,27 @@ -+package org.purpurmc.purpur.command; -+ -+import com.mojang.brigadier.CommandDispatcher; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import net.minecraft.server.level.ServerPlayer; -+import org.purpurmc.purpur.task.CompassTask; -+ -+public class CompassCommand { -+ public static void register(CommandDispatcher dispatcher) { -+ dispatcher.register(Commands.literal("compass") -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.compass")) -+ .executes(context -> { -+ ServerPlayer player = context.getSource().getPlayerOrException(); -+ CompassTask task = CompassTask.instance(); -+ if (player.compassBar()) { -+ task.removePlayer(player.getBukkitEntity()); -+ player.compassBar(false); -+ } else { -+ task.addPlayer(player.getBukkitEntity()); -+ player.compassBar(true); -+ } -+ return 1; -+ }) -+ ); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/task/BossBarTask.java b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java -index d38b3c4a722396cc3b61a9a8ed7e39cea4ae65cb..d333334f323049ca97e756324cff0b23eddacd2a 100644 ---- a/src/main/java/org/purpurmc/purpur/task/BossBarTask.java -+++ b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java -@@ -90,10 +90,12 @@ public abstract class BossBarTask extends BukkitRunnable { - - public static void startAll() { - TPSBarTask.instance().start(); -+ CompassTask.instance().start(); - } - - public static void stopAll() { - TPSBarTask.instance().stop(); -+ CompassTask.instance().stop(); - } - - public static void addToAll(ServerPlayer player) { -@@ -101,9 +103,13 @@ public abstract class BossBarTask extends BukkitRunnable { - if (player.tpsBar()) { - TPSBarTask.instance().addPlayer(bukkit); - } -+ if (player.compassBar()) { -+ CompassTask.instance().addPlayer(bukkit); -+ } - } - - public static void removeFromAll(Player player) { - TPSBarTask.instance().removePlayer(player); -+ CompassTask.instance().removePlayer(player); - } - } -diff --git a/src/main/java/org/purpurmc/purpur/task/CompassTask.java b/src/main/java/org/purpurmc/purpur/task/CompassTask.java -new file mode 100644 -index 0000000000000000000000000000000000000000..bece7eefc8ba8822b433835526251d2fb916c025 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/task/CompassTask.java -@@ -0,0 +1,68 @@ -+package org.purpurmc.purpur.task; -+ -+import net.kyori.adventure.bossbar.BossBar; -+import net.kyori.adventure.text.Component; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.world.item.Items; -+import org.bukkit.entity.Player; -+import org.purpurmc.purpur.PurpurConfig; -+ -+public class CompassTask extends BossBarTask { -+ private static CompassTask instance; -+ -+ private int tick = 0; -+ -+ public static CompassTask instance() { -+ if (instance == null) { -+ instance = new CompassTask(); -+ } -+ return instance; -+ } -+ -+ @Override -+ public void run() { -+ if (++tick < PurpurConfig.commandCompassBarTickInterval) { -+ return; -+ } -+ tick = 0; -+ -+ MinecraftServer.getServer().getAllLevels().forEach((level) -> { -+ if (level.purpurConfig.compassItemShowsBossBar) { -+ level.players().forEach(player -> { -+ if (!player.compassBar()) { -+ if (player.getMainHandItem().getItem() != Items.COMPASS && player.getOffhandItem().getItem() != Items.COMPASS) { -+ removePlayer(player.getBukkitEntity()); -+ } else if (!hasPlayer(player.getUUID())) { -+ addPlayer(player.getBukkitEntity()); -+ } -+ } -+ }); -+ } -+ }); -+ -+ super.run(); -+ } -+ -+ @Override -+ BossBar createBossBar() { -+ return BossBar.bossBar(Component.text(""), PurpurConfig.commandCompassBarProgressPercent, PurpurConfig.commandCompassBarProgressColor, PurpurConfig.commandCompassBarProgressOverlay); -+ } -+ -+ @Override -+ void updateBossBar(BossBar bossbar, Player player) { -+ float yaw = player.getLocation().getYaw(); -+ int length = PurpurConfig.commandCompassBarTitle.length(); -+ int pos = (int) ((normalize(yaw) * (length / 720F)) + (length / 2F)); -+ bossbar.name(Component.text(PurpurConfig.commandCompassBarTitle.substring(pos - 25, pos + 25))); -+ } -+ -+ private float normalize(float yaw) { -+ while (yaw < -180.0F) { -+ yaw += 360.0F; -+ } -+ while (yaw > 180.0F) { -+ yaw -= 360.0F; -+ } -+ return yaw; -+ } -+} diff --git a/patches/server/0191-Toggle-for-kinetic-damage.patch b/patches/server/0191-Toggle-for-kinetic-damage.patch deleted file mode 100644 index 1addaa713..000000000 --- a/patches/server/0191-Toggle-for-kinetic-damage.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Wed, 4 Aug 2021 11:44:26 +0200 -Subject: [PATCH] Toggle for kinetic damage - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 54a612dd2fcdf6972f7580fbd814f461df07b7f6..549579f2bc2e1fd23ece1ead543e3e5242f52ce0 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2993,6 +2993,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - - if (f3 > 0.0F) { - this.playSound(this.getFallDamageSound((int) f3), 1.0F, 1.0F); -+ if (level().purpurConfig.elytraKineticDamage) // Purpur - this.hurt(this.damageSources().flyIntoWall(), f3); - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 963540e5c3eb6dfbb78b089bba013ef348c8487f..7a2a3243e6d1e22dcbd57674db06bf7cb42abfed 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -182,12 +182,14 @@ public class PurpurWorldConfig { - public boolean elytraIgnoreUnbreaking = false; - public int elytraDamagePerFireworkBoost = 0; - public int elytraDamagePerTridentBoost = 0; -+ public boolean elytraKineticDamage = true; - private void elytraSettings() { - elytraDamagePerSecond = getInt("gameplay-mechanics.elytra.damage-per-second", elytraDamagePerSecond); - elytraDamageMultiplyBySpeed = getDouble("gameplay-mechanics.elytra.damage-multiplied-by-speed", elytraDamageMultiplyBySpeed); - elytraIgnoreUnbreaking = getBoolean("gameplay-mechanics.elytra.ignore-unbreaking", elytraIgnoreUnbreaking); - elytraDamagePerFireworkBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.firework", elytraDamagePerFireworkBoost); - elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost); -+ elytraKineticDamage = getBoolean("gameplay-mechanics.elytra.kinetic-damage", elytraKineticDamage); - } - - public int entityLifeSpan = 0; diff --git a/patches/server/0192-Add-Option-for-disable-observer-clocks.patch b/patches/server/0192-Add-Option-for-disable-observer-clocks.patch deleted file mode 100644 index f71d1040c..000000000 --- a/patches/server/0192-Add-Option-for-disable-observer-clocks.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Mon, 5 Jul 2021 06:00:17 +0200 -Subject: [PATCH] Add Option for disable observer clocks - -Allow to disable observer clocks: https://www.spigotmc.org/attachments/observerclock-gif.365936/ - -diff --git a/src/main/java/net/minecraft/world/level/block/ObserverBlock.java b/src/main/java/net/minecraft/world/level/block/ObserverBlock.java -index b38fbe5121f293f425d7673a6ce49b11d0ced0d9..2a74f42672b92393b52a61c27c5b8af77c8c6070 100644 ---- a/src/main/java/net/minecraft/world/level/block/ObserverBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ObserverBlock.java -@@ -71,6 +71,7 @@ public class ObserverBlock extends DirectionalBlock { - @Override - protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { - if (state.getValue(ObserverBlock.FACING) == direction && !(Boolean) state.getValue(ObserverBlock.POWERED)) { -+ if (!world.getMinecraftWorld().purpurConfig.disableObserverClocks || !(neighborState.getBlock() instanceof ObserverBlock) || neighborState.getValue(ObserverBlock.FACING).getOpposite() != direction) // Purpur - this.startSignal(world, pos); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 7a2a3243e6d1e22dcbd57674db06bf7cb42abfed..4513d3e5441e1b68e890836e168c64e9b363f466 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -369,6 +369,11 @@ public class PurpurWorldConfig { - villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate); - } - -+ public boolean disableObserverClocks = false; -+ private void observerSettings() { -+ disableObserverClocks = getBoolean("blocks.observer.disable-clock", disableObserverClocks); -+ } -+ - public int playerNetheriteFireResistanceDuration = 0; - public int playerNetheriteFireResistanceAmplifier = 0; - public boolean playerNetheriteFireResistanceAmbient = false; diff --git a/patches/server/0193-Customizeable-Zombie-Villager-curing-times.patch b/patches/server/0193-Customizeable-Zombie-Villager-curing-times.patch deleted file mode 100644 index af8658aac..000000000 --- a/patches/server/0193-Customizeable-Zombie-Villager-curing-times.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Fri, 6 Aug 2021 22:30:10 +0200 -Subject: [PATCH] Customizeable Zombie Villager curing times - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index 2ec3a09135f85a5de68e77511f3f213adf08712c..d909138942212ee090ff513b1817414c93457425 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -222,7 +222,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - if (this.hasEffect(MobEffects.WEAKNESS)) { - itemstack.consume(1, player); - if (!this.level().isClientSide) { -- this.startConverting(player.getUUID(), this.random.nextInt(2401) + 3600); -+ this.startConverting(player.getUUID(), this.random.nextInt(level().purpurConfig.zombieVillagerCuringTimeMax - level().purpurConfig.zombieVillagerCuringTimeMin + 1) + level().purpurConfig.zombieVillagerCuringTimeMin); // Purpur - } - - return InteractionResult.SUCCESS; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 4513d3e5441e1b68e890836e168c64e9b363f466..69753e7dc0fbc59a6e9d84479a5141a740e2fd15 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2828,6 +2828,8 @@ public class PurpurWorldConfig { - public double zombieVillagerJockeyChance = 0.05D; - public boolean zombieVillagerJockeyTryExistingChickens = true; - public boolean zombieVillagerTakeDamageFromWater = false; -+ public int zombieVillagerCuringTimeMin = 3600; -+ public int zombieVillagerCuringTimeMax = 6000; - private void zombieVillagerSettings() { - zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); - zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); -@@ -2843,6 +2845,8 @@ public class PurpurWorldConfig { - zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance); - zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens); - zombieVillagerTakeDamageFromWater = getBoolean("mobs.zombie_villager.takes-damage-from-water", zombieVillagerTakeDamageFromWater); -+ zombieVillagerCuringTimeMin = getInt("mobs.zombie_villager.curing_time.min", zombieVillagerCuringTimeMin); -+ zombieVillagerCuringTimeMax = getInt("mobs.zombie_villager.curing_time.max", zombieVillagerCuringTimeMax); - } - - public boolean zombifiedPiglinRidable = false; diff --git a/patches/server/0194-Option-for-sponges-to-work-on-lava-and-mud.patch b/patches/server/0194-Option-for-sponges-to-work-on-lava-and-mud.patch deleted file mode 100644 index adcf1ca6b..000000000 --- a/patches/server/0194-Option-for-sponges-to-work-on-lava-and-mud.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Sat, 7 Aug 2021 20:23:31 +0200 -Subject: [PATCH] Option for sponges to work on lava and mud - -Co-authored by: granny - -diff --git a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java -index a676ccfa6b02e8986df6f6a2e04cbb06b3edd0ff..6fe44572e34ad3e3a1851e73138bd8b778eb7849 100644 ---- a/src/main/java/net/minecraft/world/level/block/SpongeBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SpongeBlock.java -@@ -77,7 +77,7 @@ public class SpongeBlock extends Block { - FluidState fluid = blockList.getFluidState(blockposition1); - // CraftBukkit end - -- if (!fluid.is(FluidTags.WATER)) { -+ if (!fluid.is(FluidTags.WATER) && (!world.purpurConfig.spongeAbsorbsLava || !fluid.is(FluidTags.LAVA)) && (!world.purpurConfig.spongeAbsorbsWaterFromMud || !iblockdata.is(Blocks.MUD))) { // Purpur - return false; - } else { - Block block = iblockdata.getBlock(); -@@ -92,6 +92,10 @@ public class SpongeBlock extends Block { - - if (iblockdata.getBlock() instanceof LiquidBlock) { - blockList.setBlock(blockposition1, Blocks.AIR.defaultBlockState(), 3); // CraftBukkit -+ // Purpur start -+ } else if (iblockdata.is(Blocks.MUD)) { -+ blockList.setBlock(blockposition1, Blocks.CLAY.defaultBlockState(), 3); -+ // Purpur end - } else { - if (!iblockdata.is(Blocks.KELP) && !iblockdata.is(Blocks.KELP_PLANT) && !iblockdata.is(Blocks.SEAGRASS) && !iblockdata.is(Blocks.TALL_SEAGRASS)) { - return false; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 69753e7dc0fbc59a6e9d84479a5141a740e2fd15..b69e224dc04758fec2bd0a2631848f4dc5a67b85 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1005,9 +1005,13 @@ public class PurpurWorldConfig { - - public int spongeAbsorptionArea = 65; - public int spongeAbsorptionRadius = 6; -+ public boolean spongeAbsorbsLava = false; -+ public boolean spongeAbsorbsWaterFromMud = false; - private void spongeSettings() { - spongeAbsorptionArea = getInt("blocks.sponge.absorption.area", spongeAbsorptionArea); - spongeAbsorptionRadius = getInt("blocks.sponge.absorption.radius", spongeAbsorptionRadius); -+ spongeAbsorbsLava = getBoolean("blocks.sponge.absorbs-lava", spongeAbsorbsLava); -+ spongeAbsorbsWaterFromMud = getBoolean("blocks.sponge.absorbs-water-from-mud", spongeAbsorbsWaterFromMud); - } - - public boolean turtleEggsBreakFromExpOrbs = false; diff --git a/patches/server/0195-Toggle-for-Wither-s-spawn-sound.patch b/patches/server/0195-Toggle-for-Wither-s-spawn-sound.patch deleted file mode 100644 index 104d0fc9d..000000000 --- a/patches/server/0195-Toggle-for-Wither-s-spawn-sound.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Sat, 7 Aug 2021 21:27:56 +0200 -Subject: [PATCH] Toggle for Wither's spawn sound - - -diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 01d193d2584b62897687bd088fb590de8a4ab279..a030fe21a88a9486cc8367710a96af67c761635c 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -425,7 +425,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - } - // CraftBukkit end - -- if (!this.isSilent()) { -+ if (!this.isSilent() && level().purpurConfig.witherPlaySpawnSound) { - // CraftBukkit start - Use relative location for far away sounds - // this.level().globalLevelEvent(1023, new BlockPosition(this), 0); - int viewDistance = ((ServerLevel) this.level()).getCraftServer().getViewDistance() * 16; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b69e224dc04758fec2bd0a2631848f4dc5a67b85..eb64ddde8162833ae522ea88befc2c837a3e6b53 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2673,6 +2673,7 @@ public class PurpurWorldConfig { - public boolean witherTakeDamageFromWater = false; - public boolean witherCanRideVehicles = false; - public float witherExplosionRadius = 1.0F; -+ public boolean witherPlaySpawnSound = true; - private void witherSettings() { - witherRidable = getBoolean("mobs.wither.ridable", witherRidable); - witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); -@@ -2694,6 +2695,7 @@ public class PurpurWorldConfig { - witherTakeDamageFromWater = getBoolean("mobs.wither.takes-damage-from-water", witherTakeDamageFromWater); - witherCanRideVehicles = getBoolean("mobs.wither.can-ride-vehicles", witherCanRideVehicles); - witherExplosionRadius = (float) getDouble("mobs.wither.explosion-radius", witherExplosionRadius); -+ witherPlaySpawnSound = getBoolean("mobs.wither.play-spawn-sound", witherPlaySpawnSound); - } - - public boolean witherSkeletonRidable = false; diff --git a/patches/server/0196-Cactus-breaks-from-solid-neighbors-config.patch b/patches/server/0196-Cactus-breaks-from-solid-neighbors-config.patch deleted file mode 100644 index 5eef83775..000000000 --- a/patches/server/0196-Cactus-breaks-from-solid-neighbors-config.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 7 Aug 2021 03:37:56 -0500 -Subject: [PATCH] Cactus breaks from solid neighbors config - - -diff --git a/src/main/java/net/minecraft/world/level/block/CactusBlock.java b/src/main/java/net/minecraft/world/level/block/CactusBlock.java -index ff4dda48116a2969704b355ff96407ba869b466e..9200d75b05ce535f7b7f5c1572cd8f6261c6955b 100644 ---- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java -@@ -114,7 +114,7 @@ public class CactusBlock extends Block { - - enumdirection = (Direction) iterator.next(); - iblockdata1 = world.getBlockState(pos.relative(enumdirection)); -- } while (!iblockdata1.isSolid() && !world.getFluidState(pos.relative(enumdirection)).is(FluidTags.LAVA)); -+ } while ((!world.getWorldBorder().world.purpurConfig.cactusBreaksFromSolidNeighbors || !iblockdata1.isSolid()) && !world.getFluidState(pos.relative(enumdirection)).is(FluidTags.LAVA)); // Purpur - - return false; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index eb64ddde8162833ae522ea88befc2c837a3e6b53..27f34e56820351223707c305f67c5e50aadbbe4f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -846,6 +846,11 @@ public class PurpurWorldConfig { - }); - } - -+ public boolean cactusBreaksFromSolidNeighbors = true; -+ private void cactusSettings() { -+ cactusBreaksFromSolidNeighbors = getBoolean("blocks.cactus.breaks-from-solid-neighbors", cactusBreaksFromSolidNeighbors); -+ } -+ - public boolean chestOpenWithBlockOnTop = false; - private void chestSettings() { - chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); diff --git a/patches/server/0197-Config-to-remove-curse-of-binding-with-weakness.patch b/patches/server/0197-Config-to-remove-curse-of-binding-with-weakness.patch deleted file mode 100644 index 154d60583..000000000 --- a/patches/server/0197-Config-to-remove-curse-of-binding-with-weakness.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Sun, 8 Aug 2021 16:59:21 -0400 -Subject: [PATCH] Config to remove curse of binding with weakness - - -diff --git a/src/main/java/net/minecraft/world/inventory/InventoryMenu.java b/src/main/java/net/minecraft/world/inventory/InventoryMenu.java -index 9992599dbe4f4a430e822a44b03c00505abfbfaf..3fea9339420aa38b303ccf6c154aec246e617b5b 100644 ---- a/src/main/java/net/minecraft/world/inventory/InventoryMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/InventoryMenu.java -@@ -97,7 +97,7 @@ public class InventoryMenu extends RecipeBookMenu { - public boolean mayPickup(Player playerEntity) { - ItemStack itemstack = this.getItem(); - -- return !itemstack.isEmpty() && !playerEntity.isCreative() && EnchantmentHelper.hasBindingCurse(itemstack) ? false : super.mayPickup(playerEntity); -+ return !itemstack.isEmpty() && !playerEntity.isCreative() && EnchantmentHelper.hasBindingCurse(itemstack) ? playerEntity.level().purpurConfig.playerRemoveBindingWithWeakness && playerEntity.hasEffect(net.minecraft.world.effect.MobEffects.WEAKNESS) : super.mayPickup(playerEntity); // Purpur - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 27f34e56820351223707c305f67c5e50aadbbe4f..a673122f46d4e4ad48e8c42e2d50e5ea2870df24 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -404,6 +404,7 @@ public class PurpurWorldConfig { - public int playerBurpDelay = 10; - public boolean playerBurpWhenFull = false; - public boolean playerRidableInWater = false; -+ public boolean playerRemoveBindingWithWeakness = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -427,6 +428,7 @@ public class PurpurWorldConfig { - playerBurpDelay = getInt("gameplay-mechanics.player.burp-delay", playerBurpDelay); - playerBurpWhenFull = getBoolean("gameplay-mechanics.player.burp-when-full", playerBurpWhenFull); - playerRidableInWater = getBoolean("gameplay-mechanics.player.ridable-in-water", playerRidableInWater); -+ playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0198-Conduit-behavior-configuration.patch b/patches/server/0198-Conduit-behavior-configuration.patch deleted file mode 100644 index 88f09f8d8..000000000 --- a/patches/server/0198-Conduit-behavior-configuration.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Sun, 8 Aug 2021 18:14:31 -0400 -Subject: [PATCH] Conduit behavior configuration - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -index 73e532dc998e5701c1a73da846da3d3a79871b81..ff6fea842ca80c2ba51693fe62e5b74f9affdc19 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -@@ -168,7 +168,7 @@ public class ConduitBlockEntity extends BlockEntity { - if ((l > 1 || i1 > 1 || j1 > 1) && (i == 0 && (i1 == 2 || j1 == 2) || j == 0 && (l == 2 || j1 == 2) || k == 0 && (l == 2 || i1 == 2))) { - BlockPos blockposition2 = pos.offset(i, j, k); - BlockState iblockdata = world.getBlockState(blockposition2); -- Block[] ablock = ConduitBlockEntity.VALID_BLOCKS; -+ Block[] ablock = world.purpurConfig.conduitBlocks; // Purpur - int k1 = ablock.length; - - for (int l1 = 0; l1 < k1; ++l1) { -@@ -188,13 +188,13 @@ public class ConduitBlockEntity extends BlockEntity { - - private static void applyEffects(Level world, BlockPos pos, List activatingBlocks) { - // CraftBukkit start -- ConduitBlockEntity.applyEffects(world, pos, ConduitBlockEntity.getRange(activatingBlocks)); -+ ConduitBlockEntity.applyEffects(world, pos, ConduitBlockEntity.getRange(activatingBlocks, world)); // Purpur - } - -- public static int getRange(List list) { -+ public static int getRange(List list, Level world) { // Purpur - // CraftBukkit end - int i = list.size(); -- int j = i / 7 * 16; -+ int j = i / 7 * world.purpurConfig.conduitDistance; // Purpur - // CraftBukkit start - return j; - } -@@ -237,20 +237,20 @@ public class ConduitBlockEntity extends BlockEntity { - tileentityconduit.destroyTarget = ConduitBlockEntity.findDestroyTarget(world, blockposition, tileentityconduit.destroyTargetUUID); - tileentityconduit.destroyTargetUUID = null; - } else if (tileentityconduit.destroyTarget == null) { -- List list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(blockposition), (entityliving1) -> { -+ List list1 = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(blockposition, world), (entityliving1) -> { // Purpur - return entityliving1 instanceof Enemy && entityliving1.isInWaterOrRain(); - }); - - if (!list1.isEmpty()) { - tileentityconduit.destroyTarget = (LivingEntity) list1.get(world.random.nextInt(list1.size())); - } -- } else if (!tileentityconduit.destroyTarget.isAlive() || !blockposition.closerThan(tileentityconduit.destroyTarget.blockPosition(), 8.0D)) { -+ } else if (!tileentityconduit.destroyTarget.isAlive() || !blockposition.closerThan(tileentityconduit.destroyTarget.blockPosition(), world.purpurConfig.conduitDamageDistance)) { // Purpur - tileentityconduit.destroyTarget = null; - } - - // CraftBukkit start - if (damageTarget && tileentityconduit.destroyTarget != null) { -- if (tileentityconduit.destroyTarget.hurt(world.damageSources().magic().directBlock(world, blockposition), 4.0F)) { -+ if (tileentityconduit.destroyTarget.hurt(world.damageSources().magic().directBlock(world, blockposition), world.purpurConfig.conduitDamageAmount)) { // Purpur - world.playSound(null, tileentityconduit.destroyTarget.getX(), tileentityconduit.destroyTarget.getY(), tileentityconduit.destroyTarget.getZ(), SoundEvents.CONDUIT_ATTACK_TARGET, SoundSource.BLOCKS, 1.0F, 1.0F); - } - // CraftBukkit end -@@ -275,16 +275,22 @@ public class ConduitBlockEntity extends BlockEntity { - } - - public static AABB getDestroyRangeAABB(BlockPos pos) { -+ // Purpur start -+ return getDestroyRangeAABB(pos, null); -+ } -+ -+ private static AABB getDestroyRangeAABB(BlockPos pos, Level level) { -+ // Purpur end - int i = pos.getX(); - int j = pos.getY(); - int k = pos.getZ(); - -- return (new AABB((double) i, (double) j, (double) k, (double) (i + 1), (double) (j + 1), (double) (k + 1))).inflate(8.0D); -+ return (new AABB((double) i, (double) j, (double) k, (double) (i + 1), (double) (j + 1), (double) (k + 1))).inflate(level == null ? 8.0D : level.purpurConfig.conduitDamageDistance); // Purpur - } - - @Nullable - private static LivingEntity findDestroyTarget(Level world, BlockPos pos, UUID uuid) { -- List list = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(pos), (entityliving) -> { -+ List list = world.getEntitiesOfClass(LivingEntity.class, ConduitBlockEntity.getDestroyRangeAABB(pos, world), (entityliving) -> { // Purpur - return entityliving.getUUID().equals(uuid); - }); - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java b/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java -index c1759aeb3e6ad0e4eb66cba3da1b120dd1dce812..1a91bc2e422db0eba65694ac046f1b362c6b0cd6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java -@@ -73,7 +73,7 @@ public class CraftConduit extends CraftBlockEntityState impl - public int getRange() { - this.ensureNoWorldGeneration(); - ConduitBlockEntity conduit = (ConduitBlockEntity) this.getTileEntityFromWorld(); -- return (conduit != null) ? ConduitBlockEntity.getRange(conduit.effectBlocks) : 0; -+ return (conduit != null) ? ConduitBlockEntity.getRange(conduit.effectBlocks, this.world.getHandle()) : 0; // Purpur - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index a673122f46d4e4ad48e8c42e2d50e5ea2870df24..25c361154866194de70c5d2365c25b4c0148e877 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2894,4 +2894,27 @@ public class PurpurWorldConfig { - private void hungerSettings() { - hungerStarvationDamage = (float) getDouble("hunger.starvation-damage", hungerStarvationDamage); - } -+ -+ public int conduitDistance = 16; -+ public double conduitDamageDistance = 8; -+ public float conduitDamageAmount = 4; -+ public Block[] conduitBlocks; -+ private void conduitSettings() { -+ conduitDistance = getInt("blocks.conduit.effect-distance", conduitDistance); -+ conduitDamageDistance = getDouble("blocks.conduit.mob-damage.distance", conduitDamageDistance); -+ conduitDamageAmount = (float) getDouble("blocks.conduit.mob-damage.damage-amount", conduitDamageAmount); -+ List conduitBlockList = new ArrayList<>(); -+ getList("blocks.conduit.valid-ring-blocks", new ArrayList(){{ -+ add("minecraft:prismarine"); -+ add("minecraft:prismarine_bricks"); -+ add("minecraft:sea_lantern"); -+ add("minecraft:dark_prismarine"); -+ }}).forEach(key -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(key.toString())); -+ if (!block.defaultBlockState().isAir()) { -+ conduitBlockList.add(block); -+ } -+ }); -+ conduitBlocks = conduitBlockList.toArray(Block[]::new); -+ } - } diff --git a/patches/server/0199-Cauldron-fill-chances.patch b/patches/server/0199-Cauldron-fill-chances.patch deleted file mode 100644 index d7f48bf81..000000000 --- a/patches/server/0199-Cauldron-fill-chances.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Sun, 8 Aug 2021 18:38:44 -0400 -Subject: [PATCH] Cauldron fill chances - - -diff --git a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java -index c9968934f4ecaa8d81e545f279b3001c7b1ce545..03e4fce6f8226451365fc2831b5bf1e5e6091730 100644 ---- a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java -@@ -37,7 +37,7 @@ public class CauldronBlock extends AbstractCauldronBlock { - } - - protected static boolean shouldHandlePrecipitation(Level world, Biome.Precipitation precipitation) { -- return precipitation == Biome.Precipitation.RAIN ? world.getRandom().nextFloat() < 0.05F : (precipitation == Biome.Precipitation.SNOW ? world.getRandom().nextFloat() < 0.1F : false); -+ return precipitation == Biome.Precipitation.RAIN ? world.getRandom().nextFloat() < world.purpurConfig.cauldronRainChance : (precipitation == Biome.Precipitation.SNOW ? world.getRandom().nextFloat() < world.purpurConfig.cauldronPowderSnowChance : false); // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -index a2bd54dae4b0460d200f6d5300194a7ef5a28830..bf189a171530abfc9bba5db5a305feb391f2cbee 100644 ---- a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java -@@ -190,7 +190,7 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate - - @VisibleForTesting - public static void maybeTransferFluid(BlockState state, ServerLevel world, BlockPos pos, float dripChance) { -- if (dripChance <= 0.17578125F || dripChance <= 0.05859375F) { -+ if (dripChance <= world.purpurConfig.cauldronDripstoneWaterFillChance || dripChance <= world.purpurConfig.cauldronDripstoneLavaFillChance) { // Purpur - if (PointedDripstoneBlock.isStalactiteStartPos(state, world, pos)) { - Optional optional = PointedDripstoneBlock.getFluidAboveStalactite(world, pos, state); - -@@ -199,13 +199,13 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate - float f1; - - if (fluidtype == Fluids.WATER) { -- f1 = 0.17578125F; -+ f1 = world.purpurConfig.cauldronDripstoneWaterFillChance; // Purpur - } else { - if (fluidtype != Fluids.LAVA) { - return; - } - -- f1 = 0.05859375F; -+ f1 = world.purpurConfig.cauldronDripstoneLavaFillChance; // Purpur - } - - if (dripChance < f1) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 25c361154866194de70c5d2365c25b4c0148e877..0227caeb0efa2b9aa1d9e8cb1cb13997ebbb7a1c 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2917,4 +2917,15 @@ public class PurpurWorldConfig { - }); - conduitBlocks = conduitBlockList.toArray(Block[]::new); - } -+ -+ public float cauldronRainChance = 0.05F; -+ public float cauldronPowderSnowChance = 0.1F; -+ public float cauldronDripstoneWaterFillChance = 0.17578125F; -+ public float cauldronDripstoneLavaFillChance = 0.05859375F; -+ private void cauldronSettings() { -+ cauldronRainChance = (float) getDouble("blocks.cauldron.fill-chances.rain", cauldronRainChance); -+ cauldronPowderSnowChance = (float) getDouble("blocks.cauldron.fill-chances.powder-snow", cauldronPowderSnowChance); -+ cauldronDripstoneWaterFillChance = (float) getDouble("blocks.cauldron.fill-chances.dripstone-water", cauldronDripstoneWaterFillChance); -+ cauldronDripstoneLavaFillChance = (float) getDouble("blocks.cauldron.fill-chances.dripstone-lava", cauldronDripstoneLavaFillChance); -+ } - } diff --git a/patches/server/0200-Config-to-allow-mobs-to-pathfind-over-rails.patch b/patches/server/0200-Config-to-allow-mobs-to-pathfind-over-rails.patch deleted file mode 100644 index 051804cbb..000000000 --- a/patches/server/0200-Config-to-allow-mobs-to-pathfind-over-rails.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Sun, 8 Aug 2021 22:50:23 -0400 -Subject: [PATCH] Config to allow mobs to pathfind over rails - - -diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -index d5004290e40a1ff5e0fcfe75f8da34ae15962359..31ae0f466ae522d767907ec5066b26695f327b96 100644 ---- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -@@ -240,7 +240,7 @@ public class WalkNodeEvaluator extends NodeEvaluator { - if ((node == null || node.costMalus < 0.0F) - && maxYStep > 0 - && (pathType != PathType.FENCE || this.canWalkOverFences()) -- && pathType != PathType.UNPASSABLE_RAIL -+ && (this.mob.level().purpurConfig.mobsIgnoreRails || pathType != PathType.UNPASSABLE_RAIL) // Purpur - && pathType != PathType.TRAPDOOR - && pathType != PathType.POWDER_SNOW) { - node = this.tryJumpOn(x, y, z, maxYStep, prevFeetY, direction, nodeType, mutableBlockPos); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 0227caeb0efa2b9aa1d9e8cb1cb13997ebbb7a1c..c5e32e0e1865cdbd81b9077038717dab4db46f4d 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -138,6 +138,7 @@ public class PurpurWorldConfig { - public double voidDamageDealt = 4.0D; - public int raidCooldownSeconds = 0; - public int animalBreedingCooldownSeconds = 0; -+ public boolean mobsIgnoreRails = false; - private void miscGameplayMechanicsSettings() { - useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); -@@ -159,6 +160,7 @@ public class PurpurWorldConfig { - voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); - raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); - animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds); -+ mobsIgnoreRails = getBoolean("gameplay-mechanics.mobs-ignore-rails", mobsIgnoreRails); - } - - public int daytimeTicks = 12000; diff --git a/patches/server/0201-Shulker-change-color-with-dye.patch b/patches/server/0201-Shulker-change-color-with-dye.patch deleted file mode 100644 index 9bc5a11f2..000000000 --- a/patches/server/0201-Shulker-change-color-with-dye.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 21 Aug 2021 00:07:39 -0500 -Subject: [PATCH] Shulker change color with dye - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index 73063abbd051f1d044a8b2c0530cc8d2a96a6331..687fadf1ef64c5ae7e00c5da15b82245e07d3a39 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -23,6 +23,8 @@ import net.minecraft.tags.DamageTypeTags; - import net.minecraft.util.Mth; - import net.minecraft.world.Difficulty; - import net.minecraft.world.DifficultyInstance; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.InteractionResult; - import net.minecraft.world.damagesource.DamageSource; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntitySelector; -@@ -48,6 +50,8 @@ import net.minecraft.world.entity.player.Player; - import net.minecraft.world.entity.projectile.AbstractArrow; - import net.minecraft.world.entity.projectile.ShulkerBullet; - import net.minecraft.world.item.DyeColor; -+import net.minecraft.world.item.DyeItem; -+import net.minecraft.world.item.ItemStack; - import net.minecraft.world.level.Level; - import net.minecraft.world.level.ServerLevelAccessor; - import net.minecraft.world.level.block.Blocks; -@@ -124,6 +128,19 @@ public class Shulker extends AbstractGolem implements VariantHolder -Date: Mon, 9 Aug 2021 13:22:20 +0200 -Subject: [PATCH] Added the ability to add combustible items - - -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java -index 1af7e1548f0648890a1ef2fc0ff4e4c3a56c947c..decea1697c075e7549ccc7501c8e59357d198a60 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractFurnaceMenu.java -@@ -147,7 +147,13 @@ public abstract class AbstractFurnaceMenu extends RecipeBookMenu { - } else if (slot != 1 && slot != 0) { - if (this.canSmelt(itemstack1)) { - if (!this.moveItemStackTo(itemstack1, 0, 1, false)) { -- return ItemStack.EMPTY; -+ // Purpur start - fix #625 -+ if (this.isFuel(itemstack1)) { -+ if (!this.moveItemStackTo(itemstack1, 1, 2, false)) { -+ return ItemStack.EMPTY; -+ } -+ } -+ // Purpur end - } - } else if (this.isFuel(itemstack1)) { - if (!this.moveItemStackTo(itemstack1, 1, 2, false)) { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -index ce2c424068001eec16032361baa206f6a5aa5332..c02d638b8f117156c815821207a91c55796f00b2 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -214,6 +214,22 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - } - } - -+ // Purpur start -+ public static void addFuel(ItemStack itemStack, Integer burnTime) { -+ Map map = Maps.newLinkedHashMap(); -+ map.putAll(getFuel()); -+ map.put(itemStack.getItem(), burnTime); -+ AbstractFurnaceBlockEntity.fuelCache = com.google.common.collect.ImmutableMap.copyOf(map); -+ } -+ -+ public static void removeFuel(ItemStack itemStack) { -+ Map map = Maps.newLinkedHashMap(); -+ map.putAll(getFuel()); -+ map.remove(itemStack.getItem()); -+ AbstractFurnaceBlockEntity.fuelCache = com.google.common.collect.ImmutableMap.copyOf(map); -+ } -+ // Purpur End -+ - // CraftBukkit start - add fields and methods - private int maxStack = MAX_STACK; - public List transaction = new java.util.ArrayList(); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index a52ddb9fe006c2cbaf34686fc53cfdbe5e70de01..f4b611754a0b4a14c31595bc2a5e8acf8bf849bc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1589,6 +1589,19 @@ public final class CraftServer implements Server { - return true; - } - -+ // Purpur Start -+ @Override -+ public void addFuel(org.bukkit.Material material, int burnTime) { -+ Preconditions.checkArgument(burnTime > 0, "BurnTime must be greater than 0"); -+ net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity.addFuel(net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material)), burnTime); -+ } -+ -+ @Override -+ public void removeFuel(org.bukkit.Material material) { -+ net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity.removeFuel(net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material))); -+ } -+ // Purpur End -+ - @Override - public List getRecipesFor(ItemStack result) { - Preconditions.checkArgument(result != null, "ItemStack cannot be null"); diff --git a/patches/server/0204-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch b/patches/server/0204-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch deleted file mode 100644 index 0d670738a..000000000 --- a/patches/server/0204-Option-for-if-rain-and-thunder-should-stop-on-sleep.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Mon, 23 Aug 2021 17:59:29 +0200 -Subject: [PATCH] Option for if rain and thunder should stop on sleep - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 83ec2e31d81d6209953252a3780552c3cf110c68..42db3e64b120b753e98a0fd7e3f56c7d28256fd2 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1391,6 +1391,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - @VisibleForTesting - public void resetWeatherCycle() { - // CraftBukkit start -+ if (this.purpurConfig.rainStopsAfterSleep) // Purpur - this.serverLevelData.setRaining(false, org.bukkit.event.weather.WeatherChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents - // If we stop due to everyone sleeping we should reset the weather duration to some other random value. - // Not that everyone ever manages to get the whole server to sleep at the same time.... -@@ -1398,6 +1399,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - this.serverLevelData.setRainTime(0); - } - // CraftBukkit end -+ if (this.purpurConfig.thunderStopsAfterSleep) // Purpur - this.serverLevelData.setThundering(false, org.bukkit.event.weather.ThunderChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents - // CraftBukkit start - // If we stop due to everyone sleeping we should reset the weather duration to some other random value. -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index aa037b2fb2957be96db3d200294c41e43f6d820f..ef65be19cc55c3c473338f02c9687e74b490b358 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -139,6 +139,8 @@ public class PurpurWorldConfig { - public int raidCooldownSeconds = 0; - public int animalBreedingCooldownSeconds = 0; - public boolean mobsIgnoreRails = false; -+ public boolean rainStopsAfterSleep = true; -+ public boolean thunderStopsAfterSleep = true; - private void miscGameplayMechanicsSettings() { - useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); -@@ -161,6 +163,8 @@ public class PurpurWorldConfig { - raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); - animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds); - mobsIgnoreRails = getBoolean("gameplay-mechanics.mobs-ignore-rails", mobsIgnoreRails); -+ rainStopsAfterSleep = getBoolean("gameplay-mechanics.rain-stops-after-sleep", rainStopsAfterSleep); -+ thunderStopsAfterSleep = getBoolean("gameplay-mechanics.thunder-stops-after-sleep", thunderStopsAfterSleep); - } - - public int daytimeTicks = 12000; diff --git a/patches/server/0205-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch b/patches/server/0205-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch deleted file mode 100644 index 5fca4b152..000000000 --- a/patches/server/0205-Chance-for-azalea-blocks-to-grow-into-trees-naturall.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 23 Aug 2021 20:57:04 -0500 -Subject: [PATCH] Chance for azalea blocks to grow into trees naturally - - -diff --git a/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java b/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java -index fad69dfc20574ab23634b14252b50929cca75b21..7082486f6b760bed2a61938f493d5124722b58e2 100644 ---- a/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/AzaleaBlock.java -@@ -49,6 +49,20 @@ public class AzaleaBlock extends BushBlock implements BonemealableBlock { - - @Override - public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { -+ // Purpur start -+ growTree(world, random, pos, state); -+ } -+ -+ @Override -+ public void randomTick(net.minecraft.world.level.block.state.BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { -+ double chance = state.getBlock() == Blocks.FLOWERING_AZALEA ? world.purpurConfig.floweringAzaleaGrowthChance : world.purpurConfig.azaleaGrowthChance; -+ if (chance > 0.0D && world.getMaxLocalRawBrightness(pos.above()) > 9 && random.nextDouble() < chance) { -+ growTree(world, random, pos, state); -+ } -+ } -+ -+ private void growTree(ServerLevel world, RandomSource random, BlockPos pos, net.minecraft.world.level.block.state.BlockState state) { -+ // Purpur end - TreeGrower.AZALEA.growTree(world, world.getChunkSource().getGenerator(), pos, state, random); - } - -diff --git a/src/main/java/net/minecraft/world/level/block/Blocks.java b/src/main/java/net/minecraft/world/level/block/Blocks.java -index 260906f493416d98ab574a7262fce5e9b7e40c64..ce639e4a2d87202a10ef4fc73274c4b2c4e95720 100644 ---- a/src/main/java/net/minecraft/world/level/block/Blocks.java -+++ b/src/main/java/net/minecraft/world/level/block/Blocks.java -@@ -7389,6 +7389,7 @@ public class Blocks { - BlockBehaviour.Properties.of() - .mapColor(MapColor.PLANT) - .forceSolidOff() -+ .randomTicks() // Purpur - .instabreak() - .sound(SoundType.AZALEA) - .noOcclusion() -@@ -7401,6 +7402,7 @@ public class Blocks { - BlockBehaviour.Properties.of() - .mapColor(MapColor.PLANT) - .forceSolidOff() -+ .randomTicks() // Purpur - .instabreak() - .sound(SoundType.FLOWERING_AZALEA) - .noOcclusion() -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ef65be19cc55c3c473338f02c9687e74b490b358..49837f5ebccfb0d6fbfefe379f52433b44c5aa79 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -806,6 +806,11 @@ public class PurpurWorldConfig { - anvilColorsUseMiniMessage = getBoolean("blocks.anvil.use-mini-message", anvilColorsUseMiniMessage); - } - -+ public double azaleaGrowthChance = 0.0D; -+ private void azaleaSettings() { -+ azaleaGrowthChance = getDouble("blocks.azalea.growth-chance", azaleaGrowthChance); -+ } -+ - public int beaconLevelOne = 20; - public int beaconLevelTwo = 30; - public int beaconLevelThree = 40; -@@ -943,6 +948,11 @@ public class PurpurWorldConfig { - farmlandTramplingFeatherFalling = getBoolean("blocks.farmland.feather-fall-distance-affects-trampling", farmlandTramplingFeatherFalling); - } - -+ public double floweringAzaleaGrowthChance = 0.0D; -+ private void floweringAzaleaSettings() { -+ floweringAzaleaGrowthChance = getDouble("blocks.flowering_azalea.growth-chance", floweringAzaleaGrowthChance); -+ } -+ - public boolean furnaceUseLavaFromUnderneath = false; - private void furnaceSettings() { - if (PurpurConfig.version < 17) { diff --git a/patches/server/0206-Shift-right-click-to-use-exp-for-mending.patch b/patches/server/0206-Shift-right-click-to-use-exp-for-mending.patch deleted file mode 100644 index 07182adf0..000000000 --- a/patches/server/0206-Shift-right-click-to-use-exp-for-mending.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 24 Aug 2021 16:48:35 -0500 -Subject: [PATCH] Shift right click to use exp for mending - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index a810eaa7dc319f5ea69b239190ae91838bfad4ec..6d194797d8fe2cd6e5652d596f4bc66ffc3b6375 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -513,6 +513,7 @@ public class ServerPlayerGameMode { - public InteractionHand interactHand; - public ItemStack interactItemStack; - public InteractionResult useItemOn(ServerPlayer player, Level world, ItemStack stack, InteractionHand hand, BlockHitResult hitResult) { -+ if (shiftClickMended(stack)) return InteractionResult.SUCCESS; // Purpur - BlockPos blockposition = hitResult.getBlockPos(); - BlockState iblockdata = world.getBlockState(blockposition); - boolean cancelledBlock = false; -@@ -622,4 +623,18 @@ public class ServerPlayerGameMode { - public void setLevel(ServerLevel world) { - this.level = world; - } -+ -+ // Purpur start -+ public boolean shiftClickMended(ItemStack itemstack) { -+ if (this.player.level().purpurConfig.shiftRightClickRepairsMendingPoints > 0 && this.player.isShiftKeyDown() && this.player.getBukkitEntity().hasPermission("purpur.mending_shift_click")) { -+ int points = Math.min(this.player.totalExperience, this.player.level().purpurConfig.shiftRightClickRepairsMendingPoints); -+ if (points > 0 && itemstack.isDamaged() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.MENDING, itemstack) > 0) { -+ this.player.giveExperiencePoints(-points); -+ this.player.level().addFreshEntity(new net.minecraft.world.entity.ExperienceOrb(this.player.level(), this.player.getX(), this.player.getY(), this.player.getZ(), points, org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN, this.player, this.player)); -+ return true; -+ } -+ } -+ return false; -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index cc3728902da9e10df2bb0e3edbb765bffd51d808..222436febf0b6ea93b57b8a4c0a98998a9430873 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2060,6 +2060,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - boolean cancelled; - if (movingobjectposition == null || movingobjectposition.getType() != HitResult.Type.BLOCK) { -+ if (this.player.gameMode.shiftClickMended(itemstack)) return; // Purpur - org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemstack, enumhand); - cancelled = event.useItemInHand() == Event.Result.DENY; - } else { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 49837f5ebccfb0d6fbfefe379f52433b44c5aa79..fb785f51d7774d31ed50f71f8048301fc2561ed0 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -411,6 +411,7 @@ public class PurpurWorldConfig { - public boolean playerBurpWhenFull = false; - public boolean playerRidableInWater = false; - public boolean playerRemoveBindingWithWeakness = false; -+ public int shiftRightClickRepairsMendingPoints = 0; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -435,6 +436,7 @@ public class PurpurWorldConfig { - playerBurpWhenFull = getBoolean("gameplay-mechanics.player.burp-when-full", playerBurpWhenFull); - playerRidableInWater = getBoolean("gameplay-mechanics.player.ridable-in-water", playerRidableInWater); - playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness); -+ shiftRightClickRepairsMendingPoints = getInt("gameplay-mechanics.player.shift-right-click-repairs-mending-points", shiftRightClickRepairsMendingPoints); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0207-Dolphins-naturally-aggressive-to-players-chance.patch b/patches/server/0207-Dolphins-naturally-aggressive-to-players-chance.patch deleted file mode 100644 index e75951668..000000000 --- a/patches/server/0207-Dolphins-naturally-aggressive-to-players-chance.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 30 Aug 2021 22:14:39 -0500 -Subject: [PATCH] Dolphins naturally aggressive to players chance - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -index 38112239035b0c66c429c0762199867e70e0a67a..e539eefb6e6d3172611d1f9185a1138001481885 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -@@ -81,6 +81,7 @@ public class Dolphin extends WaterAnimal { - public static final Predicate ALLOWED_ITEMS = (entityitem) -> { - return !entityitem.hasPickUpDelay() && entityitem.isAlive() && entityitem.isInWater(); - }; -+ private boolean isNaturallyAggressiveToPlayers; // Purpur - private int spitCooldown; // Purpur - - public Dolphin(EntityType type, Level world) { -@@ -172,6 +173,7 @@ public class Dolphin extends WaterAnimal { - public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { - this.setAirSupply(this.getMaxAirSupply()); - this.setXRot(0.0F); -+ this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance; // Purpur - return super.finalizeSpawn(world, difficulty, spawnReason, entityData); - } - -@@ -236,6 +238,7 @@ public class Dolphin extends WaterAnimal { - protected void registerGoals() { - this.goalSelector.addGoal(0, new BreathAirGoal(this)); - this.goalSelector.addGoal(0, new TryFindWaterGoal(this)); -+ this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this)); - this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0D)); -@@ -243,12 +246,13 @@ public class Dolphin extends WaterAnimal { - this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); - this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 6.0F)); - this.goalSelector.addGoal(5, new DolphinJumpGoal(this, 10)); -- this.goalSelector.addGoal(6, new MeleeAttackGoal(this, 1.2000000476837158D, true)); -+ //this.goalSelector.addGoal(6, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - moved up - this.goalSelector.addGoal(8, new Dolphin.PlayWithItemsGoal()); - this.goalSelector.addGoal(8, new FollowBoatGoal(this)); - this.goalSelector.addGoal(9, new AvoidEntityGoal<>(this, Guardian.class, 8.0F, 1.0D, 1.0D)); - this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Guardian.class})).setAlertOthers()); -+ this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, target -> isNaturallyAggressiveToPlayers)); // Purpur - } - - public static AttributeSupplier.Builder createAttributes() { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index fb785f51d7774d31ed50f71f8048301fc2561ed0..b1a941d2747ca93354c9abb67df8419114f27ff7 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1333,6 +1333,7 @@ public class PurpurWorldConfig { - public double dolphinMaxHealth = 10.0D; - public boolean dolphinDisableTreasureSearching = false; - public boolean dolphinTakeDamageFromWater = false; -+ public double dolphinNaturallyAggressiveToPlayersChance = 0.0D; - private void dolphinSettings() { - dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); - dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable); -@@ -1347,6 +1348,7 @@ public class PurpurWorldConfig { - dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth); - dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching); - dolphinTakeDamageFromWater = getBoolean("mobs.dolphin.takes-damage-from-water", dolphinTakeDamageFromWater); -+ dolphinNaturallyAggressiveToPlayersChance = getDouble("mobs.dolphin.naturally-aggressive-to-players-chance", dolphinNaturallyAggressiveToPlayersChance); - } - - public boolean donkeyRidableInWater = false; diff --git a/patches/server/0208-Cows-naturally-aggressive-to-players-chance.patch b/patches/server/0208-Cows-naturally-aggressive-to-players-chance.patch deleted file mode 100644 index dd14b76e4..000000000 --- a/patches/server/0208-Cows-naturally-aggressive-to-players-chance.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 30 Aug 2021 22:49:53 -0500 -Subject: [PATCH] Cows naturally aggressive to players chance - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java -index 8c908891c6c683332d8877ab3fa084a0849b17a9..541cc6c70178a430ac8e3ab8f6a2250b8ea1d964 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java -@@ -39,6 +39,7 @@ import org.bukkit.event.player.PlayerBucketFillEvent; - // CraftBukkit end - - public class Cow extends Animal { -+ private boolean isNaturallyAggressiveToPlayers; // Purpur - - private static final EntityDimensions BABY_DIMENSIONS = EntityType.COW.getDimensions().scale(0.5F).withEyeHeight(0.665F); - -@@ -66,6 +67,7 @@ public class Cow extends Animal { - @Override - public void initAttributes() { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth); -+ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.cowNaturallyAggressiveToPlayersDamage); // Purpur - } - - @Override -@@ -78,11 +80,18 @@ public class Cow extends Animal { - return this.level().purpurConfig.cowTakeDamageFromWater; - } - -+ @Override -+ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData entityData) { -+ this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance; -+ return super.finalizeSpawn(world, difficulty, spawnReason, entityData); -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new PanicGoal(this, 2.0D)); -+ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); - this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, (itemstack) -> { - return level().purpurConfig.cowFeedMushrooms > 0 && (itemstack.is(Blocks.RED_MUSHROOM.asItem()) || itemstack.is(Blocks.BROWN_MUSHROOM.asItem())) || itemstack.is(ItemTags.COW_FOOD); // Purpur -@@ -91,6 +100,7 @@ public class Cow extends Animal { - this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); - this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); -+ this.targetSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, target -> isNaturallyAggressiveToPlayers)); // Purpur - } - - @Override -@@ -99,7 +109,7 @@ public class Cow extends Animal { - } - - public static AttributeSupplier.Builder createAttributes() { -- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D); -+ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, 0.20000000298023224D).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b1a941d2747ca93354c9abb67df8419114f27ff7..0edff6f99dbea98f0d80f2a48d52d86874430ff5 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1282,7 +1282,14 @@ public class PurpurWorldConfig { - public int cowFeedMushrooms = 0; - public int cowBreedingTicks = 6000; - public boolean cowTakeDamageFromWater = false; -+ public double cowNaturallyAggressiveToPlayersChance = 0.0D; -+ public double cowNaturallyAggressiveToPlayersDamage = 2.0D; - private void cowSettings() { -+ if (PurpurConfig.version < 22) { -+ double oldValue = getDouble("mobs.cow.naturally-aggressive-to-players-chance", cowNaturallyAggressiveToPlayersChance); -+ set("mobs.cow.naturally-aggressive-to-players-chance", null); -+ set("mobs.cow.naturally-aggressive-to-players.chance", oldValue); -+ } - cowRidable = getBoolean("mobs.cow.ridable", cowRidable); - cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); - cowControllable = getBoolean("mobs.cow.controllable", cowControllable); -@@ -1295,6 +1302,8 @@ public class PurpurWorldConfig { - cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); - cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks); - cowTakeDamageFromWater = getBoolean("mobs.cow.takes-damage-from-water", cowTakeDamageFromWater); -+ cowNaturallyAggressiveToPlayersChance = getDouble("mobs.cow.naturally-aggressive-to-players.chance", cowNaturallyAggressiveToPlayersChance); -+ cowNaturallyAggressiveToPlayersDamage = getDouble("mobs.cow.naturally-aggressive-to-players.damage", cowNaturallyAggressiveToPlayersDamage); - } - - public boolean creeperRidable = false; diff --git a/patches/server/0209-Option-for-beds-to-explode-on-villager-sleep.patch b/patches/server/0209-Option-for-beds-to-explode-on-villager-sleep.patch deleted file mode 100644 index 8ee26831e..000000000 --- a/patches/server/0209-Option-for-beds-to-explode-on-villager-sleep.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Tue, 31 Aug 2021 16:48:29 +0200 -Subject: [PATCH] Option for beds to explode on villager sleep - - -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index a7c85c9efd13145cc061a3a0076b44a7af9812b9..1bace0d549ea4a4b45ac4cd1409524989ecac4ca 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -1101,6 +1101,12 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - - @Override - public void startSleeping(BlockPos pos) { -+ // Purpur start -+ if (level().purpurConfig.bedExplodeOnVillagerSleep && this.level().getBlockState(pos).getBlock() instanceof net.minecraft.world.level.block.BedBlock) { -+ this.level().explode(null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (float) this.level().purpurConfig.bedExplosionPower, this.level().purpurConfig.bedExplosionFire, this.level().purpurConfig.bedExplosionEffect); -+ return; -+ } -+ // Purpur end - super.startSleeping(pos); - this.brain.setMemory(MemoryModuleType.LAST_SLEPT, this.level().getGameTime()); // CraftBukkit - decompile error - this.brain.eraseMemory(MemoryModuleType.WALK_TARGET); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 0edff6f99dbea98f0d80f2a48d52d86874430ff5..613dcb1b68169c724dbf63a6327dab5b50dd4a8d 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -825,6 +825,7 @@ public class PurpurWorldConfig { - } - - public boolean bedExplode = true; -+ public boolean bedExplodeOnVillagerSleep = false; - public double bedExplosionPower = 5.0D; - public boolean bedExplosionFire = true; - public net.minecraft.world.level.Level.ExplosionInteraction bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -@@ -835,6 +836,7 @@ public class PurpurWorldConfig { - } - } - bedExplode = getBoolean("blocks.bed.explode", bedExplode); -+ bedExplodeOnVillagerSleep = getBoolean("blocks.bed.explode-on-villager-sleep", bedExplodeOnVillagerSleep); - bedExplosionPower = getDouble("blocks.bed.explosion-power", bedExplosionPower); - bedExplosionFire = getBoolean("blocks.bed.explosion-fire", bedExplosionFire); - try { diff --git a/patches/server/0210-Halloween-options-and-optimizations.patch b/patches/server/0210-Halloween-options-and-optimizations.patch deleted file mode 100644 index 95eff8c09..000000000 --- a/patches/server/0210-Halloween-options-and-optimizations.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: DoctaEnkoda -Date: Mon, 13 Sep 2021 04:48:21 +0200 -Subject: [PATCH] Halloween options and optimizations - - -diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index a7847b6ca5b203fd693337928f31a9043be163d7..a50d58240c58a0fea4ae8fc24689870807103199 100644 ---- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java -+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -301,7 +301,7 @@ public class Bat extends AmbientCreature { - int i = world.getMaxLocalRawBrightness(pos); - byte b0 = 4; - -- if (Bat.isHalloween()) { -+ if (Bat.isHalloweenSeason(world.getMinecraftWorld())) { // Purpur - b0 = 7; - } else if (random.nextBoolean()) { - return false; -@@ -311,6 +311,7 @@ public class Bat extends AmbientCreature { - } - } - -+ public static boolean isHalloweenSeason(Level level) { return level.purpurConfig.forceHalloweenSeason || isHalloween(); } // Purpur - private static boolean isHalloween() { - LocalDate localdate = LocalDate.now(); - int i = localdate.get(ChronoField.DAY_OF_MONTH); -diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -index 919767affe2ede755cf83398436fbf1581ad508f..8515e6360c1630385884a60f652f65fdefeaf540 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -135,11 +135,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - this.reassessWeaponGoal(); - this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot - if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { -- LocalDate localdate = LocalDate.now(); -- int i = localdate.get(ChronoField.DAY_OF_MONTH); -- int j = localdate.get(ChronoField.MONTH_OF_YEAR); -- -- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) { -+ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(world.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur - this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); - this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index 53f7659aed2378b36f1923a0208c7f86048eb85b..d5a5e51e23328deac09d6990539d8207b1567912 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -575,11 +575,7 @@ public class Zombie extends Monster { - } - - if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { -- LocalDate localdate = LocalDate.now(); -- int i = localdate.get(ChronoField.DAY_OF_MONTH); -- int j = localdate.get(ChronoField.MONTH_OF_YEAR); -- -- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) { -+ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(world.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur - this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); - this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 613dcb1b68169c724dbf63a6327dab5b50dd4a8d..1b7ebd3fe3cefd1ca26957835a93e103641ddb7a 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1675,6 +1675,13 @@ public class PurpurWorldConfig { - guardianTakeDamageFromWater = getBoolean("mobs.guardian.takes-damage-from-water", guardianTakeDamageFromWater); - } - -+ public boolean forceHalloweenSeason = false; -+ public float chanceHeadHalloweenOnEntity = 0.25F; -+ private void halloweenSetting() { -+ forceHalloweenSeason = getBoolean("gameplay-mechanics.halloween.force", forceHalloweenSeason); -+ chanceHeadHalloweenOnEntity = (float) getDouble("gameplay-mechanics.halloween.head-chance", chanceHeadHalloweenOnEntity); -+ } -+ - public boolean hoglinRidable = false; - public boolean hoglinRidableInWater = true; - public boolean hoglinControllable = true; diff --git a/patches/server/0211-Config-for-grindstones.patch b/patches/server/0211-Config-for-grindstones.patch deleted file mode 100644 index 2dd7aa81b..000000000 --- a/patches/server/0211-Config-for-grindstones.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Wed, 29 Sep 2021 13:37:57 -0400 -Subject: [PATCH] Config for grindstones - - -diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -index db9444dda248260372d96ce239a590e88a4c1142..5824636332eb35ae6bee9cc0661ee95901bb8c4b 100644 ---- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -@@ -130,7 +130,7 @@ public class GrindstoneMenu extends AbstractContainerMenu { - Enchantment enchantment = (Enchantment) ((Holder) entry.getKey()).value(); - int k = entry.getIntValue(); - -- if (!enchantment.isCurse()) { -+ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(enchantment)) { // Purpur - j += enchantment.getMinCost(k); - } - } -@@ -229,7 +229,7 @@ public class GrindstoneMenu extends AbstractContainerMenu { - Entry> entry = (Entry) iterator.next(); - Enchantment enchantment = (Enchantment) ((Holder) entry.getKey()).value(); - -- if (!enchantment.isCurse() || itemenchantments_a.getLevel(enchantment) == 0) { -+ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(enchantment) || itemenchantments_a.getLevel(enchantment) == 0) { // Purpur - itemenchantments_a.upgrade(enchantment, entry.getIntValue()); - } - } -@@ -237,10 +237,70 @@ public class GrindstoneMenu extends AbstractContainerMenu { - }); - } - -+ // Purpur start -+ private java.util.List> GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST = java.util.List.of( -+ // DataComponents.MAX_STACK_SIZE, -+ // DataComponents.DAMAGE, -+ // DataComponents.BLOCK_STATE, -+ DataComponents.CUSTOM_DATA, -+ // DataComponents.MAX_DAMAGE, -+ // DataComponents.UNBREAKABLE, -+ // DataComponents.CUSTOM_NAME, -+ // DataComponents.ITEM_NAME, -+ // DataComponents.LORE, -+ // DataComponents.RARITY, -+ // DataComponents.ENCHANTMENTS, -+ // DataComponents.CAN_PLACE_ON, -+ // DataComponents.CAN_BREAK, -+ DataComponents.ATTRIBUTE_MODIFIERS, -+ DataComponents.CUSTOM_MODEL_DATA, -+ // DataComponents.HIDE_ADDITIONAL_TOOLTIP, -+ // DataComponents.HIDE_TOOLTIP, -+ // DataComponents.REPAIR_COST, -+ // DataComponents.CREATIVE_SLOT_LOCK, -+ // DataComponents.ENCHANTMENT_GLINT_OVERRIDE, -+ // DataComponents.INTANGIBLE_PROJECTILE, -+ // DataComponents.FOOD, -+ // DataComponents.FIRE_RESISTANT, -+ // DataComponents.TOOL, -+ // DataComponents.STORED_ENCHANTMENTS, -+ DataComponents.DYED_COLOR, -+ // DataComponents.MAP_COLOR, -+ // DataComponents.MAP_ID, -+ // DataComponents.MAP_DECORATIONS, -+ // DataComponents.MAP_POST_PROCESSING, -+ // DataComponents.CHARGED_PROJECTILES, -+ // DataComponents.BUNDLE_CONTENTS, -+ // DataComponents.POTION_CONTENTS, -+ DataComponents.SUSPICIOUS_STEW_EFFECTS -+ // DataComponents.WRITABLE_BOOK_CONTENT, -+ // DataComponents.WRITTEN_BOOK_CONTENT, -+ // DataComponents.TRIM, -+ // DataComponents.DEBUG_STICK_STATE, -+ // DataComponents.ENTITY_DATA, -+ // DataComponents.BUCKET_ENTITY_DATA, -+ // DataComponents.BLOCK_ENTITY_DATA, -+ // DataComponents.INSTRUMENT, -+ // DataComponents.OMINOUS_BOTTLE_AMPLIFIER, -+ // DataComponents.RECIPES, -+ // DataComponents.LODESTONE_TRACKER, -+ // DataComponents.FIREWORK_EXPLOSION, -+ // DataComponents.FIREWORKS, -+ // DataComponents.PROFILE, -+ // DataComponents.NOTE_BLOCK_SOUND, -+ // DataComponents.BANNER_PATTERNS, -+ // DataComponents.BASE_COLOR, -+ // DataComponents.POT_DECORATIONS, -+ // DataComponents.CONTAINER, -+ // DataComponents.BEES, -+ // DataComponents.LOCK, -+ // DataComponents.CONTAINER_LOOT, -+ ); -+ // Purpur end - private ItemStack removeNonCursesFrom(ItemStack item) { - ItemEnchantments itemenchantments = EnchantmentHelper.updateEnchantments(item, (itemenchantments_a) -> { - itemenchantments_a.removeIf((holder) -> { -- return !((Enchantment) holder.value()).isCurse(); -+ return !org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value()); - }); - }); - -@@ -255,6 +315,23 @@ public class GrindstoneMenu extends AbstractContainerMenu { - } - - item.set(DataComponents.REPAIR_COST, i); -+ -+ // Purpur start -+ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder(); -+ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveAttributes) { -+ item.getComponents().forEach(typedDataComponent -> { -+ if (GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST.contains(typedDataComponent.type())) { -+ builder.remove(typedDataComponent.type()); -+ } -+ }); -+ } -+ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveDisplay) { -+ builder.remove(DataComponents.CUSTOM_NAME); -+ builder.remove(DataComponents.LORE); -+ } -+ item.applyComponents(builder.build()); -+ // Purpur end -+ - return item; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index b56afa30c04350b5e9ca4ea2d33f9e7c58559380..7f0a9a239791cfb1d721d24f907b89ae2dd4c64a 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -309,6 +309,9 @@ public class PurpurConfig { - public static int beeInsideBeeHive = 3; - public static boolean anvilCumulativeCost = true; - public static int lightningRodRange = 128; -+ public static Set grindstoneIgnoredEnchants = new HashSet<>(); -+ public static boolean grindstoneRemoveAttributes = false; -+ public static boolean grindstoneRemoveDisplay = false; - private static void blockSettings() { - if (version < 3) { - boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); -@@ -343,6 +346,19 @@ public class PurpurConfig { - beeInsideBeeHive = getInt("settings.blocks.beehive.max-bees-inside", beeInsideBeeHive); - anvilCumulativeCost = getBoolean("settings.blocks.anvil.cumulative-cost", anvilCumulativeCost); - lightningRodRange = getInt("settings.blocks.lightning_rod.range", lightningRodRange); -+ ArrayList defaultCurses = new ArrayList<>(){{ -+ add("minecraft:binding_curse"); -+ add("minecraft:vanishing_curse"); -+ }}; -+ if (version < 24 && !getBoolean("settings.blocks.grindstone.ignore-curses", true)) { -+ defaultCurses.clear(); -+ } -+ getList("settings.blocks.grindstone.ignored-enchants", defaultCurses).forEach(key -> { -+ Enchantment enchantment = BuiltInRegistries.ENCHANTMENT.get(new ResourceLocation(key.toString())); -+ grindstoneIgnoredEnchants.add(enchantment); -+ }); -+ grindstoneRemoveAttributes = getBoolean("settings.blocks.grindstone.remove-attributes", grindstoneRemoveAttributes); -+ grindstoneRemoveDisplay = getBoolean("settings.blocks.grindstone.remove-name-and-lore", grindstoneRemoveDisplay); - } - - public static boolean allowInfinityMending = false; diff --git a/patches/server/0212-UPnP-Port-Forwarding.patch b/patches/server/0212-UPnP-Port-Forwarding.patch deleted file mode 100644 index 6865e4805..000000000 --- a/patches/server/0212-UPnP-Port-Forwarding.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 22 Jan 2020 20:13:40 -0600 -Subject: [PATCH] UPnP Port Forwarding - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 6d84eb68e3160f772d6832513df2bc4db87b594e..0f4fde2097b9db59b6c29935462f305f34747b3b 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -317,6 +317,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Thu, 14 Oct 2021 01:53:20 -0700 -Subject: [PATCH] Campfire option for lit when placed - - -diff --git a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -index d6fffb0953494e8667cc456137cac0f5deebfbb6..f7a2244b998aebe354d38eec7aa22fd94ce404c9 100644 ---- a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -@@ -133,7 +133,7 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB - BlockPos blockposition = ctx.getClickedPos(); - boolean flag = world.getFluidState(blockposition).getType() == Fluids.WATER; - -- return (BlockState) ((BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(CampfireBlock.WATERLOGGED, flag)).setValue(CampfireBlock.SIGNAL_FIRE, this.isSmokeSource(world.getBlockState(blockposition.below())))).setValue(CampfireBlock.LIT, !flag)).setValue(CampfireBlock.FACING, ctx.getHorizontalDirection()); -+ return (BlockState) ((BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(CampfireBlock.WATERLOGGED, flag)).setValue(CampfireBlock.SIGNAL_FIRE, this.isSmokeSource(world.getBlockState(blockposition.below())))).setValue(CampfireBlock.LIT, world.purpurConfig.campFireLitWhenPlaced ? !flag : world.purpurConfig.campFireLitWhenPlaced)).setValue(CampfireBlock.FACING, ctx.getHorizontalDirection()); // Purpur - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 1b7ebd3fe3cefd1ca26957835a93e103641ddb7a..88d300ebbfa907712ddd77c2ca7dd91e04d22f21 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -868,6 +868,11 @@ public class PurpurWorldConfig { - cactusBreaksFromSolidNeighbors = getBoolean("blocks.cactus.breaks-from-solid-neighbors", cactusBreaksFromSolidNeighbors); - } - -+ public boolean campFireLitWhenPlaced = true; -+ private void campFireSettings() { -+ campFireLitWhenPlaced = getBoolean("blocks.campfire.lit-when-placed", campFireLitWhenPlaced); -+ } -+ - public boolean chestOpenWithBlockOnTop = false; - private void chestSettings() { - chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); diff --git a/patches/server/0214-options-to-extinguish-fire-blocks-with-snowballs.patch b/patches/server/0214-options-to-extinguish-fire-blocks-with-snowballs.patch deleted file mode 100644 index d3e4d711e..000000000 --- a/patches/server/0214-options-to-extinguish-fire-blocks-with-snowballs.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Thu, 14 Oct 2021 02:05:52 -0700 -Subject: [PATCH] options to extinguish fire blocks with snowballs - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java -index f59a2903bfb8ae591a638ea5bb387caaa93ce664..1b9d0e28e518c501b4b93ae385ddd64aeade97d5 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java -@@ -63,6 +63,36 @@ public class Snowball extends ThrowableItemProjectile { - entity.hurt(this.damageSources().thrown(this, this.getOwner()), (float) i); - } - -+ // Purpur start - borrowed and modified code from ThrownPotion#onHitBlock and ThrownPotion#dowseFire -+ @Override -+ protected void onHitBlock(net.minecraft.world.phys.BlockHitResult blockHitResult) { -+ super.onHitBlock(blockHitResult); -+ -+ if (!this.level().isClientSide) { -+ net.minecraft.core.BlockPos blockposition = blockHitResult.getBlockPos(); -+ net.minecraft.core.BlockPos blockposition1 = blockposition.relative(blockHitResult.getDirection()); -+ -+ net.minecraft.world.level.block.state.BlockState iblockdata = this.level().getBlockState(blockposition); -+ -+ if (this.level().purpurConfig.snowballExtinguishesFire && this.level().getBlockState(blockposition1).is(net.minecraft.world.level.block.Blocks.FIRE)) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition1, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) { -+ this.level().removeBlock(blockposition1, false); -+ } -+ } else if (this.level().purpurConfig.snowballExtinguishesCandles && net.minecraft.world.level.block.AbstractCandleBlock.isLit(iblockdata)) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.setValue(net.minecraft.world.level.block.AbstractCandleBlock.LIT, false))) { -+ net.minecraft.world.level.block.AbstractCandleBlock.extinguish(null, iblockdata, this.level(), blockposition); -+ } -+ } else if (this.level().purpurConfig.snowballExtinguishesCampfires && net.minecraft.world.level.block.CampfireBlock.isLitCampfire(iblockdata)) { -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.setValue(net.minecraft.world.level.block.CampfireBlock.LIT, false))) { -+ this.level().levelEvent(null, 1009, blockposition, 0); -+ net.minecraft.world.level.block.CampfireBlock.dowse(this.getOwner(), this.level(), blockposition, iblockdata); -+ this.level().setBlockAndUpdate(blockposition, iblockdata.setValue(net.minecraft.world.level.block.CampfireBlock.LIT, false)); -+ } -+ } -+ } -+ } -+ // Purpur end -+ - @Override - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 88d300ebbfa907712ddd77c2ca7dd91e04d22f21..d005e045f5fc2a9442fb070ebf984f34785ecc9e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -231,6 +231,9 @@ public class PurpurWorldConfig { - public int glowBerriesEatGlowDuration = 0; - public boolean shulkerBoxItemDropContentsWhenDestroyed = true; - public boolean compassItemShowsBossBar = false; -+ public boolean snowballExtinguishesFire = false; -+ public boolean snowballExtinguishesCandles = false; -+ public boolean snowballExtinguishesCampfires = false; - private void itemSettings() { - itemImmuneToCactus.clear(); - getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { -@@ -279,6 +282,9 @@ public class PurpurWorldConfig { - glowBerriesEatGlowDuration = getInt("gameplay-mechanics.item.glow_berries.eat-glow-duration", glowBerriesEatGlowDuration); - shulkerBoxItemDropContentsWhenDestroyed = getBoolean("gameplay-mechanics.item.shulker_box.drop-contents-when-destroyed", shulkerBoxItemDropContentsWhenDestroyed); - compassItemShowsBossBar = getBoolean("gameplay-mechanics.item.compass.holding-shows-bossbar", compassItemShowsBossBar); -+ snowballExtinguishesFire = getBoolean("gameplay-mechanics.item.snowball.extinguish.fire", snowballExtinguishesFire); -+ snowballExtinguishesCandles = getBoolean("gameplay-mechanics.item.snowball.extinguish.candles", snowballExtinguishesCandles); -+ snowballExtinguishesCampfires = getBoolean("gameplay-mechanics.item.snowball.extinguish.campfires", snowballExtinguishesCampfires); - } - - public double minecartMaxSpeed = 0.4D; diff --git a/patches/server/0215-Add-option-to-disable-zombie-villagers-cure.patch b/patches/server/0215-Add-option-to-disable-zombie-villagers-cure.patch deleted file mode 100644 index 7fb8dcede..000000000 --- a/patches/server/0215-Add-option-to-disable-zombie-villagers-cure.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: rafael59r2 <12960698+rafael59r2@users.noreply.github.com> -Date: Tue, 19 Oct 2021 13:10:44 +0100 -Subject: [PATCH] Add option to disable zombie villagers cure - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index d909138942212ee090ff513b1817414c93457425..fe43c744cccdc07d5e449ce3ede85f4c7d898018 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -219,7 +219,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - ItemStack itemstack = player.getItemInHand(hand); - - if (itemstack.is(Items.GOLDEN_APPLE)) { -- if (this.hasEffect(MobEffects.WEAKNESS)) { -+ if (this.hasEffect(MobEffects.WEAKNESS) && level().purpurConfig.zombieVillagerCureEnabled) { // Purpur - itemstack.consume(1, player); - if (!this.level().isClientSide) { - this.startConverting(player.getUUID(), this.random.nextInt(level().purpurConfig.zombieVillagerCuringTimeMax - level().purpurConfig.zombieVillagerCuringTimeMin + 1) + level().purpurConfig.zombieVillagerCuringTimeMin); // Purpur -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index d005e045f5fc2a9442fb070ebf984f34785ecc9e..8d4c3c4a06d40841e8446485364393e36e686fdd 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2894,6 +2894,7 @@ public class PurpurWorldConfig { - public boolean zombieVillagerTakeDamageFromWater = false; - public int zombieVillagerCuringTimeMin = 3600; - public int zombieVillagerCuringTimeMax = 6000; -+ public boolean zombieVillagerCureEnabled = true; - private void zombieVillagerSettings() { - zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); - zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); -@@ -2911,6 +2912,7 @@ public class PurpurWorldConfig { - zombieVillagerTakeDamageFromWater = getBoolean("mobs.zombie_villager.takes-damage-from-water", zombieVillagerTakeDamageFromWater); - zombieVillagerCuringTimeMin = getInt("mobs.zombie_villager.curing_time.min", zombieVillagerCuringTimeMin); - zombieVillagerCuringTimeMax = getInt("mobs.zombie_villager.curing_time.max", zombieVillagerCuringTimeMax); -+ zombieVillagerCureEnabled = getBoolean("mobs.zombie_villager.cure.enabled", zombieVillagerCureEnabled); - } - - public boolean zombifiedPiglinRidable = false; diff --git a/patches/server/0216-Persistent-BlockEntity-Lore-and-DisplayName.patch b/patches/server/0216-Persistent-BlockEntity-Lore-and-DisplayName.patch deleted file mode 100644 index f76de1cf7..000000000 --- a/patches/server/0216-Persistent-BlockEntity-Lore-and-DisplayName.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> -Date: Wed, 30 Sep 2020 14:32:46 -0700 -Subject: [PATCH] Persistent BlockEntity Lore and DisplayName - -Makes it so that when a BlockEntity is placed in the world and then broken, -the dropped ItemStack retains any original custom display name/lore. - -diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java -index 2649188930653610b8aaaeb18797c80879cd572a..7572c289758001c7417a192f0e6e994ffa8408b3 100644 ---- a/src/main/java/net/minecraft/world/item/BlockItem.java -+++ b/src/main/java/net/minecraft/world/item/BlockItem.java -@@ -157,7 +157,16 @@ public class BlockItem extends Item { - } - - protected boolean updateCustomBlockEntityTag(BlockPos pos, Level world, @Nullable Player player, ItemStack stack, BlockState state) { -- return BlockItem.updateCustomBlockEntityTag(world, player, pos, stack); -+ // Purpur start -+ boolean handled = updateCustomBlockEntityTag(world, player, pos, stack); -+ if (world.purpurConfig.persistentTileEntityLore) { -+ BlockEntity blockEntity1 = world.getBlockEntity(pos); -+ if (blockEntity1 != null) { -+ blockEntity1.setPersistentLore(stack.getOrDefault(DataComponents.LORE, net.minecraft.world.item.component.ItemLore.EMPTY)); -+ } -+ } -+ return handled; -+ // Purpur end - } - - @Nullable -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 6f7e90d406b088fee0eb254f8042bd404d8f36fa..7ffe51eedc9d086424cf450026bdc260249864c4 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -312,7 +312,7 @@ public class Block extends BlockBehaviour implements ItemLike { - public static void dropResources(BlockState state, LevelAccessor world, BlockPos pos, @Nullable BlockEntity blockEntity) { - if (world instanceof ServerLevel) { - Block.getDrops(state, (ServerLevel) world, pos, blockEntity).forEach((itemstack) -> { -- Block.popResource((ServerLevel) world, pos, itemstack); -+ Block.popResource((ServerLevel) world, pos, applyLoreFromTile(itemstack, blockEntity)); // Purpur - }); - state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY, true); - } -@@ -331,7 +331,7 @@ public class Block extends BlockBehaviour implements ItemLike { - event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping - event.callEvent(); - for (org.bukkit.inventory.ItemStack drop : event.getDrops()) { -- popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop)); -+ popResource(serverLevel, pos, applyLoreFromTile(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop), blockEntity)); // Purpur - } - state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping - block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping -@@ -348,13 +348,32 @@ public class Block extends BlockBehaviour implements ItemLike { - // Paper end - Properly handle xp dropping - if (world instanceof ServerLevel) { - Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> { -- Block.popResource(world, pos, itemstack1); -+ Block.popResource(world, pos, applyLoreFromTile(itemstack1, blockEntity)); // Purpur - }); - state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper - Properly handle xp dropping - } - - } - -+ // Purpur start -+ private static ItemStack applyLoreFromTile(ItemStack stack, @Nullable BlockEntity blockEntity) { -+ if (stack.getItem() instanceof BlockItem) { -+ if (blockEntity != null && blockEntity.getLevel() instanceof ServerLevel) { -+ net.minecraft.world.item.component.ItemLore lore = blockEntity.getPersistentLore(); -+ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder(); -+ if (blockEntity.getLevel().purpurConfig.persistentTileEntityLore && lore != null) { -+ builder.set(net.minecraft.core.component.DataComponents.LORE, lore); -+ } -+ if (!blockEntity.getLevel().purpurConfig.persistentTileEntityDisplayName) { -+ builder.remove(net.minecraft.core.component.DataComponents.CUSTOM_NAME); -+ } -+ stack.applyComponents(builder.build()); -+ } -+ } -+ return stack; -+ } -+ // Purpur end -+ - public static void popResource(Level world, BlockPos pos, ItemStack stack) { - double d0 = (double) EntityType.ITEM.getHeight() / 2.0D; - double d1 = (double) pos.getX() + 0.5D + Mth.nextDouble(world.random, -0.25D, 0.25D); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 6349f2e0a5ba30d250f5ffe43771f325c0999a76..8dc1436fe78759cee5247cc28e8a18999e738a1b 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -87,6 +87,12 @@ public abstract class BlockEntity { - if (persistentDataTag instanceof CompoundTag) { - this.persistentDataContainer.putAll((CompoundTag) persistentDataTag); - } -+ // Purpur start -+ if (nbt.contains("Purpur.persistentLore")) { -+ net.minecraft.world.item.component.ItemLore.CODEC.decode(net.minecraft.nbt.NbtOps.INSTANCE, nbt.getCompound("Purpur.persistentLore")).result() -+ .ifPresent(tag -> this.persistentLore = tag.getFirst()); -+ } -+ // Purpur end - } - // CraftBukkit end - -@@ -103,6 +109,15 @@ public abstract class BlockEntity { - this.loadAdditional(nbt, registryLookup); - } - -+ // Purpur start -+ protected void saveAdditional(CompoundTag nbt) { -+ if (this.persistentLore != null) { -+ net.minecraft.world.item.component.ItemLore.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, this.persistentLore).result() -+ .ifPresent(tag -> nbt.put("Purpur.persistentLore", tag)); -+ } -+ } -+ // Purpur end -+ - protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registryLookup) {} - - public final CompoundTag saveWithFullMetadata(HolderLookup.Provider registryLookup) { -@@ -407,4 +422,16 @@ public abstract class BlockEntity { - - T getOrDefault(DataComponentType type, T fallback); - } -+ // Purpur start -+ @Nullable -+ private net.minecraft.world.item.component.ItemLore persistentLore = null; -+ -+ public void setPersistentLore(net.minecraft.world.item.component.ItemLore lore) { -+ this.persistentLore = lore; -+ } -+ -+ public @org.jetbrains.annotations.Nullable net.minecraft.world.item.component.ItemLore getPersistentLore() { -+ return this.persistentLore; -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 8d4c3c4a06d40841e8446485364393e36e686fdd..abe3614f2286db8945bc6c4eadd01ec8a7f93555 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -130,6 +130,8 @@ public class PurpurWorldConfig { - public boolean milkCuresBadOmen = true; - public boolean noteBlockIgnoreAbove = false; - public boolean persistentDroppableEntityDisplayNames = true; -+ public boolean persistentTileEntityLore = false; -+ public boolean persistentTileEntityDisplayName = true; - public boolean projectilesBypassMobGriefing = false; - public boolean tickFluids = true; - public double mobsBlindnessMultiplier = 1; -@@ -153,6 +155,14 @@ public class PurpurWorldConfig { - imposeTeleportRestrictionsOnGateways = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-gateways", imposeTeleportRestrictionsOnGateways); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); - noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove); -+ if (PurpurConfig.version < 35) { -+ boolean oldVal = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityLore); -+ set("gameplay-mechanics.persistent-tileentity-display-names-and-lore", null); -+ set("gameplay-mechanics.persistent-tileentity-lore", oldVal); -+ set("gameplay-mechanics.persistent-tileentity-display-name", !oldVal); -+ } -+ persistentTileEntityLore = getBoolean("gameplay-mechanics.persistent-tileentity-lore", persistentTileEntityLore); -+ persistentTileEntityDisplayName = getBoolean("gameplay-mechanics.persistent-tileentity-display-name", persistentTileEntityDisplayName); - persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); - projectilesBypassMobGriefing = getBoolean("gameplay-mechanics.projectiles-bypass-mob-griefing", projectilesBypassMobGriefing); - tickFluids = getBoolean("gameplay-mechanics.tick-fluids", tickFluids); diff --git a/patches/server/0217-Signs-allow-color-codes.patch b/patches/server/0217-Signs-allow-color-codes.patch deleted file mode 100644 index f547212e5..000000000 --- a/patches/server/0217-Signs-allow-color-codes.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 6 Jun 2019 17:40:30 -0500 -Subject: [PATCH] Signs allow color codes - - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index e9d9cb47221075447aac66dd30ce6e8f08962cf5..635e6b46081ec0078b687818310e623cbbf1cc1f 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -1683,6 +1683,7 @@ public class ServerPlayer extends Player { - - @Override - public void openTextEdit(SignBlockEntity sign, boolean front) { -+ if (level().purpurConfig.signAllowColors) this.connection.send(sign.getTranslatedUpdatePacket(textFilteringEnabled, front)); // Purpur - this.connection.send(new ClientboundBlockUpdatePacket(this.level(), sign.getBlockPos())); - this.connection.send(new ClientboundOpenSignEditorPacket(sign.getBlockPos(), front)); - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -index a28be7a332659be655f419d969e0c64e659b6c21..8cd812a25b1cc05ea14675658bf9c1503ebebd51 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -@@ -201,16 +201,31 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C - return this.setText((SignText) textChanger.apply(signtext), front); - } - -+ // Purpur start -+ private Component translateColors(org.bukkit.entity.Player player, String line, Style style) { -+ if (level.purpurConfig.signAllowColors) { -+ if (player.hasPermission("purpur.sign.color")) line = line.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1"); -+ if (player.hasPermission("purpur.sign.style")) line = line.replaceAll("(?i)&([l-or])", "\u00a7$1"); -+ if (player.hasPermission("purpur.sign.magic")) line = line.replaceAll("(?i)&([kr])", "\u00a7$1"); -+ -+ return io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line)); -+ } else { -+ return Component.literal(line).setStyle(style); -+ } -+ } -+ // Purpur end -+ - private SignText setMessages(net.minecraft.world.entity.player.Player entityhuman, List list, SignText signtext, boolean front) { // CraftBukkit - SignText originalText = signtext; // CraftBukkit - for (int i = 0; i < list.size(); ++i) { - FilteredText filteredtext = (FilteredText) list.get(i); - Style chatmodifier = signtext.getMessage(i, entityhuman.isTextFilteringEnabled()).getStyle(); - -+ org.bukkit.entity.Player player = (org.bukkit.craftbukkit.entity.CraftPlayer) entityhuman.getBukkitEntity(); // Purpur - if (entityhuman.isTextFilteringEnabled()) { -- signtext = signtext.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only -+ signtext = signtext.setMessage(i, translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty()), chatmodifier)); // Paper - filter sign text to chat only // Purpur - } else { -- signtext = signtext.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.raw())).setStyle(chatmodifier), Component.literal(net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty())).setStyle(chatmodifier)); // Paper - filter sign text to chat only -+ signtext = signtext.setMessage(i, translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.raw()), chatmodifier), translateColors(player, net.minecraft.util.StringUtil.filterText(filteredtext.filteredOrEmpty()), chatmodifier)); // Paper - filter sign text to chat only // Purpur - } - } - -@@ -345,6 +360,28 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C - return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel) world, 2, s, (Component) object, world.getServer(), player); // Paper - Fix commands from signs not firing command events - } - -+ // Purpur start -+ public ClientboundBlockEntityDataPacket getTranslatedUpdatePacket(boolean filtered, boolean front) { -+ final CompoundTag nbt = new CompoundTag(); -+ this.saveAdditional(nbt, this.getLevel().registryAccess()); -+ final Component[] lines = front ? frontText.getMessages(filtered) : backText.getMessages(filtered); -+ final String side = front ? "front_text" : "back_text"; -+ for (int i = 0; i < 4; i++) { -+ final var component = io.papermc.paper.adventure.PaperAdventure.asAdventure(lines[i]); -+ final String line = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().serialize(component); -+ final var text = net.kyori.adventure.text.Component.text(line); -+ final String json = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(text); -+ if (!nbt.contains(side)) nbt.put(side, new CompoundTag()); -+ final CompoundTag sideNbt = nbt.getCompound(side); -+ if (!sideNbt.contains("messages")) sideNbt.put("messages", new net.minecraft.nbt.ListTag()); -+ final net.minecraft.nbt.ListTag messagesNbt = sideNbt.getList("messages", Tag.TAG_STRING); -+ messagesNbt.set(i, net.minecraft.nbt.StringTag.valueOf(json)); -+ } -+ nbt.putString("PurpurEditor", "true"); -+ return ClientboundBlockEntityDataPacket.create(this, (blockEntity, registryAccess) -> nbt); -+ } -+ // Purpur end -+ - @Override - public ClientboundBlockEntityDataPacket getUpdatePacket() { - return ClientboundBlockEntityDataPacket.create(this); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index abe3614f2286db8945bc6c4eadd01ec8a7f93555..6fce1773a4b5008f3234e06b556bf12e140eb1c1 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1041,6 +1041,11 @@ public class PurpurWorldConfig { - } - } - -+ public boolean signAllowColors = false; -+ private void signSettings() { -+ signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors); -+ } -+ - public boolean slabHalfBreak = false; - private void slabSettings() { - slabHalfBreak = getBoolean("blocks.slab.break-individual-slabs-when-sneaking", slabHalfBreak); diff --git a/patches/server/0218-Kelp-cave-weeping-and-twisting-vines-configurable-ma.patch b/patches/server/0218-Kelp-cave-weeping-and-twisting-vines-configurable-ma.patch deleted file mode 100644 index 68ed8eff9..000000000 --- a/patches/server/0218-Kelp-cave-weeping-and-twisting-vines-configurable-ma.patch +++ /dev/null @@ -1,182 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 22 Nov 2020 20:13:27 -0600 -Subject: [PATCH] Kelp, cave, weeping, and twisting vines configurable max - growth age - - -diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java -index 635fc086d832c641f840cf36d18cdc0fcc3beef3..e3ff7b8059da499cfde1106f6d51156931b292dc 100644 ---- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java -@@ -94,4 +94,11 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements Bonemealabl - public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { - world.setBlock(pos, state.setValue(BERRIES, Boolean.valueOf(true)), 2); - } -+ -+ // Purpur start -+ @Override -+ public int getMaxGrowthAge() { -+ return org.purpurmc.purpur.PurpurConfig.caveVinesMaxGrowthAge; -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java -index cf05da1c86e3018db11dc079bf50317b6639e5cc..8e9903899ac91e9431f00675c1f5ac4a18e61593 100644 ---- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java -@@ -34,12 +34,12 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements - - @Override - public BlockState getStateForPlacement(LevelAccessor world) { -- return (BlockState) this.defaultBlockState().setValue(GrowingPlantHeadBlock.AGE, world.getRandom().nextInt(25)); -+ return (BlockState) this.defaultBlockState().setValue(GrowingPlantHeadBlock.AGE, world.getRandom().nextInt(getMaxGrowthAge())); // Purpur - } - - @Override - protected boolean isRandomlyTicking(BlockState state) { -- return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25; -+ return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < getMaxGrowthAge(); // Purpur - } - - @Override -@@ -55,7 +55,7 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements - } else { - modifier = world.spigotConfig.caveVinesModifier; - } -- if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25 && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution -+ if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < getMaxGrowthAge() && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution // Purpur - // Spigot end - BlockPos blockposition1 = pos.relative(this.growthDirection); - -@@ -77,11 +77,11 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements - } - - public BlockState getMaxAgeState(BlockState state) { -- return (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, 25); -+ return (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, getMaxGrowthAge()); // Purpur - } - - public boolean isMaxAge(BlockState state) { -- return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) == 25; -+ return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) >= getMaxGrowthAge(); // Purpur - } - - protected BlockState updateBodyAfterConvertedFromHead(BlockState from, BlockState to) { -@@ -123,13 +123,13 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements - @Override - public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { - BlockPos blockposition1 = pos.relative(this.growthDirection); -- int i = Math.min((Integer) state.getValue(GrowingPlantHeadBlock.AGE) + 1, 25); -+ int i = Math.min((Integer) state.getValue(GrowingPlantHeadBlock.AGE) + 1, getMaxGrowthAge()); // Purpur - int j = this.getBlocksToGrowWhenBonemealed(random); - - for (int k = 0; k < j && this.canGrowInto(world.getBlockState(blockposition1)); ++k) { - world.setBlockAndUpdate(blockposition1, (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, i)); - blockposition1 = blockposition1.relative(this.growthDirection); -- i = Math.min(i + 1, 25); -+ i = Math.min(i + 1, getMaxGrowthAge()); // Purpur - } - - } -@@ -142,4 +142,6 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements - protected GrowingPlantHeadBlock getHeadBlock() { - return this; - } -+ -+ public abstract int getMaxGrowthAge(); // Purpur - } -diff --git a/src/main/java/net/minecraft/world/level/block/KelpBlock.java b/src/main/java/net/minecraft/world/level/block/KelpBlock.java -index 784b19bc78c8ad9476b6dac37b6778a409a7c675..d49dd8b20d3785cc9482ed2a34fbd7aed4c9e537 100644 ---- a/src/main/java/net/minecraft/world/level/block/KelpBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/KelpBlock.java -@@ -72,4 +72,11 @@ public class KelpBlock extends GrowingPlantHeadBlock implements LiquidBlockConta - protected FluidState getFluidState(BlockState state) { - return Fluids.WATER.getSource(false); - } -+ -+ // Purpur start -+ @Override -+ public int getMaxGrowthAge() { -+ return org.purpurmc.purpur.PurpurConfig.kelpMaxGrowthAge; -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java b/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java -index 6342bb11a162b9e6d9475c5989b1670d77e8f0fb..f8be92512446d3f0e5f0f21222bbefd04ab2838a 100644 ---- a/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TwistingVinesBlock.java -@@ -34,4 +34,11 @@ public class TwistingVinesBlock extends GrowingPlantHeadBlock { - protected boolean canGrowInto(BlockState state) { - return NetherVines.isValidGrowthState(state); - } -+ -+ // Purpur start -+ @Override -+ public int getMaxGrowthAge() { -+ return org.purpurmc.purpur.PurpurConfig.twistingVinesMaxGrowthAge; -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java b/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java -index 3dec5a082606ee35a8c8d7f746480262d6a189c5..b2f6ccae9576c176263e51a232e17a08d54543b3 100644 ---- a/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/WeepingVinesBlock.java -@@ -34,4 +34,11 @@ public class WeepingVinesBlock extends GrowingPlantHeadBlock { - protected boolean canGrowInto(BlockState state) { - return NetherVines.isValidGrowthState(state); - } -+ -+ // Purpur start -+ @Override -+ public int getMaxGrowthAge() { -+ return org.purpurmc.purpur.PurpurConfig.weepingVinesMaxGrowthAge; -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index f79d0e3907dd89ff0abf8220392bb4e23cf9003e..9ded52a0022e33a6b69191b5fa758d6cc7eb076f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -312,6 +312,10 @@ public class PurpurConfig { - public static Set grindstoneIgnoredEnchants = new HashSet<>(); - public static boolean grindstoneRemoveAttributes = false; - public static boolean grindstoneRemoveDisplay = false; -+ public static int caveVinesMaxGrowthAge = 25; -+ public static int kelpMaxGrowthAge = 25; -+ public static int twistingVinesMaxGrowthAge = 25; -+ public static int weepingVinesMaxGrowthAge = 25; - private static void blockSettings() { - if (version < 3) { - boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); -@@ -359,6 +363,30 @@ public class PurpurConfig { - }); - grindstoneRemoveAttributes = getBoolean("settings.blocks.grindstone.remove-attributes", grindstoneRemoveAttributes); - grindstoneRemoveDisplay = getBoolean("settings.blocks.grindstone.remove-name-and-lore", grindstoneRemoveDisplay); -+ caveVinesMaxGrowthAge = getInt("settings.blocks.cave_vines.max-growth-age", caveVinesMaxGrowthAge); -+ if (caveVinesMaxGrowthAge > 25) { -+ caveVinesMaxGrowthAge = 25; -+ log(Level.WARNING, "blocks.cave_vines.max-growth-age is set to above maximum allowed value of 25"); -+ log(Level.WARNING, "Using value of 25 to prevent issues"); -+ } -+ kelpMaxGrowthAge = getInt("settings.blocks.kelp.max-growth-age", kelpMaxGrowthAge); -+ if (kelpMaxGrowthAge > 25) { -+ kelpMaxGrowthAge = 25; -+ log(Level.WARNING, "blocks.kelp.max-growth-age is set to above maximum allowed value of 25"); -+ log(Level.WARNING, "Using value of 25 to prevent issues"); -+ } -+ twistingVinesMaxGrowthAge = getInt("settings.blocks.twisting_vines.max-growth-age", twistingVinesMaxGrowthAge); -+ if (twistingVinesMaxGrowthAge > 25) { -+ twistingVinesMaxGrowthAge = 25; -+ log(Level.WARNING, "blocks.twisting_vines.max-growth-age is set to above maximum allowed value of 25"); -+ log(Level.WARNING, "Using value of 25 to prevent issues"); -+ } -+ weepingVinesMaxGrowthAge = getInt("settings.blocks.weeping_vines.max-growth-age", weepingVinesMaxGrowthAge); -+ if (weepingVinesMaxGrowthAge > 25) { -+ weepingVinesMaxGrowthAge = 25; -+ log(Level.WARNING, "blocks.weeping_vines.max-growth-age is set to above maximum allowed value of 25"); -+ log(Level.WARNING, "Using value of 25 to prevent issues"); -+ } - } - - public static boolean allowInfinityMending = false; diff --git a/patches/server/0219-Mobs-always-drop-experience.patch b/patches/server/0219-Mobs-always-drop-experience.patch deleted file mode 100644 index 9aaf8f194..000000000 --- a/patches/server/0219-Mobs-always-drop-experience.patch +++ /dev/null @@ -1,2306 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Tue, 21 Dec 2021 20:40:42 -0600 -Subject: [PATCH] Mobs always drop experience - - -diff --git a/src/main/java/net/minecraft/world/entity/GlowSquid.java b/src/main/java/net/minecraft/world/entity/GlowSquid.java -index 70e3d583f7a039a5c67428ce9e8beb1922574c7b..3e2ea26c23e88c395856b65001f2895db6a52bd4 100644 ---- a/src/main/java/net/minecraft/world/entity/GlowSquid.java -+++ b/src/main/java/net/minecraft/world/entity/GlowSquid.java -@@ -51,6 +51,11 @@ public class GlowSquid extends Squid { - return this.level().purpurConfig.glowSquidTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.glowSquidAlwaysDropExp; -+ } -+ - @Override - protected ParticleOptions getInkParticle() { - return ParticleTypes.GLOW_SQUID_INK; -diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index a50d58240c58a0fea4ae8fc24689870807103199..47a7c7f9527e1c4ea457eeafe0e11145653a871f 100644 ---- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java -+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -282,6 +282,11 @@ public class Bat extends AmbientCreature { - return this.level().purpurConfig.batTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.batAlwaysDropExp; -+ } -+ - @Override - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 91c013f7ab58f570d0ebe2773932fcdb49344b3c..926c30db9b28a30fe5d6c8d20f3972dec0d7b4d0 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -482,6 +482,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - return this.level().purpurConfig.beeTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.beeAlwaysDropExp; -+ } -+ - @Override - public int getRemainingPersistentAngerTime() { - return (Integer) this.entityData.get(Bee.DATA_REMAINING_ANGER_TIME); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 17aaeb734a5c1b16bd7771c909958f3acc956b7a..3e1345f1c534320e07820d573f5c8dba49746425 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -144,6 +144,11 @@ public class Cat extends TamableAnimal implements VariantHolder { - return this.level().purpurConfig.foxTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.foxAlwaysDropExp; -+ } -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -index 8b08476457a6ead1a3c3e2ab35d08a8e0625c43e..12bc57d36d76f49596df0004fda31a6a678be60c 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java -@@ -98,6 +98,11 @@ public class IronGolem extends AbstractGolem implements NeutralMob { - this.summoner = summoner; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.ironGolemAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - if (level().purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur -diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index 6cb8d85986f4d891dfbb66b83163ed23bac694f6..06fac8dae42451f912c2db14d792461cee3dba83 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -+++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -96,6 +96,11 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder { - public boolean isSensitiveToWater() { - return this.level().purpurConfig.rabbitTakeDamageFromWater; - } -+ -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.rabbitAlwaysDropExp; -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/Salmon.java b/src/main/java/net/minecraft/world/entity/animal/Salmon.java -index e101c3bf425902908c43ffa18867fb83a5e1f16e..382e47f26ee94506cb76463a677351b9bdcf8040 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Salmon.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Salmon.java -@@ -35,6 +35,11 @@ public class Salmon extends AbstractSchoolingFish { - return this.level().purpurConfig.salmonTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.salmonAlwaysDropExp; -+ } -+ - @Override - public int getMaxSchoolSize() { - return 5; -diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -index afec39ba3b51b121fd7ae937e7bac060ef430dfd..9e617b3f1ec4eac5f83bdf19a3563cdc81b008d8 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java -@@ -149,6 +149,11 @@ public class Sheep extends Animal implements Shearable { - return this.level().purpurConfig.sheepTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.sheepAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - this.eatBlockGoal = new EatBlockGoal(this); -diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index 8f2348a7fe830a85985ce2b19cb2a9159bca711f..69cdccca01fe7d10e6d958e16d91efe08f699505 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -+++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -84,6 +84,11 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM - this.summoner = summoner; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.snowGolemAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index 0d05879eadeff8731028d78d89d5d32142818ea2..b86676ebcd6c301e5dd857d8e84e1db2c1da416b 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Squid.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -93,6 +93,11 @@ public class Squid extends WaterAnimal { - return this.level().purpurConfig.squidTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.squidAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -index 4ac998e9d96aed3b0ea0ec3f9dcd5fdd74c45d24..2d04addd17d2c358fff598012b323cd7d8bf007e 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -+++ b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java -@@ -89,6 +89,11 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder - return this.level().purpurConfig.tropicalFishTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.tropicalFishAlwaysDropExp; -+ } -+ - public static String getPredefinedName(int variant) { - return "entity.minecraft.tropical_fish.predefined." + variant; - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index b146ac72584d998cee4279133b3b19051fbf14c9..01dc59695f295657b1cd7bb015558bfc2ce73b47 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -119,6 +119,11 @@ public class Turtle extends Animal { - return this.level().purpurConfig.turtleTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.turtleAlwaysDropExp; -+ } -+ - public void setHomePos(BlockPos pos) { - this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos... - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -index 31b5d874fdc6f7d2eaabe877b32b64d360cb48e3..e1f6202df983be2510436538904a45beedbdc9c2 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java -@@ -224,6 +224,11 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder getModelRotationValues() { - return this.modelRotationValues; -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 412b44ea2d33ef68721b91da9f550738c6c780ba..79c27b5717fec000ea94138ebc76dbabf5b2eeaf 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -118,6 +118,11 @@ public class Goat extends Animal { - return this.level().purpurConfig.goatTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.goatAlwaysDropExp; -+ } -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(Goat.MEMORY_TYPES, Goat.SENSOR_TYPES); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -index 891ea1cca8495c08a1817096c8c4277f5311d6c7..94021abe521aea4a70f5eaa78fb05f9f71b7c38c 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java -@@ -47,6 +47,11 @@ public class Donkey extends AbstractChestedHorse { - return this.level().purpurConfig.donkeyTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.donkeyAlwaysDropExp; -+ } -+ - @Override - protected SoundEvent getAmbientSound() { - return SoundEvents.DONKEY_AMBIENT; -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -index e623284b353831d1a540af40e139ac16091dcbf6..fdf9ec418b0fc567e286ac79dbdbeddac568ad67 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java -@@ -76,6 +76,11 @@ public class Horse extends AbstractHorse implements VariantHolder { - return this.level().purpurConfig.horseTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.horseAlwaysDropExp; -+ } -+ - @Override - protected void randomizeAttributes(RandomSource random) { - this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)generateMaxHealth(random::nextInt)); -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 12ff4091674f7efb3e324df0df2d798dcbc46027..7d2a5c806fd0f1228c45b8a8b56d7ba13b899a2d 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -@@ -150,6 +150,11 @@ public class Llama extends AbstractChestedHorse implements VariantHolder type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - return checkMonsterSpawnRules(type, world, spawnReason, pos, random) && (MobSpawnType.isSpawner(spawnReason) || world.canSeeSky(pos)); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -index e2393be574475377fd401d55ab0be9b483e705e6..ae036a16e3677dfba451f4eb4505036d45e50cf3 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java -@@ -85,6 +85,11 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { - return this.level().purpurConfig.illusionerTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.illusionerAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -index adacdbf9fac7d1504be73e2e5a7526e8258a126d..e7c79e8c72226285eb5a4763dcf8ddd27078539c 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -+++ b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java -@@ -71,6 +71,11 @@ public class MagmaCube extends Slime { - return this.level().purpurConfig.magmaCubeTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.magmaCubeAlwaysDropExp; -+ } -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index bebc6f9f7e49e9dd34fa295d9ce3e8397feb280c..0d81540d048cd4a08962bd24d3bdd49db708f83f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -142,6 +142,11 @@ public class Phantom extends FlyingMob implements Enemy { - return this.level().purpurConfig.phantomTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.phantomAlwaysDropExp; -+ } -+ - @Override - public boolean isFlapping() { - return (this.getUniqueFlapTickOffset() + this.tickCount) % Phantom.TICKS_PER_FLAP == 0; -diff --git a/src/main/java/net/minecraft/world/entity/monster/Pillager.java b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -index a405764724d7f4b586d8510450a6258417495942..ae3eb87af8d3853be82c2002507141e43ab644de 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Pillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Pillager.java -@@ -85,6 +85,11 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve - return this.level().purpurConfig.pillagerTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.pillagerAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index ea9714b561d2cccad3ce012a118d200100ccd1e8..9551bd7c9bed37cf17910e7f71b82ed20fb2d759 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -101,6 +101,11 @@ public class Ravager extends Raider { - return this.level().purpurConfig.ravagerTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.ravagerAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -index 687fadf1ef64c5ae7e00c5da15b82245e07d3a39..1afa6dc4f2a6437cd4cc3e49694e79641fcc13ad 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java -@@ -141,6 +141,11 @@ public class Shulker extends AbstractGolem implements VariantHolder type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - BlockPos blockPos = pos; - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java -index 585614f7825700da28c7c832bdfc6a9eb0b78b5f..5ea5bf9c0e11b0e1f9fe50093899c6e35ee6cf4f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Strider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java -@@ -124,6 +124,11 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - return this.level().purpurConfig.striderBreedingTicks; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.striderAlwaysDropExp; -+ } -+ - public static boolean checkStriderSpawnRules(EntityType type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java -index d85e4baa892ebd987993bd39c895e5f1d310e30e..691f319719280f873140df7d93c821417e32e8f7 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vex.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java -@@ -112,6 +112,11 @@ public class Vex extends Monster implements TraceableEntity { - public boolean isSensitiveToWater() { - return this.level().purpurConfig.vexTakeDamageFromWater; - } -+ -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.vexAlwaysDropExp; -+ } - // Purpur end - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -index ded53c16dfd850c9c520878bc75414ebc188ea8a..e7703aa5467e7551bff06fab4c11d76237bda2e0 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java -@@ -77,6 +77,11 @@ public class Vindicator extends AbstractIllager { - return this.level().purpurConfig.vindicatorTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.vindicatorAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java -index 51d35e7f510c76d1fc18c67dbb56707207b39e4e..b4aab57b9aaab2ed1322ca41d4bf3c60f155902c 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Witch.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java -@@ -82,6 +82,11 @@ public class Witch extends Raider implements RangedAttackMob { - return this.level().purpurConfig.witchTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.witchAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - super.registerGoals(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -index 9865cc694e6ef02543a4b04cde37be3dc285475b..8c62d39c54acf274200667ae30c517cd4416b22f 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java -@@ -59,6 +59,11 @@ public class WitherSkeleton extends AbstractSkeleton { - return this.level().purpurConfig.witherSkeletonTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.witherSkeletonAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -index 76d47ba17dd140572a0be40dfda18c24851198bb..451762b3cd023b8c5828f68e2778aada9c50ab85 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java -@@ -107,6 +107,11 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { - return this.level().purpurConfig.zoglinTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.zoglinAlwaysDropExp; -+ } -+ - @Override - protected Brain.Provider brainProvider() { - return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index d5a5e51e23328deac09d6990539d8207b1567912..d48d22157a89f98c1bbabc70b0bb31187038176d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -144,6 +144,11 @@ public class Zombie extends Monster { - return this.level().purpurConfig.zombieTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.zombieAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index fe43c744cccdc07d5e449ce3ede85f4c7d898018..091095d1690bdd4d0870910b19e5e4ee3a3f9e7c 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -127,6 +127,11 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - return level().purpurConfig.zombieVillagerJockeyTryExistingChickens; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.zombieVillagerAlwaysDropExp; -+ } -+ - @Override - protected void defineSynchedData(SynchedEntityData.Builder builder) { - super.defineSynchedData(builder); -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -index bd2953448e568b1a20bcc6a889cef83b88418548..5bae3215ee0bf222c3bd77b3131f3d01ac6c9c41 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -104,6 +104,11 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { - return level().purpurConfig.zombifiedPiglinJockeyTryExistingChickens; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.zombifiedPiglinAlwaysDropExp; -+ } -+ - @Override - public void setPersistentAngerTarget(@Nullable UUID angryAt) { - this.persistentAngerTarget = angryAt; -diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index 9ca294d5177ec7d541433d644d2fb90d937b011c..a69a4d860cf537322cdf96bfd42e55d3fc684dd1 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -122,6 +122,11 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - return this.level().purpurConfig.hoglinTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.hoglinAlwaysDropExp; -+ } -+ - @Override - public boolean canBeLeashed(Player player) { - return !this.isLeashed(); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index e5b24bd8e31ca5748185181bb6741760c86a92a1..811b622945ecf67cff1992c3cdd4fcd84f33fb68 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -121,6 +121,11 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento - return this.level().purpurConfig.piglinTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.piglinAlwaysDropExp; -+ } -+ - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -index 6c7e0f177382cb6329002dcde270f6ce51f08f9f..71d2501e88a99819ef305fa8715418aad65ec81d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java -@@ -89,6 +89,11 @@ public class PiglinBrute extends AbstractPiglin { - return this.level().purpurConfig.piglinBruteTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.piglinBruteAlwaysDropExp; -+ } -+ - public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 50.0).add(Attributes.MOVEMENT_SPEED, 0.35F).add(Attributes.ATTACK_DAMAGE, 7.0); - } -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 1bace0d549ea4a4b45ac4cd1409524989ecac4ca..17a247455dd853ae98e2f82f64a99bccc4d27438 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -194,6 +194,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - return this.level().purpurConfig.villagerTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.villagerAlwaysDropExp; -+ } -+ - @Override - public Brain getBrain() { - return (Brain) super.getBrain(); // CraftBukkit - decompile error -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index 0d11200ab580cc306602c29c61f7619565d8261d..62f5e5cfe5745deced2811d14d0c7ebb2c2c6948 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -103,6 +103,11 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - return this.level().purpurConfig.wanderingTraderTakeDamageFromWater; - } - -+ @Override -+ protected boolean isAlwaysExperienceDropper() { -+ return this.level().purpurConfig.wanderingTraderAlwaysDropExp; -+ } -+ - @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new FloatGoal(this)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 6fce1773a4b5008f3234e06b556bf12e140eb1c1..fd8c8c6e563662926002fb1c72aaea0ba2999cdb 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1108,12 +1108,14 @@ public class PurpurWorldConfig { - public double axolotlMaxHealth = 14.0D; - public int axolotlBreedingTicks = 6000; - public boolean axolotlTakeDamageFromWater = false; -+ public boolean axolotlAlwaysDropExp = false; - private void axolotlSettings() { - axolotlRidable = getBoolean("mobs.axolotl.ridable", axolotlRidable); - axolotlControllable = getBoolean("mobs.axolotl.controllable", axolotlControllable); - axolotlMaxHealth = getDouble("mobs.axolotl.attributes.max_health", axolotlMaxHealth); - axolotlBreedingTicks = getInt("mobs.axolotl.breeding-delay-ticks", axolotlBreedingTicks); - axolotlTakeDamageFromWater = getBoolean("mobs.axolotl.takes-damage-from-water", axolotlTakeDamageFromWater); -+ axolotlAlwaysDropExp = getBoolean("mobs.axolotl.always-drop-exp", axolotlAlwaysDropExp); - } - - public boolean batRidable = false; -@@ -1129,6 +1131,7 @@ public class PurpurWorldConfig { - public double batArmorToughness = 0.0D; - public double batAttackKnockback = 0.0D; - public boolean batTakeDamageFromWater = false; -+ public boolean batAlwaysDropExp = false; - private void batSettings() { - batRidable = getBoolean("mobs.bat.ridable", batRidable); - batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater); -@@ -1148,6 +1151,7 @@ public class PurpurWorldConfig { - batArmorToughness = getDouble("mobs.bat.attributes.armor_toughness", batArmorToughness); - batAttackKnockback = getDouble("mobs.bat.attributes.attack_knockback", batAttackKnockback); - batTakeDamageFromWater = getBoolean("mobs.bat.takes-damage-from-water", batTakeDamageFromWater); -+ batAlwaysDropExp = getBoolean("mobs.bat.always-drop-exp", batAlwaysDropExp); - } - - public boolean beeRidable = false; -@@ -1159,6 +1163,7 @@ public class PurpurWorldConfig { - public boolean beeTakeDamageFromWater = false; - public boolean beeCanWorkAtNight = false; - public boolean beeCanWorkInRain = false; -+ public boolean beeAlwaysDropExp = false; - private void beeSettings() { - beeRidable = getBoolean("mobs.bee.ridable", beeRidable); - beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); -@@ -1174,6 +1179,7 @@ public class PurpurWorldConfig { - beeTakeDamageFromWater = getBoolean("mobs.bee.takes-damage-from-water", beeTakeDamageFromWater); - beeCanWorkAtNight = getBoolean("mobs.bee.can-work-at-night", beeCanWorkAtNight); - beeCanWorkInRain = getBoolean("mobs.bee.can-work-in-rain", beeCanWorkInRain); -+ beeAlwaysDropExp = getBoolean("mobs.bee.always-drop-exp", beeAlwaysDropExp); - } - - public boolean blazeRidable = false; -@@ -1182,6 +1188,7 @@ public class PurpurWorldConfig { - public double blazeMaxY = 320D; - public double blazeMaxHealth = 20.0D; - public boolean blazeTakeDamageFromWater = true; -+ public boolean blazeAlwaysDropExp = false; - private void blazeSettings() { - blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); - blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); -@@ -1194,6 +1201,7 @@ public class PurpurWorldConfig { - } - blazeMaxHealth = getDouble("mobs.blaze.attributes.max_health", blazeMaxHealth); - blazeTakeDamageFromWater = getBoolean("mobs.blaze.takes-damage-from-water", blazeTakeDamageFromWater); -+ blazeAlwaysDropExp = getBoolean("mobs.blaze.always-drop-exp", blazeAlwaysDropExp); - } - - public boolean camelRidableInWater = false; -@@ -1225,6 +1233,7 @@ public class PurpurWorldConfig { - public int catBreedingTicks = 6000; - public DyeColor catDefaultCollarColor = DyeColor.RED; - public boolean catTakeDamageFromWater = false; -+ public boolean catAlwaysDropExp = false; - private void catSettings() { - catRidable = getBoolean("mobs.cat.ridable", catRidable); - catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); -@@ -1245,6 +1254,7 @@ public class PurpurWorldConfig { - catDefaultCollarColor = DyeColor.RED; - } - catTakeDamageFromWater = getBoolean("mobs.cat.takes-damage-from-water", catTakeDamageFromWater); -+ catAlwaysDropExp = getBoolean("mobs.cat.always-drop-exp", catAlwaysDropExp); - } - - public boolean caveSpiderRidable = false; -@@ -1252,6 +1262,7 @@ public class PurpurWorldConfig { - public boolean caveSpiderControllable = true; - public double caveSpiderMaxHealth = 12.0D; - public boolean caveSpiderTakeDamageFromWater = false; -+ public boolean caveSpiderAlwaysDropExp = false; - private void caveSpiderSettings() { - caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable); - caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater); -@@ -1263,6 +1274,7 @@ public class PurpurWorldConfig { - } - caveSpiderMaxHealth = getDouble("mobs.cave_spider.attributes.max_health", caveSpiderMaxHealth); - caveSpiderTakeDamageFromWater = getBoolean("mobs.cave_spider.takes-damage-from-water", caveSpiderTakeDamageFromWater); -+ caveSpiderAlwaysDropExp = getBoolean("mobs.cave_spider.always-drop-exp", caveSpiderAlwaysDropExp); - } - - public boolean chickenRidable = false; -@@ -1272,6 +1284,7 @@ public class PurpurWorldConfig { - public boolean chickenRetaliate = false; - public int chickenBreedingTicks = 6000; - public boolean chickenTakeDamageFromWater = false; -+ public boolean chickenAlwaysDropExp = false; - private void chickenSettings() { - chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); - chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); -@@ -1285,12 +1298,14 @@ public class PurpurWorldConfig { - chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); - chickenBreedingTicks = getInt("mobs.chicken.breeding-delay-ticks", chickenBreedingTicks); - chickenTakeDamageFromWater = getBoolean("mobs.chicken.takes-damage-from-water", chickenTakeDamageFromWater); -+ chickenAlwaysDropExp = getBoolean("mobs.chicken.always-drop-exp", chickenAlwaysDropExp); - } - - public boolean codRidable = false; - public boolean codControllable = true; - public double codMaxHealth = 3.0D; - public boolean codTakeDamageFromWater = false; -+ public boolean codAlwaysDropExp = false; - private void codSettings() { - codRidable = getBoolean("mobs.cod.ridable", codRidable); - codControllable = getBoolean("mobs.cod.controllable", codControllable); -@@ -1301,6 +1316,7 @@ public class PurpurWorldConfig { - } - codMaxHealth = getDouble("mobs.cod.attributes.max_health", codMaxHealth); - codTakeDamageFromWater = getBoolean("mobs.cod.takes-damage-from-water", codTakeDamageFromWater); -+ codAlwaysDropExp = getBoolean("mobs.cod.always-drop-exp", codAlwaysDropExp); - } - - public boolean cowRidable = false; -@@ -1312,6 +1328,7 @@ public class PurpurWorldConfig { - public boolean cowTakeDamageFromWater = false; - public double cowNaturallyAggressiveToPlayersChance = 0.0D; - public double cowNaturallyAggressiveToPlayersDamage = 2.0D; -+ public boolean cowAlwaysDropExp = false; - private void cowSettings() { - if (PurpurConfig.version < 22) { - double oldValue = getDouble("mobs.cow.naturally-aggressive-to-players-chance", cowNaturallyAggressiveToPlayersChance); -@@ -1332,6 +1349,7 @@ public class PurpurWorldConfig { - cowTakeDamageFromWater = getBoolean("mobs.cow.takes-damage-from-water", cowTakeDamageFromWater); - cowNaturallyAggressiveToPlayersChance = getDouble("mobs.cow.naturally-aggressive-to-players.chance", cowNaturallyAggressiveToPlayersChance); - cowNaturallyAggressiveToPlayersDamage = getDouble("mobs.cow.naturally-aggressive-to-players.damage", cowNaturallyAggressiveToPlayersDamage); -+ cowAlwaysDropExp = getBoolean("mobs.cow.always-drop-exp", cowAlwaysDropExp); - } - - public boolean creeperRidable = false; -@@ -1344,6 +1362,7 @@ public class PurpurWorldConfig { - public boolean creeperTakeDamageFromWater = false; - public boolean creeperExplodeWhenKilled = false; - public boolean creeperHealthRadius = false; -+ public boolean creeperAlwaysDropExp = false; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -1360,6 +1379,7 @@ public class PurpurWorldConfig { - creeperTakeDamageFromWater = getBoolean("mobs.creeper.takes-damage-from-water", creeperTakeDamageFromWater); - creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled); - creeperHealthRadius = getBoolean("mobs.creeper.health-impacts-explosion", creeperHealthRadius); -+ creeperAlwaysDropExp = getBoolean("mobs.creeper.always-drop-exp", creeperAlwaysDropExp); - } - - public boolean dolphinRidable = false; -@@ -1371,6 +1391,7 @@ public class PurpurWorldConfig { - public boolean dolphinDisableTreasureSearching = false; - public boolean dolphinTakeDamageFromWater = false; - public double dolphinNaturallyAggressiveToPlayersChance = 0.0D; -+ public boolean dolphinAlwaysDropExp = false; - private void dolphinSettings() { - dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); - dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable); -@@ -1386,6 +1407,7 @@ public class PurpurWorldConfig { - dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching); - dolphinTakeDamageFromWater = getBoolean("mobs.dolphin.takes-damage-from-water", dolphinTakeDamageFromWater); - dolphinNaturallyAggressiveToPlayersChance = getDouble("mobs.dolphin.naturally-aggressive-to-players-chance", dolphinNaturallyAggressiveToPlayersChance); -+ dolphinAlwaysDropExp = getBoolean("mobs.dolphin.always-drop-exp", dolphinAlwaysDropExp); - } - - public boolean donkeyRidableInWater = false; -@@ -1397,6 +1419,7 @@ public class PurpurWorldConfig { - public double donkeyMovementSpeedMax = 0.175D; - public int donkeyBreedingTicks = 6000; - public boolean donkeyTakeDamageFromWater = false; -+ public boolean donkeyAlwaysDropExp = false; - private void donkeySettings() { - donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); - if (PurpurConfig.version < 10) { -@@ -1414,6 +1437,7 @@ public class PurpurWorldConfig { - donkeyMovementSpeedMax = getDouble("mobs.donkey.attributes.movement_speed.max", donkeyMovementSpeedMax); - donkeyBreedingTicks = getInt("mobs.donkey.breeding-delay-ticks", donkeyBreedingTicks); - donkeyTakeDamageFromWater = getBoolean("mobs.donkey.takes-damage-from-water", donkeyTakeDamageFromWater); -+ donkeyAlwaysDropExp = getBoolean("mobs.donkey.always-drop-exp", donkeyAlwaysDropExp); - } - - public boolean drownedRidable = false; -@@ -1426,6 +1450,7 @@ public class PurpurWorldConfig { - public boolean drownedJockeyTryExistingChickens = true; - public boolean drownedTakeDamageFromWater = false; - public boolean drownedBreakDoors = false; -+ public boolean drownedAlwaysDropExp = false; - private void drownedSettings() { - drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); - drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); -@@ -1442,12 +1467,14 @@ public class PurpurWorldConfig { - drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens); - drownedTakeDamageFromWater = getBoolean("mobs.drowned.takes-damage-from-water", drownedTakeDamageFromWater); - drownedBreakDoors = getBoolean("mobs.drowned.can-break-doors", drownedBreakDoors); -+ drownedAlwaysDropExp = getBoolean("mobs.drowned.always-drop-exp", drownedAlwaysDropExp); - } - - public boolean elderGuardianRidable = false; - public boolean elderGuardianControllable = true; - public double elderGuardianMaxHealth = 80.0D; - public boolean elderGuardianTakeDamageFromWater = false; -+ public boolean elderGuardianAlwaysDropExp = false; - private void elderGuardianSettings() { - elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable); - elderGuardianControllable = getBoolean("mobs.elder_guardian.controllable", elderGuardianControllable); -@@ -1458,6 +1485,7 @@ public class PurpurWorldConfig { - } - elderGuardianMaxHealth = getDouble("mobs.elder_guardian.attributes.max_health", elderGuardianMaxHealth); - elderGuardianTakeDamageFromWater = getBoolean("mobs.elder_guardian.takes-damage-from-water", elderGuardianTakeDamageFromWater); -+ elderGuardianAlwaysDropExp = getBoolean("mobs.elder_guardian.always-drop-exp", elderGuardianAlwaysDropExp); - } - - public boolean enderDragonRidable = false; -@@ -1503,6 +1531,7 @@ public class PurpurWorldConfig { - public boolean endermanIgnorePlayerDragonHead = false; - public boolean endermanDisableStareAggro = false; - public boolean endermanIgnoreProjectiles = false; -+ public boolean endermanAlwaysDropExp = false; - private void endermanSettings() { - endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); - endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); -@@ -1526,6 +1555,7 @@ public class PurpurWorldConfig { - endermanIgnorePlayerDragonHead = getBoolean("mobs.enderman.ignore-players-wearing-dragon-head", endermanIgnorePlayerDragonHead); - endermanDisableStareAggro = getBoolean("mobs.enderman.disable-player-stare-aggression", endermanDisableStareAggro); - endermanIgnoreProjectiles = getBoolean("mobs.enderman.ignore-projectiles", endermanIgnoreProjectiles); -+ endermanAlwaysDropExp = getBoolean("mobs.enderman.always-drop-exp", endermanAlwaysDropExp); - } - - public boolean endermiteRidable = false; -@@ -1533,6 +1563,7 @@ public class PurpurWorldConfig { - public boolean endermiteControllable = true; - public double endermiteMaxHealth = 8.0D; - public boolean endermiteTakeDamageFromWater = false; -+ public boolean endermiteAlwaysDropExp = false; - private void endermiteSettings() { - endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable); - endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater); -@@ -1544,6 +1575,7 @@ public class PurpurWorldConfig { - } - endermiteMaxHealth = getDouble("mobs.endermite.attributes.max_health", endermiteMaxHealth); - endermiteTakeDamageFromWater = getBoolean("mobs.endermite.takes-damage-from-water", endermiteTakeDamageFromWater); -+ endermiteAlwaysDropExp = getBoolean("mobs.endermite.always-drop-exp", endermiteAlwaysDropExp); - } - - public boolean evokerRidable = false; -@@ -1552,6 +1584,7 @@ public class PurpurWorldConfig { - public double evokerMaxHealth = 24.0D; - public boolean evokerBypassMobGriefing = false; - public boolean evokerTakeDamageFromWater = false; -+ public boolean evokerAlwaysDropExp = false; - private void evokerSettings() { - evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); - evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); -@@ -1564,6 +1597,7 @@ public class PurpurWorldConfig { - evokerMaxHealth = getDouble("mobs.evoker.attributes.max_health", evokerMaxHealth); - evokerBypassMobGriefing = getBoolean("mobs.evoker.bypass-mob-griefing", evokerBypassMobGriefing); - evokerTakeDamageFromWater = getBoolean("mobs.evoker.takes-damage-from-water", evokerTakeDamageFromWater); -+ evokerAlwaysDropExp = getBoolean("mobs.evoker.always-drop-exp", evokerAlwaysDropExp); - } - - public boolean foxRidable = false; -@@ -1574,6 +1608,7 @@ public class PurpurWorldConfig { - public int foxBreedingTicks = 6000; - public boolean foxBypassMobGriefing = false; - public boolean foxTakeDamageFromWater = false; -+ public boolean foxAlwaysDropExp = false; - private void foxSettings() { - foxRidable = getBoolean("mobs.fox.ridable", foxRidable); - foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); -@@ -1588,6 +1623,7 @@ public class PurpurWorldConfig { - foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks); - foxBypassMobGriefing = getBoolean("mobs.fox.bypass-mob-griefing", foxBypassMobGriefing); - foxTakeDamageFromWater = getBoolean("mobs.fox.takes-damage-from-water", foxTakeDamageFromWater); -+ foxAlwaysDropExp = getBoolean("mobs.fox.always-drop-exp", foxAlwaysDropExp); - } - - public boolean frogRidable = false; -@@ -1609,6 +1645,7 @@ public class PurpurWorldConfig { - public double ghastMaxY = 320D; - public double ghastMaxHealth = 10.0D; - public boolean ghastTakeDamageFromWater = false; -+ public boolean ghastAlwaysDropExp = false; - private void ghastSettings() { - ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); - ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater); -@@ -1621,6 +1658,7 @@ public class PurpurWorldConfig { - } - ghastMaxHealth = getDouble("mobs.ghast.attributes.max_health", ghastMaxHealth); - ghastTakeDamageFromWater = getBoolean("mobs.ghast.takes-damage-from-water", ghastTakeDamageFromWater); -+ ghastAlwaysDropExp = getBoolean("mobs.ghast.always-drop-exp", ghastAlwaysDropExp); - } - - public boolean giantRidable = false; -@@ -1634,6 +1672,7 @@ public class PurpurWorldConfig { - public boolean giantHaveAI = false; - public boolean giantHaveHostileAI = false; - public boolean giantTakeDamageFromWater = false; -+ public boolean giantAlwaysDropExp = false; - private void giantSettings() { - giantRidable = getBoolean("mobs.giant.ridable", giantRidable); - giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater); -@@ -1655,6 +1694,7 @@ public class PurpurWorldConfig { - giantHaveAI = getBoolean("mobs.giant.have-ai", giantHaveAI); - giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI); - giantTakeDamageFromWater = getBoolean("mobs.giant.takes-damage-from-water", giantTakeDamageFromWater); -+ giantAlwaysDropExp = getBoolean("mobs.giant.always-drop-exp", giantAlwaysDropExp); - } - - public boolean glowSquidRidable = false; -@@ -1662,12 +1702,14 @@ public class PurpurWorldConfig { - public double glowSquidMaxHealth = 10.0D; - public boolean glowSquidsCanFly = false; - public boolean glowSquidTakeDamageFromWater = false; -+ public boolean glowSquidAlwaysDropExp = false; - private void glowSquidSettings() { - glowSquidRidable = getBoolean("mobs.glow_squid.ridable", glowSquidRidable); - glowSquidControllable = getBoolean("mobs.glow_squid.controllable", glowSquidControllable); - glowSquidMaxHealth = getDouble("mobs.glow_squid.attributes.max_health", glowSquidMaxHealth); - glowSquidsCanFly = getBoolean("mobs.glow_squid.can-fly", glowSquidsCanFly); - glowSquidTakeDamageFromWater = getBoolean("mobs.glow_squid.takes-damage-from-water", glowSquidTakeDamageFromWater); -+ glowSquidAlwaysDropExp = getBoolean("mobs.glow_squid.always-drop-exp", glowSquidAlwaysDropExp); - } - - public boolean goatRidable = false; -@@ -1676,6 +1718,7 @@ public class PurpurWorldConfig { - public double goatMaxHealth = 10.0D; - public int goatBreedingTicks = 6000; - public boolean goatTakeDamageFromWater = false; -+ public boolean goatAlwaysDropExp = false; - private void goatSettings() { - goatRidable = getBoolean("mobs.goat.ridable", goatRidable); - goatRidableInWater = getBoolean("mobs.goat.ridable-in-water", goatRidableInWater); -@@ -1683,12 +1726,14 @@ public class PurpurWorldConfig { - goatMaxHealth = getDouble("mobs.goat.attributes.max_health", goatMaxHealth); - goatBreedingTicks = getInt("mobs.goat.breeding-delay-ticks", goatBreedingTicks); - goatTakeDamageFromWater = getBoolean("mobs.goat.takes-damage-from-water", goatTakeDamageFromWater); -+ goatAlwaysDropExp = getBoolean("mobs.goat.always-drop-exp", goatAlwaysDropExp); - } - - public boolean guardianRidable = false; - public boolean guardianControllable = true; - public double guardianMaxHealth = 30.0D; - public boolean guardianTakeDamageFromWater = false; -+ public boolean guardianAlwaysDropExp = false; - private void guardianSettings() { - guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable); - guardianControllable = getBoolean("mobs.guardian.controllable", guardianControllable); -@@ -1699,6 +1744,7 @@ public class PurpurWorldConfig { - } - guardianMaxHealth = getDouble("mobs.guardian.attributes.max_health", guardianMaxHealth); - guardianTakeDamageFromWater = getBoolean("mobs.guardian.takes-damage-from-water", guardianTakeDamageFromWater); -+ guardianAlwaysDropExp = getBoolean("mobs.guardian.always-drop-exp", guardianAlwaysDropExp); - } - - public boolean forceHalloweenSeason = false; -@@ -1714,6 +1760,7 @@ public class PurpurWorldConfig { - public double hoglinMaxHealth = 40.0D; - public int hoglinBreedingTicks = 6000; - public boolean hoglinTakeDamageFromWater = false; -+ public boolean hoglinAlwaysDropExp = false; - private void hoglinSettings() { - hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); - hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); -@@ -1726,6 +1773,7 @@ public class PurpurWorldConfig { - hoglinMaxHealth = getDouble("mobs.hoglin.attributes.max_health", hoglinMaxHealth); - hoglinBreedingTicks = getInt("mobs.hoglin.breeding-delay-ticks", hoglinBreedingTicks); - hoglinTakeDamageFromWater = getBoolean("mobs.hoglin.takes-damage-from-water", hoglinTakeDamageFromWater); -+ hoglinAlwaysDropExp = getBoolean("mobs.hoglin.always-drop-exp", hoglinAlwaysDropExp); - } - - public boolean horseRidableInWater = false; -@@ -1737,6 +1785,7 @@ public class PurpurWorldConfig { - public double horseMovementSpeedMax = 0.3375D; - public int horseBreedingTicks = 6000; - public boolean horseTakeDamageFromWater = false; -+ public boolean horseAlwaysDropExp = false; - private void horseSettings() { - horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); - if (PurpurConfig.version < 10) { -@@ -1754,6 +1803,7 @@ public class PurpurWorldConfig { - horseMovementSpeedMax = getDouble("mobs.horse.attributes.movement_speed.max", horseMovementSpeedMax); - horseBreedingTicks = getInt("mobs.horse.breeding-delay-ticks", horseBreedingTicks); - horseTakeDamageFromWater = getBoolean("mobs.horse.takes-damage-from-water", horseTakeDamageFromWater); -+ horseAlwaysDropExp = getBoolean("mobs.horse.always-drop-exp", horseAlwaysDropExp); - } - - public boolean huskRidable = false; -@@ -1765,6 +1815,7 @@ public class PurpurWorldConfig { - public double huskJockeyChance = 0.05D; - public boolean huskJockeyTryExistingChickens = true; - public boolean huskTakeDamageFromWater = false; -+ public boolean huskAlwaysDropExp = false; - private void huskSettings() { - huskRidable = getBoolean("mobs.husk.ridable", huskRidable); - huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); -@@ -1780,6 +1831,7 @@ public class PurpurWorldConfig { - huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance); - huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens); - huskTakeDamageFromWater = getBoolean("mobs.husk.takes-damage-from-water", huskTakeDamageFromWater); -+ huskAlwaysDropExp = getBoolean("mobs.husk.always-drop-exp", huskAlwaysDropExp); - } - - public boolean illusionerRidable = false; -@@ -1789,6 +1841,7 @@ public class PurpurWorldConfig { - public double illusionerFollowRange = 18.0D; - public double illusionerMaxHealth = 32.0D; - public boolean illusionerTakeDamageFromWater = false; -+ public boolean illusionerAlwaysDropExp = false; - private void illusionerSettings() { - illusionerRidable = getBoolean("mobs.illusioner.ridable", illusionerRidable); - illusionerRidableInWater = getBoolean("mobs.illusioner.ridable-in-water", illusionerRidableInWater); -@@ -1806,6 +1859,7 @@ public class PurpurWorldConfig { - } - illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max_health", illusionerMaxHealth); - illusionerTakeDamageFromWater = getBoolean("mobs.illusioner.takes-damage-from-water", illusionerTakeDamageFromWater); -+ illusionerAlwaysDropExp = getBoolean("mobs.illusioner.always-drop-exp", illusionerAlwaysDropExp); - } - - public boolean ironGolemRidable = false; -@@ -1816,6 +1870,7 @@ public class PurpurWorldConfig { - public boolean ironGolemTakeDamageFromWater = false; - public boolean ironGolemPoppyCalm = false; - public boolean ironGolemHealCalm = false; -+ public boolean ironGolemAlwaysDropExp = false; - private void ironGolemSettings() { - ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); - ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); -@@ -1830,6 +1885,7 @@ public class PurpurWorldConfig { - ironGolemTakeDamageFromWater = getBoolean("mobs.iron_golem.takes-damage-from-water", ironGolemTakeDamageFromWater); - ironGolemPoppyCalm = getBoolean("mobs.iron_golem.poppy-calms-anger", ironGolemPoppyCalm); - ironGolemHealCalm = getBoolean("mobs.iron_golem.healing-calms-anger", ironGolemHealCalm); -+ ironGolemAlwaysDropExp = getBoolean("mobs.iron_golem.always-drop-exp", ironGolemAlwaysDropExp); - } - - public boolean llamaRidable = false; -@@ -1844,6 +1900,7 @@ public class PurpurWorldConfig { - public int llamaBreedingTicks = 6000; - public boolean llamaTakeDamageFromWater = false; - public boolean llamaJoinCaravans = true; -+ public boolean llamaAlwaysDropExp = false; - private void llamaSettings() { - llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); - llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); -@@ -1864,6 +1921,7 @@ public class PurpurWorldConfig { - llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks); - llamaTakeDamageFromWater = getBoolean("mobs.llama.takes-damage-from-water", llamaTakeDamageFromWater); - llamaJoinCaravans = getBoolean("mobs.llama.join-caravans", llamaJoinCaravans); -+ llamaAlwaysDropExp = getBoolean("mobs.llama.always-drop-exp", llamaAlwaysDropExp); - } - - public boolean magmaCubeRidable = false; -@@ -1874,6 +1932,7 @@ public class PurpurWorldConfig { - public Map magmaCubeMaxHealthCache = new HashMap<>(); - public Map magmaCubeAttackDamageCache = new HashMap<>(); - public boolean magmaCubeTakeDamageFromWater = false; -+ public boolean magmaCubeAlwaysDropExp = false; - private void magmaCubeSettings() { - magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable); - magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater); -@@ -1888,6 +1947,7 @@ public class PurpurWorldConfig { - magmaCubeMaxHealthCache.clear(); - magmaCubeAttackDamageCache.clear(); - magmaCubeTakeDamageFromWater = getBoolean("mobs.magma_cube.takes-damage-from-water", magmaCubeTakeDamageFromWater); -+ magmaCubeAlwaysDropExp = getBoolean("mobs.magma_cube.always-drop-exp", magmaCubeAlwaysDropExp); - } - - public boolean mooshroomRidable = false; -@@ -1896,6 +1956,7 @@ public class PurpurWorldConfig { - public double mooshroomMaxHealth = 10.0D; - public int mooshroomBreedingTicks = 6000; - public boolean mooshroomTakeDamageFromWater = false; -+ public boolean mooshroomAlwaysDropExp = false; - private void mooshroomSettings() { - mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); - mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); -@@ -1908,6 +1969,7 @@ public class PurpurWorldConfig { - mooshroomMaxHealth = getDouble("mobs.mooshroom.attributes.max_health", mooshroomMaxHealth); - mooshroomBreedingTicks = getInt("mobs.mooshroom.breeding-delay-ticks", mooshroomBreedingTicks); - mooshroomTakeDamageFromWater = getBoolean("mobs.mooshroom.takes-damage-from-water", mooshroomTakeDamageFromWater); -+ mooshroomAlwaysDropExp = getBoolean("mobs.mooshroom.always-drop-exp", mooshroomAlwaysDropExp); - } - - public boolean muleRidableInWater = false; -@@ -1919,6 +1981,7 @@ public class PurpurWorldConfig { - public double muleMovementSpeedMax = 0.175D; - public int muleBreedingTicks = 6000; - public boolean muleTakeDamageFromWater = false; -+ public boolean muleAlwaysDropExp = false; - private void muleSettings() { - muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); - if (PurpurConfig.version < 10) { -@@ -1936,6 +1999,7 @@ public class PurpurWorldConfig { - muleMovementSpeedMax = getDouble("mobs.mule.attributes.movement_speed.max", muleMovementSpeedMax); - muleBreedingTicks = getInt("mobs.mule.breeding-delay-ticks", muleBreedingTicks); - muleTakeDamageFromWater = getBoolean("mobs.mule.takes-damage-from-water", muleTakeDamageFromWater); -+ muleAlwaysDropExp = getBoolean("mobs.mule.always-drop-exp", muleAlwaysDropExp); - } - - public boolean ocelotRidable = false; -@@ -1944,6 +2008,7 @@ public class PurpurWorldConfig { - public double ocelotMaxHealth = 10.0D; - public int ocelotBreedingTicks = 6000; - public boolean ocelotTakeDamageFromWater = false; -+ public boolean ocelotAlwaysDropExp = false; - private void ocelotSettings() { - ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); - ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); -@@ -1956,6 +2021,7 @@ public class PurpurWorldConfig { - ocelotMaxHealth = getDouble("mobs.ocelot.attributes.max_health", ocelotMaxHealth); - ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks); - ocelotTakeDamageFromWater = getBoolean("mobs.ocelot.takes-damage-from-water", ocelotTakeDamageFromWater); -+ ocelotAlwaysDropExp = getBoolean("mobs.ocelot.always-drop-exp", ocelotAlwaysDropExp); - } - - public boolean pandaRidable = false; -@@ -1964,6 +2030,7 @@ public class PurpurWorldConfig { - public double pandaMaxHealth = 20.0D; - public int pandaBreedingTicks = 6000; - public boolean pandaTakeDamageFromWater = false; -+ public boolean pandaAlwaysDropExp = false; - private void pandaSettings() { - pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); - pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); -@@ -1976,6 +2043,7 @@ public class PurpurWorldConfig { - pandaMaxHealth = getDouble("mobs.panda.attributes.max_health", pandaMaxHealth); - pandaBreedingTicks = getInt("mobs.panda.breeding-delay-ticks", pandaBreedingTicks); - pandaTakeDamageFromWater = getBoolean("mobs.panda.takes-damage-from-water", pandaTakeDamageFromWater); -+ pandaAlwaysDropExp = getBoolean("mobs.panda.always-drop-exp", pandaAlwaysDropExp); - } - - public boolean parrotRidable = false; -@@ -1985,6 +2053,7 @@ public class PurpurWorldConfig { - public double parrotMaxHealth = 6.0D; - public boolean parrotTakeDamageFromWater = false; - public boolean parrotBreedable = false; -+ public boolean parrotAlwaysDropExp = false; - private void parrotSettings() { - parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); - parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); -@@ -1998,6 +2067,7 @@ public class PurpurWorldConfig { - parrotMaxHealth = getDouble("mobs.parrot.attributes.max_health", parrotMaxHealth); - parrotTakeDamageFromWater = getBoolean("mobs.parrot.takes-damage-from-water", parrotTakeDamageFromWater); - parrotBreedable = getBoolean("mobs.parrot.can-breed", parrotBreedable); -+ parrotAlwaysDropExp = getBoolean("mobs.parrot.always-drop-exp", parrotAlwaysDropExp); - } - - public boolean phantomRidable = false; -@@ -2025,6 +2095,7 @@ public class PurpurWorldConfig { - public boolean phantomBurnInDaylight = true; - public boolean phantomFlamesOnSwoop = false; - public boolean phantomTakeDamageFromWater = false; -+ public boolean phantomAlwaysDropExp = false; - private void phantomSettings() { - phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); - phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -@@ -2060,6 +2131,7 @@ public class PurpurWorldConfig { - phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); - phantomFlamesOnSwoop = getBoolean("mobs.phantom.flames-on-swoop", phantomFlamesOnSwoop); - phantomTakeDamageFromWater = getBoolean("mobs.phantom.takes-damage-from-water", phantomTakeDamageFromWater); -+ phantomAlwaysDropExp = getBoolean("mobs.phantom.always-drop-exp", phantomAlwaysDropExp); - } - - public boolean pigRidable = false; -@@ -2069,6 +2141,7 @@ public class PurpurWorldConfig { - public boolean pigGiveSaddleBack = false; - public int pigBreedingTicks = 6000; - public boolean pigTakeDamageFromWater = false; -+ public boolean pigAlwaysDropExp = false; - private void pigSettings() { - pigRidable = getBoolean("mobs.pig.ridable", pigRidable); - pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); -@@ -2082,6 +2155,7 @@ public class PurpurWorldConfig { - pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); - pigBreedingTicks = getInt("mobs.pig.breeding-delay-ticks", pigBreedingTicks); - pigTakeDamageFromWater = getBoolean("mobs.pig.takes-damage-from-water", pigTakeDamageFromWater); -+ pigAlwaysDropExp = getBoolean("mobs.pig.always-drop-exp", pigAlwaysDropExp); - } - - public boolean piglinRidable = false; -@@ -2091,6 +2165,7 @@ public class PurpurWorldConfig { - public boolean piglinBypassMobGriefing = false; - public boolean piglinTakeDamageFromWater = false; - public int piglinPortalSpawnModifier = 2000; -+ public boolean piglinAlwaysDropExp = false; - private void piglinSettings() { - piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); - piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); -@@ -2104,6 +2179,7 @@ public class PurpurWorldConfig { - piglinBypassMobGriefing = getBoolean("mobs.piglin.bypass-mob-griefing", piglinBypassMobGriefing); - piglinTakeDamageFromWater = getBoolean("mobs.piglin.takes-damage-from-water", piglinTakeDamageFromWater); - piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier); -+ piglinAlwaysDropExp = getBoolean("mobs.piglin.always-drop-exp", piglinAlwaysDropExp); - } - - public boolean piglinBruteRidable = false; -@@ -2111,6 +2187,7 @@ public class PurpurWorldConfig { - public boolean piglinBruteControllable = true; - public double piglinBruteMaxHealth = 50.0D; - public boolean piglinBruteTakeDamageFromWater = false; -+ public boolean piglinBruteAlwaysDropExp = false; - private void piglinBruteSettings() { - piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable); - piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater); -@@ -2122,6 +2199,7 @@ public class PurpurWorldConfig { - } - piglinBruteMaxHealth = getDouble("mobs.piglin_brute.attributes.max_health", piglinBruteMaxHealth); - piglinBruteTakeDamageFromWater = getBoolean("mobs.piglin_brute.takes-damage-from-water", piglinBruteTakeDamageFromWater); -+ piglinBruteAlwaysDropExp = getBoolean("mobs.piglin_brute.always-drop-exp", piglinBruteAlwaysDropExp); - } - - public boolean pillagerRidable = false; -@@ -2130,6 +2208,7 @@ public class PurpurWorldConfig { - public double pillagerMaxHealth = 24.0D; - public boolean pillagerBypassMobGriefing = false; - public boolean pillagerTakeDamageFromWater = false; -+ public boolean pillagerAlwaysDropExp = false; - private void pillagerSettings() { - pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); - pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); -@@ -2142,6 +2221,7 @@ public class PurpurWorldConfig { - pillagerMaxHealth = getDouble("mobs.pillager.attributes.max_health", pillagerMaxHealth); - pillagerBypassMobGriefing = getBoolean("mobs.pillager.bypass-mob-griefing", pillagerBypassMobGriefing); - pillagerTakeDamageFromWater = getBoolean("mobs.pillager.takes-damage-from-water", pillagerTakeDamageFromWater); -+ pillagerAlwaysDropExp = getBoolean("mobs.pillager.always-drop-exp", pillagerAlwaysDropExp); - } - - public boolean polarBearRidable = false; -@@ -2152,6 +2232,7 @@ public class PurpurWorldConfig { - public Item polarBearBreedableItem = null; - public int polarBearBreedingTicks = 6000; - public boolean polarBearTakeDamageFromWater = false; -+ public boolean polarBearAlwaysDropExp = false; - private void polarBearSettings() { - polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); - polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); -@@ -2167,12 +2248,14 @@ public class PurpurWorldConfig { - if (item != Items.AIR) polarBearBreedableItem = item; - polarBearBreedingTicks = getInt("mobs.polar_bear.breeding-delay-ticks", polarBearBreedingTicks); - polarBearTakeDamageFromWater = getBoolean("mobs.polar_bear.takes-damage-from-water", polarBearTakeDamageFromWater); -+ polarBearAlwaysDropExp = getBoolean("mobs.polar_bear.always-drop-exp", polarBearAlwaysDropExp); - } - - public boolean pufferfishRidable = false; - public boolean pufferfishControllable = true; - public double pufferfishMaxHealth = 3.0D; - public boolean pufferfishTakeDamageFromWater = false; -+ public boolean pufferfishAlwaysDropExp = false; - private void pufferfishSettings() { - pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable); - pufferfishControllable = getBoolean("mobs.pufferfish.controllable", pufferfishControllable); -@@ -2183,6 +2266,7 @@ public class PurpurWorldConfig { - } - pufferfishMaxHealth = getDouble("mobs.pufferfish.attributes.max_health", pufferfishMaxHealth); - pufferfishTakeDamageFromWater = getBoolean("mobs.pufferfish.takes-damage-from-water", pufferfishTakeDamageFromWater); -+ pufferfishAlwaysDropExp = getBoolean("mobs.pufferfish.always-drop-exp", pufferfishAlwaysDropExp); - } - - public boolean rabbitRidable = false; -@@ -2194,6 +2278,7 @@ public class PurpurWorldConfig { - public int rabbitBreedingTicks = 6000; - public boolean rabbitBypassMobGriefing = false; - public boolean rabbitTakeDamageFromWater = false; -+ public boolean rabbitAlwaysDropExp = false; - private void rabbitSettings() { - rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); - rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); -@@ -2209,6 +2294,7 @@ public class PurpurWorldConfig { - rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks); - rabbitBypassMobGriefing = getBoolean("mobs.rabbit.bypass-mob-griefing", rabbitBypassMobGriefing); - rabbitTakeDamageFromWater = getBoolean("mobs.rabbit.takes-damage-from-water", rabbitTakeDamageFromWater); -+ rabbitAlwaysDropExp = getBoolean("mobs.rabbit.always-drop-exp", rabbitAlwaysDropExp); - } - - public boolean ravagerRidable = false; -@@ -2218,6 +2304,7 @@ public class PurpurWorldConfig { - public boolean ravagerBypassMobGriefing = false; - public boolean ravagerTakeDamageFromWater = false; - public List ravagerGriefableBlocks = new ArrayList<>(); -+ public boolean ravagerAlwaysDropExp = false; - private void ravagerSettings() { - ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); - ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); -@@ -2247,12 +2334,14 @@ public class PurpurWorldConfig { - ravagerGriefableBlocks.add(block); - } - }); -+ ravagerAlwaysDropExp = getBoolean("mobs.ravager.always-drop-exp", ravagerAlwaysDropExp); - } - - public boolean salmonRidable = false; - public boolean salmonControllable = true; - public double salmonMaxHealth = 3.0D; - public boolean salmonTakeDamageFromWater = false; -+ public boolean salmonAlwaysDropExp = false; - private void salmonSettings() { - salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable); - salmonControllable = getBoolean("mobs.salmon.controllable", salmonControllable); -@@ -2263,6 +2352,7 @@ public class PurpurWorldConfig { - } - salmonMaxHealth = getDouble("mobs.salmon.attributes.max_health", salmonMaxHealth); - salmonTakeDamageFromWater = getBoolean("mobs.salmon.takes-damage-from-water", salmonTakeDamageFromWater); -+ salmonAlwaysDropExp = getBoolean("mobs.salmon.always-drop-exp", salmonAlwaysDropExp); - } - - public boolean sheepRidable = false; -@@ -2272,6 +2362,7 @@ public class PurpurWorldConfig { - public int sheepBreedingTicks = 6000; - public boolean sheepBypassMobGriefing = false; - public boolean sheepTakeDamageFromWater = false; -+ public boolean sheepAlwaysDropExp = false; - private void sheepSettings() { - sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); - sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); -@@ -2285,6 +2376,7 @@ public class PurpurWorldConfig { - sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks); - sheepBypassMobGriefing = getBoolean("mobs.sheep.bypass-mob-griefing", sheepBypassMobGriefing); - sheepTakeDamageFromWater = getBoolean("mobs.sheep.takes-damage-from-water", sheepTakeDamageFromWater); -+ sheepAlwaysDropExp = getBoolean("mobs.sheep.always-drop-exp", sheepAlwaysDropExp); - } - - public boolean shulkerRidable = false; -@@ -2298,6 +2390,7 @@ public class PurpurWorldConfig { - public String shulkerSpawnFromBulletNearbyEquation = "(nearby - 1) / 5.0"; - public boolean shulkerSpawnFromBulletRandomColor = false; - public boolean shulkerChangeColorWithDye = false; -+ public boolean shulkerAlwaysDropExp = false; - private void shulkerSettings() { - shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); - shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); -@@ -2315,6 +2408,7 @@ public class PurpurWorldConfig { - shulkerSpawnFromBulletNearbyEquation = getString("mobs.shulker.spawn-from-bullet.nearby-equation", shulkerSpawnFromBulletNearbyEquation); - shulkerSpawnFromBulletRandomColor = getBoolean("mobs.shulker.spawn-from-bullet.random-color", shulkerSpawnFromBulletRandomColor); - shulkerChangeColorWithDye = getBoolean("mobs.shulker.change-color-with-dye", shulkerChangeColorWithDye); -+ shulkerAlwaysDropExp = getBoolean("mobs.shulker.always-drop-exp", shulkerAlwaysDropExp); - } - - public boolean silverfishRidable = false; -@@ -2323,6 +2417,7 @@ public class PurpurWorldConfig { - public double silverfishMaxHealth = 8.0D; - public boolean silverfishBypassMobGriefing = false; - public boolean silverfishTakeDamageFromWater = false; -+ public boolean silverfishAlwaysDropExp = false; - private void silverfishSettings() { - silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); - silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); -@@ -2335,6 +2430,7 @@ public class PurpurWorldConfig { - silverfishMaxHealth = getDouble("mobs.silverfish.attributes.max_health", silverfishMaxHealth); - silverfishBypassMobGriefing = getBoolean("mobs.silverfish.bypass-mob-griefing", silverfishBypassMobGriefing); - silverfishTakeDamageFromWater = getBoolean("mobs.silverfish.takes-damage-from-water", silverfishTakeDamageFromWater); -+ silverfishAlwaysDropExp = getBoolean("mobs.silverfish.always-drop-exp", silverfishAlwaysDropExp); - } - - public boolean skeletonRidable = false; -@@ -2342,6 +2438,7 @@ public class PurpurWorldConfig { - public boolean skeletonControllable = true; - public double skeletonMaxHealth = 20.0D; - public boolean skeletonTakeDamageFromWater = false; -+ public boolean skeletonAlwaysDropExp = false; - private void skeletonSettings() { - skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); - skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); -@@ -2353,6 +2450,7 @@ public class PurpurWorldConfig { - } - skeletonMaxHealth = getDouble("mobs.skeleton.attributes.max_health", skeletonMaxHealth); - skeletonTakeDamageFromWater = getBoolean("mobs.skeleton.takes-damage-from-water", skeletonTakeDamageFromWater); -+ skeletonAlwaysDropExp = getBoolean("mobs.skeleton.always-drop-exp", skeletonAlwaysDropExp); - } - - public boolean skeletonHorseRidable = false; -@@ -2365,6 +2463,7 @@ public class PurpurWorldConfig { - public double skeletonHorseMovementSpeedMin = 0.2D; - public double skeletonHorseMovementSpeedMax = 0.2D; - public boolean skeletonHorseTakeDamageFromWater = false; -+ public boolean skeletonHorseAlwaysDropExp = false; - private void skeletonHorseSettings() { - skeletonHorseRidable = getBoolean("mobs.skeleton_horse.ridable", skeletonHorseRidable); - skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater); -@@ -2382,6 +2481,7 @@ public class PurpurWorldConfig { - skeletonHorseMovementSpeedMin = getDouble("mobs.skeleton_horse.attributes.movement_speed.min", skeletonHorseMovementSpeedMin); - skeletonHorseMovementSpeedMax = getDouble("mobs.skeleton_horse.attributes.movement_speed.max", skeletonHorseMovementSpeedMax); - skeletonHorseTakeDamageFromWater = getBoolean("mobs.skeleton_horse.takes-damage-from-water", skeletonHorseTakeDamageFromWater); -+ skeletonHorseAlwaysDropExp = getBoolean("mobs.skeleton_horse.always-drop-exp", skeletonHorseAlwaysDropExp); - } - - public boolean slimeRidable = false; -@@ -2392,6 +2492,7 @@ public class PurpurWorldConfig { - public Map slimeMaxHealthCache = new HashMap<>(); - public Map slimeAttackDamageCache = new HashMap<>(); - public boolean slimeTakeDamageFromWater = false; -+ public boolean slimeAlwaysDropExp = false; - private void slimeSettings() { - slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable); - slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater); -@@ -2406,6 +2507,7 @@ public class PurpurWorldConfig { - slimeMaxHealthCache.clear(); - slimeAttackDamageCache.clear(); - slimeTakeDamageFromWater = getBoolean("mobs.slime.takes-damage-from-water", slimeTakeDamageFromWater); -+ slimeAlwaysDropExp = getBoolean("mobs.slime.always-drop-exp", slimeAlwaysDropExp); - } - - public boolean snowGolemRidable = false; -@@ -2420,6 +2522,7 @@ public class PurpurWorldConfig { - public double snowGolemAttackDistance = 1.25D; - public boolean snowGolemBypassMobGriefing = false; - public boolean snowGolemTakeDamageFromWater = true; -+ public boolean snowGolemAlwaysDropExp = false; - private void snowGolemSettings() { - snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); - snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); -@@ -2438,6 +2541,7 @@ public class PurpurWorldConfig { - snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance); - snowGolemBypassMobGriefing = getBoolean("mobs.snow_golem.bypass-mob-griefing", snowGolemBypassMobGriefing); - snowGolemTakeDamageFromWater = getBoolean("mobs.snow_golem.takes-damage-from-water", snowGolemTakeDamageFromWater); -+ snowGolemAlwaysDropExp = getBoolean("mobs.snow_golem.always-drop-exp", snowGolemAlwaysDropExp); - } - - public boolean snifferRidable = false; -@@ -2460,6 +2564,7 @@ public class PurpurWorldConfig { - public double squidOffsetWaterCheck = 0.0D; - public boolean squidsCanFly = false; - public boolean squidTakeDamageFromWater = false; -+ public boolean squidAlwaysDropExp = false; - private void squidSettings() { - squidRidable = getBoolean("mobs.squid.ridable", squidRidable); - squidControllable = getBoolean("mobs.squid.controllable", squidControllable); -@@ -2473,6 +2578,7 @@ public class PurpurWorldConfig { - squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); - squidsCanFly = getBoolean("mobs.squid.can-fly", squidsCanFly); - squidTakeDamageFromWater = getBoolean("mobs.squid.takes-damage-from-water", squidTakeDamageFromWater); -+ squidAlwaysDropExp = getBoolean("mobs.squid.always-drop-exp", squidAlwaysDropExp); - } - - public boolean spiderRidable = false; -@@ -2480,6 +2586,7 @@ public class PurpurWorldConfig { - public boolean spiderControllable = true; - public double spiderMaxHealth = 16.0D; - public boolean spiderTakeDamageFromWater = false; -+ public boolean spiderAlwaysDropExp = false; - private void spiderSettings() { - spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable); - spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater); -@@ -2491,6 +2598,7 @@ public class PurpurWorldConfig { - } - spiderMaxHealth = getDouble("mobs.spider.attributes.max_health", spiderMaxHealth); - spiderTakeDamageFromWater = getBoolean("mobs.spider.takes-damage-from-water", spiderTakeDamageFromWater); -+ spiderAlwaysDropExp = getBoolean("mobs.spider.always-drop-exp", spiderAlwaysDropExp); - } - - public boolean strayRidable = false; -@@ -2498,6 +2606,7 @@ public class PurpurWorldConfig { - public boolean strayControllable = true; - public double strayMaxHealth = 20.0D; - public boolean strayTakeDamageFromWater = false; -+ public boolean strayAlwaysDropExp = false; - private void straySettings() { - strayRidable = getBoolean("mobs.stray.ridable", strayRidable); - strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater); -@@ -2509,6 +2618,7 @@ public class PurpurWorldConfig { - } - strayMaxHealth = getDouble("mobs.stray.attributes.max_health", strayMaxHealth); - strayTakeDamageFromWater = getBoolean("mobs.stray.takes-damage-from-water", strayTakeDamageFromWater); -+ strayAlwaysDropExp = getBoolean("mobs.stray.always-drop-exp", strayAlwaysDropExp); - } - - public boolean striderRidable = false; -@@ -2518,6 +2628,7 @@ public class PurpurWorldConfig { - public int striderBreedingTicks = 6000; - public boolean striderGiveSaddleBack = false; - public boolean striderTakeDamageFromWater = true; -+ public boolean striderAlwaysDropExp = false; - private void striderSettings() { - striderRidable = getBoolean("mobs.strider.ridable", striderRidable); - striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); -@@ -2531,6 +2642,7 @@ public class PurpurWorldConfig { - striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks); - striderGiveSaddleBack = getBoolean("mobs.strider.give-saddle-back", striderGiveSaddleBack); - striderTakeDamageFromWater = getBoolean("mobs.strider.takes-damage-from-water", striderTakeDamageFromWater); -+ striderAlwaysDropExp = getBoolean("mobs.strider.always-drop-exp", striderAlwaysDropExp); - } - - public boolean tadpoleRidable = false; -@@ -2553,6 +2665,7 @@ public class PurpurWorldConfig { - public double traderLlamaMovementSpeedMax = 0.175D; - public int traderLlamaBreedingTicks = 6000; - public boolean traderLlamaTakeDamageFromWater = false; -+ public boolean traderLlamaAlwaysDropExp = false; - private void traderLlamaSettings() { - traderLlamaRidable = getBoolean("mobs.trader_llama.ridable", traderLlamaRidable); - traderLlamaRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", traderLlamaRidableInWater); -@@ -2572,12 +2685,14 @@ public class PurpurWorldConfig { - traderLlamaMovementSpeedMax = getDouble("mobs.trader_llama.attributes.movement_speed.max", traderLlamaMovementSpeedMax); - traderLlamaBreedingTicks = getInt("mobs.trader_llama.breeding-delay-ticks", traderLlamaBreedingTicks); - traderLlamaTakeDamageFromWater = getBoolean("mobs.trader_llama.takes-damage-from-water", traderLlamaTakeDamageFromWater); -+ traderLlamaAlwaysDropExp = getBoolean("mobs.trader_llama.always-drop-exp", traderLlamaAlwaysDropExp); - } - - public boolean tropicalFishRidable = false; - public boolean tropicalFishControllable = true; - public double tropicalFishMaxHealth = 3.0D; - public boolean tropicalFishTakeDamageFromWater = false; -+ public boolean tropicalFishAlwaysDropExp = false; - private void tropicalFishSettings() { - tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable); - tropicalFishControllable = getBoolean("mobs.tropical_fish.controllable", tropicalFishControllable); -@@ -2588,6 +2703,7 @@ public class PurpurWorldConfig { - } - tropicalFishMaxHealth = getDouble("mobs.tropical_fish.attributes.max_health", tropicalFishMaxHealth); - tropicalFishTakeDamageFromWater = getBoolean("mobs.tropical_fish.takes-damage-from-water", tropicalFishTakeDamageFromWater); -+ tropicalFishAlwaysDropExp = getBoolean("mobs.tropical_fish.always-drop-exp", tropicalFishAlwaysDropExp); - } - - public boolean turtleRidable = false; -@@ -2596,6 +2712,7 @@ public class PurpurWorldConfig { - public double turtleMaxHealth = 30.0D; - public int turtleBreedingTicks = 6000; - public boolean turtleTakeDamageFromWater = false; -+ public boolean turtleAlwaysDropExp = false; - private void turtleSettings() { - turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); - turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); -@@ -2608,6 +2725,7 @@ public class PurpurWorldConfig { - turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth); - turtleBreedingTicks = getInt("mobs.turtle.breeding-delay-ticks", turtleBreedingTicks); - turtleTakeDamageFromWater = getBoolean("mobs.turtle.takes-damage-from-water", turtleTakeDamageFromWater); -+ turtleAlwaysDropExp = getBoolean("mobs.turtle.always-drop-exp", turtleAlwaysDropExp); - } - - public boolean vexRidable = false; -@@ -2616,6 +2734,7 @@ public class PurpurWorldConfig { - public double vexMaxY = 320D; - public double vexMaxHealth = 14.0D; - public boolean vexTakeDamageFromWater = false; -+ public boolean vexAlwaysDropExp = false; - private void vexSettings() { - vexRidable = getBoolean("mobs.vex.ridable", vexRidable); - vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater); -@@ -2628,6 +2747,7 @@ public class PurpurWorldConfig { - } - vexMaxHealth = getDouble("mobs.vex.attributes.max_health", vexMaxHealth); - vexTakeDamageFromWater = getBoolean("mobs.vex.takes-damage-from-water", vexTakeDamageFromWater); -+ vexAlwaysDropExp = getBoolean("mobs.vex.always-drop-exp", vexAlwaysDropExp); - } - - public boolean villagerRidable = false; -@@ -2643,6 +2763,7 @@ public class PurpurWorldConfig { - public boolean villagerBypassMobGriefing = false; - public boolean villagerTakeDamageFromWater = false; - public boolean villagerAllowTrading = true; -+ public boolean villagerAlwaysDropExp = false; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -2662,6 +2783,7 @@ public class PurpurWorldConfig { - villagerBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerBypassMobGriefing); - villagerTakeDamageFromWater = getBoolean("mobs.villager.takes-damage-from-water", villagerTakeDamageFromWater); - villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading); -+ villagerAlwaysDropExp = getBoolean("mobs.villager.always-drop-exp", villagerAlwaysDropExp); - } - - public boolean vindicatorRidable = false; -@@ -2670,6 +2792,7 @@ public class PurpurWorldConfig { - public double vindicatorMaxHealth = 24.0D; - public double vindicatorJohnnySpawnChance = 0D; - public boolean vindicatorTakeDamageFromWater = false; -+ public boolean vindicatorAlwaysDropExp = false; - private void vindicatorSettings() { - vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); - vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); -@@ -2682,6 +2805,7 @@ public class PurpurWorldConfig { - vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth); - vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance); - vindicatorTakeDamageFromWater = getBoolean("mobs.vindicator.takes-damage-from-water", vindicatorTakeDamageFromWater); -+ vindicatorAlwaysDropExp = getBoolean("mobs.vindicator.always-drop-exp", vindicatorAlwaysDropExp); - } - - public boolean wanderingTraderRidable = false; -@@ -2692,6 +2816,7 @@ public class PurpurWorldConfig { - public boolean wanderingTraderCanBeLeashed = false; - public boolean wanderingTraderTakeDamageFromWater = false; - public boolean wanderingTraderAllowTrading = true; -+ public boolean wanderingTraderAlwaysDropExp = false; - private void wanderingTraderSettings() { - wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); - wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); -@@ -2706,6 +2831,7 @@ public class PurpurWorldConfig { - wanderingTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", wanderingTraderCanBeLeashed); - wanderingTraderTakeDamageFromWater = getBoolean("mobs.wandering_trader.takes-damage-from-water", wanderingTraderTakeDamageFromWater); - wanderingTraderAllowTrading = getBoolean("mobs.wandering_trader.allow-trading", wanderingTraderAllowTrading); -+ wanderingTraderAlwaysDropExp = getBoolean("mobs.wandering_trader.always-drop-exp", wanderingTraderAlwaysDropExp); - } - - public boolean wardenRidable = false; -@@ -2722,6 +2848,7 @@ public class PurpurWorldConfig { - public boolean witchControllable = true; - public double witchMaxHealth = 26.0D; - public boolean witchTakeDamageFromWater = false; -+ public boolean witchAlwaysDropExp = false; - private void witchSettings() { - witchRidable = getBoolean("mobs.witch.ridable", witchRidable); - witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater); -@@ -2733,6 +2860,7 @@ public class PurpurWorldConfig { - } - witchMaxHealth = getDouble("mobs.witch.attributes.max_health", witchMaxHealth); - witchTakeDamageFromWater = getBoolean("mobs.witch.takes-damage-from-water", witchTakeDamageFromWater); -+ witchAlwaysDropExp = getBoolean("mobs.witch.always-drop-exp", witchAlwaysDropExp); - } - - public boolean witherRidable = false; -@@ -2747,6 +2875,7 @@ public class PurpurWorldConfig { - public boolean witherCanRideVehicles = false; - public float witherExplosionRadius = 1.0F; - public boolean witherPlaySpawnSound = true; -+ public boolean witherAlwaysDropExp = false; - private void witherSettings() { - witherRidable = getBoolean("mobs.wither.ridable", witherRidable); - witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); -@@ -2769,6 +2898,7 @@ public class PurpurWorldConfig { - witherCanRideVehicles = getBoolean("mobs.wither.can-ride-vehicles", witherCanRideVehicles); - witherExplosionRadius = (float) getDouble("mobs.wither.explosion-radius", witherExplosionRadius); - witherPlaySpawnSound = getBoolean("mobs.wither.play-spawn-sound", witherPlaySpawnSound); -+ witherAlwaysDropExp = getBoolean("mobs.wither.always-drop-exp", witherAlwaysDropExp); - } - - public boolean witherSkeletonRidable = false; -@@ -2776,6 +2906,7 @@ public class PurpurWorldConfig { - public boolean witherSkeletonControllable = true; - public double witherSkeletonMaxHealth = 20.0D; - public boolean witherSkeletonTakeDamageFromWater = false; -+ public boolean witherSkeletonAlwaysDropExp = false; - private void witherSkeletonSettings() { - witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable); - witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater); -@@ -2787,6 +2918,7 @@ public class PurpurWorldConfig { - } - witherSkeletonMaxHealth = getDouble("mobs.wither_skeleton.attributes.max_health", witherSkeletonMaxHealth); - witherSkeletonTakeDamageFromWater = getBoolean("mobs.wither_skeleton.takes-damage-from-water", witherSkeletonTakeDamageFromWater); -+ witherSkeletonAlwaysDropExp = getBoolean("mobs.wither_skeleton.always-drop-exp", witherSkeletonAlwaysDropExp); - } - - public boolean wolfRidable = false; -@@ -2798,6 +2930,7 @@ public class PurpurWorldConfig { - public double wolfNaturalRabid = 0.0D; - public int wolfBreedingTicks = 6000; - public boolean wolfTakeDamageFromWater = false; -+ public boolean wolfAlwaysDropExp = false; - private void wolfSettings() { - wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); - wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); -@@ -2817,6 +2950,7 @@ public class PurpurWorldConfig { - wolfNaturalRabid = getDouble("mobs.wolf.spawn-rabid-chance", wolfNaturalRabid); - wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks); - wolfTakeDamageFromWater = getBoolean("mobs.wolf.takes-damage-from-water", wolfTakeDamageFromWater); -+ wolfAlwaysDropExp = getBoolean("mobs.wolf.always-drop-exp", wolfAlwaysDropExp); - } - - public boolean zoglinRidable = false; -@@ -2824,6 +2958,7 @@ public class PurpurWorldConfig { - public boolean zoglinControllable = true; - public double zoglinMaxHealth = 40.0D; - public boolean zoglinTakeDamageFromWater = false; -+ public boolean zoglinAlwaysDropExp = false; - private void zoglinSettings() { - zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable); - zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater); -@@ -2835,6 +2970,7 @@ public class PurpurWorldConfig { - } - zoglinMaxHealth = getDouble("mobs.zoglin.attributes.max_health", zoglinMaxHealth); - zoglinTakeDamageFromWater = getBoolean("mobs.zoglin.takes-damage-from-water", zoglinTakeDamageFromWater); -+ zoglinAlwaysDropExp = getBoolean("mobs.zoglin.always-drop-exp", zoglinAlwaysDropExp); - } - - public boolean zombieRidable = false; -@@ -2848,6 +2984,7 @@ public class PurpurWorldConfig { - public boolean zombieAggressiveTowardsVillagerWhenLagging = true; - public boolean zombieBypassMobGriefing = false; - public boolean zombieTakeDamageFromWater = false; -+ public boolean zombieAlwaysDropExp = false; - private void zombieSettings() { - zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); - zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); -@@ -2865,6 +3002,7 @@ public class PurpurWorldConfig { - zombieAggressiveTowardsVillagerWhenLagging = getBoolean("mobs.zombie.aggressive-towards-villager-when-lagging", zombieAggressiveTowardsVillagerWhenLagging); - zombieBypassMobGriefing = getBoolean("mobs.zombie.bypass-mob-griefing", zombieBypassMobGriefing); - zombieTakeDamageFromWater = getBoolean("mobs.zombie.takes-damage-from-water", zombieTakeDamageFromWater); -+ zombieAlwaysDropExp = getBoolean("mobs.zombie.always-drop-exp", zombieAlwaysDropExp); - } - - public boolean zombieHorseRidable = false; -@@ -2878,6 +3016,7 @@ public class PurpurWorldConfig { - public double zombieHorseMovementSpeedMax = 0.2D; - public double zombieHorseSpawnChance = 0.0D; - public boolean zombieHorseTakeDamageFromWater = false; -+ public boolean zombieHorseAlwaysDropExp = false; - private void zombieHorseSettings() { - zombieHorseRidable = getBoolean("mobs.zombie_horse.ridable", zombieHorseRidable); - zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); -@@ -2896,6 +3035,7 @@ public class PurpurWorldConfig { - zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax); - zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); - zombieHorseTakeDamageFromWater = getBoolean("mobs.zombie_horse.takes-damage-from-water", zombieHorseTakeDamageFromWater); -+ zombieHorseAlwaysDropExp = getBoolean("mobs.zombie_horse.always-drop-exp", zombieHorseAlwaysDropExp); - } - - public boolean zombieVillagerRidable = false; -@@ -2910,6 +3050,7 @@ public class PurpurWorldConfig { - public int zombieVillagerCuringTimeMin = 3600; - public int zombieVillagerCuringTimeMax = 6000; - public boolean zombieVillagerCureEnabled = true; -+ public boolean zombieVillagerAlwaysDropExp = false; - private void zombieVillagerSettings() { - zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); - zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); -@@ -2928,6 +3069,7 @@ public class PurpurWorldConfig { - zombieVillagerCuringTimeMin = getInt("mobs.zombie_villager.curing_time.min", zombieVillagerCuringTimeMin); - zombieVillagerCuringTimeMax = getInt("mobs.zombie_villager.curing_time.max", zombieVillagerCuringTimeMax); - zombieVillagerCureEnabled = getBoolean("mobs.zombie_villager.cure.enabled", zombieVillagerCureEnabled); -+ zombieVillagerAlwaysDropExp = getBoolean("mobs.zombie_villager.always-drop-exp", zombieVillagerAlwaysDropExp); - } - - public boolean zombifiedPiglinRidable = false; -@@ -2940,6 +3082,7 @@ public class PurpurWorldConfig { - public boolean zombifiedPiglinJockeyTryExistingChickens = true; - public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = true; - public boolean zombifiedPiglinTakeDamageFromWater = false; -+ public boolean zombifiedPiglinAlwaysDropExp = false; - private void zombifiedPiglinSettings() { - zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); - zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); -@@ -2956,6 +3099,7 @@ public class PurpurWorldConfig { - zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); - zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry); - zombifiedPiglinTakeDamageFromWater = getBoolean("mobs.zombified_piglin.takes-damage-from-water", zombifiedPiglinTakeDamageFromWater); -+ zombifiedPiglinAlwaysDropExp = getBoolean("mobs.zombified_piglin.always-drop-exp", zombifiedPiglinAlwaysDropExp); - } - - public float hungerStarvationDamage = 1.0F; diff --git a/patches/server/0220-Grindstone-API.patch b/patches/server/0220-Grindstone-API.patch deleted file mode 100644 index 479f112fa..000000000 --- a/patches/server/0220-Grindstone-API.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 27 Dec 2021 08:11:00 -0600 -Subject: [PATCH] Grindstone API - - -diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -index 5824636332eb35ae6bee9cc0661ee95901bb8c4b..1d181de9c8fd45b4d9f0230f80d5752ff5c1a432 100644 ---- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java -@@ -95,9 +95,11 @@ public class GrindstoneMenu extends AbstractContainerMenu { - - @Override - public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) { -+ ItemStack itemstack = activeQuickItem == null ? stack : activeQuickItem; // Purpur - context.execute((world, blockposition) -> { -+ org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent grindstoneTakeResultEvent = new org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), this.getExperienceAmount(world)); grindstoneTakeResultEvent.callEvent(); // Purpur - if (world instanceof ServerLevel) { -- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Paper -+ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), grindstoneTakeResultEvent.getExperienceAmount(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Paper // Purpur - } - - world.levelEvent(1042, blockposition, 0); -@@ -393,7 +395,9 @@ public class GrindstoneMenu extends AbstractContainerMenu { - return ItemStack.EMPTY; - } - -+ this.activeQuickItem = itemstack; // Purpur - slot1.onTake(player, itemstack1); -+ this.activeQuickItem = null; // Purpur - } - - return itemstack; diff --git a/patches/server/0221-Ability-for-hoe-to-replant-crops-and-nether-warts.patch b/patches/server/0221-Ability-for-hoe-to-replant-crops-and-nether-warts.patch deleted file mode 100644 index 9b761a70a..000000000 --- a/patches/server/0221-Ability-for-hoe-to-replant-crops-and-nether-warts.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Tue, 28 Dec 2021 16:22:20 -0600 -Subject: [PATCH] Ability for hoe to replant crops and nether warts - - -diff --git a/src/main/java/net/minecraft/world/level/block/BushBlock.java b/src/main/java/net/minecraft/world/level/block/BushBlock.java -index a7b4b5600e3c889c69ac22294899713d50b5fe5c..a27e298ffdfa6956be9cde429d2cd45483a51fed 100644 ---- a/src/main/java/net/minecraft/world/level/block/BushBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java -@@ -52,4 +52,24 @@ public abstract class BushBlock extends Block { - protected boolean isPathfindable(BlockState state, PathComputationType type) { - return type == PathComputationType.AIR && !this.hasCollision ? true : super.isPathfindable(state, type); - } -+ -+ // Purpur start -+ public void playerDestroyAndReplant(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, net.minecraft.world.item.ItemStack itemInHand, net.minecraft.world.level.ItemLike itemToReplant) { -+ player.awardStat(net.minecraft.stats.Stats.BLOCK_MINED.get(this)); -+ player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); -+ java.util.List dropList = Block.getDrops(state, (net.minecraft.server.level.ServerLevel) world, pos, blockEntity, player, itemInHand); -+ -+ boolean planted = false; -+ for (net.minecraft.world.item.ItemStack itemToDrop : dropList) { -+ if (!planted && itemToDrop.getItem() == itemToReplant) { -+ world.setBlock(pos, defaultBlockState(), 3); -+ itemToDrop.setCount(itemToDrop.getCount() - 1); -+ planted = true; -+ } -+ Block.popResource(world, pos, itemToDrop); -+ } -+ -+ state.spawnAfterBreak((net.minecraft.server.level.ServerLevel) world, pos, itemInHand, true); -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java -index a69e7e8da81bd13578d230cc1e3f0f900817cbfd..5a190834baef60c7b61074393f8856a933902d81 100644 ---- a/src/main/java/net/minecraft/world/level/block/CropBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java -@@ -214,4 +214,15 @@ public class CropBlock extends BushBlock implements BonemealableBlock { - protected void createBlockStateDefinition(StateDefinition.Builder builder) { - builder.add(CropBlock.AGE); - } -+ -+ // Purpur start -+ @Override -+ public void playerDestroy(Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) { -+ if (world.purpurConfig.hoeReplantsCrops && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) { -+ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, getBaseSeedId()); -+ } else { -+ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp); -+ } -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java -index acbd60a2f162fe0e254e36d0e8e7face3fc8a7b3..da1c7999ca64199387054de46489d3ff4a299289 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java -@@ -68,4 +68,15 @@ public class NetherWartBlock extends BushBlock { - protected void createBlockStateDefinition(StateDefinition.Builder builder) { - builder.add(NetherWartBlock.AGE); - } -+ -+ // Purpur start -+ @Override -+ public void playerDestroy(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) { -+ if (world.purpurConfig.hoeReplantsNetherWarts && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) { -+ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, Items.NETHER_WART); -+ } else { -+ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp); -+ } -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index fd8c8c6e563662926002fb1c72aaea0ba2999cdb..b492b7f6c8c959fa379bd75d5d89e99065421e93 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -548,6 +548,8 @@ public class PurpurWorldConfig { - public Map axeWeatherables = new HashMap<>(); - public Map hoeTillables = new HashMap<>(); - public Map shovelFlattenables = new HashMap<>(); -+ public boolean hoeReplantsCrops = false; -+ public boolean hoeReplantsNetherWarts = false; - private void toolSettings() { - axeStrippables.clear(); - axeWaxables.clear(); -@@ -815,6 +817,8 @@ public class PurpurWorldConfig { - }); - shovelFlattenables.put(block, new Flattenable(into, drops)); - }); -+ hoeReplantsCrops = getBoolean("tools.hoe.replant-crops", hoeReplantsCrops); -+ hoeReplantsNetherWarts = getBoolean("tools.hoe.replant-nether-warts", hoeReplantsNetherWarts); - } - - public boolean anvilAllowColors = false; diff --git a/patches/server/0222-Turtle-eggs-random-tick-crack-chance.patch b/patches/server/0222-Turtle-eggs-random-tick-crack-chance.patch deleted file mode 100644 index 0e08edaa4..000000000 --- a/patches/server/0222-Turtle-eggs-random-tick-crack-chance.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 31 Dec 2021 06:18:54 -0600 -Subject: [PATCH] Turtle eggs random tick crack chance - - -diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -index 0c732cfbd9ce50198a3f85ae8ef2263d7ae0bc1a..2f0e8aeb9c45853fca12ddd78a7d51813a600e67 100644 ---- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -@@ -170,7 +170,7 @@ public class TurtleEggBlock extends Block { - private boolean shouldUpdateHatchLevel(Level world) { - float f = world.getTimeOfDay(1.0F); - -- return (double) f < 0.69D && (double) f > 0.65D ? true : world.random.nextInt(500) == 0; -+ return (double) f < 0.69D && (double) f > 0.65D ? true : world.random.nextInt(world.purpurConfig.turtleEggsRandomTickCrackChance) == 0; - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b492b7f6c8c959fa379bd75d5d89e99065421e93..9ed53d42189f7f7562ed96b4af39a02db2cb2ff5 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1075,11 +1075,13 @@ public class PurpurWorldConfig { - public boolean turtleEggsBreakFromItems = false; - public boolean turtleEggsBreakFromMinecarts = false; - public boolean turtleEggsBypassMobGriefing = false; -+ public int turtleEggsRandomTickCrackChance = 500; - private void turtleEggSettings() { - turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs); - turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems); - turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); - turtleEggsBypassMobGriefing = getBoolean("blocks.turtle_egg.bypass-mob-griefing", turtleEggsBypassMobGriefing); -+ turtleEggsRandomTickCrackChance = getInt("blocks.turtle_egg.random-tick-crack-chance", turtleEggsRandomTickCrackChance); - } - - public int waterInfiniteRequiredSources = 2; diff --git a/patches/server/0223-Mob-head-visibility-percent.patch b/patches/server/0223-Mob-head-visibility-percent.patch deleted file mode 100644 index fb48f5b3b..000000000 --- a/patches/server/0223-Mob-head-visibility-percent.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 31 Dec 2021 06:40:19 -0600 -Subject: [PATCH] Mob head visibility percent - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 549579f2bc2e1fd23ece1ead543e3e5242f52ce0..119d2e57995fa20f34b88963b93c945ff87e0cab 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1071,9 +1071,20 @@ public abstract class LivingEntity extends Entity implements Attackable { - ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); - EntityType entitytypes = entity.getType(); - -- if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL) || entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD) || entitytypes == EntityType.PIGLIN && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.PIGLIN_BRUTE && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) { -- d0 *= 0.5D; -+ // Purpur start -+ if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL)) { -+ d0 *= entity.level().purpurConfig.skeletonHeadVisibilityPercent; -+ } -+ else if (entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD)) { -+ d0 *= entity.level().purpurConfig.zombieHeadVisibilityPercent; -+ } -+ else if (entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) { -+ d0 *= entity.level().purpurConfig.creeperHeadVisibilityPercent; - } -+ else if ((entitytypes == EntityType.PIGLIN || entitytypes == EntityType.PIGLIN_BRUTE) && itemstack.is(Items.PIGLIN_HEAD)) { -+ d0 *= entity.level().purpurConfig.piglinHeadVisibilityPercent; -+ } -+ // Purpur end - - // Purpur start - if (entity instanceof LivingEntity entityliving) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 9ed53d42189f7f7562ed96b4af39a02db2cb2ff5..77ee5bc60d953e72c6695ce1ce19276f61ae2057 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1369,6 +1369,7 @@ public class PurpurWorldConfig { - public boolean creeperExplodeWhenKilled = false; - public boolean creeperHealthRadius = false; - public boolean creeperAlwaysDropExp = false; -+ public double creeperHeadVisibilityPercent = 0.5D; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -1386,6 +1387,7 @@ public class PurpurWorldConfig { - creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled); - creeperHealthRadius = getBoolean("mobs.creeper.health-impacts-explosion", creeperHealthRadius); - creeperAlwaysDropExp = getBoolean("mobs.creeper.always-drop-exp", creeperAlwaysDropExp); -+ creeperHeadVisibilityPercent = getDouble("mobs.creeper.head-visibility-percent", creeperHeadVisibilityPercent); - } - - public boolean dolphinRidable = false; -@@ -2172,6 +2174,7 @@ public class PurpurWorldConfig { - public boolean piglinTakeDamageFromWater = false; - public int piglinPortalSpawnModifier = 2000; - public boolean piglinAlwaysDropExp = false; -+ public double piglinHeadVisibilityPercent = 0.5D; - private void piglinSettings() { - piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); - piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); -@@ -2186,6 +2189,7 @@ public class PurpurWorldConfig { - piglinTakeDamageFromWater = getBoolean("mobs.piglin.takes-damage-from-water", piglinTakeDamageFromWater); - piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier); - piglinAlwaysDropExp = getBoolean("mobs.piglin.always-drop-exp", piglinAlwaysDropExp); -+ piglinHeadVisibilityPercent = getDouble("mobs.piglin.head-visibility-percent", piglinHeadVisibilityPercent); - } - - public boolean piglinBruteRidable = false; -@@ -2445,6 +2449,7 @@ public class PurpurWorldConfig { - public double skeletonMaxHealth = 20.0D; - public boolean skeletonTakeDamageFromWater = false; - public boolean skeletonAlwaysDropExp = false; -+ public double skeletonHeadVisibilityPercent = 0.5D; - private void skeletonSettings() { - skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); - skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); -@@ -2457,6 +2462,7 @@ public class PurpurWorldConfig { - skeletonMaxHealth = getDouble("mobs.skeleton.attributes.max_health", skeletonMaxHealth); - skeletonTakeDamageFromWater = getBoolean("mobs.skeleton.takes-damage-from-water", skeletonTakeDamageFromWater); - skeletonAlwaysDropExp = getBoolean("mobs.skeleton.always-drop-exp", skeletonAlwaysDropExp); -+ skeletonHeadVisibilityPercent = getDouble("mobs.skeleton.head-visibility-percent", skeletonHeadVisibilityPercent); - } - - public boolean skeletonHorseRidable = false; -@@ -2991,6 +2997,7 @@ public class PurpurWorldConfig { - public boolean zombieBypassMobGriefing = false; - public boolean zombieTakeDamageFromWater = false; - public boolean zombieAlwaysDropExp = false; -+ public double zombieHeadVisibilityPercent = 0.5D; - private void zombieSettings() { - zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); - zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); -@@ -3009,6 +3016,7 @@ public class PurpurWorldConfig { - zombieBypassMobGriefing = getBoolean("mobs.zombie.bypass-mob-griefing", zombieBypassMobGriefing); - zombieTakeDamageFromWater = getBoolean("mobs.zombie.takes-damage-from-water", zombieTakeDamageFromWater); - zombieAlwaysDropExp = getBoolean("mobs.zombie.always-drop-exp", zombieAlwaysDropExp); -+ zombieHeadVisibilityPercent = getDouble("mobs.zombie.head-visibility-percent", zombieHeadVisibilityPercent); - } - - public boolean zombieHorseRidable = false; diff --git a/patches/server/0224-Configurable-valid-characters-for-usernames.patch b/patches/server/0224-Configurable-valid-characters-for-usernames.patch deleted file mode 100644 index ca0221545..000000000 --- a/patches/server/0224-Configurable-valid-characters-for-usernames.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 1 Jan 2022 18:38:58 -0600 -Subject: [PATCH] Configurable valid characters for usernames - - -diff --git a/src/main/java/net/minecraft/util/StringUtil.java b/src/main/java/net/minecraft/util/StringUtil.java -index 0bd191acb9596d3aa21c337230d26f09d26f6888..20211f40aeeade9217ece087688974bdf55afc56 100644 ---- a/src/main/java/net/minecraft/util/StringUtil.java -+++ b/src/main/java/net/minecraft/util/StringUtil.java -@@ -69,6 +69,7 @@ public class StringUtil { - - // Paper start - Username validation - public static boolean isReasonablePlayerName(final String name) { -+ if (true) return org.purpurmc.purpur.PurpurConfig.usernameValidCharactersPattern.matcher(name).matches(); // Purpur - if (name.isEmpty() || name.length() > 16) { - return false; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 9ded52a0022e33a6b69191b5fa758d6cc7eb076f..cd27c2a3343133d688592791bec2a031410ff93f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -452,4 +452,11 @@ public class PurpurConfig { - private static void networkSettings() { - useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP); - } -+ -+ public static java.util.regex.Pattern usernameValidCharactersPattern; -+ private static void usernameValidationSettings() { -+ String defaultPattern = "^[a-zA-Z0-9_.]*$"; -+ String setPattern = getString("settings.username-valid-characters", defaultPattern); -+ usernameValidCharactersPattern = java.util.regex.Pattern.compile(setPattern == null || setPattern.isBlank() ? defaultPattern : setPattern); -+ } - } diff --git a/patches/server/0226-Stop-bees-from-dying-after-stinging.patch b/patches/server/0226-Stop-bees-from-dying-after-stinging.patch deleted file mode 100644 index 43b8cccca..000000000 --- a/patches/server/0226-Stop-bees-from-dying-after-stinging.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 3 Jan 2022 01:19:46 -0600 -Subject: [PATCH] Stop bees from dying after stinging - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 926c30db9b28a30fe5d6c8d20f3972dec0d7b4d0..221c0051c7a0e20c1b7a464df26eb63c4e997eee 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -435,6 +435,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - this.hurt(this.damageSources().drown(), 1.0F); - } - -+ if (flag && !this.level().purpurConfig.beeDiesAfterSting) setHasStung(false); else // Purpur - if (flag) { - ++this.timeSinceSting; - if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 77ee5bc60d953e72c6695ce1ce19276f61ae2057..c57bf82ab2ef1827b76f57ed8aff9aee08706fb3 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1170,6 +1170,7 @@ public class PurpurWorldConfig { - public boolean beeCanWorkAtNight = false; - public boolean beeCanWorkInRain = false; - public boolean beeAlwaysDropExp = false; -+ public boolean beeDiesAfterSting = true; - private void beeSettings() { - beeRidable = getBoolean("mobs.bee.ridable", beeRidable); - beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); -@@ -1186,6 +1187,7 @@ public class PurpurWorldConfig { - beeCanWorkAtNight = getBoolean("mobs.bee.can-work-at-night", beeCanWorkAtNight); - beeCanWorkInRain = getBoolean("mobs.bee.can-work-in-rain", beeCanWorkInRain); - beeAlwaysDropExp = getBoolean("mobs.bee.always-drop-exp", beeAlwaysDropExp); -+ beeDiesAfterSting = getBoolean("mobs.bee.dies-after-sting", beeDiesAfterSting); - } - - public boolean blazeRidable = false; diff --git a/patches/server/0227-Give-bee-counts-in-beehives-to-Purpur-clients.patch b/patches/server/0227-Give-bee-counts-in-beehives-to-Purpur-clients.patch deleted file mode 100644 index 18cb6556b..000000000 --- a/patches/server/0227-Give-bee-counts-in-beehives-to-Purpur-clients.patch +++ /dev/null @@ -1,184 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Thu, 30 Dec 2021 09:56:43 -0600 -Subject: [PATCH] Give bee counts in beehives to Purpur clients - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 0f4fde2097b9db59b6c29935462f305f34747b3b..5081a631a94920db0307341261755eac399fea1e 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1071,6 +1071,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop STREAM_CODEC = CustomPacketPayload.codec(ClientboundBeehivePayload::write, ClientboundBeehivePayload::new); -+ public static final Type TYPE = new Type<>(new ResourceLocation("purpur", "beehive_s2c")); -+ -+ public ClientboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) { -+ this(friendlyByteBuf.readBlockPos(), friendlyByteBuf.readInt()); -+ } -+ -+ private void write(FriendlyByteBuf friendlyByteBuf) { -+ friendlyByteBuf.writeBlockPos(this.pos); -+ friendlyByteBuf.writeInt(this.numOfBees); -+ } -+ -+ @Override -+ public @NotNull Type type() { -+ return TYPE; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java b/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java -new file mode 100644 -index 0000000000000000000000000000000000000000..27689754565bf048d1206d540913495d7194a54d ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java -@@ -0,0 +1,26 @@ -+package org.purpurmc.purpur.network; -+ -+import net.minecraft.core.BlockPos; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.codec.StreamCodec; -+import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -+import net.minecraft.resources.ResourceLocation; -+import org.jetbrains.annotations.NotNull; -+ -+public record ServerboundBeehivePayload(BlockPos pos) implements CustomPacketPayload { -+ public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ServerboundBeehivePayload::write, ServerboundBeehivePayload::new); -+ public static final Type TYPE = new Type<>(new ResourceLocation("purpur", "beehive_c2s")); -+ -+ public ServerboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) { -+ this(friendlyByteBuf.readBlockPos()); -+ } -+ -+ private void write(FriendlyByteBuf friendlyByteBuf) { -+ friendlyByteBuf.writeBlockPos(this.pos); -+ } -+ -+ @Override -+ public @NotNull Type type() { -+ return TYPE; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java -new file mode 100644 -index 0000000000000000000000000000000000000000..56fc359ea32228c2589ac30c9d00a9c4bea30db7 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java -@@ -0,0 +1,67 @@ -+package org.purpurmc.purpur.task; -+ -+import io.netty.buffer.Unpooled; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.level.block.entity.BeehiveBlockEntity; -+import net.minecraft.world.level.block.entity.BlockEntity; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.entity.CraftPlayer; -+import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin; -+import org.bukkit.entity.Player; -+import org.bukkit.plugin.PluginBase; -+import org.bukkit.plugin.messaging.PluginMessageListener; -+import org.jetbrains.annotations.NotNull; -+import org.purpurmc.purpur.network.ClientboundBeehivePayload; -+import org.purpurmc.purpur.network.ServerboundBeehivePayload; -+ -+public class BeehiveTask implements PluginMessageListener { -+ -+ private static BeehiveTask instance; -+ -+ public static BeehiveTask instance() { -+ if (instance == null) { -+ instance = new BeehiveTask(); -+ } -+ return instance; -+ } -+ -+ private final PluginBase plugin = new MinecraftInternalPlugin(); -+ -+ private BeehiveTask() { -+ } -+ -+ public void register() { -+ Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString()); -+ Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString(), this); -+ } -+ -+ public void unregister() { -+ Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString()); -+ Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString()); -+ } -+ -+ @Override -+ public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] bytes) { -+ FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.copiedBuffer(bytes)); -+ ServerboundBeehivePayload payload = ServerboundBeehivePayload.STREAM_CODEC.decode(byteBuf); -+ -+ ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); -+ -+ // targeted block info max range specified in client at net.minecraft.client.gui.hud.DebugHud#render -+ if (!payload.pos().getCenter().closerThan(serverPlayer.position(), 20)) return; // Targeted Block info max range is 20 -+ if (serverPlayer.level().getChunkIfLoaded(payload.pos()) == null) return; -+ -+ BlockEntity blockEntity = serverPlayer.level().getBlockEntity(payload.pos()); -+ if (!(blockEntity instanceof BeehiveBlockEntity beehive)) { -+ return; -+ } -+ -+ ClientboundBeehivePayload customPacketPayload = new ClientboundBeehivePayload(payload.pos(), beehive.getOccupantCount()); -+ FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ ClientboundBeehivePayload.STREAM_CODEC.encode(friendlyByteBuf, customPacketPayload); -+ byte[] byteArray = new byte[friendlyByteBuf.readableBytes()]; -+ friendlyByteBuf.readBytes(byteArray); -+ player.sendPluginMessage(this.plugin, customPacketPayload.type().id().toString(), byteArray); -+ } -+} diff --git a/patches/server/0228-Configurable-farmland-trample-height.patch b/patches/server/0228-Configurable-farmland-trample-height.patch deleted file mode 100644 index 0501b9fda..000000000 --- a/patches/server/0228-Configurable-farmland-trample-height.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Tue, 4 Jan 2022 11:56:48 -0600 -Subject: [PATCH] Configurable farmland trample height - -This is _not_ in block height or an exact science. -During my testing I found very inconsistent values -for the fallDistance variable. Here are the results -of those tests (https://imgur.com/BojltJF): - -Value set -> Actual fall distance needed to trample - 1.0 -> 1.25 - 1.5 -> 1.75 - 2.0 -> 2.25 - 2.5 -> 2.87 - 3.0 -> 3.5 - 3.5 -> 4.25 - 4.0 -> 4.25 - 4.5 -> 5.0 - 5.0 -> 5.87 - 5.5 -> 5.87 - 6.0 -> 6.75 - -diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index 12a0c69f8fec30fad64cbb00af2ca1bbf0ea5153..d0ec0722496ed931b48c4e7076fddbb1ed36e111 100644 ---- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -111,7 +111,7 @@ public class FarmBlock extends Block { - @Override - public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { - super.fallOn(world, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage. -- if (!world.isClientSide && world.random.nextFloat() < fallDistance - 0.5F && entity instanceof LivingEntity && (entity instanceof Player || world.purpurConfig.farmlandBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { // Purpur -+ if (!world.isClientSide && (world.purpurConfig.farmlandTrampleHeight >= 0D ? fallDistance >= world.purpurConfig.farmlandTrampleHeight : world.random.nextFloat() < fallDistance - 0.5F) && entity instanceof LivingEntity && (entity instanceof Player || world.purpurConfig.farmlandBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { // Purpur - // CraftBukkit start - Interact soil - org.bukkit.event.Cancellable cancellable; - if (entity instanceof Player) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index c57bf82ab2ef1827b76f57ed8aff9aee08706fb3..ed600eacc335f9468db65e0ebde622451ab7a6a8 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -968,6 +968,7 @@ public class PurpurWorldConfig { - public boolean farmlandTramplingDisabled = false; - public boolean farmlandTramplingOnlyPlayers = false; - public boolean farmlandTramplingFeatherFalling = false; -+ public double farmlandTrampleHeight = -1D; - private void farmlandSettings() { - farmlandBypassMobGriefing = getBoolean("blocks.farmland.bypass-mob-griefing", farmlandBypassMobGriefing); - farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); -@@ -975,6 +976,7 @@ public class PurpurWorldConfig { - farmlandTramplingDisabled = getBoolean("blocks.farmland.disable-trampling", farmlandTramplingDisabled); - farmlandTramplingOnlyPlayers = getBoolean("blocks.farmland.only-players-trample", farmlandTramplingOnlyPlayers); - farmlandTramplingFeatherFalling = getBoolean("blocks.farmland.feather-fall-distance-affects-trampling", farmlandTramplingFeatherFalling); -+ farmlandTrampleHeight = getDouble("blocks.farmland.trample-height", farmlandTrampleHeight); - } - - public double floweringAzaleaGrowthChance = 0.0D; diff --git a/patches/server/0229-Configurable-player-pickup-exp-delay.patch b/patches/server/0229-Configurable-player-pickup-exp-delay.patch deleted file mode 100644 index ce253f4c1..000000000 --- a/patches/server/0229-Configurable-player-pickup-exp-delay.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 10 Jan 2022 10:04:31 -0600 -Subject: [PATCH] Configurable player pickup exp delay - -Default vanilla value is to delay 2 ticks between picking up exp orbs. -Players only pick up 1 orb at a time, so even with setting this to 0 -players still only pick up one orb every tick. However, setting this -to any negative number will pick up all orbs instantly. - -diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -index 7ca70e9ddda24e2fe661c7b13fa439a6c19726dd..ce608784e0e35b67dde377436aaf42c956ce0644 100644 ---- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java -@@ -320,7 +320,7 @@ public class ExperienceOrb extends Entity { - public void playerTouch(Player player) { - if (!this.level().isClientSide) { - if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent -- player.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(player, 2, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; -+ player.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(player, this.level().purpurConfig.playerExpPickupDelay, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; // Purpur - player.take(this, 1); - int i = this.repairPlayerItems(player, this.value); - -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 0460bdb52ce6b29cf57ef8f2d7f430e761c82d85..845c4af5d5d38d54de4a1b20fe32bf5dd4776a29 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -632,7 +632,7 @@ public abstract class Player extends LivingEntity { - while (iterator.hasNext()) { - Entity entity = (Entity) iterator.next(); - -- if (entity.getType() == EntityType.EXPERIENCE_ORB) { -+ if (entity.getType() == EntityType.EXPERIENCE_ORB && entity.level().purpurConfig.playerExpPickupDelay >= 0) { // Purpur - list1.add(entity); - } else if (!entity.isRemoved()) { - this.touch(entity); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ed600eacc335f9468db65e0ebde622451ab7a6a8..ae3e4547a7bd00432d51ead5bdef5703499c297f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -428,6 +428,7 @@ public class PurpurWorldConfig { - public boolean playerRidableInWater = false; - public boolean playerRemoveBindingWithWeakness = false; - public int shiftRightClickRepairsMendingPoints = 0; -+ public int playerExpPickupDelay = 2; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -453,6 +454,7 @@ public class PurpurWorldConfig { - playerRidableInWater = getBoolean("gameplay-mechanics.player.ridable-in-water", playerRidableInWater); - playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness); - shiftRightClickRepairsMendingPoints = getInt("gameplay-mechanics.player.shift-right-click-repairs-mending-points", shiftRightClickRepairsMendingPoints); -+ playerExpPickupDelay = getInt("gameplay-mechanics.player.exp-pickup-delay-ticks", playerExpPickupDelay); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0230-Allow-void-trading.patch b/patches/server/0230-Allow-void-trading.patch deleted file mode 100644 index 6230ad656..000000000 --- a/patches/server/0230-Allow-void-trading.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 15 Jan 2022 03:27:29 -0600 -Subject: [PATCH] Allow void trading - - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 42db3e64b120b753e98a0fd7e3f56c7d28256fd2..ae2b9732b2795ea7faec96af4c27ccb04f772307 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2855,7 +2855,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - // Spigot Start - if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message - // Paper start - Fix merchant inventory not closing on entity removal -- if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { -+ if (!entity.level().purpurConfig.playerVoidTrading && entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { // Purpur - merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); - } - // Paper end - Fix merchant inventory not closing on entity removal -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ae3e4547a7bd00432d51ead5bdef5703499c297f..38f417bde3e05124a9ebc23c2c5ea2f4d9d7cefe 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -429,6 +429,7 @@ public class PurpurWorldConfig { - public boolean playerRemoveBindingWithWeakness = false; - public int shiftRightClickRepairsMendingPoints = 0; - public int playerExpPickupDelay = 2; -+ public boolean playerVoidTrading = false; - private void playerSettings() { - if (PurpurConfig.version < 19) { - boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); -@@ -455,6 +456,7 @@ public class PurpurWorldConfig { - playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness); - shiftRightClickRepairsMendingPoints = getInt("gameplay-mechanics.player.shift-right-click-repairs-mending-points", shiftRightClickRepairsMendingPoints); - playerExpPickupDelay = getInt("gameplay-mechanics.player.exp-pickup-delay-ticks", playerExpPickupDelay); -+ playerVoidTrading = getBoolean("gameplay-mechanics.player.allow-void-trading", playerVoidTrading); - } - - public boolean silkTouchEnabled = false; diff --git a/patches/server/0231-Configurable-phantom-size.patch b/patches/server/0231-Configurable-phantom-size.patch deleted file mode 100644 index be3b119dc..000000000 --- a/patches/server/0231-Configurable-phantom-size.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 17 Jan 2022 21:28:49 -0600 -Subject: [PATCH] Configurable phantom size - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index 0d81540d048cd4a08962bd24d3bdd49db708f83f..26077bd6eeedbdae84613188cb0f336abb3563d2 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -265,7 +265,11 @@ public class Phantom extends FlyingMob implements Enemy { - @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { - this.anchorPoint = this.blockPosition().above(5); -- this.setPhantomSize(0); -+ // Purpur start -+ int min = world.getLevel().purpurConfig.phantomMinSize; -+ int max = world.getLevel().purpurConfig.phantomMaxSize; -+ this.setPhantomSize(min == max ? min : world.getRandom().nextInt(max + 1 - min) + min); -+ // Purpur end - return super.finalizeSpawn(world, difficulty, spawnReason, entityData); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 38f417bde3e05124a9ebc23c2c5ea2f4d9d7cefe..b66b8eda76779e3e5807907dc3ce28e4504299a0 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2112,6 +2112,8 @@ public class PurpurWorldConfig { - public boolean phantomFlamesOnSwoop = false; - public boolean phantomTakeDamageFromWater = false; - public boolean phantomAlwaysDropExp = false; -+ public int phantomMinSize = 0; -+ public int phantomMaxSize = 0; - private void phantomSettings() { - phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); - phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -@@ -2148,6 +2150,13 @@ public class PurpurWorldConfig { - phantomFlamesOnSwoop = getBoolean("mobs.phantom.flames-on-swoop", phantomFlamesOnSwoop); - phantomTakeDamageFromWater = getBoolean("mobs.phantom.takes-damage-from-water", phantomTakeDamageFromWater); - phantomAlwaysDropExp = getBoolean("mobs.phantom.always-drop-exp", phantomAlwaysDropExp); -+ phantomMinSize = Mth.clamp(getInt("mobs.phantom.size.min", phantomMinSize), 0, 64); -+ phantomMaxSize = Mth.clamp(getInt("mobs.phantom.size.max", phantomMaxSize), 0, 64); -+ if (phantomMinSize > phantomMaxSize) { -+ phantomMinSize = phantomMinSize ^ phantomMaxSize; -+ phantomMaxSize = phantomMinSize ^ phantomMaxSize; -+ phantomMinSize = phantomMinSize ^ phantomMaxSize; -+ } - } - - public boolean pigRidable = false; diff --git a/patches/server/0232-Max-joins-per-second.patch b/patches/server/0232-Max-joins-per-second.patch deleted file mode 100644 index 14ae2c131..000000000 --- a/patches/server/0232-Max-joins-per-second.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Tue, 18 Jan 2022 06:35:54 -0600 -Subject: [PATCH] Max joins per second - -When this option is set to true the `max-joins-per-tick` setting in paper.yml will be used per second instead of per tick - -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 02833deaa2bb7e5abc655bc1bdbe15c4b3ac7119..71b021513f30376c7b09d83059deea89cc92385f 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -608,11 +608,20 @@ public class Connection extends SimpleChannelInboundHandler> { - private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world - private static int joinAttemptsThisTick; // Paper - Buffer joins to world - private static int currTick; // Paper - Buffer joins to world -+ private static int tickSecond; // Purpur - public void tick() { - this.flushQueue(); - // Paper start - Buffer joins to world - if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) { - Connection.currTick = net.minecraft.server.MinecraftServer.currentTick; -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.maxJoinsPerSecond) { -+ if (++Connection.tickSecond > 20) { -+ Connection.tickSecond = 0; -+ Connection.joinAttemptsThisTick = 0; -+ } -+ } else -+ // Purpur end - Connection.joinAttemptsThisTick = 0; - } - // Paper end - Buffer joins to world -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 0d6b99822a3a743fe50362702afdca52f6a4a88e..5879af630bc3711a17d51f455585ccd31f7a6d88 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -456,8 +456,10 @@ public class PurpurConfig { - } - - public static boolean useUPnP = false; -+ public static boolean maxJoinsPerSecond = false; - private static void networkSettings() { - useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP); -+ maxJoinsPerSecond = getBoolean("settings.network.max-joins-per-second", maxJoinsPerSecond); - } - - public static java.util.regex.Pattern usernameValidCharactersPattern; diff --git a/patches/server/0233-Configurable-minimum-demand-for-trades.patch b/patches/server/0233-Configurable-minimum-demand-for-trades.patch deleted file mode 100644 index 19a768732..000000000 --- a/patches/server/0233-Configurable-minimum-demand-for-trades.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Totorewa <76272501+totorewa@users.noreply.github.com> -Date: Fri, 7 Jan 2022 21:34:57 +1300 -Subject: [PATCH] Configurable minimum demand for trades - -Addresses MC-163962 where villager demand decreases indefinitely. Paper -adds a patch to fix this by preventing demand from going below zero. -This patch adds a config option to allow the minimum demand to instead -be configurable. - -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 17a247455dd853ae98e2f82f64a99bccc4d27438..4fa66af33ede3949f4e0236c806e3373f9dea730 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -545,7 +545,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - while (iterator.hasNext()) { - MerchantOffer merchantrecipe = (MerchantOffer) iterator.next(); - -- merchantrecipe.updateDemand(); -+ merchantrecipe.updateDemand(this.level().purpurConfig.villagerMinimumDemand); // Purpur - } - - } -diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -index 0efc8d997b34302c3e0a5d7ec73a11a940dbeefe..af157881d440b34cfe79fbc9b03cc9ef28515eb8 100644 ---- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java -@@ -131,7 +131,12 @@ public class MerchantOffer { - } - - public void updateDemand() { -- this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962 -+ // Purpur start -+ this.updateDemand(0); -+ } -+ public void updateDemand(int minimumDemand) { -+ this.demand = Math.max(minimumDemand, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962 -+ // Purpur end - } - - public ItemStack assemble() { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index b66b8eda76779e3e5807907dc3ce28e4504299a0..e9bd0ab6bdfe6662ac26732bb91c3c21e91c4225 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2793,6 +2793,7 @@ public class PurpurWorldConfig { - public boolean villagerTakeDamageFromWater = false; - public boolean villagerAllowTrading = true; - public boolean villagerAlwaysDropExp = false; -+ public int villagerMinimumDemand = 0; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -2813,6 +2814,7 @@ public class PurpurWorldConfig { - villagerTakeDamageFromWater = getBoolean("mobs.villager.takes-damage-from-water", villagerTakeDamageFromWater); - villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading); - villagerAlwaysDropExp = getBoolean("mobs.villager.always-drop-exp", villagerAlwaysDropExp); -+ villagerMinimumDemand = getInt("mobs.villager.minimum-demand", villagerMinimumDemand); - } - - public boolean vindicatorRidable = false; diff --git a/patches/server/0234-Lobotomize-stuck-villagers.patch b/patches/server/0234-Lobotomize-stuck-villagers.patch deleted file mode 100644 index bcb788061..000000000 --- a/patches/server/0234-Lobotomize-stuck-villagers.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 3 Dec 2020 17:56:18 -0600 -Subject: [PATCH] Lobotomize stuck villagers - - -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 4fa66af33ede3949f4e0236c806e3373f9dea730..dd74825c04543ae8c0bb1ab5eef6c8a152b621fd 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -142,6 +142,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - }, MemoryModuleType.MEETING_POINT, (entityvillager, holder) -> { - return holder.is(PoiTypes.MEETING); - }); -+ private boolean isLobotomized = false; public boolean isLobotomized() { return this.isLobotomized; } // Purpur -+ private int notLobotomizedCount = 0; // Purpur - - public Villager(EntityType entityType, Level world) { - this(entityType, world, VillagerType.PLAINS); -@@ -199,6 +201,48 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - return this.level().purpurConfig.villagerAlwaysDropExp; - } - -+ private boolean checkLobotomized() { -+ int interval = this.level().purpurConfig.villagerLobotomizeCheckInterval; -+ boolean shouldCheckForTradeLocked = this.level().purpurConfig.villagerLobotomizeWaitUntilTradeLocked; -+ if (this.notLobotomizedCount > 3) { -+ // check half as often if not lobotomized for the last 3+ consecutive checks -+ interval *= 2; -+ } -+ if (this.level().getGameTime() % interval == 0) { -+ // offset Y for short blocks like dirt_path/farmland -+ this.isLobotomized = !(shouldCheckForTradeLocked && this.getVillagerXp() == 0) && !canTravelFrom(BlockPos.containing(this.position().x, this.getBoundingBox().minY + 0.0625D, this.position().z)); -+ -+ if (this.isLobotomized) { -+ this.notLobotomizedCount = 0; -+ } else { -+ this.notLobotomizedCount++; -+ } -+ } -+ return this.isLobotomized; -+ } -+ -+ private boolean canTravelFrom(BlockPos pos) { -+ return canTravelTo(pos.east()) || canTravelTo(pos.west()) || canTravelTo(pos.north()) || canTravelTo(pos.south()); -+ } -+ -+ private boolean canTravelTo(BlockPos pos) { -+ net.minecraft.world.level.block.state.BlockState state = this.level().getBlockStateIfLoaded(pos); -+ if (state == null) { -+ // chunk not loaded -+ return false; -+ } -+ net.minecraft.world.level.block.Block bottom = state.getBlock(); -+ if (bottom instanceof net.minecraft.world.level.block.FenceBlock || -+ bottom instanceof net.minecraft.world.level.block.FenceGateBlock || -+ bottom instanceof net.minecraft.world.level.block.WallBlock) { -+ // bottom block is too tall to get over -+ return false; -+ } -+ net.minecraft.world.level.block.Block top = level().getBlockState(pos.above()).getBlock(); -+ // only if both blocks have no collision -+ return !bottom.hasCollision && !top.hasCollision; -+ } -+ - @Override - public Brain getBrain() { - return (Brain) super.getBrain(); // CraftBukkit - decompile error -@@ -295,10 +339,19 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - // Paper start - this.customServerAiStep(false); - } -- protected void customServerAiStep(final boolean inactive) { -+ protected void customServerAiStep(boolean inactive) { // Purpur - not final - // Paper end - this.level().getProfiler().push("villagerBrain"); -+ // Purpur start -+ if (this.level().purpurConfig.villagerLobotomizeEnabled) { -+ // treat as inactive if lobotomized -+ inactive = inactive || checkLobotomized(); -+ } else { -+ this.isLobotomized = false; -+ } -+ // Purpur end - if (!inactive) this.getBrain().tick((ServerLevel) this.level(), this); // Paper -+ else if (this.isLobotomized && shouldRestock()) restock(); // Purpur - /*// Purpur start // Purpur - TODO: Pufferfish - if (!inactive && (getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider - this.getBrain().tick((ServerLevel) this.level(), this); // Paper -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -index 6c15d40979fd3e3d246a447c432b321fbf29ada3..6ace76a829c88e2e747dbbcce0a6582c615fc56d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -@@ -252,4 +252,11 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { - getHandle().getGossips().gossips.clear(); - } - // Paper end -+ -+ // Purpur start -+ @Override -+ public boolean isLobotomized() { -+ return getHandle().isLobotomized(); -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e9bd0ab6bdfe6662ac26732bb91c3c21e91c4225..bf5c8eb060d88681166d4fff1704c8c63e6327ab 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2794,6 +2794,9 @@ public class PurpurWorldConfig { - public boolean villagerAllowTrading = true; - public boolean villagerAlwaysDropExp = false; - public int villagerMinimumDemand = 0; -+ public boolean villagerLobotomizeEnabled = false; -+ public int villagerLobotomizeCheckInterval = 100; -+ public boolean villagerLobotomizeWaitUntilTradeLocked = false; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -2815,6 +2818,18 @@ public class PurpurWorldConfig { - villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading); - villagerAlwaysDropExp = getBoolean("mobs.villager.always-drop-exp", villagerAlwaysDropExp); - villagerMinimumDemand = getInt("mobs.villager.minimum-demand", villagerMinimumDemand); -+ if (PurpurConfig.version < 9) { -+ boolean oldValue = getBoolean("mobs.villager.lobotomize-1x1", villagerLobotomizeEnabled); -+ set("mobs.villager.lobotomize.enabled", oldValue); -+ set("mobs.villager.lobotomize-1x1", null); -+ } -+ if (PurpurConfig.version < 27) { -+ int oldValue = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval); -+ set("mobs.villager.lobotomize.check-interval", oldValue == 60 ? 100 : oldValue); -+ } -+ villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled); -+ villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval); -+ villagerLobotomizeWaitUntilTradeLocked = getBoolean("mobs.villager.lobotomize.wait-until-trade-locked", villagerLobotomizeWaitUntilTradeLocked); - } - - public boolean vindicatorRidable = false; diff --git a/patches/server/0235-Option-for-villager-display-trade-item.patch b/patches/server/0235-Option-for-villager-display-trade-item.patch deleted file mode 100644 index 2742b5219..000000000 --- a/patches/server/0235-Option-for-villager-display-trade-item.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Tue, 25 Jan 2022 15:03:48 -0600 -Subject: [PATCH] Option for villager display trade item - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java -index 18dad0825616c4167a0a7555689ee64910a87e09..6945992491027d43eca4f1ca697ad45ce06ded55 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java -@@ -46,6 +46,7 @@ public class ShowTradesToPlayer extends Behavior { - - @Override - public boolean canStillUse(ServerLevel world, Villager entity, long time) { -+ if (!entity.level().purpurConfig.villagerDisplayTradeItem) return false; // Purpur - return this.checkExtraStartConditions(world, entity) - && this.lookTime > 0 - && entity.getBrain().getMemory(MemoryModuleType.INTERACTION_TARGET).isPresent(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index bf5c8eb060d88681166d4fff1704c8c63e6327ab..aec0e4eec5095c12c7f52e5f955a6a04d05c9819 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2797,6 +2797,7 @@ public class PurpurWorldConfig { - public boolean villagerLobotomizeEnabled = false; - public int villagerLobotomizeCheckInterval = 100; - public boolean villagerLobotomizeWaitUntilTradeLocked = false; -+ public boolean villagerDisplayTradeItem = true; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -2830,6 +2831,7 @@ public class PurpurWorldConfig { - villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled); - villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval); - villagerLobotomizeWaitUntilTradeLocked = getBoolean("mobs.villager.lobotomize.wait-until-trade-locked", villagerLobotomizeWaitUntilTradeLocked); -+ villagerDisplayTradeItem = getBoolean("mobs.villager.display-trade-item", villagerDisplayTradeItem); - } - - public boolean vindicatorRidable = false; diff --git a/patches/server/0236-MC-238526-Fix-spawner-not-spawning-water-animals-cor.patch b/patches/server/0236-MC-238526-Fix-spawner-not-spawning-water-animals-cor.patch deleted file mode 100644 index e9256eddd..000000000 --- a/patches/server/0236-MC-238526-Fix-spawner-not-spawning-water-animals-cor.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 30 Jan 2022 02:03:34 -0600 -Subject: [PATCH] MC-238526 - Fix spawner not spawning water animals correctly - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java -index 6f22705072fecbe91196e4966fca2eeec060f120..ed2ae44f7cef5aed17d10cc8a7df0a2276f9f16b 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java -@@ -72,6 +72,6 @@ public abstract class WaterAnimal extends PathfinderMob { - i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i); - j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j); - // Paper end - Make water animal spawn height configurable -- return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER); -+ return ((reason == MobSpawnType.SPAWNER && world.getMinecraftWorld().purpurConfig.spawnerFixMC238526) || (pos.getY() >= j && pos.getY() <= i)) && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER); // Purpur - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index aec0e4eec5095c12c7f52e5f955a6a04d05c9819..05307f584d96b95e9b81239316a256310422c039 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1062,8 +1062,10 @@ public class PurpurWorldConfig { - } - - public boolean spawnerDeactivateByRedstone = false; -+ public boolean spawnerFixMC238526 = false; - private void spawnerSettings() { - spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); -+ spawnerFixMC238526 = getBoolean("blocks.spawner.fix-mc-238526", spawnerFixMC238526); - } - - public int spongeAbsorptionArea = 65; diff --git a/patches/server/0237-Config-for-mob-last-hurt-by-player-time.patch b/patches/server/0237-Config-for-mob-last-hurt-by-player-time.patch deleted file mode 100644 index ae1b68e82..000000000 --- a/patches/server/0237-Config-for-mob-last-hurt-by-player-time.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Tue, 8 Feb 2022 13:35:48 -0600 -Subject: [PATCH] Config for mob last hurt by player time - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 119d2e57995fa20f34b88963b93c945ff87e0cab..36022a0ab50655363d26be7dba765e2261baccdf 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1561,13 +1561,13 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (entity1 instanceof net.minecraft.world.entity.player.Player) { - net.minecraft.world.entity.player.Player entityhuman = (net.minecraft.world.entity.player.Player) entity1; - -- this.lastHurtByPlayerTime = 100; -+ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur - this.lastHurtByPlayer = entityhuman; - } else if (entity1 instanceof Wolf) { - Wolf entitywolf = (Wolf) entity1; - - if (entitywolf.isTame()) { -- this.lastHurtByPlayerTime = 100; -+ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur - LivingEntity entityliving2 = entitywolf.getOwner(); - - if (entityliving2 instanceof net.minecraft.world.entity.player.Player) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 1a8a76aa31bd1d1670be6e9cada162c540084cf9..b452ebbe11145987fb5e66b39993898457322080 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -@@ -505,7 +505,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { - net.minecraft.server.level.ServerPlayer entityPlayer = killer == null ? null : ((CraftPlayer) killer).getHandle(); - getHandle().lastHurtByPlayer = entityPlayer; - getHandle().lastHurtByMob = entityPlayer; -- getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : 100; // 100 value taken from EntityLiving#damageEntity -+ getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : getHandle().level().purpurConfig.mobLastHurtByPlayerTime; // 100 value taken from EntityLiving#damageEntity // Purpur - } - // Paper end - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 05307f584d96b95e9b81239316a256310422c039..389aac3c02c16bbfe3f266e66e53f6107b27e4dd 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -143,6 +143,7 @@ public class PurpurWorldConfig { - public boolean mobsIgnoreRails = false; - public boolean rainStopsAfterSleep = true; - public boolean thunderStopsAfterSleep = true; -+ public int mobLastHurtByPlayerTime = 100; - private void miscGameplayMechanicsSettings() { - useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); -@@ -175,6 +176,7 @@ public class PurpurWorldConfig { - mobsIgnoreRails = getBoolean("gameplay-mechanics.mobs-ignore-rails", mobsIgnoreRails); - rainStopsAfterSleep = getBoolean("gameplay-mechanics.rain-stops-after-sleep", rainStopsAfterSleep); - thunderStopsAfterSleep = getBoolean("gameplay-mechanics.thunder-stops-after-sleep", thunderStopsAfterSleep); -+ mobLastHurtByPlayerTime = getInt("gameplay-mechanics.mob-last-hurt-by-player-time", mobLastHurtByPlayerTime); - } - - public int daytimeTicks = 12000; diff --git a/patches/server/0238-Anvil-repair-damage-options.patch b/patches/server/0238-Anvil-repair-damage-options.patch deleted file mode 100644 index 1d67d451e..000000000 --- a/patches/server/0238-Anvil-repair-damage-options.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Sat, 12 Feb 2022 01:08:18 +0100 -Subject: [PATCH] Anvil repair/damage options - - -diff --git a/src/main/java/net/minecraft/world/level/block/AnvilBlock.java b/src/main/java/net/minecraft/world/level/block/AnvilBlock.java -index 923357251ad950ec4f893e8771fcfa99de8a60c5..78a341ac80806f86f2ca0bd895fb091a9257519e 100644 ---- a/src/main/java/net/minecraft/world/level/block/AnvilBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/AnvilBlock.java -@@ -59,6 +59,53 @@ public class AnvilBlock extends FallingBlock { - return this.defaultBlockState().setValue(FACING, ctx.getHorizontalDirection().getClockWise()); - } - -+ // Purpur start - repairable/damageable anvils -+ @Override -+ protected net.minecraft.world.ItemInteractionResult useItemOn(final net.minecraft.world.item.ItemStack stack, final BlockState state, final Level world, final BlockPos pos, final Player player, final net.minecraft.world.InteractionHand hand, final BlockHitResult hit) { -+ if (world.purpurConfig.anvilRepairIngotsAmount > 0 && stack.is(net.minecraft.world.item.Items.IRON_INGOT)) { -+ if (stack.getCount() < world.purpurConfig.anvilRepairIngotsAmount) { -+ // not enough iron ingots, play "error" sound and consume -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return net.minecraft.world.ItemInteractionResult.CONSUME; -+ } -+ if (state.is(Blocks.DAMAGED_ANVIL)) { -+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); -+ } else if (state.is(Blocks.CHIPPED_ANVIL)) { -+ world.setBlock(pos, Blocks.ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); -+ } else if (state.is(Blocks.ANVIL)) { -+ // anvil is already fully repaired, play "error" sound and consume -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return net.minecraft.world.ItemInteractionResult.CONSUME; -+ } -+ if (!player.getAbilities().instabuild) { -+ stack.shrink(world.purpurConfig.anvilRepairIngotsAmount); -+ } -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_PLACE, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return net.minecraft.world.ItemInteractionResult.CONSUME; -+ } -+ if (world.purpurConfig.anvilDamageObsidianAmount > 0 && stack.is(net.minecraft.world.item.Items.OBSIDIAN)) { -+ if (stack.getCount() < world.purpurConfig.anvilDamageObsidianAmount) { -+ // not enough obsidian, play "error" sound and consume -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return net.minecraft.world.ItemInteractionResult.CONSUME; -+ } -+ if (state.is(Blocks.DAMAGED_ANVIL)) { -+ world.destroyBlock(pos, false); -+ } else if (state.is(Blocks.CHIPPED_ANVIL)) { -+ world.setBlock(pos, Blocks.DAMAGED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); -+ } else if (state.is(Blocks.ANVIL)) { -+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); -+ } -+ if (!player.getAbilities().instabuild) { -+ stack.shrink(world.purpurConfig.anvilDamageObsidianAmount); -+ } -+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_LAND, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); -+ return net.minecraft.world.ItemInteractionResult.CONSUME; -+ } -+ return net.minecraft.world.ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; -+ } -+ // Purpur end -+ - @Override - protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { - if (world.isClientSide) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 389aac3c02c16bbfe3f266e66e53f6107b27e4dd..fbb2ecbf00395175d7660c5a9fe4987db9ce13b1 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -829,9 +829,13 @@ public class PurpurWorldConfig { - - public boolean anvilAllowColors = false; - public boolean anvilColorsUseMiniMessage; -+ public int anvilRepairIngotsAmount = 0; -+ public int anvilDamageObsidianAmount = 0; - private void anvilSettings() { - anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors); - anvilColorsUseMiniMessage = getBoolean("blocks.anvil.use-mini-message", anvilColorsUseMiniMessage); -+ anvilRepairIngotsAmount = getInt("blocks.anvil.iron-ingots-used-for-repair", anvilRepairIngotsAmount); -+ anvilDamageObsidianAmount = getInt("blocks.anvil.obsidian-used-for-damage", anvilDamageObsidianAmount); - } - - public double azaleaGrowthChance = 0.0D; diff --git a/patches/server/0239-Option-to-disable-turtle-egg-trampling-with-feather-.patch b/patches/server/0239-Option-to-disable-turtle-egg-trampling-with-feather-.patch deleted file mode 100644 index 79abce6ed..000000000 --- a/patches/server/0239-Option-to-disable-turtle-egg-trampling-with-feather-.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Mon, 9 May 2022 23:18:09 +0200 -Subject: [PATCH] Option to disable turtle egg trampling with feather falling - - -diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -index 2f0e8aeb9c45853fca12ddd78a7d51813a600e67..08ba90f760abb9fb62311dddd7b5bdbd0d9518d7 100644 ---- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java -@@ -219,7 +219,13 @@ public class TurtleEggBlock extends Block { - if (!(entity instanceof LivingEntity)) { - return false; - } -- if (entity instanceof Player) return true; -+ if (world.purpurConfig.turtleEggsTramplingFeatherFalling) { -+ java.util.Iterator armor = ((LivingEntity) entity).getArmorSlots().iterator(); -+ return !armor.hasNext() || net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) < (int) entity.fallDistance; -+ } -+ if (entity instanceof Player) { -+ return true; -+ } - - return world.purpurConfig.turtleEggsBypassMobGriefing || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); - // Purpur end -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index fbb2ecbf00395175d7660c5a9fe4987db9ce13b1..ebce13b3a25f26c22bbe8a25d38b76027b630401 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1090,12 +1090,14 @@ public class PurpurWorldConfig { - public boolean turtleEggsBreakFromMinecarts = false; - public boolean turtleEggsBypassMobGriefing = false; - public int turtleEggsRandomTickCrackChance = 500; -+ public boolean turtleEggsTramplingFeatherFalling = false; - private void turtleEggSettings() { - turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs); - turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems); - turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); - turtleEggsBypassMobGriefing = getBoolean("blocks.turtle_egg.bypass-mob-griefing", turtleEggsBypassMobGriefing); - turtleEggsRandomTickCrackChance = getInt("blocks.turtle_egg.random-tick-crack-chance", turtleEggsRandomTickCrackChance); -+ turtleEggsTramplingFeatherFalling = getBoolean("blocks.turtle_egg.feather-fall-distance-affects-trampling", turtleEggsTramplingFeatherFalling); - } - - public int waterInfiniteRequiredSources = 2; diff --git a/patches/server/0240-Add-toggle-for-enchant-level-clamping.patch b/patches/server/0240-Add-toggle-for-enchant-level-clamping.patch deleted file mode 100644 index e1bddbfc0..000000000 --- a/patches/server/0240-Add-toggle-for-enchant-level-clamping.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Sat, 30 Apr 2022 10:32:40 +0200 -Subject: [PATCH] Add toggle for enchant level clamping - - -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 5443013060b62e3bfcc51cddca96d1c0bc59fe72..8925440dbc35dbc4a7d59f13511d7afeda803260 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -119,6 +119,11 @@ public class Main { - JvmProfiler.INSTANCE.start(Environment.SERVER); - } - -+ // Purpur start - load config files early -+ org.bukkit.configuration.file.YamlConfiguration purpurConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("purpur-settings")); -+ org.purpurmc.purpur.PurpurConfig.clampEnchantLevels = purpurConfiguration.getBoolean("settings.enchantment.clamp-levels"); -+ // Purpur end - load config files early -+ - io.papermc.paper.plugin.PluginInitializerManager.load(optionset); // Paper - Bootstrap.bootStrap(); - Bootstrap.validate(); -diff --git a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java -index af18de11dd55938b6091f5ab183bd3fe4e8df152..2c741860afa1fa4d5798c68b84ec3fe13157ff09 100644 ---- a/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java -+++ b/src/main/java/net/minecraft/world/item/enchantment/ItemEnchantments.java -@@ -37,7 +37,7 @@ public class ItemEnchantments implements TooltipProvider { - public static final ItemEnchantments EMPTY = new ItemEnchantments(new Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), true); - // Paper end - public static final int MAX_LEVEL = 255; -- private static final Codec LEVEL_CODEC = Codec.intRange(0, 255); -+ private static final Codec LEVEL_CODEC = Codec.intRange(0, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)); // Purpur - private static final Codec>> LEVELS_CODEC = Codec.unboundedMap( // Paper - BuiltInRegistries.ENCHANTMENT.holderByNameCodec(), LEVEL_CODEC - ) -@@ -72,7 +72,7 @@ public class ItemEnchantments implements TooltipProvider { - - for (Entry> entry : enchantments.object2IntEntrySet()) { - int i = entry.getIntValue(); -- if (i < 0 || i > 255) { -+ if (i < 0 || i > (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)) { // Purpur - throw new IllegalArgumentException("Enchantment " + entry.getKey() + " has invalid level " + i); - } - } -@@ -169,13 +169,13 @@ public class ItemEnchantments implements TooltipProvider { - if (level <= 0) { - this.enchantments.removeInt(enchantment.builtInRegistryHolder()); - } else { -- this.enchantments.put(enchantment.builtInRegistryHolder(), Math.min(level, 255)); -+ this.enchantments.put(enchantment.builtInRegistryHolder(), Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767))); - } - } - - public void upgrade(Enchantment enchantment, int level) { - if (level > 0) { -- this.enchantments.merge(enchantment.builtInRegistryHolder(), Math.min(level, 255), Integer::max); -+ this.enchantments.merge(enchantment.builtInRegistryHolder(), Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)), Integer::max); - } - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 5879af630bc3711a17d51f455585ccd31f7a6d88..7462474f7eff9f50644d0b7ceac341f237c93df0 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -398,6 +398,7 @@ public class PurpurConfig { - public static boolean allowHigherEnchantsLevels = true; - public static boolean allowUnsafeEnchantCommand = false; - public static boolean replaceIncompatibleEnchants = false; -+ public static boolean clampEnchantLevels = true; - private static void enchantmentSettings() { - if (version < 5) { - boolean oldValue = getBoolean("settings.enchantment.allow-infinite-and-mending-together", false); -@@ -421,6 +422,7 @@ public class PurpurConfig { - allowHigherEnchantsLevels = getBoolean("settings.enchantment.anvil.allow-higher-enchants-levels", allowHigherEnchantsLevels); - allowUnsafeEnchantCommand = getBoolean("settings.enchantment.allow-unsafe-enchant-command", allowUnsafeEnchants); // allowUnsafeEnchants as default for backwards compatability - replaceIncompatibleEnchants = getBoolean("settings.enchantment.anvil.replace-incompatible-enchants", replaceIncompatibleEnchants); -+ clampEnchantLevels = getBoolean("settings.enchantment.clamp-levels", clampEnchantLevels); - } - - public static boolean endermanShortHeight = false; diff --git a/patches/server/0242-Implement-configurable-search-radius-for-villagers-t.patch b/patches/server/0242-Implement-configurable-search-radius-for-villagers-t.patch deleted file mode 100644 index fbf0fc98e..000000000 --- a/patches/server/0242-Implement-configurable-search-radius-for-villagers-t.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 8 Jun 2022 14:13:39 -0400 -Subject: [PATCH] Implement configurable search radius for villagers to spawn - iron golems - - -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index dd74825c04543ae8c0bb1ab5eef6c8a152b621fd..dcf580d852ede8ea01f5d91944a224ec6eca73e4 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -1095,6 +1095,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - } - - public void spawnGolemIfNeeded(ServerLevel world, long time, int requiredCount) { -+ if (world.purpurConfig.villagerSpawnIronGolemRadius > 0 && world.getEntitiesOfClass(net.minecraft.world.entity.animal.IronGolem.class, getBoundingBox().inflate(world.purpurConfig.villagerSpawnIronGolemRadius)).size() > world.purpurConfig.villagerSpawnIronGolemLimit) return; // Purpur - if (this.wantsToSpawnGolem(time)) { - AABB axisalignedbb = this.getBoundingBox().inflate(10.0D, 10.0D, 10.0D); - List list = world.getEntitiesOfClass(Villager.class, axisalignedbb); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index ebce13b3a25f26c22bbe8a25d38b76027b630401..31497cad3276cc2e9bd5a0e745619eb04fecf25a 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2808,6 +2808,8 @@ public class PurpurWorldConfig { - public int villagerLobotomizeCheckInterval = 100; - public boolean villagerLobotomizeWaitUntilTradeLocked = false; - public boolean villagerDisplayTradeItem = true; -+ public int villagerSpawnIronGolemRadius = 0; -+ public int villagerSpawnIronGolemLimit = 0; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -2842,6 +2844,8 @@ public class PurpurWorldConfig { - villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval); - villagerLobotomizeWaitUntilTradeLocked = getBoolean("mobs.villager.lobotomize.wait-until-trade-locked", villagerLobotomizeWaitUntilTradeLocked); - villagerDisplayTradeItem = getBoolean("mobs.villager.display-trade-item", villagerDisplayTradeItem); -+ villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius); -+ villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit); - } - - public boolean vindicatorRidable = false; diff --git a/patches/server/0243-Stonecutter-damage.patch b/patches/server/0243-Stonecutter-damage.patch deleted file mode 100644 index 16c3d43be..000000000 --- a/patches/server/0243-Stonecutter-damage.patch +++ /dev/null @@ -1,160 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 8 Jun 2022 14:19:35 -0400 -Subject: [PATCH] Stonecutter damage - - -diff --git a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -index a375d40ec6365ba8704ba3ece22dd5b2de9857b5..357a79d72a2de02a019595e457fe432bf409e516 100644 ---- a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -+++ b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -@@ -101,6 +101,8 @@ public class CombatTracker { - // Purpur start - if (damageSource.isScissors()) { - return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgRunWithScissors, this.mob); -+ } else if (damageSource.isStonecutter()) { -+ return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgStonecutter, this.mob); - } - // Purpur end - return damageSource.getLocalizedDeathMessage(this.mob); -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -index 894668c96ac36e737910a25cf89651236246200c..812091bf6efc067b21b9723b8241360d4b4c79e7 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -@@ -30,6 +30,7 @@ public class DamageSource { - private boolean melting = false; - private boolean poison = false; - private boolean scissors = false; // Purpur -+ private boolean stonecutter = false; // Purpur - @Nullable - private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API - -@@ -69,6 +70,15 @@ public class DamageSource { - public boolean isScissors() { - return this.scissors; - } -+ -+ public DamageSource stonecutter() { -+ this.stonecutter = true; -+ return this; -+ } -+ -+ public boolean isStonecutter() { -+ return this.stonecutter; -+ } - // Purpur end - - // Paper start - fix DamageSource API -@@ -114,6 +124,7 @@ public class DamageSource { - damageSource.poison = this.isPoison(); - damageSource.melting = this.isMelting(); - damageSource.scissors = this.isScissors(); // Purpur -+ damageSource.stonecutter = this.isStonecutter(); // Purpur - return damageSource; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSources.java b/src/main/java/net/minecraft/world/damagesource/DamageSources.java -index 13b596a1e06fa66396c43a6c72659d4342bf6549..5ffe772e29dfd422b664e8123e7f5cf396158674 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSources.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSources.java -@@ -45,12 +45,14 @@ public class DamageSources { - private final DamageSource melting; - private final DamageSource poison; - private final DamageSource scissors; // Purpur -+ private final DamageSource stonecutter; // Purpur - - public DamageSources(RegistryAccess registryManager) { - this.damageTypes = registryManager.registryOrThrow(Registries.DAMAGE_TYPE); - this.melting = this.source(DamageTypes.ON_FIRE).melting(); - this.poison = this.source(DamageTypes.MAGIC).poison(); - this.scissors = this.source(DamageTypes.MAGIC).scissors(); // Purpur -+ this.stonecutter = this.source(DamageTypes.MAGIC).stonecutter(); // Purpur - // CraftBukkit end - this.inFire = this.source(DamageTypes.IN_FIRE); - this.lightningBolt = this.source(DamageTypes.LIGHTNING_BOLT); -@@ -103,6 +105,9 @@ public class DamageSources { - public DamageSource scissors() { - return this.scissors; - } -+ public DamageSource stonecutter() { -+ return this.stonecutter; -+ } - // Purpur end - - public DamageSource inFire() { -diff --git a/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java b/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java -index c6ecb378d0cb2ac05b8f22f92fb85df060038f77..b0199a8ffb1ea4cafeadedb8b833063db177b3cd 100644 ---- a/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/StonecutterBlock.java -@@ -98,4 +98,14 @@ public class StonecutterBlock extends Block { - protected boolean isPathfindable(BlockState state, PathComputationType type) { - return false; - } -+ -+ // Purpur start -+ @Override -+ public void stepOn(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.Entity entity) { -+ if (level.purpurConfig.stonecutterDamage > 0.0F && entity instanceof net.minecraft.world.entity.LivingEntity) { -+ entity.hurt(entity.damageSources().stonecutter().directBlock(level, pos), level.purpurConfig.stonecutterDamage); -+ } -+ super.stepOn(level, pos, state, entity); -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -index 31ae0f466ae522d767907ec5066b26695f327b96..f26383cf896785333dbd6f86348d5a5f67a6731f 100644 ---- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -@@ -491,7 +491,7 @@ public class WalkNodeEvaluator extends NodeEvaluator { - return PathType.TRAPDOOR; - } else if (blockState.is(Blocks.POWDER_SNOW)) { - return PathType.POWDER_SNOW; -- } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH)) { -+ } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH) || blockState.is(Blocks.STONECUTTER)) { // Purpur - return PathType.DAMAGE_OTHER; - } else if (blockState.is(Blocks.HONEY_BLOCK)) { - return PathType.STICKY_HONEY; -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index a49193a023bbd9b65bcd3652dc9c241720500755..6fed586c9a778f7a57e1b4ca2e6f2dbc15c8769d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1130,7 +1130,7 @@ public class CraftEventFactory { - return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), entity, DamageCause.LAVA, bukkitDamageSource, modifiers, modifierFunctions, cancelled); - } else if (source.getDirectBlock() != null) { - DamageCause cause; -- if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL)) { -+ if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL) || source.isStonecutter()) { // Purpur - cause = DamageCause.CONTACT; - } else if (source.is(DamageTypes.HOT_FLOOR)) { - cause = DamageCause.HOT_FLOOR; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 7462474f7eff9f50644d0b7ceac341f237c93df0..cb8f67f0ad3531b110613c0ffb3c0cc23da23529 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -209,8 +209,10 @@ public class PurpurConfig { - } - - public static String deathMsgRunWithScissors = " slipped and fell on their shears"; -+ public static String deathMsgStonecutter = " has sawed themself in half"; - private static void deathMessages() { - deathMsgRunWithScissors = getString("settings.messages.death-message.run-with-scissors", deathMsgRunWithScissors); -+ deathMsgStonecutter = getString("settings.messages.death-message.stonecutter", deathMsgStonecutter); - } - - public static boolean advancementOnlyBroadcastToAffectedPlayer = false; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 31497cad3276cc2e9bd5a0e745619eb04fecf25a..37f638b7f1fe63a2b8e44b40a4ef6f6f419684fc 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1085,6 +1085,11 @@ public class PurpurWorldConfig { - spongeAbsorbsWaterFromMud = getBoolean("blocks.sponge.absorbs-water-from-mud", spongeAbsorbsWaterFromMud); - } - -+ public float stonecutterDamage = 0.0F; -+ private void stonecutterSettings() { -+ stonecutterDamage = (float) getDouble("blocks.stonecutter.damage", stonecutterDamage); -+ } -+ - public boolean turtleEggsBreakFromExpOrbs = false; - public boolean turtleEggsBreakFromItems = false; - public boolean turtleEggsBreakFromMinecarts = false; diff --git a/patches/server/0244-Configurable-damage-settings-for-magma-blocks.patch b/patches/server/0244-Configurable-damage-settings-for-magma-blocks.patch deleted file mode 100644 index dc19fb56d..000000000 --- a/patches/server/0244-Configurable-damage-settings-for-magma-blocks.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Wed, 8 Jun 2022 14:32:55 -0400 -Subject: [PATCH] Configurable damage settings for magma blocks - - -diff --git a/src/main/java/net/minecraft/world/level/block/MagmaBlock.java b/src/main/java/net/minecraft/world/level/block/MagmaBlock.java -index 77bbdc15472d656fd40e841a70e34d3d31580819..55ae530fac54236ea5614f8e92c30febc744f179 100644 ---- a/src/main/java/net/minecraft/world/level/block/MagmaBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/MagmaBlock.java -@@ -29,7 +29,7 @@ public class MagmaBlock extends Block { - - @Override - public void stepOn(Level world, BlockPos pos, BlockState state, Entity entity) { -- if (!entity.isSteppingCarefully() && entity instanceof LivingEntity && !EnchantmentHelper.hasFrostWalker((LivingEntity) entity)) { -+ if ((!entity.isSteppingCarefully() || world.purpurConfig.magmaBlockDamageWhenSneaking) && entity instanceof LivingEntity && (world.purpurConfig.magmaBlockDamageWithFrostWalker || !EnchantmentHelper.hasFrostWalker((LivingEntity) entity))) { // Purpur - entity.hurt(world.damageSources().hotFloor().directBlock(world, pos), 1.0F); // CraftBukkit - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 37f638b7f1fe63a2b8e44b40a4ef6f6f419684fc..8e95fce5be2c9ba2893b2ccc60a2fd6ea2927a62 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1026,6 +1026,13 @@ public class PurpurWorldConfig { - pistonBlockPushLimit = getInt("blocks.piston.block-push-limit", pistonBlockPushLimit); - } - -+ public boolean magmaBlockDamageWhenSneaking = false; -+ public boolean magmaBlockDamageWithFrostWalker = false; -+ private void magmaBlockSettings() { -+ magmaBlockDamageWhenSneaking = getBoolean("blocks.magma-block.damage-when-sneaking", magmaBlockDamageWhenSneaking); -+ magmaBlockDamageWithFrostWalker = getBoolean("blocks.magma-block.damage-with-frost-walker", magmaBlockDamageWithFrostWalker); -+ } -+ - public boolean powderSnowBypassMobGriefing = false; - private void powderSnowSettings() { - powderSnowBypassMobGriefing = getBoolean("blocks.powder_snow.bypass-mob-griefing", powderSnowBypassMobGriefing); diff --git a/patches/server/0245-Add-config-for-snow-on-blue-ice.patch b/patches/server/0245-Add-config-for-snow-on-blue-ice.patch deleted file mode 100644 index 543e3dec5..000000000 --- a/patches/server/0245-Add-config-for-snow-on-blue-ice.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 8 Jun 2022 15:19:41 -0400 -Subject: [PATCH] Add config for snow on blue ice - - -diff --git a/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java b/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java -index 93e8e5107ac047c1f2579b4fe6b0a202edb695f6..f82d275aac7bf3949d3dcc412c7e39e115c69458 100644 ---- a/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SnowLayerBlock.java -@@ -88,6 +88,12 @@ public class SnowLayerBlock extends Block { - protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { - BlockState iblockdata1 = world.getBlockState(pos.below()); - -+ // Purpur start -+ if (iblockdata1.is(Blocks.BLUE_ICE) && !world.getWorldBorder().world.purpurConfig.snowOnBlueIce) { -+ return false; -+ } -+ // Purpur end -+ - return iblockdata1.is(BlockTags.SNOW_LAYER_CANNOT_SURVIVE_ON) ? false : (iblockdata1.is(BlockTags.SNOW_LAYER_CAN_SURVIVE_ON) ? true : Block.isFaceFull(iblockdata1.getCollisionShape(world, pos.below()), Direction.UP) || iblockdata1.is((Block) this) && (Integer) iblockdata1.getValue(SnowLayerBlock.LAYERS) == 8); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 8e95fce5be2c9ba2893b2ccc60a2fd6ea2927a62..59cabf7be670c05af5c5a24080fb65e318f5a843 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1007,9 +1007,11 @@ public class PurpurWorldConfig { - - public boolean mobsSpawnOnPackedIce = true; - public boolean mobsSpawnOnBlueIce = true; -+ public boolean snowOnBlueIce = true; - private void iceSettings() { - mobsSpawnOnPackedIce = getBoolean("blocks.packed_ice.allow-mob-spawns", mobsSpawnOnPackedIce); - mobsSpawnOnBlueIce = getBoolean("blocks.blue_ice.allow-mob-spawns", mobsSpawnOnBlueIce); -+ snowOnBlueIce = getBoolean("blocks.blue_ice.allow-snow-formation", snowOnBlueIce); - } - - public int lavaInfiniteRequiredSources = 2; diff --git a/patches/server/0246-Skeletons-eat-wither-roses.patch b/patches/server/0246-Skeletons-eat-wither-roses.patch deleted file mode 100644 index 63e86f8d5..000000000 --- a/patches/server/0246-Skeletons-eat-wither-roses.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Sat, 25 Jun 2022 00:18:33 -0400 -Subject: [PATCH] Skeletons eat wither roses - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -index 1aae461eed332fe31c1449c47d0928f655c740da..9eb6ed001bfc578311300977dda6f3f156d07190 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java -@@ -14,6 +14,16 @@ import net.minecraft.world.item.Items; - import net.minecraft.world.level.ItemLike; - import net.minecraft.world.level.Level; - -+// Purpur start -+import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.level.block.Blocks; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.InteractionResult; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.core.particles.ParticleTypes; -+// Purpur end -+ - public class Skeleton extends AbstractSkeleton { - - private static final int TOTAL_CONVERSION_TIME = 300; -@@ -174,4 +184,67 @@ public class Skeleton extends AbstractSkeleton { - } - - } -+ -+ // Purpur start -+ private int witherRosesFed = 0; -+ -+ @Override -+ public InteractionResult mobInteract(Player player, InteractionHand hand) { -+ ItemStack stack = player.getItemInHand(hand); -+ -+ if (level().purpurConfig.skeletonFeedWitherRoses > 0 && this.getType() != EntityType.WITHER_SKELETON && stack.getItem() == Blocks.WITHER_ROSE.asItem()) { -+ return this.feedWitherRose(player, stack); -+ } -+ -+ return super.mobInteract(player, hand); -+ } -+ -+ private InteractionResult feedWitherRose(Player player, ItemStack stack) { -+ if (++witherRosesFed < level().purpurConfig.skeletonFeedWitherRoses) { -+ if (!player.getAbilities().instabuild) { -+ stack.shrink(1); -+ } -+ return InteractionResult.CONSUME; -+ } -+ -+ WitherSkeleton skeleton = EntityType.WITHER_SKELETON.create(level()); -+ if (skeleton == null) { -+ return InteractionResult.PASS; -+ } -+ -+ skeleton.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); -+ skeleton.setHealth(this.getHealth()); -+ skeleton.setAggressive(this.isAggressive()); -+ skeleton.copyPosition(this); -+ skeleton.setYBodyRot(this.yBodyRot); -+ skeleton.setYHeadRot(this.getYHeadRot()); -+ skeleton.yRotO = this.yRotO; -+ skeleton.xRotO = this.xRotO; -+ -+ if (this.hasCustomName()) { -+ skeleton.setCustomName(this.getCustomName()); -+ } -+ -+ if (CraftEventFactory.callEntityTransformEvent(this, skeleton, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) { -+ return InteractionResult.PASS; -+ } -+ -+ if (!new com.destroystokyo.paper.event.entity.EntityTransformedEvent(this.getBukkitEntity(), skeleton.getBukkitEntity(), com.destroystokyo.paper.event.entity.EntityTransformedEvent.TransformedReason.INFECTED).callEvent()) { -+ return InteractionResult.PASS; -+ } -+ -+ this.level().addFreshEntity(skeleton); -+ this.remove(RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); -+ if (!player.getAbilities().instabuild) { -+ stack.shrink(1); -+ } -+ -+ for (int i = 0; i < 15; ++i) { -+ ((ServerLevel) level()).sendParticles(((ServerLevel) level()).players(), null, ParticleTypes.HAPPY_VILLAGER, -+ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1, -+ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true); -+ } -+ return InteractionResult.SUCCESS; -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 59cabf7be670c05af5c5a24080fb65e318f5a843..e7f825ae88c7752468537c7df8c8fec6c1e0c983 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2491,6 +2491,7 @@ public class PurpurWorldConfig { - public boolean skeletonTakeDamageFromWater = false; - public boolean skeletonAlwaysDropExp = false; - public double skeletonHeadVisibilityPercent = 0.5D; -+ public int skeletonFeedWitherRoses = 0; - private void skeletonSettings() { - skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); - skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); -@@ -2504,6 +2505,7 @@ public class PurpurWorldConfig { - skeletonTakeDamageFromWater = getBoolean("mobs.skeleton.takes-damage-from-water", skeletonTakeDamageFromWater); - skeletonAlwaysDropExp = getBoolean("mobs.skeleton.always-drop-exp", skeletonAlwaysDropExp); - skeletonHeadVisibilityPercent = getDouble("mobs.skeleton.head-visibility-percent", skeletonHeadVisibilityPercent); -+ skeletonFeedWitherRoses = getInt("mobs.skeleton.feed-wither-roses", skeletonFeedWitherRoses); - } - - public boolean skeletonHorseRidable = false; diff --git a/patches/server/0247-Enchantment-Table-Persists-Lapis.patch b/patches/server/0247-Enchantment-Table-Persists-Lapis.patch deleted file mode 100644 index b419a33d8..000000000 --- a/patches/server/0247-Enchantment-Table-Persists-Lapis.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Sat, 25 Jun 2022 08:04:06 -0400 -Subject: [PATCH] Enchantment Table Persists Lapis - - -diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -index 5b3e33807e0e13480e3359c0cf067719e5749237..c3a644b0f8c7c5622acc9e1a496f95d432718806 100644 ---- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java -@@ -38,6 +38,12 @@ import org.bukkit.event.enchantment.PrepareItemEnchantEvent; - import org.bukkit.entity.Player; - // CraftBukkit end - -+// Purpur start -+import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.entity.EnchantingTableBlockEntity; -+import org.bukkit.craftbukkit.entity.CraftHumanEntity; -+// Purpur end -+ - public class EnchantmentMenu extends AbstractContainerMenu { - - static final ResourceLocation EMPTY_SLOT_LAPIS_LAZULI = new ResourceLocation("item/empty_slot_lapis_lazuli"); -@@ -72,6 +78,22 @@ public class EnchantmentMenu extends AbstractContainerMenu { - return context.getLocation(); - } - // CraftBukkit end -+ -+ // Purpur start -+ @Override -+ public void onClose(CraftHumanEntity who) { -+ super.onClose(who); -+ -+ if (who.getHandle().level().purpurConfig.enchantmentTableLapisPersists) { -+ access.execute((level, pos) -> { -+ BlockEntity blockEntity = level.getBlockEntity(pos); -+ if (blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) { -+ enchantmentTable.setLapis(this.getItem(1).getCount()); -+ } -+ }); -+ } -+ } -+ // Purpur end - }; - this.random = RandomSource.create(); - this.enchantmentSeed = DataSlot.standalone(); -@@ -97,6 +119,17 @@ public class EnchantmentMenu extends AbstractContainerMenu { - } - }); - -+ // Purpur start -+ access.execute((level, pos) -> { -+ if (level.purpurConfig.enchantmentTableLapisPersists) { -+ BlockEntity blockEntity = level.getBlockEntity(pos); -+ if (blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) { -+ this.getSlot(1).set(new ItemStack(Items.LAPIS_LAZULI, enchantmentTable.getLapis())); -+ } -+ } -+ }); -+ // Purpur end -+ - int j; - - for (j = 0; j < 3; ++j) { -@@ -332,6 +365,7 @@ public class EnchantmentMenu extends AbstractContainerMenu { - public void removed(net.minecraft.world.entity.player.Player player) { - super.removed(player); - this.access.execute((world, blockposition) -> { -+ if (world.purpurConfig.enchantmentTableLapisPersists) this.getSlot(1).set(ItemStack.EMPTY); // Purpur - this.clearContainer(player, this.enchantSlots); - }); - } -diff --git a/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java b/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java -index 151e856dda3aa262c846ce8793650ee582bfb749..be0ed8a14e5726d5fcea1864302b18fb75fde2b4 100644 ---- a/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EnchantingTableBlock.java -@@ -124,4 +124,18 @@ public class EnchantingTableBlock extends BaseEntityBlock { - protected boolean isPathfindable(BlockState state, PathComputationType type) { - return false; - } -+ -+ // Purpur start -+ @Override -+ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean moved) { -+ BlockEntity blockEntity = level.getBlockEntity(pos); -+ -+ if (level.purpurConfig.enchantmentTableLapisPersists && blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) { -+ net.minecraft.world.Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.LAPIS_LAZULI, enchantmentTable.getLapis())); -+ level.updateNeighbourForOutputSignal(pos, this); -+ } -+ -+ super.onRemove(state, level, pos, newState, moved); -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java -index d47bc2f54c4722a0b8c419b99ee57eb3cb25d750..fdeabdcc781b605d6f3ee18528fd380ffff95660 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java -@@ -28,6 +28,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable - private static final RandomSource RANDOM = RandomSource.create(); - @Nullable - private Component name; -+ private int lapis = 0; // Purpur - - public EnchantingTableBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.ENCHANTING_TABLE, pos, state); -@@ -39,6 +40,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable - if (this.hasCustomName()) { - nbt.putString("CustomName", Component.Serializer.toJson(this.name, registryLookup)); - } -+ nbt.putInt("Purpur.Lapis", this.lapis); // Purpur - } - - @Override -@@ -47,6 +49,7 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable - if (nbt.contains("CustomName", 8)) { - this.name = parseCustomNameSafe(nbt.getString("CustomName"), registryLookup); - } -+ this.lapis = nbt.getInt("Purpur.Lapis"); // Purpur - } - - public static void bookAnimationTick(Level world, BlockPos pos, BlockState state, EnchantingTableBlockEntity blockEntity) { -@@ -138,4 +141,14 @@ public class EnchantingTableBlockEntity extends BlockEntity implements Nameable - public void removeComponentsFromTag(CompoundTag nbt) { - nbt.remove("CustomName"); - } -+ -+ // Purpur start -+ public int getLapis() { -+ return this.lapis; -+ } -+ -+ public void setLapis(int lapis) { -+ this.lapis = lapis; -+ } -+ // Purpur - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index e7f825ae88c7752468537c7df8c8fec6c1e0c983..38f161e102c5202c79108ad150ff42af1a75658c 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1528,6 +1528,11 @@ public class PurpurWorldConfig { - elderGuardianAlwaysDropExp = getBoolean("mobs.elder_guardian.always-drop-exp", elderGuardianAlwaysDropExp); - } - -+ public boolean enchantmentTableLapisPersists = false; -+ private void enchantmentTableSettings() { -+ enchantmentTableLapisPersists = getBoolean("blocks.enchantment-table.lapis-persists", enchantmentTableLapisPersists); -+ } -+ - public boolean enderDragonRidable = false; - public boolean enderDragonRidableInWater = true; - public boolean enderDragonControllable = true; diff --git a/patches/server/0248-Spark-Profiler.patch b/patches/server/0248-Spark-Profiler.patch deleted file mode 100644 index a8bab00ce..000000000 --- a/patches/server/0248-Spark-Profiler.patch +++ /dev/null @@ -1,140 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Kerllenevich -Date: Sat, 25 Jun 2022 19:40:36 -0400 -Subject: [PATCH] Spark Profiler - -Co-authored-by: granny - -diff --git a/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java b/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java -index 6f14cb9a73faa1d0ae2939d08809d9f6c2a99e1d..4e98745670032038f7b4f8e1adabc1e00e7f15bf 100644 ---- a/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java -+++ b/src/main/java/io/papermc/paper/plugin/PluginInitializerManager.java -@@ -112,6 +112,7 @@ public class PluginInitializerManager { - @SuppressWarnings("unchecked") - java.util.List files = ((java.util.List) optionSet.valuesOf("add-plugin")).stream().map(File::toPath).toList(); - io.papermc.paper.plugin.util.EntrypointUtil.registerProvidersFromSource(io.papermc.paper.plugin.provider.source.PluginFlagProviderSource.INSTANCE, files); -+ io.papermc.paper.plugin.util.EntrypointUtil.registerProvidersFromSource(io.papermc.paper.plugin.provider.source.SparkProviderSource.INSTANCE, new File("cache", "spark.jar").toPath()); // Purpur - } - - // This will be the end of me... -diff --git a/src/main/java/io/papermc/paper/plugin/provider/source/SparkProviderSource.java b/src/main/java/io/papermc/paper/plugin/provider/source/SparkProviderSource.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cb78dac8e072b5cb3c6e52e17c9ecdf708aeedc1 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/plugin/provider/source/SparkProviderSource.java -@@ -0,0 +1,115 @@ -+package io.papermc.paper.plugin.provider.source; -+ -+import com.mojang.logging.LogUtils; -+import io.papermc.paper.plugin.entrypoint.Entrypoint; -+import io.papermc.paper.plugin.entrypoint.EntrypointHandler; -+import io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler; -+import io.papermc.paper.plugin.provider.PluginProvider; -+import java.io.BufferedReader; -+import java.io.File; -+import java.io.InputStreamReader; -+import java.math.BigInteger; -+import java.net.URL; -+import java.net.URLConnection; -+import java.nio.file.Files; -+import java.nio.file.Path; -+import java.nio.file.StandardCopyOption; -+import java.security.MessageDigest; -+import java.util.stream.Collectors; -+import org.bukkit.plugin.java.JavaPlugin; -+import org.slf4j.Logger; -+ -+public class SparkProviderSource implements ProviderSource { -+ -+ public static final SparkProviderSource INSTANCE = new SparkProviderSource(); -+ private static final FileProviderSource FILE_PROVIDER_SOURCE = new FileProviderSource("File '%s' specified by Purpur"::formatted); -+ private static final Logger LOGGER = LogUtils.getClassLogger(); -+ -+ @Override -+ public Path prepareContext(Path context) { -+ // first, check if user doesn't want spark at all -+ if (Boolean.getBoolean("Purpur.IReallyDontWantSpark")) { -+ return null; // boo! -+ } -+ -+ // second, check if user has their own spark -+ if (hasSpark()) { -+ LOGGER.info("Purpur: Using user-provided spark plugin instead of our own."); -+ return null; // let's hope it's at least the modern version :3 -+ } -+ -+ // you can't have errors in your code if you wrap the entire codebase in a try/catch block -+ try { -+ -+ // make sure the directory exists where we want to keep spark -+ File file = context.toFile(); -+ file.getParentFile().mkdirs(); -+ -+ boolean shouldDownload; -+ -+ // check if our spark exists -+ if (!file.exists()) { -+ // it does not, so let's download it -+ shouldDownload = true; -+ } else { -+ // we have a spark file, let's see if it's up-to-date by comparing shas -+ String fileSha1 = String.format("%040x", new BigInteger(1, MessageDigest.getInstance("SHA-1").digest(Files.readAllBytes(file.toPath())))); -+ String sparkSha1; -+ -+ // luck has a nifty endpoint containing the sha of the newest version -+ URLConnection urlConnection = new URL("https://sparkapi.lucko.me/download/bukkit/sha1").openConnection(); -+ -+ // set a reasonable timeout to prevent servers without internet from hanging for 60+ seconds on startup -+ urlConnection.setReadTimeout(5000); -+ urlConnection.setConnectTimeout(5000); -+ -+ // read it -+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()))) { -+ sparkSha1 = reader.lines().collect(Collectors.joining("")); -+ } -+ -+ // compare; we only download a new spark if the shas don't match -+ shouldDownload = !fileSha1.equals(sparkSha1); -+ } -+ -+ // ok, finally we can download spark if we need it -+ if (shouldDownload) { -+ URLConnection urlConnection = new URL("https://sparkapi.lucko.me/download/bukkit").openConnection(); -+ urlConnection.setReadTimeout(5000); -+ urlConnection.setConnectTimeout(5000); -+ Files.copy(urlConnection.getInputStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); -+ } -+ -+ // register the spark, newly downloaded or existing -+ return FILE_PROVIDER_SOURCE.prepareContext(context); -+ -+ } catch (Throwable e) { -+ LOGGER.error("Purpur: Failed to download and install spark plugin", e); -+ } -+ return null; -+ } -+ -+ @Override -+ public void registerProviders(final EntrypointHandler entrypointHandler, final Path context) { -+ if (context == null) { -+ return; -+ } -+ -+ try { -+ FILE_PROVIDER_SOURCE.registerProviders(entrypointHandler, context); -+ } catch (IllegalArgumentException ignored) { -+ // Ignore illegal argument exceptions from jar checking -+ } catch (Exception e) { -+ LOGGER.error("Error loading our spark plugin: " + e.getMessage(), e); -+ } -+ } -+ -+ private static boolean hasSpark() { -+ for (PluginProvider provider : LaunchEntryPointHandler.INSTANCE.get(Entrypoint.PLUGIN).getRegisteredProviders()) { -+ if (provider.getMeta().getName().equalsIgnoreCase("spark")) { -+ return true; -+ } -+ } -+ return false; -+ } -+} diff --git a/patches/server/0249-Option-to-disable-kick-for-out-of-order-chat.patch b/patches/server/0249-Option-to-disable-kick-for-out-of-order-chat.patch deleted file mode 100644 index d9f7ab48b..000000000 --- a/patches/server/0249-Option-to-disable-kick-for-out-of-order-chat.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 3 Jul 2022 04:13:57 -0500 -Subject: [PATCH] Option to disable kick for out of order chat - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 222436febf0b6ea93b57b8a4c0a98998a9430873..e54be01cb1629616c2952ea99c6f28f09a592773 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1722,7 +1722,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - do { - if (!iterator.hasNext()) { -- return false; -+ return !org.purpurmc.purpur.PurpurConfig.kickForOutOfOrderChat; // Purpur - } - - voxelshape1 = (VoxelShape) iterator.next(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index cb8f67f0ad3531b110613c0ffb3c0cc23da23529..620f1207fc773f8602b748128557f1c73f0319fb 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -461,9 +461,11 @@ public class PurpurConfig { - - public static boolean useUPnP = false; - public static boolean maxJoinsPerSecond = false; -+ public static boolean kickForOutOfOrderChat = true; - private static void networkSettings() { - useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP); - maxJoinsPerSecond = getBoolean("settings.network.max-joins-per-second", maxJoinsPerSecond); -+ kickForOutOfOrderChat = getBoolean("settings.network.kick-for-out-of-order-chat", kickForOutOfOrderChat); - } - - public static java.util.regex.Pattern usernameValidCharactersPattern; diff --git a/patches/server/0250-Config-for-sculk-shrieker-can_summon-state.patch b/patches/server/0250-Config-for-sculk-shrieker-can_summon-state.patch deleted file mode 100644 index 555f9bb73..000000000 --- a/patches/server/0250-Config-for-sculk-shrieker-can_summon-state.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Mon, 4 Jul 2022 13:32:51 -0400 -Subject: [PATCH] Config for sculk shrieker can_summon state - - -diff --git a/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java b/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java -index b6b367492ebe2af3e63381bef935c6077f6ddb27..09f34c30d9a03751ed826b26375ac5aee778cce4 100644 ---- a/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SculkShriekerBlock.java -@@ -134,7 +134,7 @@ public class SculkShriekerBlock extends BaseEntityBlock implements SimpleWaterlo - @Nullable - @Override - public BlockState getStateForPlacement(BlockPlaceContext ctx) { -- return (BlockState) this.defaultBlockState().setValue(SculkShriekerBlock.WATERLOGGED, ctx.getLevel().getFluidState(ctx.getClickedPos()).getType() == Fluids.WATER); -+ return (BlockState) this.defaultBlockState().setValue(SculkShriekerBlock.WATERLOGGED, ctx.getLevel().getFluidState(ctx.getClickedPos()).getType() == Fluids.WATER).setValue(SculkShriekerBlock.CAN_SUMMON, ctx.getLevel().purpurConfig.sculkShriekerCanSummonDefault); // Purpur - } - - @Override -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 38f161e102c5202c79108ad150ff42af1a75658c..6dc3d5a420005a859560ebb85009183b446a0531 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1066,6 +1066,11 @@ public class PurpurWorldConfig { - } - } - -+ public boolean sculkShriekerCanSummonDefault = false; -+ private void sculkShriekerSettings() { -+ sculkShriekerCanSummonDefault = getBoolean("blocks.sculk_shrieker.can-summon-default", sculkShriekerCanSummonDefault); -+ } -+ - public boolean signAllowColors = false; - private void signSettings() { - signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors); diff --git a/patches/server/0251-Config-to-not-let-coral-die.patch b/patches/server/0251-Config-to-not-let-coral-die.patch deleted file mode 100644 index 42fbf00c7..000000000 --- a/patches/server/0251-Config-to-not-let-coral-die.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Mon, 4 Jul 2022 13:57:06 -0400 -Subject: [PATCH] Config to not let coral die - - -diff --git a/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java b/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java -index ce9f189bdafec26360bfadd0f36a8bc2726e132b..d5465b48531fd4b4094874c135274abf985ee71a 100644 ---- a/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java -@@ -38,6 +38,7 @@ public abstract class BaseCoralPlantTypeBlock extends Block implements SimpleWat - } - - protected static boolean scanForWater(BlockState state, BlockGetter world, BlockPos pos) { -+ if (!((net.minecraft.world.level.LevelAccessor) world).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur - if (state.getValue(WATERLOGGED)) { - return true; - } else { -diff --git a/src/main/java/net/minecraft/world/level/block/CoralBlock.java b/src/main/java/net/minecraft/world/level/block/CoralBlock.java -index 81fe0dea8e6e23c4a78f07fc2f9c0d68cd683f11..bff97b7d3909f2ec9e58a341b901b3741927543f 100644 ---- a/src/main/java/net/minecraft/world/level/block/CoralBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CoralBlock.java -@@ -59,6 +59,7 @@ public class CoralBlock extends Block { - } - - protected boolean scanForWater(BlockGetter world, BlockPos pos) { -+ if (!((net.minecraft.world.level.LevelAccessor) world).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur - Direction[] aenumdirection = Direction.values(); - int i = aenumdirection.length; - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 6dc3d5a420005a859560ebb85009183b446a0531..9e884018d72ad9b63b8968551223451ecc09b547 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -913,6 +913,11 @@ public class PurpurWorldConfig { - composterBulkProcess = getBoolean("blocks.composter.sneak-to-bulk-process", composterBulkProcess); - } - -+ public boolean coralDieOutsideWater = true; -+ private void coralSettings() { -+ coralDieOutsideWater = getBoolean("blocks.coral.die-outside-water", coralDieOutsideWater); -+ } -+ - public boolean dispenserApplyCursedArmor = true; - public boolean dispenserPlaceAnvils = false; - private void dispenserSettings() { diff --git a/patches/server/0252-Add-local-difficulty-api.patch b/patches/server/0252-Add-local-difficulty-api.patch deleted file mode 100644 index 512458afe..000000000 --- a/patches/server/0252-Add-local-difficulty-api.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sat, 9 Jul 2022 00:57:32 -0500 -Subject: [PATCH] Add local difficulty api - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index f2b20ed5063a293f0b464548f590d652170cd1d8..b7a02ae4eda06cab8ffd1220259a061558981dec 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2424,6 +2424,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { - return (this.getHandle().getDragonFight() == null) ? null : new CraftDragonBattle(this.getHandle().getDragonFight()); - } - -+ // Purpur start -+ public float getLocalDifficultyAt(Location location) { -+ return getHandle().getCurrentDifficultyAt(io.papermc.paper.util.MCUtil.toBlockPosition(location)).getEffectiveDifficulty(); -+ } -+ // Purpur end -+ - @Override - public Collection getStructures(int x, int z) { - return this.getStructures(x, z, struct -> true); diff --git a/patches/server/0253-Add-toggle-for-RNG-manipulation.patch b/patches/server/0253-Add-toggle-for-RNG-manipulation.patch deleted file mode 100644 index 996a45aaf..000000000 --- a/patches/server/0253-Add-toggle-for-RNG-manipulation.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Encode42 -Date: Tue, 12 Jul 2022 14:16:10 -0400 -Subject: [PATCH] Add toggle for RNG manipulation - -Paper patches RNG maniplulation by using a shared (and locked) random source. -This comes with a performance gain, but technical players may prefer the ability to manipulate RNG. - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 2d1fc8734f440c284710c71abc6789e8185ec909..68e8f9913055219486ce19d95dcf9d7c76e08082 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -597,7 +597,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.bb = Entity.INITIAL_AABB; - this.stuckSpeedMultiplier = Vec3.ZERO; - this.nextStep = 1.0F; -- this.random = SHARED_RANDOM; // Paper - Share random for entities to make them more random -+ this.random = world == null || world.purpurConfig.entitySharedRandom ? SHARED_RANDOM : RandomSource.create(); // Paper - Share random for entities to make them more random // Purpur - this.remainingFireTicks = -this.getFireImmuneTicks(); - this.fluidHeight = new Object2DoubleArrayMap(2); - this.fluidOnEyes = new HashSet(); -diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index b86676ebcd6c301e5dd857d8e84e1db2c1da416b..cb950ba3ee3bdfe0ff7acdb94c7ee233d73ab22e 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Squid.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -42,7 +42,7 @@ public class Squid extends WaterAnimal { - - public Squid(EntityType type, Level world) { - super(type, world); -- //this.random.setSeed((long)this.getId()); // Paper - Share random for entities to make them more random -+ if (!world.purpurConfig.entitySharedRandom) this.random.setSeed((long)this.getId()); // Paper - Share random for entities to make them more random // Purpur - this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 9e884018d72ad9b63b8968551223451ecc09b547..f50c26f02bc7c95f7b1228588aff68296290c21b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -212,9 +212,11 @@ public class PurpurWorldConfig { - - public int entityLifeSpan = 0; - public float entityLeftHandedChance = 0.05f; -+ public boolean entitySharedRandom = true; - private void entitySettings() { - entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan); - entityLeftHandedChance = (float) getDouble("gameplay-mechanics.entity-left-handed-chance", entityLeftHandedChance); -+ entitySharedRandom = getBoolean("settings.entity.shared-random", entitySharedRandom); - } - - public boolean infinityWorksWithoutArrows = false; diff --git a/patches/server/0254-Remove-Timings.patch b/patches/server/0254-Remove-Timings.patch deleted file mode 100644 index b59617ff9..000000000 --- a/patches/server/0254-Remove-Timings.patch +++ /dev/null @@ -1,928 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 1 Jul 2022 04:03:37 -0500 -Subject: [PATCH] Remove Timings - - -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -index 6bc7c6f16a1649fc9e24e7cf90fca401e5bd4875..e1ffd62f4ebceecb9bc5471df3da406cffea0483 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java -@@ -1316,9 +1316,9 @@ public final class ChunkHolderManager { - } - - public boolean processTicketUpdates() { -- co.aikar.timings.MinecraftTimings.distanceManagerTick.startTiming(); try { // Paper - add timings for distance manager -+ //co.aikar.timings.MinecraftTimings.distanceManagerTick.startTiming(); try { // Paper - add timings for distance manager // Purpur - return this.processTicketUpdates(true, true, null); -- } finally { co.aikar.timings.MinecraftTimings.distanceManagerTick.stopTiming(); } // Paper - add timings for distance manager -+ //} finally { co.aikar.timings.MinecraftTimings.distanceManagerTick.stopTiming(); } // Paper - add timings for distance manager // Purpur - } - - private static final ThreadLocal> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>(); -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -index 56b07a3306e5735816c8d89601b519cb0db6379a..604de7aed6db44c9c84d541765e57da48883cf00 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -@@ -1779,7 +1779,7 @@ public final class NewChunkHolder { - boolean canSavePOI = !(chunk instanceof LevelChunk levelChunk && levelChunk.mustNotSave) && (poi != null && poi.isDirty()); - boolean canSaveEntities = entities != null; - -- try (co.aikar.timings.Timing ignored = this.world.timings.chunkSave.startTiming()) { // Paper -+ //try (co.aikar.timings.Timing ignored = this.world.timings.chunkSave.startTiming()) { // Paper // Purpur - if (canSaveChunk) { - canSaveChunk = this.saveChunk(chunk, unloading); - } -@@ -1793,7 +1793,7 @@ public final class NewChunkHolder { - this.lastEntityUnload = null; - } - } -- } -+ //} // Purpur - - return executedUnloadTask | canSaveChunk | canSaveEntities | canSavePOI ? new SaveStat(executedUnloadTask || canSaveChunk, canSaveEntities, canSavePOI): null; - } -diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -index 57e76b53e5e314c3e6b8856010f7a84188121582..8c134a642ccaf3530022f2e675a858d726e1dda4 100644 ---- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java -+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -@@ -51,7 +51,7 @@ public class PacketUtils { - if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players - if (listener.shouldHandleMessage(packet)) { - co.aikar.timings.Timing timing = co.aikar.timings.MinecraftTimings.getPacketTiming(packet); // Paper - timings -- try (co.aikar.timings.Timing ignored = timing.startTiming()) { // Paper - timings -+ try { // Paper - timings // Purpur - packet.handle(listener); - } catch (Exception exception) { - if (exception instanceof ReportedException) { -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 5081a631a94920db0307341261755eac399fea1e..f3c66049ab3fe087fa0fa87c2fca36c3c8b5c572 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1481,7 +1481,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - return !this.canOversleep(); - }); -- isOversleep = false;MinecraftTimings.serverOversleep.stopTiming(); -+ //isOversleep = false;MinecraftTimings.serverOversleep.stopTiming(); // Purpur - // Paper end - new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper - Server Tick Events - -@@ -1628,9 +1628,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - entityplayer.connection.suspendFlushing(); - }); -- MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper -+ //MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper // Purpur - this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // CraftBukkit -- MinecraftTimings.bukkitSchedulerTimer.stopTiming(); // Spigot // Paper -+ //MinecraftTimings.bukkitSchedulerTimer.stopTiming(); // Spigot // Paper // Purpur - // Paper start - Folia scheduler API - ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) Bukkit.getGlobalRegionScheduler()).tick(); - getAllLevels().forEach(level -> { -@@ -1743,21 +1743,21 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop list = Lists.newArrayList(); - List list1 = this.level.players(); - ObjectIterator objectiterator = this.entityMap.values().iterator(); -- level.timings.tracker1.startTiming(); // Paper -+ //this.level.timings.tracker1.startTiming(); // Paper // Purpur - - ChunkMap.TrackedEntity playerchunkmap_entitytracker; - -@@ -1214,17 +1214,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - playerchunkmap_entitytracker.serverEntity.sendChanges(); - } - } -- level.timings.tracker1.stopTiming(); // Paper -+ //this.level.timings.tracker1.stopTiming(); // Paper // Purpur - - if (!list.isEmpty()) { - objectiterator = this.entityMap.values().iterator(); - -- level.timings.tracker2.startTiming(); // Paper -+ //this.level.timings.tracker2.startTiming(); // Paper // Purpur - while (objectiterator.hasNext()) { - playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); - playerchunkmap_entitytracker.updatePlayers(list); - } -- level.timings.tracker2.stopTiming(); // Paper -+ //this.level.timings.tracker2.stopTiming(); // Paper // Purpur - } - - } -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index b99f50604bafecbc68835974c9ed0caa91911a40..07b428ed7837642254b1edd55fd08a7beac7e303 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -274,10 +274,10 @@ public class ServerChunkCache extends ChunkSource { - if (!completablefuture.isDone()) { // Paper - io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.pushChunkWait(this.level, x1, z1); // Paper - rewrite chunk system - com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads -- this.level.timings.syncChunkLoad.startTiming(); // Paper -+ //this.level.timings.syncChunkLoad.startTiming(); // Paper // Purpur - chunkproviderserver_b.managedBlock(completablefuture::isDone); - io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.popChunkWait(); // Paper - rewrite chunk system -- this.level.timings.syncChunkLoad.stopTiming(); // Paper -+ //this.level.timings.syncChunkLoad.stopTiming(); // Paper // Purpur - } // Paper - ChunkResult chunkresult = (ChunkResult) completablefuture.join(); - ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error -@@ -425,17 +425,17 @@ public class ServerChunkCache extends ChunkSource { - - public void save(boolean flush) { - this.runDistanceManagerUpdates(); -- try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings -+ //try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings // Purpur - this.chunkMap.saveAllChunks(flush); -- } // Paper - Timings -+ //} // Paper - Timings // Purpur - } - - // Paper start - Incremental chunk and player saving; duplicate save, but call incremental - public void saveIncrementally() { - this.runDistanceManagerUpdates(); -- try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings -+ //try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings // Purpur - this.chunkMap.saveIncrementally(); -- } // Paper - Timings -+ //} // Paper - Timings // Purpur - } - // Paper end - Incremental chunk and player saving - -@@ -472,26 +472,25 @@ public class ServerChunkCache extends ChunkSource { - @Override - public void tick(BooleanSupplier shouldKeepTicking, boolean tickChunks) { - this.level.getProfiler().push("purge"); -- this.level.timings.doChunkMap.startTiming(); // Spigot -+ //this.level.timings.doChunkMap.startTiming(); // Spigot // Purpur - if (this.level.tickRateManager().runsNormally() || !tickChunks) { - this.distanceManager.purgeStaleTickets(); - } -- - this.runDistanceManagerUpdates(); -- this.level.timings.doChunkMap.stopTiming(); // Spigot -+ //this.level.timings.doChunkMap.stopTiming(); // Spigot // Purpur - this.level.getProfiler().popPush("chunks"); - if (tickChunks) { -- this.level.timings.chunks.startTiming(); // Paper - timings -+ //this.level.timings.chunks.startTiming(); // Paper - timings // Purpur - this.chunkMap.level.playerChunkLoader.tick(); // Paper - replace player chunk loader - this is mostly required to account for view distance changes - this.tickChunks(); -- this.level.timings.chunks.stopTiming(); // Paper - timings -+ //this.level.timings.chunks.stopTiming(); // Paper - timings // Purpur - this.chunkMap.tick(); - } - -- this.level.timings.doChunkUnload.startTiming(); // Spigot -+ //this.level.timings.doChunkUnload.startTiming(); // Spigot // Purpur - this.level.getProfiler().popPush("unload"); - this.chunkMap.tick(shouldKeepTicking); -- this.level.timings.doChunkUnload.stopTiming(); // Spigot -+ //this.level.timings.doChunkUnload.stopTiming(); // Spigot // Purpur - this.level.getProfiler().pop(); - this.clearCache(); - } -@@ -507,13 +506,13 @@ public class ServerChunkCache extends ChunkSource { - gameprofilerfiller.push("pollingChunks"); - gameprofilerfiller.push("filteringLoadedChunks"); - // Paper - optimise chunk tick iteration -- if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper -+ //if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper // Purpur - - // Paper - optimise chunk tick iteration - - if (this.level.tickRateManager().runsNormally()) { - gameprofilerfiller.popPush("naturalSpawnCount"); -- this.level.timings.countNaturalMobs.startTiming(); // Paper - timings -+ //this.level.timings.countNaturalMobs.startTiming(); // Paper - timings // Purpur - int k = this.distanceManager.getNaturalSpawnChunkCount(); - // Paper start - Optional per player mob spawns - int naturalSpawnChunkCount = k; -@@ -538,7 +537,7 @@ public class ServerChunkCache extends ChunkSource { - spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); - } - // Paper end - Optional per player mob spawns -- this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings -+ // this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings // Purpur - - this.lastSpawnState = spawnercreature_d; - gameprofilerfiller.popPush("spawnAndTick"); -@@ -647,19 +646,19 @@ public class ServerChunkCache extends ChunkSource { - } - } - // Paper end - optimise chunk tick iteration -- this.level.timings.chunkTicks.stopTiming(); // Paper -+ // this.level.timings.chunkTicks.stopTiming(); // Paper // Purpur - - gameprofilerfiller.popPush("customSpawners"); - if (flag) { -- try (co.aikar.timings.Timing ignored = this.level.timings.miscMobSpawning.startTiming()) { // Paper - timings -+ //try (co.aikar.timings.Timing ignored = this.level.timings.miscMobSpawning.startTiming()) { // Paper - timings // Purpur - this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); -- } // Paper - timings -+ //} // Paper - timings // Purpur - } - } - - gameprofilerfiller.popPush("broadcast"); - // Paper - optimise chunk tick iteration -- this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing -+ //this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing // Purpur - // Paper start - optimise chunk tick iteration - if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) { - it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet copy = this.chunkMap.needsChangeBroadcasting.clone(); -@@ -673,7 +672,7 @@ public class ServerChunkCache extends ChunkSource { - } - } - // Paper end - optimise chunk tick iteration -- this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing -+ //this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing // Purpur - // Paper - optimise chunk tick iteration - gameprofilerfiller.pop(); - gameprofilerfiller.pop(); -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index ae2b9732b2795ea7faec96af4c27ccb04f772307..a84a9218838fb42c49a00c0d5f28e9e486fc7dac 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -872,7 +872,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - - gameprofilerfiller.popPush("tickPending"); -- this.timings.scheduledBlocks.startTiming(); // Paper -+ //this.timings.scheduledBlocks.startTiming(); // Paper // Purpur - if (!this.isDebug() && flag) { - j = this.getGameTime(); - gameprofilerfiller.push("blockTicks"); -@@ -881,24 +881,24 @@ public class ServerLevel extends Level implements WorldGenLevel { - this.fluidTicks.tick(j, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks - gameprofilerfiller.pop(); - } -- this.timings.scheduledBlocks.stopTiming(); // Paper -+ //this.timings.scheduledBlocks.stopTiming(); // Paper // Purpur - - gameprofilerfiller.popPush("raid"); - if (flag) { -- this.timings.raids.startTiming(); // Paper - timings -+ // this.timings.raids.startTiming(); // Paper - timings // Purpur - this.raids.tick(); -- this.timings.raids.stopTiming(); // Paper - timings -+ // this.timings.raids.stopTiming(); // Paper - timings // Purpur - } - - gameprofilerfiller.popPush("chunkSource"); -- this.timings.chunkProviderTick.startTiming(); // Paper - timings -+ //this.timings.chunkProviderTick.startTiming(); // Paper - timings // Purpur - this.getChunkSource().tick(shouldKeepTicking, true); -- this.timings.chunkProviderTick.stopTiming(); // Paper - timings -+ //this.timings.chunkProviderTick.stopTiming(); // Paper - timings // Purpur - gameprofilerfiller.popPush("blockEvents"); - if (flag) { -- this.timings.doSounds.startTiming(); // Spigot -+ // this.timings.doSounds.startTiming(); // Spigot // Purpur - this.runBlockEvents(); -- this.timings.doSounds.stopTiming(); // Spigot -+ // this.timings.doSounds.stopTiming(); // Spigot // Purpur - } - - this.handlingTick = false; -@@ -911,7 +911,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - - if (flag1 || this.emptyTime++ < 300) { - gameprofilerfiller.push("entities"); -- this.timings.tickEntities.startTiming(); // Spigot -+ //this.timings.tickEntities.startTiming(); // Spigot // Purpur - if (this.dragonFight != null && flag) { - gameprofilerfiller.push("dragonFight"); - this.dragonFight.tick(); -@@ -919,7 +919,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - - org.spigotmc.ActivationRange.activateEntities(this); // Spigot -- this.timings.entityTick.startTiming(); // Spigot -+ //this.timings.entityTick.startTiming(); // Spigot // Purpur - this.entityTickList.forEach((entity) -> { - if (!entity.isRemoved()) { - if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed -@@ -946,8 +946,8 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - } - }); -- this.timings.entityTick.stopTiming(); // Spigot -- this.timings.tickEntities.stopTiming(); // Spigot -+ //this.timings.entityTick.stopTiming(); // Spigot // Purpur -+ //this.timings.tickEntities.stopTiming(); // Spigot // Purpur - gameprofilerfiller.pop(); - this.tickBlockEntities(); - } -@@ -1089,7 +1089,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - } // Paper - Option to disable ice and snow - - gameprofilerfiller.popPush("tickBlocks"); -- timings.chunkTicksBlocks.startTiming(); // Paper -+ //timings.chunkTicksBlocks.startTiming(); // Paper // Purpur - if (randomTickSpeed > 0) { - // Paper start - optimize random block ticking - LevelChunkSection[] sections = chunk.getSections(); -@@ -1123,7 +1123,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - // Paper end - optimise random block ticking - -- timings.chunkTicksBlocks.stopTiming(); // Paper -+ //timings.chunkTicksBlocks.stopTiming(); // Paper // Purpur - gameprofilerfiller.pop(); - } - -@@ -1467,8 +1467,8 @@ public class ServerLevel extends Level implements WorldGenLevel { - // Spigot end - // Paper start- timings - final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity); -- timer = isActive ? entity.getType().tickTimer.startTiming() : entity.getType().inactiveTickTimer.startTiming(); // Paper -- try { -+ //timer = isActive ? entity.getType().tickTimer.startTiming() : entity.getType().inactiveTickTimer.startTiming(); // Paper // Purpur -+ //try { // Purpur - // Paper end - timings - entity.setOldPosAndRot(); - ProfilerFiller gameprofilerfiller = this.getProfiler(); -@@ -1484,7 +1484,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - entity.postTick(); // CraftBukkit - } else { entity.inactiveTick(); } // Paper - EAR 2 - this.getProfiler().pop(); -- } finally { timer.stopTiming(); } // Paper - timings -+ //} finally { timer.stopTiming(); } // Paper - timings // Purpur - Iterator iterator = entity.getPassengers().iterator(); - - while (iterator.hasNext()) { -@@ -1507,8 +1507,8 @@ public class ServerLevel extends Level implements WorldGenLevel { - if (passenger instanceof Player || this.entityTickList.contains(passenger)) { - // Paper - EAR 2 - final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(passenger); -- co.aikar.timings.Timing timer = isActive ? passenger.getType().passengerTickTimer.startTiming() : passenger.getType().passengerInactiveTickTimer.startTiming(); // Paper -- try { -+ //co.aikar.timings.Timing timer = isActive ? passenger.getType().passengerTickTimer.startTiming() : passenger.getType().passengerInactiveTickTimer.startTiming(); // Paper // Purpur -+ //try { // Purpur - // Paper end - passenger.setOldPosAndRot(); - ++passenger.tickCount; -@@ -1538,7 +1538,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - this.tickPassenger(passenger, entity2); - } - -- } finally { timer.stopTiming(); }// Paper - EAR2 timings -+ //} finally { timer.stopTiming(); }// Paper - EAR2 timings // Purpur - } - } else { - passenger.stopRiding(); -@@ -1558,14 +1558,14 @@ public class ServerLevel extends Level implements WorldGenLevel { - org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); - } - -- try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) { -+ //try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) { // Purpur - if (doFull) { - this.saveLevelData(true); // Paper - Write SavedData IO async - } - -- this.timings.worldSaveChunks.startTiming(); // Paper -+ //this.timings.worldSaveChunks.startTiming(); // Paper // Purpur - if (!this.noSave()) chunkproviderserver.saveIncrementally(); -- this.timings.worldSaveChunks.stopTiming(); // Paper -+ //this.timings.worldSaveChunks.stopTiming(); // Paper // Purpur - - // Copied from save() - // CraftBukkit start - moved from MinecraftServer.saveChunks -@@ -1577,7 +1577,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); - } - // CraftBukkit end -- } -+ //} // Purpur - } - // Paper end - Incremental chunk and player saving - -@@ -1591,7 +1591,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - - if (!savingDisabled) { - org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld())); // CraftBukkit -- try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { // Paper -+ //try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { // Paper // Purpur // Purpur - if (progressListener != null) { - progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel")); - } -@@ -1601,11 +1601,11 @@ public class ServerLevel extends Level implements WorldGenLevel { - progressListener.progressStage(Component.translatable("menu.savingChunks")); - } - -- timings.worldSaveChunks.startTiming(); // Paper -+ //timings.worldSaveChunks.startTiming(); // Paper // Purpur - if (!close) chunkproviderserver.save(flush); // Paper - rewrite chunk system - if (close) chunkproviderserver.close(true); // Paper - rewrite chunk system -- timings.worldSaveChunks.stopTiming(); // Paper -- }// Paper -+ //timings.worldSaveChunks.stopTiming(); // Paper // Purpur -+ //}// Paper // Purpur - // Paper - rewrite chunk system - entity saving moved into ChunkHolder - - } else if (close) { chunkproviderserver.close(false); } // Paper - rewrite chunk system -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index e54be01cb1629616c2952ea99c6f28f09a592773..a3e29942d3db9e5e63c839b4e32394639f60b680 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2537,7 +2537,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - public void handleCommand(String s) { // Paper - private -> public - org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + s); // Paper - Add async catcher -- co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper -+ //co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper // Purpur - if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot - this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s); - -@@ -2547,7 +2547,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.cserver.getPluginManager().callEvent(event); - - if (event.isCancelled()) { -- co.aikar.timings.MinecraftTimings.playerCommandTimer.stopTiming(); // Paper -+ //co.aikar.timings.MinecraftTimings.playerCommandTimer.stopTiming(); // Paper // Purpur - return; - } - -@@ -2560,7 +2560,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - java.util.logging.Logger.getLogger(ServerGamePacketListenerImpl.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); - return; - } finally { -- co.aikar.timings.MinecraftTimings.playerCommandTimer.stopTiming(); // Paper -+ //co.aikar.timings.MinecraftTimings.playerCommandTimer.stopTiming(); // Paper // Purpur - } - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index d20a7a79e27db1092ff78910df5d45982971cc3e..b863f6fe65c796a1d3102cc3eddb5d6c5becd3ac 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1273,7 +1273,7 @@ public abstract class PlayerList { - - public void saveAll(int interval) { - io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main -- MinecraftTimings.savePlayers.startTiming(); // Paper -+ //MinecraftTimings.savePlayers.startTiming(); // Paper // Purpur - int numSaved = 0; - long now = MinecraftServer.currentTick; - for (int i = 0; i < this.players.size(); ++i) { -@@ -1284,7 +1284,7 @@ public abstract class PlayerList { - } - // Paper end - Incremental chunk and player saving - } -- MinecraftTimings.savePlayers.stopTiming(); // Paper -+ //MinecraftTimings.savePlayers.stopTiming(); // Paper // Purpur - return null; }); // Paper - ensure main - } - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java -index 9379dd4056018b52c93ed4888dcdc94579bd9691..612a14806ec63b0dcf31814396282f4b7f4a527c 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java -@@ -59,9 +59,9 @@ public abstract class Behavior implements BehaviorContro - this.status = Behavior.Status.RUNNING; - int i = this.minDuration + world.getRandom().nextInt(this.maxDuration + 1 - this.minDuration); - this.endTimestamp = time + (long)i; -- this.timing.startTiming(); // Paper - behavior timings -+ //this.timing.startTiming(); // Paper - behavior timings // Purpur - this.start(world, entity, time); -- this.timing.stopTiming(); // Paper - behavior timings -+ //this.timing.stopTiming(); // Paper - behavior timings // Purpur - return true; - } else { - return false; -@@ -73,13 +73,13 @@ public abstract class Behavior implements BehaviorContro - - @Override - public final void tickOrStop(ServerLevel world, E entity, long time) { -- this.timing.startTiming(); // Paper - behavior timings -+ //this.timing.startTiming(); // Paper - behavior timings // Purpur - if (!this.timedOut(time) && this.canStillUse(world, entity, time)) { - this.tick(world, entity, time); - } else { - this.doStop(world, entity, time); - } -- this.timing.stopTiming(); // Paper - behavior timings -+ //this.timing.stopTiming(); // Paper - behavior timings // Purpur - } - - protected void tick(ServerLevel world, E entity, long time) { -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java -index 85b4b24361e785acf75571ff98f924c00ae80748..09a7b418ddf564c0be13297f7c216db2e7ae1578 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java -@@ -53,10 +53,10 @@ public abstract class Sensor { - if (--this.timeToTick <= 0L) { - // Paper start - configurable sensor tick rate and timings - this.timeToTick = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.sensor.get(entity.getType(), this.configKey), this.scanRate); -- this.timing.startTiming(); -+ //this.timing.startTiming(); // Purpur - // Paper end - this.doTick(world, entity); -- this.timing.stopTiming(); // Paper - sensor timings -+ //this.timing.stopTiming(); // Paper - sensor timings // Purpur - } - } - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index edd9762e2475aa8828930ada59eb331a8e8d3970..4d00d72d66adfb282d354e22703552b333138694 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -1306,15 +1306,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - ProfilerFiller gameprofilerfiller = this.getProfiler(); - - gameprofilerfiller.push("blockEntities"); -- this.timings.tileEntityPending.startTiming(); // Spigot -+ //this.timings.tileEntityPending.startTiming(); // Spigot // Purpur - this.tickingBlockEntities = true; - if (!this.pendingBlockEntityTickers.isEmpty()) { - this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); - this.pendingBlockEntityTickers.clear(); - } -- this.timings.tileEntityPending.stopTiming(); // Spigot -+ //this.timings.tileEntityPending.stopTiming(); // Spigot // Purpur - -- this.timings.tileEntityTick.startTiming(); // Spigot -+ //this.timings.tileEntityTick.startTiming(); // Spigot // Purpur - // Spigot start - // Iterator iterator = this.blockEntityTickers.iterator(); - boolean flag = this.tickRateManager().runsNormally(); -@@ -1343,7 +1343,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 - -- this.timings.tileEntityTick.stopTiming(); // Spigot -+ //this.timings.tileEntityTick.stopTiming(); // Spigot // Purpur - this.tickingBlockEntities = false; - co.aikar.timings.TimingHistory.tileEntityTicks += this.blockEntityTickers.size(); // Paper - gameprofilerfiller.pop(); -diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index ed8032495af9ce9c23419224814b8d27e4a97c17..2812505185df691e8f08932aa0bba162a7d9db86 100644 ---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java -+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -128,7 +128,7 @@ public final class NaturalSpawner { - - public static void spawnForChunk(ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnState info, boolean spawnAnimals, boolean spawnMonsters, boolean rareSpawn) { - world.getProfiler().push("spawner"); -- world.timings.mobSpawn.startTiming(); // Spigot -+ //world.timings.mobSpawn.startTiming(); // Spigot // Purpur - MobCategory[] aenumcreaturetype = NaturalSpawner.SPAWNING_CATEGORIES; - int i = aenumcreaturetype.length; - -@@ -181,7 +181,7 @@ public final class NaturalSpawner { - } - } - -- world.timings.mobSpawn.stopTiming(); // Spigot -+ //world.timings.mobSpawn.stopTiming(); // Spigot // Purpur - world.getProfiler().pop(); - } - -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 2a8609e33716949ff1877b6d10f64a9d7a7c81e9..e8d14bf4120dd9861e4ccb8bd6c14e175343c55d 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -785,7 +785,7 @@ public class LevelChunk extends ChunkAccess { - this.chunkHolder.getEntityChunk().callEntitiesLoadEvent(); // Paper - rewrite chunk system - - if (this.needsDecoration) { -- try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper -+ //try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper // Purpur - this.needsDecoration = false; - java.util.Random random = new java.util.Random(); - random.setSeed(this.level.getSeed()); -@@ -805,7 +805,7 @@ public class LevelChunk extends ChunkAccess { - } - } - server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); -- } // Paper -+ //} // Paper // Purpur - } - } - } -@@ -1161,7 +1161,7 @@ public class LevelChunk extends ChunkAccess { - ProfilerFiller gameprofilerfiller = LevelChunk.this.level.getProfiler(); - - gameprofilerfiller.push(this::getType); -- this.blockEntity.tickTimer.startTiming(); // Spigot -+ //this.blockEntity.tickTimer.startTiming(); // Spigot // Purpur - BlockState iblockdata = LevelChunk.this.getBlockState(blockposition); - - if (this.blockEntity.getType().isValid(iblockdata)) { -@@ -1188,7 +1188,7 @@ public class LevelChunk extends ChunkAccess { - // Paper end - Prevent block entity and entity crashes - // Spigot start - } finally { -- this.blockEntity.tickTimer.stopTiming(); -+ //this.blockEntity.tickTimer.stopTiming(); // Purpur - // Spigot end - } - } -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index c1e2d3a75b9d4710ab6d8b5c62af4bc136a2b668..ca8ae8e1c51b937dac916e0b0dc94b5e2e61efeb 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -515,10 +515,10 @@ public class CraftScheduler implements BukkitScheduler { - this.runners.remove(task.getTaskId()); - } - } -- MinecraftTimings.bukkitSchedulerFinishTimer.startTiming(); // Paper -+ //MinecraftTimings.bukkitSchedulerFinishTimer.startTiming(); // Paper // Purpur - this.pending.addAll(temp); - temp.clear(); -- MinecraftTimings.bukkitSchedulerFinishTimer.stopTiming(); // Paper -+ //MinecraftTimings.bukkitSchedulerFinishTimer.stopTiming(); // Paper // Purpur - //this.debugHead = this.debugHead.getNextHead(currentTick); // Paper - } - -@@ -561,7 +561,7 @@ public class CraftScheduler implements BukkitScheduler { - } - - void parsePending() { // Paper -- if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); // Paper -+ //if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); // Paper // Purpur - CraftTask head = this.head; - CraftTask task = head.getNext(); - CraftTask lastTask = head; -@@ -580,7 +580,7 @@ public class CraftScheduler implements BukkitScheduler { - task.setNext(null); - } - this.head = lastTask; -- if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); // Paper -+ //if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); // Paper // Purpur - } - - private boolean isReady(final int currentTick) { -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java -index ea26d9464644b5217879b8c21b4da28e57708dcb..5835dc236b3f5291a804f7fb14a12eb466d4e0ba 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java -@@ -96,13 +96,13 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot - - @Override - public void run() { -- try (Timing ignored = timings.startTiming()) { // Paper -+ //try (Timing ignored = timings.startTiming()) { // Paper // Purpur - if (this.rTask != null) { - this.rTask.run(); - } else { - this.cTask.accept(this); - } -- } // Paper -+ //} // Paper // Purpur - } - - long getCreatedAt() { -diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -index b3e1adeb932da9b3bed16acd94e2f16da48a7c72..d3ec817e95628f1fc8be4a29c9a0f13c7d5fd552 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java -@@ -115,7 +115,7 @@ public final class CraftScoreboardManager implements ScoreboardManager { - public void forAllObjectives(ObjectiveCriteria criteria, ScoreHolder holder, Consumer consumer) { - // Paper start - add timings for scoreboard search - // plugins leaking scoreboards will make this very expensive, let server owners debug it easily -- co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.startTimingIfSync(); -+ //co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.startTimingIfSync(); // Purpur - try { - // Paper end - add timings for scoreboard search - for (CraftScoreboard scoreboard : this.scoreboards) { -@@ -123,7 +123,7 @@ public final class CraftScoreboardManager implements ScoreboardManager { - board.forAllObjectives(criteria, holder, (score) -> consumer.accept(score)); - } - } finally { // Paper start - add timings for scoreboard search -- co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.stopTimingIfSync(); -+ //co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.stopTimingIfSync(); // Purpur - } - // Paper end - add timings for scoreboard search - } -diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index a8fc07e06039e1418e020f7c1ad2cd36b9b94eb4..de2b469f06f6679aed1d20156052bfbef5e7c30b 100644 ---- a/src/main/java/org/spigotmc/ActivationRange.java -+++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -168,7 +168,7 @@ public class ActivationRange - */ - public static void activateEntities(Level world) - { -- MinecraftTimings.entityActivationCheckTimer.startTiming(); -+ //MinecraftTimings.entityActivationCheckTimer.startTiming(); // Purpur - final int miscActivationRange = world.spigotConfig.miscActivationRange; - final int raiderActivationRange = world.spigotConfig.raiderActivationRange; - final int animalActivationRange = world.spigotConfig.animalActivationRange; -@@ -228,7 +228,7 @@ public class ActivationRange - } - // Paper end - } -- MinecraftTimings.entityActivationCheckTimer.stopTiming(); -+ //MinecraftTimings.entityActivationCheckTimer.stopTiming(); // Purpur - } - - /** diff --git a/patches/server/0256-Add-more-logger-output-for-invalid-movement-kicks.patch b/patches/server/0256-Add-more-logger-output-for-invalid-movement-kicks.patch deleted file mode 100644 index 90fbc22da..000000000 --- a/patches/server/0256-Add-more-logger-output-for-invalid-movement-kicks.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Wed, 27 Jul 2022 00:42:39 -0500 -Subject: [PATCH] Add more logger output for invalid movement kicks - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index a3e29942d3db9e5e63c839b4e32394639f60b680..478f3bba5e0768c8ab800d7cb591f07db1bc20da 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -753,6 +753,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - if (packet.getId() == this.awaitingTeleport) { - if (this.awaitingPositionFromClient == null) { - this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause -+ ServerGamePacketListenerImpl.LOGGER.warn("Disconnected on accept teleport packet. Was not expecting position data from client at this time"); // Purpur - return; - } - -@@ -1358,8 +1359,16 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - @Override - public void handleMovePlayer(ServerboundMovePlayerPacket packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); -- if (ServerGamePacketListenerImpl.containsInvalidValues(packet.getX(0.0D), packet.getY(0.0D), packet.getZ(0.0D), packet.getYRot(0.0F), packet.getXRot(0.0F))) { -+ // Purpur start -+ boolean invalidX = Double.isNaN(packet.getX(0.0D)); -+ boolean invalidY = Double.isNaN(packet.getY(0.0D)); -+ boolean invalidZ = Double.isNaN(packet.getZ(0.0D)); -+ boolean invalidYaw = !Floats.isFinite(packet.getYRot(0.0F)); -+ boolean invalidPitch = !Floats.isFinite(packet.getXRot(0.0F)); -+ if (invalidX || invalidY || invalidZ || invalidYaw || invalidPitch) { - this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause -+ ServerGamePacketListenerImpl.LOGGER.warn(String.format("Disconnected on move player packet. Invalid data: x=%b, y=%b, z=%b, yaw=%b, pitch=%b", invalidX, invalidY, invalidZ, invalidYaw, invalidPitch)); -+ // Purpur end - } else { - ServerLevel worldserver = this.player.serverLevel(); - diff --git a/patches/server/0257-Add-Bee-API.patch b/patches/server/0257-Add-Bee-API.patch deleted file mode 100644 index b09f65216..000000000 --- a/patches/server/0257-Add-Bee-API.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SageSphinx63920 -Date: Mon, 25 Jul 2022 19:33:49 +0200 -Subject: [PATCH] Add Bee API - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 221c0051c7a0e20c1b7a464df26eb63c4e997eee..539170813921de2dfcd7ef84dd7512d73cd27e68 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -797,6 +797,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - if (optional.isPresent()) { - Bee.this.savedFlowerPos = (BlockPos) optional.get(); - Bee.this.navigation.moveTo((double) Bee.this.savedFlowerPos.getX() + 0.5D, (double) Bee.this.savedFlowerPos.getY() + 0.5D, (double) Bee.this.savedFlowerPos.getZ() + 0.5D, 1.2000000476837158D); -+ new org.purpurmc.purpur.event.entity.BeeFoundFlowerEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos)).callEvent(); // Purpur - return true; - } else { - Bee.this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(Bee.this.random, 20, 60); -@@ -853,6 +854,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - this.pollinating = false; - Bee.this.navigation.stop(); - Bee.this.remainingCooldownBeforeLocatingNewFlower = 200; -+ new org.purpurmc.purpur.event.entity.BeeStopPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), Bee.this.savedFlowerPos == null ? null : io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos), Bee.this.hasNectar()).callEvent(); // Purpur - } - - @Override -@@ -899,6 +901,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - this.setWantedPos(); - } - -+ if (this.successfulPollinatingTicks == 0) new org.purpurmc.purpur.event.entity.BeeStartedPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos)).callEvent(); // Purpur - ++this.successfulPollinatingTicks; - if (Bee.this.random.nextFloat() < 0.05F && this.successfulPollinatingTicks > this.lastSoundPlayedTick + 60) { - this.lastSoundPlayedTick = this.successfulPollinatingTicks; diff --git a/patches/server/0258-Debug-Marker-API.patch b/patches/server/0258-Debug-Marker-API.patch deleted file mode 100644 index 7db6b893c..000000000 --- a/patches/server/0258-Debug-Marker-API.patch +++ /dev/null @@ -1,148 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: YouHaveTrouble -Date: Sat, 23 Jul 2022 14:40:38 +0200 -Subject: [PATCH] Debug Marker API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index f4b611754a0b4a14c31595bc2a5e8acf8bf849bc..5285433e69cb34d0b856f3e81bf1888aa30eb6f3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1600,6 +1600,42 @@ public final class CraftServer implements Server { - public void removeFuel(org.bukkit.Material material) { - net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity.removeFuel(net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material))); - } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration) { -+ sendBlockHighlight(location, duration, "", 0x6400FF00); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, int argb) { -+ sendBlockHighlight(location, duration, "", argb); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text) { -+ sendBlockHighlight(location, duration, text, 0x6400FF00); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text, int argb) { -+ this.worlds.forEach((name, world) -> world.sendBlockHighlight(location, duration, text, argb)); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) { -+ sendBlockHighlight(location, duration, "", color, transparency); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) { -+ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range"); -+ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB()); -+ } -+ -+ @Override -+ public void clearBlockHighlights() { -+ this.worlds.forEach((name, world) -> clearBlockHighlights()); -+ } - // Purpur End - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index b7a02ae4eda06cab8ffd1220259a061558981dec..226ff7c6048b510be2e71ecc5d5ff3581092aa5e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2428,6 +2428,42 @@ public class CraftWorld extends CraftRegionAccessor implements World { - public float getLocalDifficultyAt(Location location) { - return getHandle().getCurrentDifficultyAt(io.papermc.paper.util.MCUtil.toBlockPosition(location)).getEffectiveDifficulty(); - } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration) { -+ sendBlockHighlight(location, duration, "", 0x6400FF00); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, int argb) { -+ sendBlockHighlight(location, duration, "", argb); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text) { -+ sendBlockHighlight(location, duration, text, 0x6400FF00); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text, int argb) { -+ net.minecraft.network.protocol.game.DebugPackets.sendGameTestAddMarker(getHandle(), io.papermc.paper.util.MCUtil.toBlockPosition(location), text, argb, duration); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) { -+ sendBlockHighlight(location, duration, "", color, transparency); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) { -+ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range"); -+ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB()); -+ } -+ -+ @Override -+ public void clearBlockHighlights() { -+ net.minecraft.network.protocol.game.DebugPackets.sendGameTestClearPacket(getHandle()); -+ } - // Purpur end - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index cf5897f8fed0c390ee75ca3b5b1037cfe1bdc43d..db60b3d722a67a5beb6f80d0900132317d0e9476 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3574,5 +3574,43 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - public void resetIdleTimer() { - getHandle().resetLastActionTime(); - } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration) { -+ sendBlockHighlight(location, duration, "", 0x6400FF00); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, int argb) { -+ sendBlockHighlight(location, duration, "", argb); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text) { -+ sendBlockHighlight(location, duration, text, 0x6400FF00); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text, int argb) { -+ if (this.getHandle().connection == null) return; -+ this.getHandle().connection.send(new net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket(new net.minecraft.network.protocol.common.custom.GameTestAddMarkerDebugPayload(io.papermc.paper.util.MCUtil.toBlockPosition(location), argb, text, duration))); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) { -+ sendBlockHighlight(location, duration, "", color, transparency); -+ } -+ -+ @Override -+ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) { -+ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range"); -+ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB()); -+ } -+ -+ @Override -+ public void clearBlockHighlights() { -+ if (this.getHandle().connection == null) return; -+ this.getHandle().connection.send(new net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket(new net.minecraft.network.protocol.common.custom.GameTestClearMarkersDebugPayload())); -+ } - // Purpur end - } diff --git a/patches/server/0259-mob-spawning-option-to-ignore-creative-players.patch b/patches/server/0259-mob-spawning-option-to-ignore-creative-players.patch deleted file mode 100644 index e7d688571..000000000 --- a/patches/server/0259-mob-spawning-option-to-ignore-creative-players.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Fri, 26 Aug 2022 22:44:41 -0700 -Subject: [PATCH] mob spawning option to ignore creative players - - -diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index 35e94c06361795d032f995e8282f8b35c075dae7..0f90a6803851eba51e164772c984b1cd1193d882 100644 ---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java -+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -253,7 +253,7 @@ public final class NaturalSpawner { - blockposition_mutableblockposition.set(l, i, i1); - double d0 = (double) l + 0.5D; - double d1 = (double) i1 + 0.5D; -- Player entityhuman = world.getNearestPlayer(d0, (double) i, d1, -1.0D, false); -+ Player entityhuman = world.getNearestPlayer(d0, (double) i, d1, -1.0D, world.purpurConfig.mobSpawningIgnoreCreativePlayers); // Purpur - - if (entityhuman != null) { - double d2 = entityhuman.distanceToSqr(d0, (double) i, d1); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index f50c26f02bc7c95f7b1228588aff68296290c21b..8763375984c9cbd9d4862a0130602e11a55292f5 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -385,6 +385,7 @@ public class PurpurWorldConfig { - public boolean phantomSpawning; - public boolean villagerTraderSpawning; - public boolean villageSiegeSpawning; -+ public boolean mobSpawningIgnoreCreativePlayers = false; - private void mobSpawnerSettings() { - // values of "default" or null will default to true only if the world environment is normal (aka overworld) - Predicate predicate = (bool) -> (bool != null && bool) || (bool == null && environment == World.Environment.NORMAL); -@@ -393,6 +394,7 @@ public class PurpurWorldConfig { - phantomSpawning = getBoolean("gameplay-mechanics.mob-spawning.phantoms", predicate); - villagerTraderSpawning = getBoolean("gameplay-mechanics.mob-spawning.wandering-traders", predicate); - villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate); -+ mobSpawningIgnoreCreativePlayers = getBoolean("gameplay-mechanics.mob-spawning.ignore-creative-players", mobSpawningIgnoreCreativePlayers); - } - - public boolean disableObserverClocks = false; diff --git a/patches/server/0260-Add-skeleton-bow-accuracy-option.patch b/patches/server/0260-Add-skeleton-bow-accuracy-option.patch deleted file mode 100644 index 3f012cd02..000000000 --- a/patches/server/0260-Add-skeleton-bow-accuracy-option.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Fri, 2 Sep 2022 13:04:53 -0500 -Subject: [PATCH] Add skeleton bow accuracy option - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -index 8515e6360c1630385884a60f652f65fdefeaf540..e80307198b051cbcd9f72b36e459276848dcb4c9 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -183,7 +183,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo - double d2 = target.getZ() - this.getZ(); - double d3 = Math.sqrt(d0 * d0 + d2 * d2); - -- entityarrow.shoot(d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float) (14 - this.level().getDifficulty().getId() * 4)); -+ entityarrow.shoot(d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, this.level().purpurConfig.skeletonBowAccuracyMap.getOrDefault(this.level().getDifficulty().getId(), (float) (14 - this.level().getDifficulty().getId() * 4))); // Purpur - // CraftBukkit start - org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), entityarrow.getPickupItem(), entityarrow, net.minecraft.world.InteractionHand.MAIN_HAND, 0.8F, true); // Paper - if (event.isCancelled()) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 8763375984c9cbd9d4862a0130602e11a55292f5..7b028800a99d627a9efcd2a718e281ab7a67cfad 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2511,6 +2511,8 @@ public class PurpurWorldConfig { - public boolean skeletonAlwaysDropExp = false; - public double skeletonHeadVisibilityPercent = 0.5D; - public int skeletonFeedWitherRoses = 0; -+ public String skeletonBowAccuracy = "14 - difficulty * 4"; -+ public Map skeletonBowAccuracyMap = new HashMap<>(); - private void skeletonSettings() { - skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); - skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); -@@ -2525,6 +2527,18 @@ public class PurpurWorldConfig { - skeletonAlwaysDropExp = getBoolean("mobs.skeleton.always-drop-exp", skeletonAlwaysDropExp); - skeletonHeadVisibilityPercent = getDouble("mobs.skeleton.head-visibility-percent", skeletonHeadVisibilityPercent); - skeletonFeedWitherRoses = getInt("mobs.skeleton.feed-wither-roses", skeletonFeedWitherRoses); -+ final String defaultSkeletonBowAccuracy = skeletonBowAccuracy; -+ skeletonBowAccuracy = getString("mobs.skeleton.bow-accuracy", skeletonBowAccuracy); -+ for (int i = 1; i < 4; i++) { -+ final float divergence; -+ try { -+ divergence = ((Number) Entity.scriptEngine.eval("let difficulty = " + i + "; " + skeletonBowAccuracy)).floatValue(); -+ } catch (javax.script.ScriptException e) { -+ e.printStackTrace(); -+ break; -+ } -+ skeletonBowAccuracyMap.put(i, divergence); -+ } - } - - public boolean skeletonHorseRidable = false; diff --git a/patches/server/0261-Add-death-screen-API.patch b/patches/server/0261-Add-death-screen-API.patch deleted file mode 100644 index fa328d3ec..000000000 --- a/patches/server/0261-Add-death-screen-API.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Fri, 23 Sep 2022 18:41:05 -0700 -Subject: [PATCH] Add death screen API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index db60b3d722a67a5beb6f80d0900132317d0e9476..88948526f9acf4bb2157484b80891902fd843b02 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3612,5 +3612,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - if (this.getHandle().connection == null) return; - this.getHandle().connection.send(new net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket(new net.minecraft.network.protocol.common.custom.GameTestClearMarkersDebugPayload())); - } -+ -+ @Override -+ public void sendDeathScreen(net.kyori.adventure.text.Component message) { -+ if (this.getHandle().connection == null) return; -+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundPlayerCombatKillPacket(getEntityId(), io.papermc.paper.adventure.PaperAdventure.asVanilla(message))); -+ } - // Purpur end - } diff --git a/patches/server/0262-Implement-ram-and-rambar-commands.patch b/patches/server/0262-Implement-ram-and-rambar-commands.patch deleted file mode 100644 index ec2e7056f..000000000 --- a/patches/server/0262-Implement-ram-and-rambar-commands.patch +++ /dev/null @@ -1,360 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Mon, 26 Sep 2022 07:43:30 -0500 -Subject: [PATCH] Implement ram and rambar commands - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index d3c42c19a051fb3a670e541fc746b55717192a91..13dfb3e506d50c0b191baf5d05bbfc28c20be0ae 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -258,6 +258,8 @@ public class Commands { - org.purpurmc.purpur.command.UptimeCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.TPSBarCommand.register(this.dispatcher); // Purpur - org.purpurmc.purpur.command.CompassCommand.register(this.dispatcher); // Purpur -+ org.purpurmc.purpur.command.RamBarCommand.register(this.dispatcher); // Purpur -+ org.purpurmc.purpur.command.RamCommand.register(this.dispatcher); // Purpur - } - - if (environment.includeIntegrated) { -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index ad9d42e886bc1e2529ca13990626169ab2354898..d7e4a9fe9676563845d9981523bff1a7ff12282c 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -301,6 +301,7 @@ public class ServerPlayer extends Player { - public boolean purpurClient = false; // Purpur - private boolean tpsBar = false; // Purpur - private boolean compassBar = false; // Purpur -+ private boolean ramBar = false; // Purpur - - // Paper start - replace player chunk loader - private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); -@@ -613,6 +614,7 @@ public class ServerPlayer extends Player { - - if (nbt.contains("Purpur.TPSBar")) { this.tpsBar = nbt.getBoolean("Purpur.TPSBar"); } // Purpur - if (nbt.contains("Purpur.CompassBar")) { this.compassBar = nbt.getBoolean("Purpur.CompassBar"); } // Purpur -+ if (nbt.contains("Purpur.RamBar")) { this.ramBar = nbt.getBoolean("Purpur.RamBar"); } // Purpur - } - - @Override -@@ -689,6 +691,7 @@ public class ServerPlayer extends Player { - }); - } - -+ nbt.putBoolean("Purpur.RamBar", this.ramBar); // Purpur - nbt.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur - nbt.putBoolean("Purpur.CompassBar", this.compassBar); // Purpur - } -@@ -3023,5 +3026,13 @@ public class ServerPlayer extends Player { - public void compassBar(boolean compassBar) { - this.compassBar = compassBar; - } -+ -+ public boolean ramBar() { -+ return this.ramBar; -+ } -+ -+ public void ramBar(boolean ramBar) { -+ this.ramBar = ramBar; -+ } - // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 620f1207fc773f8602b748128557f1c73f0319fb..62612451c23bb146e82f4082ca8677e5dc57a08f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -182,6 +182,8 @@ public class PurpurConfig { - public static String creditsCommandOutput = "%s has been shown the end credits"; - public static String demoCommandOutput = "%s has been shown the demo screen"; - public static String pingCommandOutput = "%s's ping is %sms"; -+ public static String ramCommandOutput = "Ram Usage: / ()"; -+ public static String rambarCommandOutput = "Rambar toggled for "; - public static String tpsbarCommandOutput = "Tpsbar toggled for "; - public static String dontRunWithScissors = "Don't run with scissors!"; - public static String uptimeCommandOutput = "Server uptime is "; -@@ -199,6 +201,8 @@ public class PurpurConfig { - creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput); - demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput); - pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); -+ ramCommandOutput = getString("settings.messages.ram-command-output", ramCommandOutput); -+ rambarCommandOutput = getString("settings.messages.rambar-command-output", rambarCommandOutput); - tpsbarCommandOutput = getString("settings.messages.tpsbar-command-output", tpsbarCommandOutput); - dontRunWithScissors = getString("settings.messages.dont-run-with-scissors", dontRunWithScissors); - uptimeCommandOutput = getString("settings.messages.uptime-command-output", uptimeCommandOutput); -@@ -247,6 +251,15 @@ public class PurpurConfig { - disableGiveCommandDrops = getBoolean("settings.disable-give-dropping", disableGiveCommandDrops); - } - -+ public static String commandRamBarTitle = "Ram: / ()"; -+ public static BossBar.Overlay commandRamBarProgressOverlay = BossBar.Overlay.NOTCHED_20; -+ public static BossBar.Color commandRamBarProgressColorGood = BossBar.Color.GREEN; -+ public static BossBar.Color commandRamBarProgressColorMedium = BossBar.Color.YELLOW; -+ public static BossBar.Color commandRamBarProgressColorLow = BossBar.Color.RED; -+ public static String commandRamBarTextColorGood = ""; -+ public static String commandRamBarTextColorMedium = ""; -+ public static String commandRamBarTextColorLow = ""; -+ public static int commandRamBarTickInterval = 20; - public static String commandTPSBarTitle = "TPS: MSPT: Ping: ms"; - public static BossBar.Overlay commandTPSBarProgressOverlay = BossBar.Overlay.NOTCHED_20; - public static TPSBarTask.FillMode commandTPSBarProgressFillMode = TPSBarTask.FillMode.MSPT; -@@ -274,6 +287,16 @@ public class PurpurConfig { - public static String uptimeSecond = "%02d second"; - public static String uptimeSeconds = "%02d seconds"; - private static void commandSettings() { -+ commandRamBarTitle = getString("settings.command.rambar.title", commandRamBarTitle); -+ commandRamBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.rambar.overlay", commandRamBarProgressOverlay.name())); -+ commandRamBarProgressColorGood = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.good", commandRamBarProgressColorGood.name())); -+ commandRamBarProgressColorMedium = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.medium", commandRamBarProgressColorMedium.name())); -+ commandRamBarProgressColorLow = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.low", commandRamBarProgressColorLow.name())); -+ commandRamBarTextColorGood = getString("settings.command.rambar.text-color.good", commandRamBarTextColorGood); -+ commandRamBarTextColorMedium = getString("settings.command.rambar.text-color.medium", commandRamBarTextColorMedium); -+ commandRamBarTextColorLow = getString("settings.command.rambar.text-color.low", commandRamBarTextColorLow); -+ commandRamBarTickInterval = getInt("settings.command.rambar.tick-interval", commandRamBarTickInterval); -+ - commandTPSBarTitle = getString("settings.command.tpsbar.title", commandTPSBarTitle); - commandTPSBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.tpsbar.overlay", commandTPSBarProgressOverlay.name())); - commandTPSBarProgressFillMode = TPSBarTask.FillMode.valueOf(getString("settings.command.tpsbar.fill-mode", commandTPSBarProgressFillMode.name())); -diff --git a/src/main/java/org/purpurmc/purpur/command/RamBarCommand.java b/src/main/java/org/purpurmc/purpur/command/RamBarCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2852c07adb080c34905f5d1b19efed8ea47eecc6 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/RamBarCommand.java -@@ -0,0 +1,44 @@ -+package org.purpurmc.purpur.command; -+ -+import com.mojang.brigadier.CommandDispatcher; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.minimessage.MiniMessage; -+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import net.minecraft.commands.arguments.EntityArgument; -+import net.minecraft.server.level.ServerPlayer; -+import org.purpurmc.purpur.PurpurConfig; -+import org.purpurmc.purpur.task.RamBarTask; -+ -+import java.util.Collection; -+import java.util.Collections; -+ -+public class RamBarCommand { -+ public static void register(CommandDispatcher dispatcher) { -+ dispatcher.register(Commands.literal("rambar") -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.rambar")) -+ .executes(context -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) -+ .then(Commands.argument("targets", EntityArgument.players()) -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.rambar.other")) -+ .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) -+ ) -+ ); -+ } -+ -+ private static int execute(CommandSourceStack sender, Collection targets) { -+ for (ServerPlayer player : targets) { -+ boolean result = RamBarTask.instance().togglePlayer(player.getBukkitEntity()); -+ player.ramBar(result); -+ -+ Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.rambarCommandOutput, -+ Placeholder.component("onoff", Component.translatable(result ? "options.on" : "options.off") -+ .color(result ? NamedTextColor.GREEN : NamedTextColor.RED)), -+ Placeholder.parsed("target", player.getGameProfile().getName())); -+ -+ sender.sendSuccess(output, false); -+ } -+ return targets.size(); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/command/RamCommand.java b/src/main/java/org/purpurmc/purpur/command/RamCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..992f8dfc628c7485e335191e1308cdfd4eedfbe8 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/command/RamCommand.java -@@ -0,0 +1,30 @@ -+package org.purpurmc.purpur.command; -+ -+import com.mojang.brigadier.CommandDispatcher; -+import io.papermc.paper.adventure.PaperAdventure; -+import net.kyori.adventure.text.minimessage.MiniMessage; -+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -+import net.minecraft.commands.CommandSourceStack; -+import net.minecraft.commands.Commands; -+import org.purpurmc.purpur.PurpurConfig; -+import org.purpurmc.purpur.task.RamBarTask; -+ -+public class RamCommand { -+ public static void register(CommandDispatcher dispatcher) { -+ dispatcher.register(Commands.literal("ram") -+ .requires(listener -> listener.hasPermission(2, "bukkit.command.ram")) -+ .executes(context -> { -+ CommandSourceStack sender = context.getSource(); -+ RamBarTask ramBar = RamBarTask.instance(); -+ sender.sendSuccess(() -> PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(PurpurConfig.ramCommandOutput, -+ Placeholder.component("allocated", ramBar.format(ramBar.getAllocated())), -+ Placeholder.component("used", ramBar.format(ramBar.getUsed())), -+ Placeholder.component("xmx", ramBar.format(ramBar.getXmx())), -+ Placeholder.component("xms", ramBar.format(ramBar.getXms())), -+ Placeholder.unparsed("percent", ((int) (ramBar.getPercent() * 100)) + "%") -+ )), false); -+ return 1; -+ }) -+ ); -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/task/BossBarTask.java b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java -index d333334f323049ca97e756324cff0b23eddacd2a..114f273dd7f8b8a3c02f0651f6944859b33a65d4 100644 ---- a/src/main/java/org/purpurmc/purpur/task/BossBarTask.java -+++ b/src/main/java/org/purpurmc/purpur/task/BossBarTask.java -@@ -89,17 +89,22 @@ public abstract class BossBarTask extends BukkitRunnable { - } - - public static void startAll() { -+ RamBarTask.instance().start(); - TPSBarTask.instance().start(); - CompassTask.instance().start(); - } - - public static void stopAll() { -+ RamBarTask.instance().stop(); - TPSBarTask.instance().stop(); - CompassTask.instance().stop(); - } - - public static void addToAll(ServerPlayer player) { - Player bukkit = player.getBukkitEntity(); -+ if (player.ramBar()) { -+ RamBarTask.instance().addPlayer(bukkit); -+ } - if (player.tpsBar()) { - TPSBarTask.instance().addPlayer(bukkit); - } -@@ -109,6 +114,7 @@ public abstract class BossBarTask extends BukkitRunnable { - } - - public static void removeFromAll(Player player) { -+ RamBarTask.instance().removePlayer(player); - TPSBarTask.instance().removePlayer(player); - CompassTask.instance().removePlayer(player); - } -diff --git a/src/main/java/org/purpurmc/purpur/task/RamBarTask.java b/src/main/java/org/purpurmc/purpur/task/RamBarTask.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8e98c0ae73e2c40002a72b5d0d246ffa0c3ab38f ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/task/RamBarTask.java -@@ -0,0 +1,117 @@ -+package org.purpurmc.purpur.task; -+ -+import net.kyori.adventure.bossbar.BossBar; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.minimessage.MiniMessage; -+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -+import org.bukkit.entity.Player; -+import org.purpurmc.purpur.PurpurConfig; -+ -+import java.lang.management.ManagementFactory; -+import java.lang.management.MemoryUsage; -+ -+public class RamBarTask extends BossBarTask { -+ private static RamBarTask instance; -+ private long allocated = 0L; -+ private long used = 0L; -+ private long xmx = 0L; -+ private long xms = 0L; -+ private float percent = 0F; -+ private int tick = 0; -+ -+ public static RamBarTask instance() { -+ if (instance == null) { -+ instance = new RamBarTask(); -+ } -+ return instance; -+ } -+ -+ @Override -+ BossBar createBossBar() { -+ return BossBar.bossBar(Component.text(""), 0.0F, instance().getBossBarColor(), PurpurConfig.commandRamBarProgressOverlay); -+ } -+ -+ @Override -+ void updateBossBar(BossBar bossbar, Player player) { -+ bossbar.progress(getBossBarProgress()); -+ bossbar.color(getBossBarColor()); -+ bossbar.name(MiniMessage.miniMessage().deserialize(PurpurConfig.commandRamBarTitle, -+ Placeholder.component("allocated", format(this.allocated)), -+ Placeholder.component("used", format(this.used)), -+ Placeholder.component("xmx", format(this.xmx)), -+ Placeholder.component("xms", format(this.xms)), -+ Placeholder.unparsed("percent", ((int) (this.percent * 100)) + "%") -+ )); -+ } -+ -+ @Override -+ public void run() { -+ if (++this.tick < PurpurConfig.commandRamBarTickInterval) { -+ return; -+ } -+ this.tick = 0; -+ -+ MemoryUsage heap = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); -+ -+ this.allocated = heap.getCommitted(); -+ this.used = heap.getUsed(); -+ this.xmx = heap.getMax(); -+ this.xms = heap.getInit(); -+ this.percent = Math.max(Math.min((float) this.used / this.xmx, 1.0F), 0.0F); -+ -+ super.run(); -+ } -+ -+ private float getBossBarProgress() { -+ return this.percent; -+ } -+ -+ private BossBar.Color getBossBarColor() { -+ if (this.percent < 0.5F) { -+ return PurpurConfig.commandRamBarProgressColorGood; -+ } else if (this.percent < 0.75F) { -+ return PurpurConfig.commandRamBarProgressColorMedium; -+ } else { -+ return PurpurConfig.commandRamBarProgressColorLow; -+ } -+ } -+ -+ public Component format(long v) { -+ String color; -+ if (this.percent < 0.60F) { -+ color = PurpurConfig.commandRamBarTextColorGood; -+ } else if (this.percent < 0.85F) { -+ color = PurpurConfig.commandRamBarTextColorMedium; -+ } else { -+ color = PurpurConfig.commandRamBarTextColorLow; -+ } -+ String value; -+ if (v < 1024) { -+ value = v + "B"; -+ } else { -+ int z = (63 - Long.numberOfLeadingZeros(v)) / 10; -+ value = String.format("%.1f%s", (double) v / (1L << (z * 10)), "BKMGTPE".charAt(z)); -+ } -+ return MiniMessage.miniMessage().deserialize(color, Placeholder.unparsed("text", value)); -+ } -+ -+ public long getAllocated() { -+ return this.allocated; -+ } -+ -+ public long getUsed() { -+ return this.used; -+ } -+ -+ public long getXmx() { -+ return this.xmx; -+ } -+ -+ public long getXms() { -+ return this.xms; -+ } -+ -+ public float getPercent() { -+ return this.percent; -+ } -+} diff --git a/patches/server/0263-Add-an-option-to-fix-MC-3304-projectile-looting.patch b/patches/server/0263-Add-an-option-to-fix-MC-3304-projectile-looting.patch deleted file mode 100644 index 6755dbff9..000000000 --- a/patches/server/0263-Add-an-option-to-fix-MC-3304-projectile-looting.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Sat, 1 Oct 2022 11:33:15 -0700 -Subject: [PATCH] Add an option to fix MC-3304 (projectile looting) - - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -index 342eaa0e3b053e9b39dc58fa92cd18cac446a844..06f7bc4d8d6679d6625a8d392777722fc97739ba 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -77,6 +77,7 @@ public abstract class AbstractArrow extends Projectile { - @Nullable - private List piercedAndKilledEntities; - public ItemStack pickupItemStack; -+ public int lootingLevel; // Purpur - - // Spigot Start - @Override -@@ -655,6 +656,12 @@ public abstract class AbstractArrow extends Projectile { - this.knockback = punch; - } - -+ // Purpur start -+ public void setLootingLevel(int looting) { -+ this.lootingLevel = looting; -+ } -+ // Purpur end -+ - public int getKnockback() { - return this.knockback; - } -diff --git a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -index d27e83c08c45b8514207f26e48ceb1a91ded94be..8f01772a7b06b2acf96a3f922cb9b481f634680b 100644 ---- a/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -+++ b/src/main/java/net/minecraft/world/item/ProjectileWeaponItem.java -@@ -131,6 +131,14 @@ public abstract class ProjectileWeaponItem extends Item { - entityarrow.setPierceLevel((byte) k); - } - -+ // Purpur start -+ int lootingLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.LOOTING, weaponStack); -+ -+ if (lootingLevel > 0) { -+ entityarrow.setLootingLevel(lootingLevel); -+ } -+ // Purpur end -+ - return entityarrow; - } - -diff --git a/src/main/java/net/minecraft/world/item/TridentItem.java b/src/main/java/net/minecraft/world/item/TridentItem.java -index 85dc79b9b969fa0cbf6964cb26bac139fa55710a..905a020dd7b365d51d5addadbbeb9555d03c5238 100644 ---- a/src/main/java/net/minecraft/world/item/TridentItem.java -+++ b/src/main/java/net/minecraft/world/item/TridentItem.java -@@ -81,6 +81,14 @@ public class TridentItem extends Item implements ProjectileItem { - entitythrowntrident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; - } - -+ // Purpur start -+ int lootingLevel = EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.LOOTING, stack); -+ -+ if (lootingLevel > 0) { -+ entitythrowntrident.setLootingLevel(lootingLevel); -+ } -+ // Purpur end -+ - // CraftBukkit start - // Paper start - PlayerLaunchProjectileEvent - com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) entitythrowntrident.getBukkitEntity()); -diff --git a/src/main/java/net/minecraft/world/level/storage/loot/functions/LootingEnchantFunction.java b/src/main/java/net/minecraft/world/level/storage/loot/functions/LootingEnchantFunction.java -index cfe953bc924f46b570e37395ac0f05ebcb82eb39..5500e7ada2dd783cc1317968a3e54696bdd73bf8 100644 ---- a/src/main/java/net/minecraft/world/level/storage/loot/functions/LootingEnchantFunction.java -+++ b/src/main/java/net/minecraft/world/level/storage/loot/functions/LootingEnchantFunction.java -@@ -57,6 +57,13 @@ public class LootingEnchantFunction extends LootItemConditionalFunction { - - if (entity instanceof LivingEntity) { - int i = EnchantmentHelper.getMobLooting((LivingEntity) entity); -+ // Purpur start -+ if (org.purpurmc.purpur.PurpurConfig.fixProjectileLootingTransfer && -+ context.getParamOrNull(LootContextParams.DIRECT_KILLER_ENTITY) -+ instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) { -+ i = arrow.lootingLevel; -+ } -+ // Purpur end - // CraftBukkit start - use lootingModifier if set by plugin - if (context.hasParam(LootContextParams.LOOTING_MOD)) { - i = context.getParamOrNull(LootContextParams.LOOTING_MOD); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 62612451c23bb146e82f4082ca8677e5dc57a08f..3b3d5bd9e645f440e033abd3c234a017972efa59 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -497,4 +497,9 @@ public class PurpurConfig { - String setPattern = getString("settings.username-valid-characters", defaultPattern); - usernameValidCharactersPattern = java.util.regex.Pattern.compile(setPattern == null || setPattern.isBlank() ? defaultPattern : setPattern); - } -+ -+ public static boolean fixProjectileLootingTransfer = false; -+ private static void fixProjectileLootingTransfer() { -+ fixProjectileLootingTransfer = getBoolean("settings.fix-projectile-looting-transfer", fixProjectileLootingTransfer); -+ } - } diff --git a/patches/server/0264-Configurable-block-blast-resistance.patch b/patches/server/0264-Configurable-block-blast-resistance.patch deleted file mode 100644 index 482d21fe3..000000000 --- a/patches/server/0264-Configurable-block-blast-resistance.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Sat, 1 Oct 2022 13:29:17 -0700 -Subject: [PATCH] Configurable block blast resistance - - -diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -index 3c1091f2a729b7d06ba6e21c37f788edb2ad1775..031fc626d2075cbe0941fecc188406712ab9953f 100644 ---- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java -@@ -86,7 +86,7 @@ public abstract class BlockBehaviour implements FeatureElement { - - protected static final Direction[] UPDATE_SHAPE_ORDER = new Direction[]{Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH, Direction.DOWN, Direction.UP}; - public final boolean hasCollision; -- protected final float explosionResistance; -+ public float explosionResistance; // Purpur - protected final -> public - protected final boolean isRandomlyTicking; - protected final SoundType soundType; - protected final float friction; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 3b3d5bd9e645f440e033abd3c234a017972efa59..b2207e2baed339adb1594f19f9a3d4a709669935 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -502,4 +502,19 @@ public class PurpurConfig { - private static void fixProjectileLootingTransfer() { - fixProjectileLootingTransfer = getBoolean("settings.fix-projectile-looting-transfer", fixProjectileLootingTransfer); - } -+ -+ private static void blastResistanceSettings() { -+ getMap("settings.blast-resistance-overrides", Collections.emptyMap()).forEach((blockId, value) -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockId)); -+ if (block == Blocks.AIR) { -+ log(Level.SEVERE, "Invalid block for `settings.blast-resistance-overrides`: " + blockId); -+ return; -+ } -+ if (!(value instanceof Number blastResistance)) { -+ log(Level.SEVERE, "Invalid blast resistance for `settings.blast-resistance-overrides." + blockId + "`: " + value); -+ return; -+ } -+ block.explosionResistance = blastResistance.floatValue(); -+ }); -+ } - } diff --git a/patches/server/0265-Configurable-block-fall-damage-modifiers.patch b/patches/server/0265-Configurable-block-fall-damage-modifiers.patch deleted file mode 100644 index 541a9698e..000000000 --- a/patches/server/0265-Configurable-block-fall-damage-modifiers.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Sat, 1 Oct 2022 18:06:52 -0700 -Subject: [PATCH] Configurable block fall damage modifiers - - -diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java -index 549e3dd09a91ddf319fe0c1ec09924cbb600c1b8..a4a988ab1399702b943019e9c4e2cde3652b4e85 100644 ---- a/src/main/java/net/minecraft/world/level/block/BedBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java -@@ -181,7 +181,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock - - @Override - public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { -- super.fallOn(world, state, pos, entity, fallDistance * 0.5F); -+ super.fallOn(world, state, pos, entity, fallDistance); // Purpur - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 7ffe51eedc9d086424cf450026bdc260249864c4..5ae3decf100d21f7d4a471c155eaf5e00e996580 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -89,6 +89,10 @@ public class Block extends BlockBehaviour implements ItemLike { - public static final int UPDATE_LIMIT = 512; - protected final StateDefinition stateDefinition; - private BlockState defaultBlockState; -+ // Purpur start -+ public float fallDamageMultiplier = 1.0F; -+ public float fallDistanceMultiplier = 1.0F; -+ // Purpur end - // Paper start - public final boolean isDestroyable() { - return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || -@@ -486,7 +490,7 @@ public class Block extends BlockBehaviour implements ItemLike { - } - - public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { -- entity.causeFallDamage(fallDistance, 1.0F, entity.damageSources().fall()); -+ entity.causeFallDamage(fallDistance * fallDistanceMultiplier, fallDamageMultiplier, entity.damageSources().fall()); // Purpur - } - - public void updateEntityAfterFallOn(BlockGetter world, Entity entity) { -diff --git a/src/main/java/net/minecraft/world/level/block/HayBlock.java b/src/main/java/net/minecraft/world/level/block/HayBlock.java -index ef364aa171a48482a45bc18cfe730ec20c3f7be6..74971d90506aa253d5ee821b5390fb2551a3a393 100644 ---- a/src/main/java/net/minecraft/world/level/block/HayBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/HayBlock.java -@@ -23,6 +23,6 @@ public class HayBlock extends RotatedPillarBlock { - - @Override - public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { -- entity.causeFallDamage(fallDistance, 0.2F, world.damageSources().fall()); -+ super.fallOn(world, state, pos, entity, fallDistance); // Purpur - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index b2207e2baed339adb1594f19f9a3d4a709669935..508b094272bede66826ad0f4908f115454b7d4f2 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -517,4 +517,50 @@ public class PurpurConfig { - block.explosionResistance = blastResistance.floatValue(); - }); - } -+ private static void blockFallMultiplierSettings() { -+ getMap("settings.block-fall-multipliers", Map.ofEntries( -+ Map.entry("minecraft:hay_block", Map.of("damage", 0.2F)), -+ Map.entry("minecraft:white_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:light_gray_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:gray_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:black_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:brown_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:pink_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:red_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:orange_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:yellow_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:green_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:lime_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:cyan_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:light_blue_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:blue_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:purple_bed", Map.of("distance", 0.5F)), -+ Map.entry("minecraft:magenta_bed", Map.of("distance", 0.5F)) -+ )).forEach((blockId, value) -> { -+ Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockId)); -+ if (block == Blocks.AIR) { -+ log(Level.SEVERE, "Invalid block for `settings.block-fall-multipliers`: " + blockId); -+ return; -+ } -+ if (!(value instanceof Map map)) { -+ log(Level.SEVERE, "Invalid fall multiplier for `settings.block-fall-multipliers." + blockId + "`: " + value -+ + ", expected a map with keys `damage` and `distance` to floats."); -+ return; -+ } -+ Object rawFallDamageMultiplier = map.get("damage"); -+ if (rawFallDamageMultiplier == null) rawFallDamageMultiplier = 1F; -+ if (!(rawFallDamageMultiplier instanceof Number fallDamageMultiplier)) { -+ log(Level.SEVERE, "Invalid multiplier for `settings.block-fall-multipliers." + blockId + ".damage`: " + map.get("damage")); -+ return; -+ } -+ Object rawFallDistanceMultiplier = map.get("distance"); -+ if (rawFallDistanceMultiplier == null) rawFallDistanceMultiplier = 1F; -+ if (!(rawFallDistanceMultiplier instanceof Number fallDistanceMultiplier)) { -+ log(Level.SEVERE, "Invalid multiplier for `settings.block-fall-multipliers." + blockId + ".distance`: " + map.get("distance")); -+ return; -+ } -+ block.fallDamageMultiplier = fallDamageMultiplier.floatValue(); -+ block.fallDistanceMultiplier = fallDistanceMultiplier.floatValue(); -+ }); -+ } - } diff --git a/patches/server/0266-Language-API.patch b/patches/server/0266-Language-API.patch deleted file mode 100644 index f52f1175a..000000000 --- a/patches/server/0266-Language-API.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Sat, 1 Oct 2022 17:08:43 -0700 -Subject: [PATCH] Language API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 5285433e69cb34d0b856f3e81bf1888aa30eb6f3..19937ffa2c93cb75ea8dba58dd5a8214adc035fa 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -403,6 +403,20 @@ public final class CraftServer implements Server { - this.serverTickManager = new CraftServerTickManager(console.tickRateManager()); - - Bukkit.setServer(this); -+ // Purpur start -+ org.purpurmc.purpur.language.Language.setLanguage(new org.purpurmc.purpur.language.Language() { -+ private net.minecraft.locale.Language language = net.minecraft.locale.Language.getInstance(); -+ @Override -+ public boolean has(@org.jetbrains.annotations.NotNull String key) { -+ return language.has(key); -+ } -+ -+ @Override -+ public @org.jetbrains.annotations.NotNull String getOrDefault(@org.jetbrains.annotations.NotNull String key) { -+ return language.getOrDefault(key); -+ } -+ }); -+ // Purpur end - - CraftRegistry.setMinecraftRegistry(console.registryAccess()); - diff --git a/patches/server/0267-Milk-Keeps-Beneficial-Effects.patch b/patches/server/0267-Milk-Keeps-Beneficial-Effects.patch deleted file mode 100644 index 6014c1a99..000000000 --- a/patches/server/0267-Milk-Keeps-Beneficial-Effects.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Rhythmic -Date: Thu, 6 Oct 2022 10:41:01 -0700 -Subject: [PATCH] Milk Keeps Beneficial Effects - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 09cbc472d89d7d8730aedb76ef584b1ff159756b..53ff232129443ba3242cfc57fc57026bf76d96e8 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1154,6 +1154,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - for (flag = false; iterator.hasNext(); flag = true) { - // CraftBukkit start - MobEffectInstance effect = (MobEffectInstance) iterator.next(); -+ if (cause == EntityPotionEffectEvent.Cause.MILK && !this.level().purpurConfig.milkClearsBeneficialEffects && effect.getEffect().value().isBeneficial()) continue; // Purpur - EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause, EntityPotionEffectEvent.Action.CLEARED); - if (event.isCancelled()) { - continue; -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -index 62f5e5cfe5745deced2811d14d0c7ebb2c2c6948..c1e573758539a151452b12466339ccf8b39c7d38 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java -@@ -115,7 +115,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill - return this.canDrinkPotion && this.level().isNight() && !entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API - })); - this.goalSelector.addGoal(0, new UseItemGoal<>(this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, (entityvillagertrader) -> { -- return this.canDrinkMilk && this.level().isDay() && entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API -+ return level().purpurConfig.milkClearsBeneficialEffects && this.canDrinkMilk && this.level().isDay() && entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API // Purpur - })); - this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this)); - this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Zombie.class, 8.0F, 0.5D, 0.5D)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 7b028800a99d627a9efcd2a718e281ab7a67cfad..fabe1529ca30dabb93287dfae4cc15ea8c11f69f 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -128,6 +128,7 @@ public class PurpurWorldConfig { - public boolean fireballsBypassMobGriefing = false; - public boolean imposeTeleportRestrictionsOnGateways = false; - public boolean milkCuresBadOmen = true; -+ public boolean milkClearsBeneficialEffects = true; - public boolean noteBlockIgnoreAbove = false; - public boolean persistentDroppableEntityDisplayNames = true; - public boolean persistentTileEntityLore = false; -@@ -155,6 +156,7 @@ public class PurpurWorldConfig { - fireballsBypassMobGriefing = getBoolean("gameplay-mechanics.fireballs-bypass-mob-griefing", fireballsBypassMobGriefing); - imposeTeleportRestrictionsOnGateways = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-gateways", imposeTeleportRestrictionsOnGateways); - milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); -+ milkClearsBeneficialEffects = getBoolean("gameplay-mechanics.milk-clears-beneficial-effects", milkClearsBeneficialEffects); - noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove); - if (PurpurConfig.version < 35) { - boolean oldVal = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityLore); diff --git a/patches/server/0268-MC-121706-Fix-mobs-not-looking-up-and-down-when-stra.patch b/patches/server/0268-MC-121706-Fix-mobs-not-looking-up-and-down-when-stra.patch deleted file mode 100644 index e539f8454..000000000 --- a/patches/server/0268-MC-121706-Fix-mobs-not-looking-up-and-down-when-stra.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Krakenied -Date: Sun, 9 Oct 2022 01:50:39 +0200 -Subject: [PATCH] MC-121706 - Fix mobs not looking up and down when strafing - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java -index 515c1f671cb2c3a7cc23053aedf404bbbe77af3e..42a1e5b9c08a9245dd0ce6d4025e3bb5d60feb62 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java -@@ -116,9 +116,9 @@ public class RangedBowAttackGoal extends Go - } - - this.mob.lookAt(livingEntity, 30.0F, 30.0F); -- } else { -+ } //else { // Purpur - fix MC-121706 - this.mob.getLookControl().setLookAt(livingEntity, 30.0F, 30.0F); -- } -+ //} // Purpur - - if (this.mob.isUsingItem()) { - if (!bl && this.seeTime < -60) { diff --git a/patches/server/0269-Add-log-suppression-for-LibraryLoader.patch b/patches/server/0269-Add-log-suppression-for-LibraryLoader.patch deleted file mode 100644 index 88afdd468..000000000 --- a/patches/server/0269-Add-log-suppression-for-LibraryLoader.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Krakenied -Date: Fri, 14 Oct 2022 23:11:16 +0200 -Subject: [PATCH] Add log suppression for LibraryLoader - - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 508b094272bede66826ad0f4908f115454b7d4f2..16273aec24a4824557c0cfb2af2ac782a7a7ab75 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -470,11 +470,14 @@ public class PurpurConfig { - public static boolean loggerSuppressIgnoredAdvancementWarnings = false; - public static boolean loggerSuppressUnrecognizedRecipeErrors = false; - public static boolean loggerSuppressSetBlockFarChunk = false; -+ public static boolean loggerSuppressLibraryLoader = false; - private static void loggerSettings() { - loggerSuppressInitLegacyMaterialError = getBoolean("settings.logger.suppress-init-legacy-material-errors", loggerSuppressInitLegacyMaterialError); - loggerSuppressIgnoredAdvancementWarnings = getBoolean("settings.logger.suppress-ignored-advancement-warnings", loggerSuppressIgnoredAdvancementWarnings); - loggerSuppressUnrecognizedRecipeErrors = getBoolean("settings.logger.suppress-unrecognized-recipe-errors", loggerSuppressUnrecognizedRecipeErrors); - loggerSuppressSetBlockFarChunk = getBoolean("settings.logger.suppress-setblock-in-far-chunk-errors", loggerSuppressSetBlockFarChunk); -+ loggerSuppressLibraryLoader = getBoolean("settings.logger.suppress-library-loader", loggerSuppressLibraryLoader); -+ org.bukkit.plugin.java.JavaPluginLoader.SuppressLibraryLoaderLogger = loggerSuppressLibraryLoader; - } - - public static boolean tpsCatchup = true; diff --git a/patches/server/0270-Add-option-to-allow-creeper-to-encircle-target-when-.patch b/patches/server/0270-Add-option-to-allow-creeper-to-encircle-target-when-.patch deleted file mode 100644 index 9e62843de..000000000 --- a/patches/server/0270-Add-option-to-allow-creeper-to-encircle-target-when-.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jared Seville -Date: Sat, 15 Oct 2022 16:01:03 -0700 -Subject: [PATCH] Add option to allow creeper to encircle target when fusing. - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java -index 137ec75ee803789deb7b1ca93dd9369c9af362b9..ca95d25af3e9a0536868b0c7fd8e7d2ff1154ee3 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/SwellGoal.java -@@ -54,6 +54,14 @@ public class SwellGoal extends Goal { - this.creeper.setSwellDir(-1); - } else { - this.creeper.setSwellDir(1); -+ // Purpur start -+ if (this.creeper.level().purpurConfig.creeperEncircleTarget) { -+ net.minecraft.world.phys.Vec3 relative = this.creeper.position().subtract(this.target.position()); -+ relative = relative.yRot((float) Math.PI / 3).normalize().multiply(2, 2, 2); -+ net.minecraft.world.phys.Vec3 destination = this.target.position().add(relative); -+ this.creeper.getNavigation().moveTo(destination.x, destination.y, destination.z, 1); -+ } -+ // Purpur end - } - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index fabe1529ca30dabb93287dfae4cc15ea8c11f69f..6d4d76eff2372edd7ecceb619c3b6650bd779fa2 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1418,6 +1418,7 @@ public class PurpurWorldConfig { - public boolean creeperHealthRadius = false; - public boolean creeperAlwaysDropExp = false; - public double creeperHeadVisibilityPercent = 0.5D; -+ public boolean creeperEncircleTarget = false; - private void creeperSettings() { - creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); - creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); -@@ -1436,6 +1437,7 @@ public class PurpurWorldConfig { - creeperHealthRadius = getBoolean("mobs.creeper.health-impacts-explosion", creeperHealthRadius); - creeperAlwaysDropExp = getBoolean("mobs.creeper.always-drop-exp", creeperAlwaysDropExp); - creeperHeadVisibilityPercent = getDouble("mobs.creeper.head-visibility-percent", creeperHeadVisibilityPercent); -+ creeperEncircleTarget = getBoolean("mobs.creeper.encircle-target", creeperEncircleTarget); - } - - public boolean dolphinRidable = false; diff --git a/patches/server/0271-Fire-Immunity-API.patch b/patches/server/0271-Fire-Immunity-API.patch deleted file mode 100644 index 2a3980e0f..000000000 --- a/patches/server/0271-Fire-Immunity-API.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Racci <90304606+DaRacci@users.noreply.github.com> -Date: Fri, 4 Feb 2022 16:10:21 +1100 -Subject: [PATCH] Fire Immunity API - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 2c3ad553272ad651e6ca26917719e6d9fffdef68..7a27388b5155e7b2478b0daa02cb616829a5d4a2 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -427,6 +427,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - private UUID originWorld; - public boolean freezeLocked = false; // Paper - Freeze Tick Lock API - public boolean fixedPose = false; // Paper - Expand Pose API -+ public @Nullable Boolean immuneToFire = null; // Purpur - Fire immune API - - public void setOrigin(@javax.annotation.Nonnull Location location) { - this.origin = location.toVector(); -@@ -1878,7 +1879,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - } - - public boolean fireImmune() { -- return this.getType().fireImmune(); -+ return this.immuneToFire != null ? immuneToFire : this.getType().fireImmune(); // Purpur - add fire immune API - } - - public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { -@@ -2575,6 +2576,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - nbttagcompound.putBoolean("Paper.FreezeLock", true); - } - // Paper end -+ // Purpur start -+ if (immuneToFire != null) { -+ nbttagcompound.putBoolean("Purpur.FireImmune", immuneToFire); -+ } -+ // Purpur end - return nbttagcompound; - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT"); -@@ -2722,6 +2728,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - freezeLocked = nbt.getBoolean("Paper.FreezeLock"); - } - // Paper end -+ // Purpur start -+ if (nbt.contains("Purpur.FireImmune")) { -+ immuneToFire = nbt.getBoolean("Purpur.FireImmune"); -+ } -+ // Purpur end - - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT"); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 3c674ecd3b80501047b4593e8872034287defd2e..0ed18542fd8e2a992dc56a5f421eaa840e0af193 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -84,6 +84,16 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - this.entityType = CraftEntityType.minecraftToBukkit(entity.getType()); - } - -+ @Override -+ public boolean isImmuneToFire() { -+ return getHandle().fireImmune(); -+ } -+ -+ @Override -+ public void setImmuneToFire(Boolean fireImmune) { -+ getHandle().immuneToFire = fireImmune; -+ } -+ - @Override - public boolean isInDaylight() { - return getHandle().isSunBurnTick(); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -index 01e4395f1669d21c30465aa1366bd2f1ae17678f..5c1cda88080850314dac196dbe71ff12e48a8aca 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -@@ -173,9 +173,14 @@ public class CraftItem extends CraftEntity implements Item { - return this.getHandle().immuneToExplosion; - } - -+ @Override -+ public void setImmuneToFire(@org.jetbrains.annotations.Nullable Boolean immuneToFire) { -+ this.getHandle().immuneToFire = (immuneToFire != null && immuneToFire); -+ } -+ - @Override - public void setImmuneToFire(boolean immuneToFire) { -- item.immuneToFire = immuneToFire; -+ this.setImmuneToFire((Boolean) immuneToFire); - } - - @Override diff --git a/patches/server/0272-Add-option-to-teleport-to-spawn-on-nether-ceiling-da.patch b/patches/server/0272-Add-option-to-teleport-to-spawn-on-nether-ceiling-da.patch deleted file mode 100644 index 5935e653e..000000000 --- a/patches/server/0272-Add-option-to-teleport-to-spawn-on-nether-ceiling-da.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 13 Nov 2022 05:05:34 -0600 -Subject: [PATCH] Add option to teleport to spawn on nether ceiling damage - - -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 7a27388b5155e7b2478b0daa02cb616829a5d4a2..3aae4fa4176c0bf170f4532ae187e3122c142a6a 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -972,6 +972,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> this.getY() >= v) - && (!(this instanceof Player player) || !player.getAbilities().invulnerable))) { - // Paper end - Configurable nether ceiling damage -+ if (this.level().purpurConfig.teleportOnNetherCeilingDamage && this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER && this instanceof ServerPlayer player) player.teleport(io.papermc.paper.util.MCUtil.toLocation(this.level, this.level.getSharedSpawnPos())); else // Purpur - this.onBelowWorld(); - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 6d4d76eff2372edd7ecceb619c3b6650bd779fa2..7a86b8a64d79128176cf0c40133494d88a50a561 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -425,6 +425,7 @@ public class PurpurWorldConfig { - public String playerDeathExpDropEquation = "expLevel * 7"; - public int playerDeathExpDropMax = 100; - public boolean teleportIfOutsideBorder = false; -+ public boolean teleportOnNetherCeilingDamage = false; - public boolean totemOfUndyingWorksInInventory = false; - public boolean playerFixStuckPortal = false; - public boolean creativeOnePunch = false; -@@ -452,6 +453,7 @@ public class PurpurWorldConfig { - playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation); - playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax); - teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); -+ teleportOnNetherCeilingDamage = getBoolean("gameplay-mechanics.player.teleport-on-nether-ceiling-damage", teleportOnNetherCeilingDamage); - totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory); - playerFixStuckPortal = getBoolean("gameplay-mechanics.player.fix-stuck-in-portal", playerFixStuckPortal); - creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); diff --git a/patches/server/0273-Added-got-ram-event.patch b/patches/server/0273-Added-got-ram-event.patch deleted file mode 100644 index 9809d3a17..000000000 --- a/patches/server/0273-Added-got-ram-event.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SageSphinx63920 -Date: Sat, 29 Oct 2022 00:06:41 +0200 -Subject: [PATCH] Added got ram event - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 4e855055abe4d300b6b126e8a9deecaab5827a33..6a3c68839d3b993c82fabd4e17f53e38ce9c38f7 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -427,6 +427,7 @@ public class Goat extends Animal { - - // Paper start - Goat ram API - public void ram(net.minecraft.world.entity.LivingEntity entity) { -+ if(!new org.purpurmc.purpur.event.entity.GoatRamEntityEvent((org.bukkit.entity.Goat) getBukkitEntity(), (org.bukkit.entity.LivingEntity) entity.getBukkitLivingEntity()).callEvent()) return; // Purpur - Brain brain = this.getBrain(); - brain.setMemory(MemoryModuleType.RAM_TARGET, entity.position()); - brain.eraseMemory(MemoryModuleType.RAM_COOLDOWN_TICKS); diff --git a/patches/server/0274-Log-skipped-entity-s-position.patch b/patches/server/0274-Log-skipped-entity-s-position.patch deleted file mode 100644 index 19da920bc..000000000 --- a/patches/server/0274-Log-skipped-entity-s-position.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Thu, 24 Nov 2022 11:00:37 -0600 -Subject: [PATCH] Log skipped entity's position - - -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index 3097529a9066841a58c899ce55b3bc0cd6af7e88..8120f39a9689dae1233b243b74825e9ff110eac3 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -625,6 +625,12 @@ public class EntityType implements FeatureElement, EntityTypeT - entity.load(nbt); - }, () -> { - EntityType.LOGGER.warn("Skipping Entity with id {}", nbt.getString("id")); -+ // Purpur start - log skipped entity's position -+ try { -+ ListTag pos = nbt.getList("Pos", 6); -+ EntityType.LOGGER.warn("Location: {} {},{},{}", world.getWorld().getName(), pos.getDouble(0), pos.getDouble(1), pos.getDouble(2)); -+ } catch (Throwable ignore) {} -+ // Purpur end - }); - } - diff --git a/patches/server/0275-End-Crystal-Cramming.patch b/patches/server/0275-End-Crystal-Cramming.patch deleted file mode 100644 index 52622f80c..000000000 --- a/patches/server/0275-End-Crystal-Cramming.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Thu, 15 Dec 2022 11:42:15 -0600 -Subject: [PATCH] End Crystal Cramming - - -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -index 8c6ce06a1845832c8b0de654657788d2daf6b71b..15ca426701f1fc821da94a4dee577fdbc4f8ff8d 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -@@ -100,6 +100,7 @@ public class EndCrystal extends Entity { - } - } - // Paper end - Fix invulnerable end crystals -+ if (this.level().purpurConfig.endCrystalCramming > 0 && this.level().getEntitiesOfClass(EndCrystal.class, getBoundingBox()).size() > this.level().purpurConfig.endCrystalCramming) this.hurt(this.damageSources().cramming(), 6.0F); // Purpur - } - - // Purpur start -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 7a86b8a64d79128176cf0c40133494d88a50a561..c89ca099f47450b78402af968ef6b8fdd82f7c75 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -956,6 +956,7 @@ public class PurpurWorldConfig { - public double basedEndCrystalExplosionPower = 6.0D; - public boolean basedEndCrystalExplosionFire = false; - public net.minecraft.world.level.Level.ExplosionInteraction basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; -+ public int endCrystalCramming = 0; - private void endCrystalSettings() { - if (PurpurConfig.version < 31) { - if ("DESTROY".equals(getString("blocks.end-crystal.baseless.explosion-effect", baselessEndCrystalExplosionEffect.name()))) { -@@ -983,6 +984,7 @@ public class PurpurWorldConfig { - log(Level.SEVERE, "Unknown value for `blocks.end-crystal.base.explosion-effect`! Using default of `BLOCK`"); - basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; - } -+ endCrystalCramming = getInt("blocks.end-crystal.cramming-amount", endCrystalCramming); - } - - public boolean farmlandBypassMobGriefing = false; diff --git a/patches/server/0276-Option-to-allow-beacon-effects-when-covered-by-tinte.patch b/patches/server/0276-Option-to-allow-beacon-effects-when-covered-by-tinte.patch deleted file mode 100644 index 3932a3d94..000000000 --- a/patches/server/0276-Option-to-allow-beacon-effects-when-covered-by-tinte.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: 12emin34 -Date: Mon, 26 Dec 2022 19:10:43 +0100 -Subject: [PATCH] Option to allow beacon effects when covered by tinted glass - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index 2b9cc89a2e71b523c90bbfa987b0f8352efff95a..5ad48d2003fbd83e60f6faa68532496131935828 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -178,6 +178,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - int j = pos.getY(); - int k = pos.getZ(); - BlockPos blockposition1; -+ boolean isTintedGlass = false; - - if (blockEntity.lastCheckY < j) { - blockposition1 = pos; -@@ -211,6 +212,9 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - } - } - } else { -+ if (world.purpurConfig.beaconAllowEffectsWithTintedGlass && block.equals(Blocks.TINTED_GLASS)) { -+ isTintedGlass = true; -+ } - if (tileentitybeacon_beaconcolortracker == null || iblockdata1.getLightBlock(world, blockposition1) >= 15 && !iblockdata1.is(Blocks.BEDROCK)) { - blockEntity.checkingBeamSections.clear(); - blockEntity.lastCheckY = l; -@@ -230,7 +234,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - blockEntity.levels = BeaconBlockEntity.updateBase(world, i, j, k); - } - -- if (blockEntity.levels > 0 && !blockEntity.beamSections.isEmpty()) { -+ if (blockEntity.levels > 0 && (!blockEntity.beamSections.isEmpty() || (world.purpurConfig.beaconAllowEffectsWithTintedGlass && isTintedGlass))) { - BeaconBlockEntity.applyEffects(world, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower, blockEntity); // Paper - Custom beacon ranges - BeaconBlockEntity.playSound(world, pos, SoundEvents.BEACON_AMBIENT); - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index c89ca099f47450b78402af968ef6b8fdd82f7c75..5e92560383bed578e0f4ece60dc1758913a9fd91 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -855,11 +855,13 @@ public class PurpurWorldConfig { - public int beaconLevelTwo = 30; - public int beaconLevelThree = 40; - public int beaconLevelFour = 50; -+ public boolean beaconAllowEffectsWithTintedGlass = false; - private void beaconSettings() { - beaconLevelOne = getInt("blocks.beacon.effect-range.level-1", beaconLevelOne); - beaconLevelTwo = getInt("blocks.beacon.effect-range.level-2", beaconLevelTwo); - beaconLevelThree = getInt("blocks.beacon.effect-range.level-3", beaconLevelThree); - beaconLevelFour = getInt("blocks.beacon.effect-range.level-4", beaconLevelFour); -+ beaconAllowEffectsWithTintedGlass = getBoolean("blocks.beacon.allow-effects-with-tinted-glass", beaconAllowEffectsWithTintedGlass); - } - - public boolean bedExplode = true; diff --git a/patches/server/0277-Add-attribute-clamping-and-armor-limit-config.patch b/patches/server/0277-Add-attribute-clamping-and-armor-limit-config.patch deleted file mode 100644 index 8eba08dd9..000000000 --- a/patches/server/0277-Add-attribute-clamping-and-armor-limit-config.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Thu, 27 Oct 2022 23:12:45 -0400 -Subject: [PATCH] Add attribute clamping and armor limit config - - -diff --git a/src/main/java/net/minecraft/world/damagesource/CombatRules.java b/src/main/java/net/minecraft/world/damagesource/CombatRules.java -index ddc880ac0c8378bc1132be5deba746c1484c941c..7a8e4b9a9f2e1e5a9c38ad330c75df1f880d3e8b 100644 ---- a/src/main/java/net/minecraft/world/damagesource/CombatRules.java -+++ b/src/main/java/net/minecraft/world/damagesource/CombatRules.java -@@ -12,7 +12,7 @@ public class CombatRules { - - public static float getDamageAfterAbsorb(float damage, DamageSource source, float armor, float armorToughnesss) { - float f = 2.0F + armorToughnesss / 4.0F; -- float g = Mth.clamp(armor - damage / f, armor * 0.2F, 20.0F); -+ float g = Mth.clamp(armor - damage / f, armor * 0.2F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur - float h = g / 25.0F; - float i = EnchantmentHelper.calculateArmorBreach(source.getEntity(), h); - float j = 1.0F - i; -@@ -20,7 +20,7 @@ public class CombatRules { - } - - public static float getDamageAfterMagicAbsorb(float damageDealt, float protection) { -- float f = Mth.clamp(protection, 0.0F, 20.0F); -+ float f = Mth.clamp(protection, 0.0F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur - return damageDealt * (1.0F - f / 25.0F); - } - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/RangedAttribute.java b/src/main/java/net/minecraft/world/entity/ai/attributes/RangedAttribute.java -index f0703302e7dbbda88de8c648d20d87c55ed9b1e0..a913ebabaa5f443afa987b972355a8f8d1723c78 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/attributes/RangedAttribute.java -+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/RangedAttribute.java -@@ -29,6 +29,7 @@ public class RangedAttribute extends Attribute { - - @Override - public double sanitizeValue(double value) { -+ if (!org.purpurmc.purpur.PurpurConfig.clampAttributes) return Double.isNaN(value) ? this.minValue : value; // Purpur - return Double.isNaN(value) ? this.minValue : Mth.clamp(value, this.minValue, this.maxValue); - } - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 16273aec24a4824557c0cfb2af2ac782a7a7ab75..e7bce4121f7bc2fe0acd8860a73c58dfed73330b 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -506,6 +506,16 @@ public class PurpurConfig { - fixProjectileLootingTransfer = getBoolean("settings.fix-projectile-looting-transfer", fixProjectileLootingTransfer); - } - -+ public static boolean clampAttributes = true; -+ private static void clampAttributes() { -+ clampAttributes = getBoolean("settings.clamp-attributes", clampAttributes); -+ } -+ -+ public static boolean limitArmor = true; -+ private static void limitArmor() { -+ limitArmor = getBoolean("settings.limit-armor", limitArmor); -+ } -+ - private static void blastResistanceSettings() { - getMap("settings.blast-resistance-overrides", Collections.emptyMap()).forEach((blockId, value) -> { - Block block = BuiltInRegistries.BLOCK.get(new ResourceLocation(blockId)); diff --git a/patches/server/0278-Config-to-remove-explosion-radius-clamp.patch b/patches/server/0278-Config-to-remove-explosion-radius-clamp.patch deleted file mode 100644 index f846613e7..000000000 --- a/patches/server/0278-Config-to-remove-explosion-radius-clamp.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nico314159 -Date: Mon, 9 Jan 2023 19:45:55 -0500 -Subject: [PATCH] Config to remove explosion radius clamp - - -diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index 6379b3b8e633d1a16532b4664e53fa5afa616ab6..69d8ff6a97335b6fe4b20a8229a77f2591b0f050 100644 ---- a/src/main/java/net/minecraft/world/level/Explosion.java -+++ b/src/main/java/net/minecraft/world/level/Explosion.java -@@ -98,7 +98,7 @@ public class Explosion { - this.hitPlayers = Maps.newHashMap(); - this.level = world; - this.source = entity; -- this.radius = (float) Math.max(power, 0.0); // CraftBukkit - clamp bad values -+ this.radius = (float) (world == null || world.purpurConfig.explosionClampRadius ? Math.max(power, 0.0) : power); // CraftBukkit - clamp bad values // Purpur - this.x = x; - this.y = y; - this.z = z; -@@ -426,7 +426,7 @@ public class Explosion { - - public void explode() { - // CraftBukkit start -- if (this.radius < 0.1F) { -+ if ((this.level == null || this.level.purpurConfig.explosionClampRadius) && this.radius < 0.1F) { // Purpur - return; - } - // CraftBukkit end -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 5e92560383bed578e0f4ece60dc1758913a9fd91..5b658bb3d48c9fb8e080728a89fb931c7be978a6 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -221,6 +221,11 @@ public class PurpurWorldConfig { - entitySharedRandom = getBoolean("settings.entity.shared-random", entitySharedRandom); - } - -+ public boolean explosionClampRadius = true; -+ private void explosionSettings() { -+ explosionClampRadius = getBoolean("gameplay-mechanics.clamp-explosion-radius", explosionClampRadius); -+ } -+ - public boolean infinityWorksWithoutArrows = false; - public boolean infinityWorksWithNormalArrows = true; - public boolean infinityWorksWithSpectralArrows = false; diff --git a/patches/server/0279-bonemealable-sugarcane-cactus-and-netherwart.patch b/patches/server/0279-bonemealable-sugarcane-cactus-and-netherwart.patch deleted file mode 100644 index 78c156054..000000000 --- a/patches/server/0279-bonemealable-sugarcane-cactus-and-netherwart.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Thu, 9 Feb 2023 00:28:03 -0800 -Subject: [PATCH] bonemealable sugarcane, cactus, and netherwart - - -diff --git a/src/main/java/net/minecraft/world/level/block/CactusBlock.java b/src/main/java/net/minecraft/world/level/block/CactusBlock.java -index 9200d75b05ce535f7b7f5c1572cd8f6261c6955b..066181ed274a492762baebf05bf51ac7848878cc 100644 ---- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java -@@ -23,7 +23,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; - import net.minecraft.world.phys.shapes.VoxelShape; - import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit - --public class CactusBlock extends Block { -+public class CactusBlock extends Block implements BonemealableBlock { // Purpur - - public static final MapCodec CODEC = simpleCodec(CactusBlock::new); - public static final IntegerProperty AGE = BlockStateProperties.AGE_15; -@@ -134,4 +134,34 @@ public class CactusBlock extends Block { - protected boolean isPathfindable(BlockState state, PathComputationType type) { - return false; - } -+ -+ // Purpur start -+ @Override -+ public boolean isValidBonemealTarget(final LevelReader world, final BlockPos pos, final BlockState state) { -+ if (!((Level) world).purpurConfig.cactusAffectedByBonemeal || !world.isEmptyBlock(pos.above())) return false; -+ -+ int cactusHeight = 0; -+ while (world.getBlockState(pos.below(cactusHeight)).is(this)) { -+ cactusHeight++; -+ } -+ -+ return cactusHeight < ((Level) world).paperConfig().maxGrowthHeight.cactus; -+ } -+ -+ @Override -+ public boolean isBonemealSuccess(Level world, RandomSource random, BlockPos pos, BlockState state) { -+ return true; -+ } -+ -+ @Override -+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { -+ int cactusHeight = 0; -+ while (world.getBlockState(pos.below(cactusHeight)).is(this)) { -+ cactusHeight++; -+ } -+ for (int i = 0; i <= world.paperConfig().maxGrowthHeight.cactus - cactusHeight; i++) { -+ world.setBlockAndUpdate(pos.above(i), state.setValue(CactusBlock.AGE, 0)); -+ } -+ } -+ // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java -index da1c7999ca64199387054de46489d3ff4a299289..b8355ea1de26c4b6905f477fb4e110f1762447b4 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherWartBlock.java -@@ -16,7 +16,7 @@ import net.minecraft.world.level.block.state.properties.IntegerProperty; - import net.minecraft.world.phys.shapes.CollisionContext; - import net.minecraft.world.phys.shapes.VoxelShape; - --public class NetherWartBlock extends BushBlock { -+public class NetherWartBlock extends BushBlock implements BonemealableBlock { // Purpur - - public static final MapCodec CODEC = simpleCodec(NetherWartBlock::new); - public static final int MAX_AGE = 3; -@@ -78,5 +78,22 @@ public class NetherWartBlock extends BushBlock { - super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp); - } - } -+ -+ @Override -+ public boolean isValidBonemealTarget(final net.minecraft.world.level.LevelReader world, final BlockPos pos, final BlockState state) { -+ return ((net.minecraft.world.level.Level) world).purpurConfig.netherWartAffectedByBonemeal && state.getValue(NetherWartBlock.AGE) < 3; -+ } -+ -+ @Override -+ public boolean isBonemealSuccess(net.minecraft.world.level.Level world, RandomSource random, BlockPos pos, BlockState state) { -+ return true; -+ } -+ -+ @Override -+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { -+ int i = Math.min(3, state.getValue(NetherWartBlock.AGE) + 1); -+ state = state.setValue(NetherWartBlock.AGE, i); -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, state, 2); // CraftBukkit -+ } - // Purpur end - } -diff --git a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java -index c48c622e92cedeaa46b929c7adfedec98dd5a3fb..6449b5c424443b5f0ee7e3fce803449418fbed2a 100644 ---- a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java -@@ -20,7 +20,7 @@ import net.minecraft.world.level.material.FluidState; - import net.minecraft.world.phys.shapes.CollisionContext; - import net.minecraft.world.phys.shapes.VoxelShape; - --public class SugarCaneBlock extends Block { -+public class SugarCaneBlock extends Block implements BonemealableBlock { // Purpur - - public static final MapCodec CODEC = simpleCodec(SugarCaneBlock::new); - public static final IntegerProperty AGE = BlockStateProperties.AGE_15; -@@ -113,4 +113,34 @@ public class SugarCaneBlock extends Block { - protected void createBlockStateDefinition(StateDefinition.Builder builder) { - builder.add(SugarCaneBlock.AGE); - } -+ -+ // Purpur start -+ @Override -+ public boolean isValidBonemealTarget(final LevelReader world, final BlockPos pos, final BlockState state) { -+ if (!((net.minecraft.world.level.Level) world).purpurConfig.sugarCanAffectedByBonemeal || !world.isEmptyBlock(pos.above())) return false; -+ -+ int reedHeight = 0; -+ while (world.getBlockState(pos.below(reedHeight)).is(this)) { -+ reedHeight++; -+ } -+ -+ return reedHeight < ((net.minecraft.world.level.Level) world).paperConfig().maxGrowthHeight.reeds; -+ } -+ -+ @Override -+ public boolean isBonemealSuccess(net.minecraft.world.level.Level world, RandomSource random, BlockPos pos, BlockState state) { -+ return true; -+ } -+ -+ @Override -+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { -+ int reedHeight = 0; -+ while (world.getBlockState(pos.below(reedHeight)).is(this)) { -+ reedHeight++; -+ } -+ for (int i = 0; i <= world.paperConfig().maxGrowthHeight.reeds - reedHeight; i++) { -+ world.setBlockAndUpdate(pos.above(i), state.setValue(SugarCaneBlock.AGE, 0)); -+ } -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 5b658bb3d48c9fb8e080728a89fb931c7be978a6..8c7508fc6163a73740aedbe9c4dee2d21c4fa0fa 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -909,8 +909,20 @@ public class PurpurWorldConfig { - } - - public boolean cactusBreaksFromSolidNeighbors = true; -+ public boolean cactusAffectedByBonemeal = false; - private void cactusSettings() { - cactusBreaksFromSolidNeighbors = getBoolean("blocks.cactus.breaks-from-solid-neighbors", cactusBreaksFromSolidNeighbors); -+ cactusAffectedByBonemeal = getBoolean("blocks.cactus.affected-by-bonemeal", cactusAffectedByBonemeal); -+ } -+ -+ public boolean sugarCanAffectedByBonemeal = false; -+ private void sugarCaneSettings() { -+ sugarCanAffectedByBonemeal = getBoolean("blocks.sugar_cane.affected-by-bonemeal", sugarCanAffectedByBonemeal); -+ } -+ -+ public boolean netherWartAffectedByBonemeal = false; -+ private void netherWartSettings() { -+ netherWartAffectedByBonemeal = getBoolean("blocks.nether_wart.affected-by-bonemeal", netherWartAffectedByBonemeal); - } - - public boolean campFireLitWhenPlaced = true; diff --git a/patches/server/0280-Add-PreExplodeEvents.patch b/patches/server/0280-Add-PreExplodeEvents.patch deleted file mode 100644 index 1b502ebb6..000000000 --- a/patches/server/0280-Add-PreExplodeEvents.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SageSphinx63920 -Date: Mon, 26 Dec 2022 23:42:37 +0100 -Subject: [PATCH] Add PreExplodeEvents - - -diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index 69d8ff6a97335b6fe4b20a8229a77f2591b0f050..f5e84bf8817e2d53557e0909d8c9e0e0e8206a16 100644 ---- a/src/main/java/net/minecraft/world/level/Explosion.java -+++ b/src/main/java/net/minecraft/world/level/Explosion.java -@@ -430,6 +430,25 @@ public class Explosion { - return; - } - // CraftBukkit end -+ -+ // Purpur start - add PreExplodeEvents -+ if(this.source != null){ -+ Location location = new Location(this.level.getWorld(), this.x, this.y, this.z); -+ if(!new org.purpurmc.purpur.event.entity.PreEntityExplodeEvent(this.source.getBukkitEntity(), location, this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F).callEvent()) { -+ this.wasCanceled = true; -+ return; -+ } -+ }else { -+ Location location = new Location(this.level.getWorld(), this.x, this.y, this.z); -+ org.bukkit.block.Block block = location.getBlock(); -+ org.bukkit.block.BlockState blockState = (this.damageSource.blockState != null) ? this.damageSource.blockState : block.getState(); -+ if(!new org.purpurmc.purpur.event.PreBlockExplodeEvent(location.getBlock(), this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, blockState).callEvent()) { -+ this.wasCanceled = true; -+ return; -+ } -+ } -+ //Purpur end -+ - this.level.gameEvent(this.source, (Holder) GameEvent.EXPLODE, new Vec3(this.x, this.y, this.z)); - Set set = Sets.newHashSet(); - boolean flag = true; diff --git a/patches/server/0283-Make-GUI-Great-Again.patch b/patches/server/0283-Make-GUI-Great-Again.patch deleted file mode 100644 index 758d27fe1..000000000 --- a/patches/server/0283-Make-GUI-Great-Again.patch +++ /dev/null @@ -1,421 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Thu, 16 Jan 2020 14:59:16 -0600 -Subject: [PATCH] Make GUI Great Again - - -diff --git a/src/log4jPlugins/java/org/purpurmc/purpur/gui/HighlightErrorConverter.java b/src/log4jPlugins/java/org/purpurmc/purpur/gui/HighlightErrorConverter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..15a226e3854d731f7724025ea3459c8ace07630c ---- /dev/null -+++ b/src/log4jPlugins/java/org/purpurmc/purpur/gui/HighlightErrorConverter.java -@@ -0,0 +1,85 @@ -+package org.purpurmc.purpur.gui.util; -+ -+import org.apache.logging.log4j.Level; -+import org.apache.logging.log4j.core.LogEvent; -+import org.apache.logging.log4j.core.config.Configuration; -+import org.apache.logging.log4j.core.config.plugins.Plugin; -+import org.apache.logging.log4j.core.layout.PatternLayout; -+import org.apache.logging.log4j.core.pattern.ConverterKeys; -+import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; -+import org.apache.logging.log4j.core.pattern.PatternConverter; -+import org.apache.logging.log4j.core.pattern.PatternFormatter; -+import org.apache.logging.log4j.core.pattern.PatternParser; -+import org.apache.logging.log4j.util.PerformanceSensitive; -+ -+import java.util.List; -+ -+@Plugin(name = "highlightGUIError", category = PatternConverter.CATEGORY) -+@ConverterKeys({"highlightGUIError"}) -+@PerformanceSensitive("allocation") -+public final class HighlightErrorConverter extends LogEventPatternConverter { -+ private static final String ERROR = "\u00A74\u00A7l"; // Bold Red -+ private static final String WARN = "\u00A7e\u00A7l"; // Bold Yellow -+ -+ private final List formatters; -+ -+ private HighlightErrorConverter(List formatters) { -+ super("highlightGUIError", null); -+ this.formatters = formatters; -+ } -+ -+ @Override -+ public void format(LogEvent event, StringBuilder toAppendTo) { -+ Level level = event.getLevel(); -+ if (level.isMoreSpecificThan(Level.ERROR)) { -+ format(ERROR, event, toAppendTo); -+ return; -+ } else if (level.isMoreSpecificThan(Level.WARN)) { -+ format(WARN, event, toAppendTo); -+ return; -+ } -+ for (PatternFormatter formatter : formatters) { -+ formatter.format(event, toAppendTo); -+ } -+ } -+ -+ private void format(String style, LogEvent event, StringBuilder toAppendTo) { -+ int start = toAppendTo.length(); -+ toAppendTo.append(style); -+ int end = toAppendTo.length(); -+ -+ for (PatternFormatter formatter : formatters) { -+ formatter.format(event, toAppendTo); -+ } -+ -+ if (toAppendTo.length() == end) { -+ toAppendTo.setLength(start); -+ } -+ } -+ -+ @Override -+ public boolean handlesThrowable() { -+ for (final PatternFormatter formatter : formatters) { -+ if (formatter.handlesThrowable()) { -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ public static HighlightErrorConverter newInstance(Configuration config, String[] options) { -+ if (options.length != 1) { -+ LOGGER.error("Incorrect number of options on highlightGUIError. Expected 1 received " + options.length); -+ return null; -+ } -+ -+ if (options[0] == null) { -+ LOGGER.error("No pattern supplied on highlightGUIError"); -+ return null; -+ } -+ -+ PatternParser parser = PatternLayout.createPatternParser(config); -+ List formatters = parser.parse(options[0]); -+ return new HighlightErrorConverter(formatters); -+ } -+} -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 0d2d254fc2795f0ec844029bd4c05cdf6dc94207..775c5de4f5094260096cef6723dd50dfe2cb0c81 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -110,6 +110,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - return; - } - // Paper start - Use TerminalConsoleAppender -+ if (DedicatedServer.this.gui == null || System.console() != null) // Purpur - has no GUI or has console (did not double-click) - new com.destroystokyo.paper.console.PaperConsole(DedicatedServer.this).start(); - /* - jline.console.ConsoleReader bufferedreader = DedicatedServer.this.reader; -diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -index 759062d219ff490a3cb19e710c4d18e3e08288e0..8f74c2ec5252b6265549589310d742337c91cb2c 100644 ---- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -+++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java -@@ -43,6 +43,11 @@ public class MinecraftServerGui extends JComponent { - private Thread logAppenderThread; - private final Collection finalizers = Lists.newArrayList(); - final AtomicBoolean isClosing = new AtomicBoolean(); -+ // Purpur start -+ private final CommandHistory history = new CommandHistory(); -+ private String currentCommand = ""; -+ private int historyIndex = 0; -+ // Purpur end - - public static MinecraftServerGui showFrameFor(final DedicatedServer server) { - try { -@@ -51,7 +56,7 @@ public class MinecraftServerGui extends JComponent { - ; - } - -- final JFrame jframe = new JFrame("Minecraft server"); -+ final JFrame jframe = new JFrame("Purpur Minecraft server"); // Purpur - final MinecraftServerGui servergui = new MinecraftServerGui(server); - - jframe.setDefaultCloseOperation(2); -@@ -59,7 +64,7 @@ public class MinecraftServerGui extends JComponent { - jframe.pack(); - jframe.setLocationRelativeTo((Component) null); - jframe.setVisible(true); -- jframe.setName("Minecraft server"); // Paper - Improve ServerGUI -+ jframe.setName("Purpur Minecraft server"); // Paper - Improve ServerGUI // Purpur - - // Paper start - Improve ServerGUI - try { -@@ -71,7 +76,7 @@ public class MinecraftServerGui extends JComponent { - jframe.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent windowevent) { - if (!servergui.isClosing.getAndSet(true)) { -- jframe.setTitle("Minecraft server - shutting down!"); -+ jframe.setTitle("Purpur Minecraft server - shutting down!"); // Purpur - server.halt(true); - servergui.runFinalizers(); - } -@@ -159,7 +164,7 @@ public class MinecraftServerGui extends JComponent { - - private JComponent buildChatPanel() { - JPanel jpanel = new JPanel(new BorderLayout()); -- JTextArea jtextarea = new JTextArea(); -+ org.purpurmc.purpur.gui.JColorTextPane jtextarea = new org.purpurmc.purpur.gui.JColorTextPane(); // Purpur - JScrollPane jscrollpane = new JScrollPane(jtextarea, 22, 30); - - jtextarea.setEditable(false); -@@ -171,10 +176,43 @@ public class MinecraftServerGui extends JComponent { - - if (!s.isEmpty()) { - this.server.handleConsoleInput(s, this.server.createCommandSourceStack()); -+ // Purpur start -+ history.add(s); -+ historyIndex = -1; -+ // Purpur end - } - - jtextfield.setText(""); - }); -+ // Purpur start -+ jtextfield.getInputMap().put(javax.swing.KeyStroke.getKeyStroke("UP"), "up"); -+ jtextfield.getInputMap().put(javax.swing.KeyStroke.getKeyStroke("DOWN"), "down"); -+ jtextfield.getActionMap().put("up", new javax.swing.AbstractAction() { -+ @Override -+ public void actionPerformed(java.awt.event.ActionEvent actionEvent) { -+ if (historyIndex < 0) { -+ currentCommand = jtextfield.getText(); -+ } -+ if (historyIndex < history.size() - 1) { -+ jtextfield.setText(history.get(++historyIndex)); -+ } -+ } -+ }); -+ jtextfield.getActionMap().put("down", new javax.swing.AbstractAction() { -+ @Override -+ public void actionPerformed(java.awt.event.ActionEvent actionEvent) { -+ if (historyIndex >= 0) { -+ if (historyIndex == 0) { -+ --historyIndex; -+ jtextfield.setText(currentCommand); -+ } else { -+ --historyIndex; -+ jtextfield.setText(history.get(historyIndex)); -+ } -+ } -+ } -+ }); -+ // Purpur end - jtextarea.addFocusListener(new FocusAdapter() { // CraftBukkit - decompile error - public void focusGained(FocusEvent focusevent) {} - }); -@@ -210,7 +248,7 @@ public class MinecraftServerGui extends JComponent { - } - - private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\e\\[[\\d;]*[^\\d;]"); // CraftBukkit // Paper -- public void print(JTextArea textArea, JScrollPane scrollPane, String message) { -+ public void print(org.purpurmc.purpur.gui.JColorTextPane textArea, JScrollPane scrollPane, String message) { // Purpur - if (!SwingUtilities.isEventDispatchThread()) { - SwingUtilities.invokeLater(() -> { - this.print(textArea, scrollPane, message); -@@ -224,11 +262,14 @@ public class MinecraftServerGui extends JComponent { - flag = (double) jscrollbar.getValue() + jscrollbar.getSize().getHeight() + (double) (MinecraftServerGui.MONOSPACED.getSize() * 4) > (double) jscrollbar.getMaximum(); - } - -+ /* // Purpur - try { - document.insertString(document.getLength(), MinecraftServerGui.ANSI.matcher(message).replaceAll(""), (AttributeSet) null); // CraftBukkit - } catch (BadLocationException badlocationexception) { - ; - } -+ */ // Purpur -+ textArea.append(message); // Purpur - - if (flag) { - jscrollbar.setValue(Integer.MAX_VALUE); -@@ -236,4 +277,16 @@ public class MinecraftServerGui extends JComponent { - - } - } -+ -+ // Purpur start -+ public static class CommandHistory extends java.util.LinkedList { -+ @Override -+ public boolean add(String command) { -+ if (size() > 1000) { -+ remove(); -+ } -+ return super.offerFirst(command); -+ } -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/gui/GUIColor.java b/src/main/java/org/purpurmc/purpur/gui/GUIColor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..550222758bf0e7deff26a6e813a860b7be365e87 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/gui/GUIColor.java -@@ -0,0 +1,58 @@ -+package org.purpurmc.purpur.gui; -+ -+import net.md_5.bungee.api.ChatColor; -+ -+import java.awt.Color; -+import java.util.HashMap; -+import java.util.Map; -+ -+public enum GUIColor { -+ BLACK(ChatColor.BLACK, new Color(0x000000)), -+ DARK_BLUE(ChatColor.DARK_BLUE, new Color(0x0000AA)), -+ DARK_GREEN(ChatColor.DARK_GREEN, new Color(0x00AA00)), -+ DARK_AQUA(ChatColor.DARK_AQUA, new Color(0x009999)), -+ DARK_RED(ChatColor.DARK_RED, new Color(0xAA0000)), -+ DARK_PURPLE(ChatColor.DARK_PURPLE, new Color(0xAA00AA)), -+ GOLD(ChatColor.GOLD, new Color(0xBB8800)), -+ GRAY(ChatColor.GRAY, new Color(0x888888)), -+ DARK_GRAY(ChatColor.DARK_GRAY, new Color(0x444444)), -+ BLUE(ChatColor.BLUE, new Color(0x5555FF)), -+ GREEN(ChatColor.GREEN, new Color(0x55FF55)), -+ AQUA(ChatColor.AQUA, new Color(0x55DDDD)), -+ RED(ChatColor.RED, new Color(0xFF5555)), -+ LIGHT_PURPLE(ChatColor.LIGHT_PURPLE, new Color(0xFF55FF)), -+ YELLOW(ChatColor.YELLOW, new Color(0xFFBB00)), -+ WHITE(ChatColor.WHITE, new Color(0xBBBBBB)); -+ -+ private final ChatColor chat; -+ private final Color color; -+ -+ private static final Map BY_CHAT = new HashMap<>(); -+ -+ GUIColor(ChatColor chat, Color color) { -+ this.chat = chat; -+ this.color = color; -+ } -+ -+ public Color getColor() { -+ return color; -+ } -+ -+ public ChatColor getChatColor() { -+ return chat; -+ } -+ -+ public String getCode() { -+ return chat.toString(); -+ } -+ -+ public static GUIColor getColor(ChatColor chat) { -+ return BY_CHAT.get(chat); -+ } -+ -+ static { -+ for (GUIColor color : values()) { -+ BY_CHAT.put(color.chat, color); -+ } -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java b/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d75fb5e77eff27d86135ed7d605dbc250b660f7d ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java -@@ -0,0 +1,83 @@ -+package org.purpurmc.purpur.gui; -+ -+import com.google.common.collect.Sets; -+import javax.swing.UIManager; -+import net.md_5.bungee.api.chat.BaseComponent; -+import net.md_5.bungee.api.chat.TextComponent; -+ -+import javax.swing.JTextPane; -+import javax.swing.Timer; -+import javax.swing.text.AttributeSet; -+import javax.swing.text.BadLocationException; -+import javax.swing.text.SimpleAttributeSet; -+import javax.swing.text.StyleConstants; -+import javax.swing.text.StyleContext; -+import java.util.Set; -+ -+public class JColorTextPane extends JTextPane { -+ private static final GUIColor DEFAULT_COLOR; -+ static { -+ DEFAULT_COLOR = UIManager.getSystemLookAndFeelClassName().equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel") -+ ? GUIColor.WHITE : GUIColor.BLACK; -+ } -+ -+ -+ public void append(String msg) { -+ // TODO: update to use adventure instead -+ BaseComponent[] components = TextComponent.fromLegacyText(DEFAULT_COLOR.getCode() + msg, DEFAULT_COLOR.getChatColor()); -+ for (BaseComponent component : components) { -+ String text = component.toPlainText(); -+ if (text == null || text.isEmpty()) { -+ continue; -+ } -+ -+ GUIColor guiColor = GUIColor.getColor(component.getColor()); -+ -+ StyleContext context = StyleContext.getDefaultStyleContext(); -+ AttributeSet attr = context.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, guiColor.getColor()); -+ attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Bold, component.isBold() || guiColor != DEFAULT_COLOR); -+ attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Italic, component.isItalic()); -+ attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Underline, component.isUnderlined()); -+ attr = context.addAttribute(attr, StyleConstants.CharacterConstants.StrikeThrough, component.isStrikethrough()); -+ //attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Blink, component.isObfuscated()); // no such thing as Blink, sadly -+ -+ try { -+ int pos = getDocument().getLength(); -+ getDocument().insertString(pos, text, attr); -+ -+ if (component.isObfuscated()) { -+ // dirty hack to blink some text -+ Blink blink = new Blink(pos, text.length(), attr, context.addAttribute(attr, StyleConstants.Foreground, getBackground())); -+ BLINKS.add(blink); -+ } -+ } catch (BadLocationException ignore) { -+ } -+ } -+ } -+ -+ private static final Set BLINKS = Sets.newHashSet(); -+ private static boolean SYNC_BLINK; -+ -+ static { -+ new Timer(500, e -> { -+ SYNC_BLINK = !SYNC_BLINK; -+ BLINKS.forEach(Blink::blink); -+ }).start(); -+ } -+ -+ public class Blink { -+ private final int start, length; -+ private final AttributeSet attr1, attr2; -+ -+ private Blink(int start, int length, AttributeSet attr1, AttributeSet attr2) { -+ this.start = start; -+ this.length = length; -+ this.attr1 = attr1; -+ this.attr2 = attr2; -+ } -+ -+ private void blink() { -+ getStyledDocument().setCharacterAttributes(start, length, SYNC_BLINK ? attr1 : attr2, true); -+ } -+ } -+} -diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml -index d2a75850af9c6ad2aca66a5f994f1b587d73eac4..a056aa167887abef9e6d531a9edd2cda433567d2 100644 ---- a/src/main/resources/log4j2.xml -+++ b/src/main/resources/log4j2.xml -@@ -2,7 +2,16 @@ - - - -- -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - diff --git a/patches/server/0284-Stored-Bee-API.patch b/patches/server/0284-Stored-Bee-API.patch deleted file mode 100644 index 525c836e8..000000000 --- a/patches/server/0284-Stored-Bee-API.patch +++ /dev/null @@ -1,253 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: EOT3000 -Date: Sat, 10 Jun 2023 20:27:12 -0400 -Subject: [PATCH] Stored Bee API - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -index d8efb00c325448d566c59418fe22268c6eb4cfce..f7a6ab35c95ffda73f17843916ddb624ad290b42 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -146,11 +146,33 @@ public class BeehiveBlockEntity extends BlockEntity { - return list; - } - -+ // Purpur start -+ public List releaseBee(BlockState iblockdata, BeehiveBlockEntity.BeeData data, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, boolean force) { -+ List list = Lists.newArrayList(); -+ -+ BeehiveBlockEntity.releaseOccupant(this.level, this.worldPosition, iblockdata, data.occupant, list, tileentitybeehive_releasestatus, this.savedFlowerPos, force); -+ -+ if (!list.isEmpty()) { -+ stored.remove(data); -+ -+ super.setChanged(); -+ } -+ -+ return list; -+ } -+ // Purpur end -+ - @VisibleForDebug - public int getOccupantCount() { - return this.stored.size(); - } - -+ // Purpur start -+ public List getStored() { -+ return stored; -+ } -+ // Purpur end -+ - // Paper start - Add EntityBlockStorage clearEntities - public void clearBees() { - this.stored.clear(); -@@ -471,9 +493,9 @@ public class BeehiveBlockEntity extends BlockEntity { - } - } - -- private static class BeeData { -+ public static class BeeData { // Purpur - change from private to public - -- private final BeehiveBlockEntity.Occupant occupant; -+ public final BeehiveBlockEntity.Occupant occupant; // Purpur - make public - private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts - private int ticksInHive; - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java -index 1a2a05160ba51d9c75f1ae6ae61d944d81428722..3beb26ad2ef0fded49a8da8c5dec64f9508c1995 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java -@@ -16,8 +16,15 @@ import org.bukkit.entity.Bee; - - public class CraftBeehive extends CraftBlockEntityState implements Beehive { - -+ private final List> storage = new ArrayList<>(); // Purpur -+ - public CraftBeehive(World world, BeehiveBlockEntity tileEntity) { - super(world, tileEntity); -+ // Purpur start - load bees to be able to modify them individually -+ for(BeehiveBlockEntity.BeeData data : tileEntity.getStored()) { -+ storage.add(new org.purpurmc.purpur.entity.PurpurStoredBee(data, this)); -+ } -+ // Purpur end - } - - protected CraftBeehive(CraftBeehive state, Location location) { -@@ -75,15 +82,54 @@ public class CraftBeehive extends CraftBlockEntityState impl - bees.add((Bee) bee.getBukkitEntity()); - } - } -- -+ storage.clear(); // Purpur - return bees; - } - -+ // Purpur start -+ @Override -+ public Bee releaseEntity(org.purpurmc.purpur.entity.StoredEntity entity) { -+ ensureNoWorldGeneration(); -+ -+ if(!getEntities().contains(entity)) { -+ return null; -+ } -+ -+ if(isPlaced()) { -+ BeehiveBlockEntity beehive = ((BeehiveBlockEntity) this.getTileEntityFromWorld()); -+ BeehiveBlockEntity.BeeData data = ((org.purpurmc.purpur.entity.PurpurStoredBee) entity).getHandle(); -+ -+ List list = beehive.releaseBee(getHandle(), data, BeeReleaseStatus.BEE_RELEASED, true); -+ -+ if (list.size() == 1) { -+ storage.remove(entity); -+ -+ return (Bee) list.get(0).getBukkitEntity(); -+ } -+ } -+ -+ return null; -+ } -+ -+ @Override -+ public List> getEntities() { -+ return new ArrayList<>(storage); -+ } -+ // Purpur end -+ - @Override - public void addEntity(Bee entity) { - Preconditions.checkArgument(entity != null, "Entity must not be null"); - -- this.getSnapshot().addOccupant(((CraftBee) entity).getHandle()); -+ int length = this.getSnapshot().getStored().size(); // Purpur -+ getSnapshot().addOccupant(((CraftBee) entity).getHandle()); -+ -+ // Purpur start - check if new bee was added, and if yes, add to stored bees -+ List storedBeeData = this.getSnapshot().getStored(); -+ if(length < storedBeeData.size()) { -+ storage.add(new org.purpurmc.purpur.entity.PurpurStoredBee(storedBeeData.getLast(), this)); -+ } -+ // Purpur end - } - - @Override -@@ -100,6 +146,7 @@ public class CraftBeehive extends CraftBlockEntityState impl - @Override - public void clearEntities() { - getSnapshot().clearBees(); -+ storage.clear(); // Purpur - } - // Paper end - } -diff --git a/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java b/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7608bf0981fa0d37031e51e57e4086cb5ec4c88b ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java -@@ -0,0 +1,106 @@ -+package org.purpurmc.purpur.entity; -+ -+import io.papermc.paper.adventure.PaperAdventure; -+import net.kyori.adventure.text.Component; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.Tag; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.world.item.component.CustomData; -+import net.minecraft.world.level.block.entity.BeehiveBlockEntity; -+import org.bukkit.block.EntityBlockStorage; -+import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; -+import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry; -+import org.bukkit.entity.Bee; -+import org.bukkit.entity.EntityType; -+import org.bukkit.persistence.PersistentDataContainer; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.Locale; -+ -+public class PurpurStoredBee implements StoredEntity { -+ private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); -+ -+ private final EntityBlockStorage blockStorage; -+ private final BeehiveBlockEntity.BeeData handle; -+ private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(PurpurStoredBee.DATA_TYPE_REGISTRY); -+ -+ private Component customName; -+ -+ public PurpurStoredBee(BeehiveBlockEntity.BeeData data, EntityBlockStorage blockStorage) { -+ this.handle = data; -+ this.blockStorage = blockStorage; -+ -+ CompoundTag customData = handle.occupant.entityData().copyTag(); -+ this.customName = customData.contains("CustomName") -+ ? PaperAdventure.asAdventure(net.minecraft.network.chat.Component.Serializer.fromJson(customData.getString("CustomName"), MinecraftServer.getDefaultRegistryAccess())) -+ : null; -+ -+ if(customData.contains("BukkitValues", Tag.TAG_COMPOUND)) { -+ this.persistentDataContainer.putAll(customData.getCompound("BukkitValues")); -+ } -+ } -+ -+ public BeehiveBlockEntity.BeeData getHandle() { -+ return handle; -+ } -+ -+ @Override -+ public @Nullable Component customName() { -+ return customName; -+ } -+ -+ @Override -+ public void customName(@Nullable Component customName) { -+ this.customName = customName; -+ } -+ -+ @Override -+ public @Nullable String getCustomName() { -+ return PaperAdventure.asPlain(customName, Locale.US); -+ } -+ -+ @Override -+ public void setCustomName(@Nullable String name) { -+ customName(name != null ? Component.text(name) : null); -+ } -+ -+ @Override -+ public @NotNull PersistentDataContainer getPersistentDataContainer() { -+ return persistentDataContainer; -+ } -+ -+ @Override -+ public boolean hasBeenReleased() { -+ return !blockStorage.getEntities().contains(this); -+ } -+ -+ @Override -+ public @Nullable Bee release() { -+ return blockStorage.releaseEntity(this); -+ } -+ -+ @Override -+ public @Nullable EntityBlockStorage getBlockStorage() { -+ if(hasBeenReleased()) { -+ return null; -+ } -+ -+ return blockStorage; -+ } -+ -+ @Override -+ public @NotNull EntityType getType() { -+ return EntityType.BEE; -+ } -+ -+ @Override -+ public void update() { -+ handle.occupant.entityData().copyTag().put("BukkitValues", this.persistentDataContainer.toTagCompound()); -+ if(customName == null) { -+ handle.occupant.entityData().copyTag().remove("CustomName"); -+ } else { -+ handle.occupant.entityData().copyTag().putString("CustomName", net.minecraft.network.chat.Component.Serializer.toJson(PaperAdventure.asVanilla(customName), MinecraftServer.getDefaultRegistryAccess())); -+ } -+ } -+} diff --git a/patches/server/0285-Shears-can-defuse-TNT.patch b/patches/server/0285-Shears-can-defuse-TNT.patch deleted file mode 100644 index 5fb2d5add..000000000 --- a/patches/server/0285-Shears-can-defuse-TNT.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrFishCakes -Date: Sun, 2 Jul 2023 00:50:14 +0100 -Subject: [PATCH] Shears can defuse TNT - -Shears can now defuse TNT. Each world can have a configured chance for the TNT to be defused when right clicking with a set of shears and damage dealt to the shears accordingly. If the TNT is defused then it will drop the TNT item instead and the entity removed from the world no longer existing. All the interaction is handled within the net.minecraft.world.entity.item.PrimedTnt class similar to how it is handled for when sheep are sheared. - -By default the option is disabled to avoid breaking any possible vanilla mechanics. - -diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index f1f352ec0e51f5db59254841a06c176c5a876fc9..dff0e7b08b973a1b29f916e63d3e4778d6c56cdc 100644 ---- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -193,4 +193,29 @@ public class PrimedTnt extends Entity implements TraceableEntity { - return !level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid(); - } - // Paper end - Option to prevent TNT from moving in water -+ // Purpur start - Shears can defuse TNT -+ @Override -+ public net.minecraft.world.InteractionResult interact(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) { -+ if (!level().isClientSide && level().purpurConfig.shearsCanDefuseTnt) { -+ final net.minecraft.world.item.ItemStack inHand = player.getItemInHand(hand); -+ -+ if (!inHand.is(net.minecraft.world.item.Items.SHEARS) || !player.getBukkitEntity().hasPermission("purpur.tnt.defuse") || -+ level().random.nextFloat() > level().purpurConfig.shearsCanDefuseTntChance) return net.minecraft.world.InteractionResult.PASS; -+ -+ net.minecraft.world.entity.item.ItemEntity tntItem = new net.minecraft.world.entity.item.ItemEntity(level(), getX(), getY(), getZ(), -+ new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.TNT)); -+ tntItem.setPickUpDelay(10); -+ -+ inHand.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand)); -+ level().addFreshEntity(tntItem, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CUSTOM); -+ -+ this.playSound(net.minecraft.sounds.SoundEvents.SHEEP_SHEAR); -+ -+ this.kill(); -+ return net.minecraft.world.InteractionResult.SUCCESS; -+ } -+ -+ return super.interact(player, hand); -+ } -+ // Purpur end - Shears can defuse TNT - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 03819b5d991d91c2e7f5e2eae50e1a7e4197336b..bd1ae536d975b5a3c54063834fd05255f15d8dad 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -3282,4 +3282,11 @@ public class PurpurWorldConfig { - cauldronDripstoneWaterFillChance = (float) getDouble("blocks.cauldron.fill-chances.dripstone-water", cauldronDripstoneWaterFillChance); - cauldronDripstoneLavaFillChance = (float) getDouble("blocks.cauldron.fill-chances.dripstone-lava", cauldronDripstoneLavaFillChance); - } -+ -+ public float shearsCanDefuseTntChance = 0.00F; -+ public boolean shearsCanDefuseTnt = false; -+ private void shearsCanDefuseTntSettings() { -+ shearsCanDefuseTntChance = (float) getDouble("gameplay-mechanics.item.shears.defuse-tnt-chance", 0.00D); -+ shearsCanDefuseTnt = shearsCanDefuseTntChance > 0.00F; -+ } - } diff --git a/patches/server/0286-Explorer-Map-API.patch b/patches/server/0286-Explorer-Map-API.patch deleted file mode 100644 index b5f2c63e7..000000000 --- a/patches/server/0286-Explorer-Map-API.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Wed, 5 Jul 2023 12:48:15 -0500 -Subject: [PATCH] Explorer Map API - - -diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java -index ce461b1a8d7fab87ae28e30205f6fab67f1808b6..608390ed36710a419de1542b80340dd3fcc7299c 100644 ---- a/src/main/java/net/minecraft/world/item/MapItem.java -+++ b/src/main/java/net/minecraft/world/item/MapItem.java -@@ -195,6 +195,7 @@ public class MapItem extends ComplexItem { - public static void renderBiomePreviewMap(ServerLevel world, ItemStack map) { - MapItemSavedData mapItemSavedData = getSavedData(map, world); - if (mapItemSavedData != null) { -+ mapItemSavedData.isExplorerMap = true; // Purpur - if (world.dimension() == mapItemSavedData.dimension) { - int i = 1 << mapItemSavedData.scale; - int j = mapItemSavedData.centerX; -diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index cf8ae635fce7ea66d4e1ab1dc05575f035fa95ef..e26f6215ca42885cb0635a3183a8df93a924ba7f 100644 ---- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -79,6 +79,7 @@ public class MapItemSavedData extends SavedData { - private final Map frameMarkers = Maps.newHashMap(); - private int trackedDecorationCount; - private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper -+ public boolean isExplorerMap; // Purpur - - // CraftBukkit start - public final CraftMapView mapView; -diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java -index 0cbbd915631904fe8c6effefb92895422b33eff6..aef19cfbecb4ddfc8dc71c4f3b2a011364c12dc2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java -+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java -@@ -47,4 +47,10 @@ public class CraftMapRenderer extends MapRenderer { - } - } - -+ // Purpur - start -+ @Override -+ public boolean isExplorerMap() { -+ return this.worldMap.isExplorerMap; -+ } -+ // Purpur - end - } diff --git a/patches/server/0287-Option-Ocelot-Spawn-Under-Sea-Level.patch b/patches/server/0287-Option-Ocelot-Spawn-Under-Sea-Level.patch deleted file mode 100644 index 5d79d6bf5..000000000 --- a/patches/server/0287-Option-Ocelot-Spawn-Under-Sea-Level.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 21 Jul 2023 11:04:47 -0500 -Subject: [PATCH] Option Ocelot Spawn Under Sea Level - - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java -index 5668aca08732e317c7bccacf1cfaae7d8666bce6..07dc8a43f4e8c54a94696b84896d32f66a207ad3 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java -@@ -293,7 +293,7 @@ public class Ocelot extends Animal { - if (world.isUnobstructed(this) && !world.containsAnyLiquid(this.getBoundingBox())) { - BlockPos blockposition = this.blockPosition(); - -- if (blockposition.getY() < world.getSeaLevel()) { -+ if (!level().purpurConfig.ocelotSpawnUnderSeaLevel && blockposition.getY() < world.getSeaLevel()) { - return false; - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index bd1ae536d975b5a3c54063834fd05255f15d8dad..0f4a926937d07f76144cd1146b48bfdadaf887b5 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2097,6 +2097,7 @@ public class PurpurWorldConfig { - public int ocelotBreedingTicks = 6000; - public boolean ocelotTakeDamageFromWater = false; - public boolean ocelotAlwaysDropExp = false; -+ public boolean ocelotSpawnUnderSeaLevel = false; - private void ocelotSettings() { - ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); - ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); -@@ -2110,6 +2111,7 @@ public class PurpurWorldConfig { - ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks); - ocelotTakeDamageFromWater = getBoolean("mobs.ocelot.takes-damage-from-water", ocelotTakeDamageFromWater); - ocelotAlwaysDropExp = getBoolean("mobs.ocelot.always-drop-exp", ocelotAlwaysDropExp); -+ ocelotSpawnUnderSeaLevel = getBoolean("mobs.ocelot.spawn-below-sea-level", ocelotSpawnUnderSeaLevel); - } - - public boolean pandaRidable = false; diff --git a/patches/server/0288-add-an-option-for-piglins-to-ignore-gold-trimmed-arm.patch b/patches/server/0288-add-an-option-for-piglins-to-ignore-gold-trimmed-arm.patch deleted file mode 100644 index 8f0bc4e20..000000000 --- a/patches/server/0288-add-an-option-for-piglins-to-ignore-gold-trimmed-arm.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Sun, 13 Aug 2023 06:26:08 -0700 -Subject: [PATCH] add an option for piglins to ignore gold-trimmed armor - - -diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -index e25af9af8f87e6762716749c367658bf6bda9e34..b7d5c0b0e3741fcf04c4bac21a82fc41e2eeed5d 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAi.java -@@ -606,11 +606,18 @@ public class PiglinAi { - ItemStack itemstack = (ItemStack) iterator.next(); - - item = itemstack.getItem(); -- } while (!(item instanceof ArmorItem) || !((ArmorItem) item).getMaterial().is(ArmorMaterials.GOLD)); -+ } while (!(item instanceof ArmorItem) || !((ArmorItem) item).getMaterial().is(ArmorMaterials.GOLD) && (!entity.level().purpurConfig.piglinIgnoresArmorWithGoldTrim || !isWearingGoldTrim(item))); // Purpur - - return true; - } - -+ // Purpur start -+ private static boolean isWearingGoldTrim(Item itemstack) { -+ net.minecraft.world.item.armortrim.ArmorTrim armorTrim = itemstack.components().get(net.minecraft.core.component.DataComponents.TRIM); -+ return armorTrim != null && armorTrim.material().is(net.minecraft.world.item.armortrim.TrimMaterials.GOLD); -+ } -+ // Purpur end -+ - private static void stopWalking(Piglin piglin) { - piglin.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET); - piglin.getNavigation().stop(); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 0f4a926937d07f76144cd1146b48bfdadaf887b5..27eadd84aed6d109e278b0ee450fc2c302f61aba 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2266,6 +2266,7 @@ public class PurpurWorldConfig { - public int piglinPortalSpawnModifier = 2000; - public boolean piglinAlwaysDropExp = false; - public double piglinHeadVisibilityPercent = 0.5D; -+ public boolean piglinIgnoresArmorWithGoldTrim = false; - private void piglinSettings() { - piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); - piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); -@@ -2281,6 +2282,7 @@ public class PurpurWorldConfig { - piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier); - piglinAlwaysDropExp = getBoolean("mobs.piglin.always-drop-exp", piglinAlwaysDropExp); - piglinHeadVisibilityPercent = getDouble("mobs.piglin.head-visibility-percent", piglinHeadVisibilityPercent); -+ piglinIgnoresArmorWithGoldTrim = getBoolean("mobs.piglin.ignores-armor-with-gold-trim", piglinIgnoresArmorWithGoldTrim); - } - - public boolean piglinBruteRidable = false; diff --git a/patches/server/0289-Add-option-for-always-showing-item-in-player-death-m.patch b/patches/server/0289-Add-option-for-always-showing-item-in-player-death-m.patch deleted file mode 100644 index 84ea3ef77..000000000 --- a/patches/server/0289-Add-option-for-always-showing-item-in-player-death-m.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MelnCat -Date: Tue, 22 Aug 2023 22:18:26 -0700 -Subject: [PATCH] Add option for always showing item in player death messages - - -diff --git a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -index 357a79d72a2de02a019595e457fe432bf409e516..4fb025a63628eb60509d90b680922a0220104bcb 100644 ---- a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -+++ b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -@@ -54,7 +54,7 @@ public class CombatTracker { - - private Component getMessageForAssistedFall(Entity attacker, Component attackerDisplayName, String itemDeathTranslationKey, String deathTranslationKey) { - ItemStack itemStack = attacker instanceof LivingEntity livingEntity ? livingEntity.getMainHandItem() : ItemStack.EMPTY; -- return !itemStack.isEmpty() && itemStack.has(DataComponents.CUSTOM_NAME) -+ return !itemStack.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemStack.has(DataComponents.CUSTOM_NAME)) // Purpur - ? Component.translatable(itemDeathTranslationKey, this.mob.getDisplayName(), attackerDisplayName, itemStack.getDisplayName()) - : Component.translatable(deathTranslationKey, this.mob.getDisplayName(), attackerDisplayName); - } -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -index 812091bf6efc067b21b9723b8241360d4b4c79e7..25e614be19b2b29b36af136b823f27f85e1650fa 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -@@ -197,7 +197,7 @@ public class DamageSource { - - ItemStack itemstack1 = itemstack; - -- return !itemstack1.isEmpty() && itemstack1.has(DataComponents.CUSTOM_NAME) ? Component.translatable(s + ".item", killed.getDisplayName(), ichatbasecomponent, itemstack1.getDisplayName()) : Component.translatable(s, killed.getDisplayName(), ichatbasecomponent); -+ return !itemstack1.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemstack1.has(DataComponents.CUSTOM_NAME)) ? Component.translatable(s + ".item", killed.getDisplayName(), ichatbasecomponent, itemstack1.getDisplayName()) : Component.translatable(s, killed.getDisplayName(), ichatbasecomponent); - } - } - -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index e7bce4121f7bc2fe0acd8860a73c58dfed73330b..6e0e871153e0ec85fd40ddf0581b6ed2932b9f99 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -576,4 +576,9 @@ public class PurpurConfig { - block.fallDistanceMultiplier = fallDistanceMultiplier.floatValue(); - }); - } -+ -+ public static boolean playerDeathsAlwaysShowItem = false; -+ private static void playerDeathsAlwaysShowItem() { -+ playerDeathsAlwaysShowItem = getBoolean("settings.player-deaths-always-show-item", playerDeathsAlwaysShowItem); -+ } - } diff --git a/patches/server/0290-place-end-crystal-on-any-block.patch b/patches/server/0290-place-end-crystal-on-any-block.patch deleted file mode 100644 index 8bf62f530..000000000 --- a/patches/server/0290-place-end-crystal-on-any-block.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Wed, 23 Aug 2023 01:39:14 -0700 -Subject: [PATCH] place end crystal on any block - - -diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -index dd1bdb4bb87a3a59c229ba76b36841d199717624..54607cea2622f259aedfe425b60e2317e4167bf9 100644 ---- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java -+++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -@@ -27,7 +27,7 @@ public class EndCrystalItem extends Item { - BlockPos blockposition = context.getClickedPos(); - BlockState iblockdata = world.getBlockState(blockposition); - -- if (!iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) { -+ if (!world.purpurConfig.endCrystalPlaceAnywhere && !iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) { - return InteractionResult.FAIL; - } else { - BlockPos blockposition1 = blockposition.above(); final BlockPos aboveBlockPosition = blockposition1; // Paper - OBFHELPER -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 27eadd84aed6d109e278b0ee450fc2c302f61aba..81c4b22a4fb7cbc2601966b646bb20294b46313e 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -978,6 +978,7 @@ public class PurpurWorldConfig { - public boolean basedEndCrystalExplosionFire = false; - public net.minecraft.world.level.Level.ExplosionInteraction basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; - public int endCrystalCramming = 0; -+ public boolean endCrystalPlaceAnywhere = false; - private void endCrystalSettings() { - if (PurpurConfig.version < 31) { - if ("DESTROY".equals(getString("blocks.end-crystal.baseless.explosion-effect", baselessEndCrystalExplosionEffect.name()))) { -@@ -1006,6 +1007,7 @@ public class PurpurWorldConfig { - basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; - } - endCrystalCramming = getInt("blocks.end-crystal.cramming-amount", endCrystalCramming); -+ endCrystalPlaceAnywhere = getBoolean("gameplay-mechanics.item.end-crystal.place-anywhere", endCrystalPlaceAnywhere); - } - - public boolean farmlandBypassMobGriefing = false; diff --git a/patches/server/0291-Add-option-to-disable-the-copper-oxidation-proximity.patch b/patches/server/0291-Add-option-to-disable-the-copper-oxidation-proximity.patch deleted file mode 100644 index 8d565ec61..000000000 --- a/patches/server/0291-Add-option-to-disable-the-copper-oxidation-proximity.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Meln Cat -Date: Mon, 9 Oct 2023 12:21:49 -0700 -Subject: [PATCH] Add option to disable the copper oxidation proximity penalty - - -diff --git a/src/main/java/net/minecraft/world/level/block/ChangeOverTimeBlock.java b/src/main/java/net/minecraft/world/level/block/ChangeOverTimeBlock.java -index daae7fd6e0148cfba8e359d990748a0c83a3376e..0e06b1bcd906e92c083dc74d56d6d0a2a36f62a7 100644 ---- a/src/main/java/net/minecraft/world/level/block/ChangeOverTimeBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ChangeOverTimeBlock.java -@@ -67,7 +67,7 @@ public interface ChangeOverTimeBlock> { - } - - float f = (float) (k + 1) / (float) (k + j + 1); -- float f1 = f * f * this.getChanceModifier(); -+ float f1 = world.purpurConfig.disableOxidationProximityPenalty ? this.getChanceModifier() : f * f * this.getChanceModifier(); // Purpur - - return random.nextFloat() < f1 ? this.getNext(state) : Optional.empty(); - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 81c4b22a4fb7cbc2601966b646bb20294b46313e..43d91390274c8cc8863e0aceb20837415b915166 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -146,6 +146,7 @@ public class PurpurWorldConfig { - public boolean rainStopsAfterSleep = true; - public boolean thunderStopsAfterSleep = true; - public int mobLastHurtByPlayerTime = 100; -+ public boolean disableOxidationProximityPenalty = false; - private void miscGameplayMechanicsSettings() { - useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); - mendingMultiplier = getDouble("gameplay-mechanics.mending-multiplier", mendingMultiplier); -@@ -181,6 +182,7 @@ public class PurpurWorldConfig { - rainStopsAfterSleep = getBoolean("gameplay-mechanics.rain-stops-after-sleep", rainStopsAfterSleep); - thunderStopsAfterSleep = getBoolean("gameplay-mechanics.thunder-stops-after-sleep", thunderStopsAfterSleep); - mobLastHurtByPlayerTime = getInt("gameplay-mechanics.mob-last-hurt-by-player-time", mobLastHurtByPlayerTime); -+ disableOxidationProximityPenalty = getBoolean("gameplay-mechanics.disable-oxidation-proximity-penalty", disableOxidationProximityPenalty); - } - - public int daytimeTicks = 12000; diff --git a/patches/server/0292-register-minecraft-debug-commands.patch b/patches/server/0292-register-minecraft-debug-commands.patch deleted file mode 100644 index db1601242..000000000 --- a/patches/server/0292-register-minecraft-debug-commands.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Sun, 18 Feb 2024 16:28:32 -0800 -Subject: [PATCH] register minecraft debug commands - - -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 13dfb3e506d50c0b191baf5d05bbfc28c20be0ae..f9d0e8ee9414b3897f268ba78a1469ddf868f51a 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -222,8 +222,8 @@ public class Commands { - JfrCommand.register(this.dispatcher); - } - -- if (SharedConstants.IS_RUNNING_IN_IDE) { -- TestCommand.register(this.dispatcher); -+ if (org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands || SharedConstants.IS_RUNNING_IN_IDE) { // Purpur -+ if (!org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands) TestCommand.register(this.dispatcher); // Purpur - ResetChunksCommand.register(this.dispatcher); - RaidCommand.register(this.dispatcher, commandRegistryAccess); - DebugPathCommand.register(this.dispatcher); -diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 8925440dbc35dbc4a7d59f13511d7afeda803260..411f1f8c6be072cfc5ba88cbec38dbc4300a41d1 100644 ---- a/src/main/java/net/minecraft/server/Main.java -+++ b/src/main/java/net/minecraft/server/Main.java -@@ -122,6 +122,7 @@ public class Main { - // Purpur start - load config files early - org.bukkit.configuration.file.YamlConfiguration purpurConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("purpur-settings")); - org.purpurmc.purpur.PurpurConfig.clampEnchantLevels = purpurConfiguration.getBoolean("settings.enchantment.clamp-levels"); -+ org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands = purpurConfiguration.getBoolean("settings.register-minecraft-debug-commands"); - // Purpur end - load config files early - - io.papermc.paper.plugin.PluginInitializerManager.load(optionset); // Paper -diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -index 6e0e871153e0ec85fd40ddf0581b6ed2932b9f99..f49108ed94f7787347c5e0a721646083d6dffafc 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java -@@ -581,4 +581,9 @@ public class PurpurConfig { - private static void playerDeathsAlwaysShowItem() { - playerDeathsAlwaysShowItem = getBoolean("settings.player-deaths-always-show-item", playerDeathsAlwaysShowItem); - } -+ -+ public static boolean registerMinecraftDebugCommands = false; -+ private static void registerMinecraftDebugCommands() { -+ registerMinecraftDebugCommands = getBoolean("settings.register-minecraft-debug-commands", registerMinecraftDebugCommands); -+ } - } diff --git a/patches/server/0293-Configurable-villager-search-radius.patch b/patches/server/0293-Configurable-villager-search-radius.patch deleted file mode 100644 index 819b508a2..000000000 --- a/patches/server/0293-Configurable-villager-search-radius.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Pantera -Date: Fri, 26 Jan 2024 15:57:24 +0900 -Subject: [PATCH] Configurable-villager-search-radius - - -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index e1b6fe9ecda25f86431baf414f1bfd3a26a8b2bd..6499e3fe49e453db11e51eaf717ca8b3b682056b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -73,7 +73,7 @@ public class AcquirePoi { - }; - // Paper start - optimise POI access - java.util.List, BlockPos>> poiposes = new java.util.ArrayList<>(); -- io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, poiPredicate, predicate2, entity.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes); -+ io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, poiPredicate, predicate2, entity.blockPosition(), world.purpurConfig.villagerAcquirePoiSearchRadius, world.purpurConfig.villagerAcquirePoiSearchRadius*world.purpurConfig.villagerAcquirePoiSearchRadius, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes); // Purpur - Set, BlockPos>> set = new java.util.HashSet<>(poiposes); - // Paper end - optimise POI access - Path path = findPathToPois(entity, set); -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -index 92731b6b593289e9f583c9b705b219e81fcd8e73..9104d7010bda6f9f73b478c11490ef9c53f76da2 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -@@ -56,7 +56,7 @@ public class NearestBedSensor extends Sensor { - // Paper start - optimise POI access - java.util.List, BlockPos>> poiposes = new java.util.ArrayList<>(); - // don't ask me why it's unbounded. ask mojang. -- io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), 48, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); -+ io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), world.purpurConfig.villagerNearestBedSensorSearchRadius, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); // Purpur - Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes)); - // Paper end - optimise POI access - if (path != null && path.canReach()) { -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 43d91390274c8cc8863e0aceb20837415b915166..710511db0e882d9795c2a1ff31570fbb05fbb0f1 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2896,6 +2896,8 @@ public class PurpurWorldConfig { - public boolean villagerDisplayTradeItem = true; - public int villagerSpawnIronGolemRadius = 0; - public int villagerSpawnIronGolemLimit = 0; -+ public int villagerAcquirePoiSearchRadius = 48; -+ public int villagerNearestBedSensorSearchRadius = 48; - private void villagerSettings() { - villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); - villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); -@@ -2932,6 +2934,8 @@ public class PurpurWorldConfig { - villagerDisplayTradeItem = getBoolean("mobs.villager.display-trade-item", villagerDisplayTradeItem); - villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius); - villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit); -+ villagerAcquirePoiSearchRadius = getInt("mobs.villager.search-radius.acquire-poi", villagerAcquirePoiSearchRadius); -+ villagerNearestBedSensorSearchRadius = getInt("mobs.villager.search-radius.nearest-bed-sensor", villagerNearestBedSensorSearchRadius); - } - - public boolean vindicatorRidable = false; diff --git a/patches/server/0294-option-to-make-ravagers-afraid-of-rabbits.patch b/patches/server/0294-option-to-make-ravagers-afraid-of-rabbits.patch deleted file mode 100644 index 765dd9d66..000000000 --- a/patches/server/0294-option-to-make-ravagers-afraid-of-rabbits.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Tue, 7 May 2024 04:59:57 -0700 -Subject: [PATCH] option to make ravagers afraid of rabbits - -https://github.com/PurpurMC/Purpur/discussions/713 - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -index 9551bd7c9bed37cf17910e7f71b82ed20fb2d759..dbfcca8adb7afa7a3101f22c2bc48aff6abae4a2 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java -@@ -111,6 +111,7 @@ public class Ravager extends Raider { - super.registerGoals(); - this.goalSelector.addGoal(0, new FloatGoal(this)); - this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -+ if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur - this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, true)); - this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4D)); - this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 710511db0e882d9795c2a1ff31570fbb05fbb0f1..d8de8710d9b8cf2ae5c434b2b0b27e76ffbbe4bf 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -2412,6 +2412,7 @@ public class PurpurWorldConfig { - public boolean ravagerTakeDamageFromWater = false; - public List ravagerGriefableBlocks = new ArrayList<>(); - public boolean ravagerAlwaysDropExp = false; -+ public boolean ravagerAvoidRabbits = false; - private void ravagerSettings() { - ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); - ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); -@@ -2442,6 +2443,7 @@ public class PurpurWorldConfig { - } - }); - ravagerAlwaysDropExp = getBoolean("mobs.ravager.always-drop-exp", ravagerAlwaysDropExp); -+ ravagerAvoidRabbits = getBoolean("mobs.ravager.avoid-rabbits", ravagerAvoidRabbits); - } - - public boolean salmonRidable = false; diff --git a/patches/server/0295-config-for-startup-commands.patch b/patches/server/0295-config-for-startup-commands.patch deleted file mode 100644 index 77e6c93cd..000000000 --- a/patches/server/0295-config-for-startup-commands.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Sun, 5 May 2024 02:27:52 -0700 -Subject: [PATCH] config for startup commands - - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index dfeae138e830e95ab823b6349a91160b02622208..21327a92b75a460c7beb3aa408502f37a7db31fa 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1188,6 +1188,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop startupCommands = new ArrayList<>(); -+ private static void startupCommands() { -+ startupCommands.clear(); -+ getList("settings.startup-commands", new ArrayList()).forEach(line -> { -+ String command = line.toString(); -+ if (command.startsWith("/")) { -+ command = command.substring(1); -+ } -+ startupCommands.add(command); -+ }); -+ } - } diff --git a/patches/server/0296-config-for-turning-bundles-into-functional-quivers.patch b/patches/server/0296-config-for-turning-bundles-into-functional-quivers.patch deleted file mode 100644 index be0cc70b5..000000000 --- a/patches/server/0296-config-for-turning-bundles-into-functional-quivers.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: granny -Date: Mon, 16 Oct 2023 21:54:47 -0700 -Subject: [PATCH] config for turning bundles into functional quivers - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 53ff232129443ba3242cfc57fc57026bf76d96e8..f5b78ae87457c0d3a550082fdf8640267f413130 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4495,6 +4495,11 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - public ItemStack getProjectile(ItemStack stack) { -+ // Purpur start -+ return getProjectile(stack, false); -+ } -+ public ItemStack getProjectile(ItemStack stack, boolean useBundleItemStack) { -+ // Purpur end - return ItemStack.EMPTY; - } - -diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java -index e60e6b3e5ae5a468cfe649ed2222412f3bc8b268..265437318f3db4331d9062d99c980f80a19211c7 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Monster.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Monster.java -@@ -144,6 +144,12 @@ public abstract class Monster extends PathfinderMob implements Enemy { - - @Override - public ItemStack getProjectile(ItemStack stack) { -+ // Purpur start -+ return getProjectile(stack, false); -+ } -+ @Override -+ public ItemStack getProjectile(ItemStack stack, boolean useBundleItemStack) { -+ // Purpur end - if (stack.getItem() instanceof ProjectileWeaponItem) { - Predicate predicate = ((ProjectileWeaponItem)stack.getItem()).getSupportedHeldProjectiles(); - ItemStack itemStack = ProjectileWeaponItem.getHeldProjectile(this, predicate); -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 845c4af5d5d38d54de4a1b20fe32bf5dd4776a29..15763ebc6c1ba3ba47d8110cf87fd4869660b2f4 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -2349,6 +2349,12 @@ public abstract class Player extends LivingEntity { - - @Override - public ItemStack getProjectile(ItemStack stack) { -+ // Purpur start -+ return getProjectile(stack, false); -+ } -+ @Override -+ public ItemStack getProjectile(ItemStack stack, boolean useBundleItemStack) { -+ // Purpur end - if (!(stack.getItem() instanceof ProjectileWeaponItem)) { - return ItemStack.EMPTY; - } else { -@@ -2363,6 +2369,38 @@ public abstract class Player extends LivingEntity { - for (int i = 0; i < this.inventory.getContainerSize(); ++i) { - ItemStack itemstack2 = this.inventory.getItem(i); - -+ // Purpur start -+ if ((this.level().purpurConfig.bowUseBundleAsQuiver || this.level().purpurConfig.crossbowUseBundleAsQuiver) && itemstack2.getItem() instanceof net.minecraft.world.item.BundleItem) { -+ net.minecraft.world.item.component.BundleContents bundleContents = itemstack2.get(net.minecraft.core.component.DataComponents.BUNDLE_CONTENTS); -+ if (bundleContents == null || bundleContents.isEmpty()) { -+ continue; -+ } -+ -+ Optional first = bundleContents.itemCopyStream().filter(predicate).findFirst(); -+ -+ if (first.isEmpty()) { -+ continue; -+ } -+ -+ ItemStack itemStack = first.get(); -+ if (useBundleItemStack) { -+ net.minecraft.world.item.component.BundleContents.Mutable mutable = new net.minecraft.world.item.component.BundleContents.Mutable(bundleContents); -+ ItemStack itemStack2 = mutable.removeOne(itemStack); -+ if (itemStack2 == null) { -+ continue; -+ } -+ -+ itemStack2.shrink(1); -+ if (itemStack2.getCount() != 0) { -+ mutable.tryInsert(itemStack2); -+ } -+ itemstack2.set(net.minecraft.core.component.DataComponents.BUNDLE_CONTENTS, mutable.toImmutable()); -+ } -+ itemStack.setCount(1); -+ return itemStack; -+ } -+ // Purpur end -+ - if (predicate.test(itemstack2)) { - return itemstack2; - } -diff --git a/src/main/java/net/minecraft/world/item/BowItem.java b/src/main/java/net/minecraft/world/item/BowItem.java -index 8bca38ec152f9612298bf6b3e10e7e0566ec3b78..2786272f45b82263e74e20407ffa7f3a439641a4 100644 ---- a/src/main/java/net/minecraft/world/item/BowItem.java -+++ b/src/main/java/net/minecraft/world/item/BowItem.java -@@ -24,7 +24,7 @@ public class BowItem extends ProjectileWeaponItem { - @Override - public void releaseUsing(ItemStack stack, Level world, LivingEntity user, int remainingUseTicks) { - if (user instanceof Player player) { -- ItemStack itemStack = player.getProjectile(stack); -+ ItemStack itemStack = player.getProjectile(stack, true); // Purpur - if (!itemStack.isEmpty()) { - int i = this.getUseDuration(stack) - remainingUseTicks; - float f = getPowerForTime(i); -diff --git a/src/main/java/net/minecraft/world/item/BundleItem.java b/src/main/java/net/minecraft/world/item/BundleItem.java -index 233c50af05085c1ecb069dd2e90d17c85f27e5ab..05843f14261764ff6add052e4ec1e3b2ef4ca6a8 100644 ---- a/src/main/java/net/minecraft/world/item/BundleItem.java -+++ b/src/main/java/net/minecraft/world/item/BundleItem.java -@@ -101,7 +101,7 @@ public class BundleItem extends Item { - @Override - public InteractionResultHolder use(Level world, Player user, InteractionHand hand) { - ItemStack itemStack = user.getItemInHand(hand); -- if (dropContents(itemStack, user)) { -+ if (!(world.purpurConfig.bowUseBundleAsQuiver || world.purpurConfig.bowUseBundleAsQuiver) && dropContents(itemStack, user)) { // Purpur - this.playDropContentsSound(user); - user.awardStat(Stats.ITEM_USED.get(this)); - return InteractionResultHolder.sidedSuccess(itemStack, world.isClientSide()); -diff --git a/src/main/java/net/minecraft/world/item/CrossbowItem.java b/src/main/java/net/minecraft/world/item/CrossbowItem.java -index 78f124f5204e4af9318ca3eeced6b1e3353b210f..40c6076a9cb17ac8120181dab77290bb0131b121 100644 ---- a/src/main/java/net/minecraft/world/item/CrossbowItem.java -+++ b/src/main/java/net/minecraft/world/item/CrossbowItem.java -@@ -62,7 +62,7 @@ public class CrossbowItem extends ProjectileWeaponItem { - if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { - this.performShooting(world, user, hand, itemStack, getShootingPower(chargedProjectiles), (float) world.purpurConfig.crossbowProjectileOffset, null); // Purpur - return InteractionResultHolder.consume(itemStack); -- } else if (!user.getProjectile(itemStack).isEmpty()) { -+ } else if (!user.getProjectile(itemStack).isEmpty()) { // Purpur - this.startSoundPlayed = false; - this.midLoadSoundPlayed = false; - user.startUsingItem(hand); -@@ -107,7 +107,7 @@ public class CrossbowItem extends ProjectileWeaponItem { - return CrossbowItem.tryLoadProjectiles(shooter, crossbow, true); - } - private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbow, boolean consume) { -- List list = draw(crossbow, shooter.getProjectile(crossbow), shooter, (org.purpurmc.purpur.PurpurConfig.allowCrossbowInfinity && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY, crossbow) > 0) || consume); -+ List list = draw(crossbow, shooter.getProjectile(crossbow, true), shooter, (org.purpurmc.purpur.PurpurConfig.allowCrossbowInfinity && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY, crossbow) > 0) || consume); // Purpur - // Paper end - Add EntityLoadCrossbowEvent - if (!list.isEmpty()) { - crossbow.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list)); -diff --git a/src/main/java/net/minecraft/world/item/component/BundleContents.java b/src/main/java/net/minecraft/world/item/component/BundleContents.java -index 00efca5920cefe60eb26654c2cdc69fb62894924..d4ce443420c9a3e2b7f0a0065f0024c756f70012 100644 ---- a/src/main/java/net/minecraft/world/item/component/BundleContents.java -+++ b/src/main/java/net/minecraft/world/item/component/BundleContents.java -@@ -119,7 +119,12 @@ public final class BundleContents implements TooltipComponent { - } - - private int findStackIndex(ItemStack stack) { -- if (!stack.isStackable()) { -+ // Purpur start -+ return this.findStackIndex(stack, false); -+ } -+ private int findStackIndex(ItemStack stack, boolean skipStackableCheck) { -+ if (!skipStackableCheck && !stack.isStackable()) { -+ // Purpur end - return -1; - } else { - for (int i = 0; i < this.items.size(); i++) { -@@ -169,10 +174,19 @@ public final class BundleContents implements TooltipComponent { - - @Nullable - public ItemStack removeOne() { -+ // Purpur start -+ return this.removeOne(null); -+ } -+ @Nullable -+ public ItemStack removeOne(ItemStack itemStack2) { -+ // Purpur end - if (this.items.isEmpty()) { - return null; - } else { -- ItemStack itemStack = this.items.remove(0).copy(); -+ // Purpur start -+ int stackIndex = itemStack2 != null ? this.findStackIndex(itemStack2, true) : -1; -+ ItemStack itemStack = this.items.remove(stackIndex == -1 ? 0 : stackIndex).copy(); -+ // Purpur end - this.weight = this.weight.subtract(BundleContents.getWeight(itemStack).multiplyBy(Fraction.getFraction(itemStack.getCount(), 1))); - return itemStack; - } -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index d8de8710d9b8cf2ae5c434b2b0b27e76ffbbe4bf..36d1d235c627bd4b9a45c332fca31c83549ccfe6 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -259,6 +259,8 @@ public class PurpurWorldConfig { - public boolean snowballExtinguishesFire = false; - public boolean snowballExtinguishesCandles = false; - public boolean snowballExtinguishesCampfires = false; -+ public boolean bowUseBundleAsQuiver = false; -+ public boolean crossbowUseBundleAsQuiver = false; - private void itemSettings() { - itemImmuneToCactus.clear(); - getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { -@@ -310,6 +312,8 @@ public class PurpurWorldConfig { - snowballExtinguishesFire = getBoolean("gameplay-mechanics.item.snowball.extinguish.fire", snowballExtinguishesFire); - snowballExtinguishesCandles = getBoolean("gameplay-mechanics.item.snowball.extinguish.candles", snowballExtinguishesCandles); - snowballExtinguishesCampfires = getBoolean("gameplay-mechanics.item.snowball.extinguish.campfires", snowballExtinguishesCampfires); -+ bowUseBundleAsQuiver = getBoolean("gameplay-mechanics.item.bow.use-bundle-as-quiver", bowUseBundleAsQuiver); -+ crossbowUseBundleAsQuiver = getBoolean("gameplay-mechanics.item.crossbow.use-bundle-as-quiver", crossbowUseBundleAsQuiver); - } - - public double minecartMaxSpeed = 0.4D; diff --git a/patches/unapplied-api/0001-Pufferfish-API-Changes.patch b/patches/unapplied-api/0001-Pufferfish-API-Changes.patch index 1fbc75a41..1259ec0fb 100644 --- a/patches/unapplied-api/0001-Pufferfish-API-Changes.patch +++ b/patches/unapplied-api/0001-Pufferfish-API-Changes.patch @@ -20,18 +20,18 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/build.gradle.kts b/build.gradle.kts -index 04853c43b99951bf0d4c96ef73724625bdaf018f..9164120d299d062c62529a7ef74eac0ded367993 100644 +index 571534b42cd9c33d6a7bb6fe3bf3a28e33f8e5de..5ceaca1bd75335f85b4876a394ea8c2643cda694 100644 --- a/build.gradle.kts +++ b/build.gradle.kts -@@ -51,6 +51,7 @@ dependencies { +@@ -66,6 +66,7 @@ dependencies { apiAndDocs("net.kyori:adventure-text-logger-slf4j") api("org.apache.logging.log4j:log4j-api:$log4jVersion") api("org.slf4j:slf4j-api:$slf4jVersion") + api("io.sentry:sentry:5.4.0") // Pufferfish - implementation("org.ow2.asm:asm:9.7") - implementation("org.ow2.asm:asm-commons:9.7") -@@ -109,6 +110,13 @@ val generateApiVersioningFile by tasks.registering { + implementation("org.ow2.asm:asm:9.7.1") + implementation("org.ow2.asm:asm-commons:9.7.1") +@@ -150,6 +151,13 @@ val generateApiVersioningFile by tasks.registering { } } @@ -214,7 +214,7 @@ index 0000000000000000000000000000000000000000..10310fdd53de28efb8a8250f6d3b0c8e +} diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java new file mode 100644 -index 0000000000000000000000000000000000000000..ab5fea0b03224bf249352ce340e94704ff713345 +index 0000000000000000000000000000000000000000..3441cdad70da1bd523c5933b1a914688718c2657 --- /dev/null +++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java @@ -0,0 +1,40 @@ @@ -235,7 +235,7 @@ index 0000000000000000000000000000000000000000..ab5fea0b03224bf249352ce340e94704 + @Deprecated + public static boolean canEnable(Logger logger) { + try { -+ if (SIMDDetection.getJavaVersion() != 17 && SIMDDetection.getJavaVersion() != 18 && SIMDDetection.getJavaVersion() != 19) { ++ if (SIMDDetection.getJavaVersion() < 17 || SIMDDetection.getJavaVersion() > 21) { + return false; + } else { + SIMDDetection.testRun = true; @@ -389,7 +389,7 @@ index 0000000000000000000000000000000000000000..ae2464920c9412ac90b819a540ee58be + +} diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java -index c80faa079eca1564847070f0338fc98024639829..e632d51d3487eb4807243b6705999ad124466bf5 100644 +index 6995f9cc08d162e3adcd3a28f6bfa6d329661999..b9edb96fc5bac8793477657dbb45ccf98ab17f27 100644 --- a/src/main/java/org/bukkit/map/MapPalette.java +++ b/src/main/java/org/bukkit/map/MapPalette.java @@ -1,6 +1,7 @@ @@ -400,7 +400,7 @@ index c80faa079eca1564847070f0338fc98024639829..e632d51d3487eb4807243b6705999ad1 import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; -@@ -40,7 +41,7 @@ public final class MapPalette { +@@ -45,7 +46,7 @@ public final class MapPalette { } @NotNull @@ -409,7 +409,7 @@ index c80faa079eca1564847070f0338fc98024639829..e632d51d3487eb4807243b6705999ad1 c(0, 0, 0, 0), c(0, 0, 0, 0), c(0, 0, 0, 0), c(0, 0, 0, 0), c(89, 125, 39), c(109, 153, 48), c(127, 178, 56), c(67, 94, 29), c(174, 164, 115), c(213, 201, 140), c(247, 233, 163), c(130, 123, 86), -@@ -211,9 +212,15 @@ public final class MapPalette { +@@ -216,9 +217,15 @@ public final class MapPalette { temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth()); byte[] result = new byte[temp.getWidth() * temp.getHeight()]; @@ -426,10 +426,10 @@ index c80faa079eca1564847070f0338fc98024639829..e632d51d3487eb4807243b6705999ad1 } diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -index fc2dae69165776d08274e34a69962cc70445f411..899d67fa782fac639fe7fb096e05c551d75bd647 100644 +index 001465eedafa51ac027a4db51cba6223edfe1171..2e6d62c4f3687e299c34e876c503b400e13be05a 100644 --- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -584,7 +584,9 @@ public final class SimplePluginManager implements PluginManager { +@@ -597,7 +597,9 @@ public final class SimplePluginManager implements PluginManager { // Paper start private void handlePluginException(String msg, Throwable ex, Plugin plugin) { @@ -439,7 +439,7 @@ index fc2dae69165776d08274e34a69962cc70445f411..899d67fa782fac639fe7fb096e05c551 callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerPluginEnableDisableException(msg, ex, plugin))); } // Paper end -@@ -654,9 +656,11 @@ public final class SimplePluginManager implements PluginManager { +@@ -667,9 +669,11 @@ public final class SimplePluginManager implements PluginManager { )); } } catch (Throwable ex) { @@ -452,7 +452,7 @@ index fc2dae69165776d08274e34a69962cc70445f411..899d67fa782fac639fe7fb096e05c551 callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event))); } diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index eaefbb00e9993d54906cc8cf35cf753c0d6c7707..301e82369603f3dd6e6c1bd380da4bacacd7ef6c 100644 +index b412aaf08901d169ac9fc89b36f9d6ccb95c53d3..45a9ca8969f635d20cc44c062fda85bbccd8f8ff 100644 --- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java @@ -336,7 +336,13 @@ public final class JavaPluginLoader implements PluginLoader { diff --git a/patches/unapplied-api/0002-Fix-pufferfish-issues.patch b/patches/unapplied-api/0002-Fix-pufferfish-issues.patch index b6b893fd9..d3cd67b69 100644 --- a/patches/unapplied-api/0002-Fix-pufferfish-issues.patch +++ b/patches/unapplied-api/0002-Fix-pufferfish-issues.patch @@ -4,21 +4,26 @@ Date: Tue, 4 Jan 2022 23:05:41 -0600 Subject: [PATCH] Fix pufferfish issues -diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java -index ab5fea0b03224bf249352ce340e94704ff713345..3441cdad70da1bd523c5933b1a914688718c2657 100644 ---- a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java -+++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java -@@ -15,7 +15,7 @@ public class SIMDChecker { - @Deprecated - public static boolean canEnable(Logger logger) { - try { -- if (SIMDDetection.getJavaVersion() != 17 && SIMDDetection.getJavaVersion() != 18 && SIMDDetection.getJavaVersion() != 19) { -+ if (SIMDDetection.getJavaVersion() < 17 || SIMDDetection.getJavaVersion() > 21) { - return false; - } else { - SIMDDetection.testRun = true; +diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java +index 652ff54e7c50412503725d628bfe72ed03059790..a7c0936a1ee80618f9a504087c88814f738f4693 100644 +--- a/src/main/java/io/papermc/paper/ServerBuildInfo.java ++++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java +@@ -19,6 +19,13 @@ public interface ServerBuildInfo { + */ + Key BRAND_PAPER_ID = Key.key("papermc", "paper"); + ++ // Purpur start ++ /** ++ * The brand id for Pufferfish. ++ */ ++ Key BRAND_PUFFERFISH_ID = Key.key("pufferfish", "pufferfish"); ++ // Purpur end ++ + /** + * Gets the {@code ServerBuildInfo}. + * diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java -index 88f1ca89fa640a686231b8eec87e70419b2d73ef..d6b91c49a267c89d7df2ddee7ccfe64675d117be 100644 +index f9e4b16a21d6cc6c9cbbe06d20c8af25e72e3ddb..4028b230e7fe1c78520f227a377a2a61e8381ecc 100644 --- a/src/test/java/org/bukkit/AnnotationTest.java +++ b/src/test/java/org/bukkit/AnnotationTest.java @@ -47,6 +47,10 @@ public class AnnotationTest { diff --git a/patches/unapplied-server/0001-Pufferfish-Server-Changes.patch b/patches/unapplied-server/0001-Pufferfish-Server-Changes.patch index 40944d98b..ab554b199 100644 --- a/patches/unapplied-server/0001-Pufferfish-Server-Changes.patch +++ b/patches/unapplied-server/0001-Pufferfish-Server-Changes.patch @@ -20,42 +20,36 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/build.gradle.kts b/build.gradle.kts -index bcfe59b6efb628ee1e7f9d60667360d4d885fb6a..4517548e2c892c2e94f91e7449660f9e36b8f14e 100644 +index 2da91ed6363c0851e4c459188f5e8ef5475e0c97..96d831791edbe6ae07325008b760f70f75c4d713 100644 --- a/build.gradle.kts +++ b/build.gradle.kts -@@ -13,8 +13,12 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) { - val alsoShade: Configuration by configurations.creating +@@ -25,7 +25,7 @@ abstract class MockitoAgentProvider : CommandLineArgumentProvider { + // Paper end - configure mockito agent that is needed in newer java versions dependencies { - implementation(project(":paper-api")) -- implementation(project(":paper-mojangapi")) + implementation(project(":pufferfish-api")) // Pufferfish // Paper -+ // Pufferfish start -+ implementation("io.papermc.paper:paper-mojangapi:1.19.2-R0.1-SNAPSHOT") { -+ exclude("io.papermc.paper", "paper-api") -+ } -+ // Pufferfish end + implementation("ca.spottedleaf:concurrentutil:0.0.2") // Paper - Add ConcurrentUtil dependency // Paper start - implementation("org.jline:jline-terminal-jansi:3.21.0") - implementation("net.minecrell:terminalconsoleappender:1.3.0") -@@ -50,6 +54,13 @@ dependencies { + implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ +@@ -61,6 +61,13 @@ dependencies { runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") + // Pufferfish start + implementation("org.yaml:snakeyaml:1.32") -+ implementation ("com.github.carleslc.Simple-YAML:Simple-Yaml:1.8.4") { ++ implementation ("me.carleslc.Simple-YAML:Simple-Yaml:1.8.4") { + exclude(group="org.yaml", module="snakeyaml") + } + // Pufferfish end + testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test - testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") - testImplementation("org.hamcrest:hamcrest:2.2") -@@ -59,6 +70,14 @@ dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") + testImplementation("org.junit.platform:junit-platform-suite-engine:1.10.0") +@@ -87,6 +94,14 @@ paperweight { + craftBukkitPackageVersion.set("v1_21_R3") // also needs to be updated in MappingEnvironment } - val craftbukkitPackageVersion = "1_20_R3" // Paper + +// Pufferfish Start +tasks.withType { @@ -67,34 +61,80 @@ index bcfe59b6efb628ee1e7f9d60667360d4d885fb6a..4517548e2c892c2e94f91e7449660f9e tasks.jar { archiveClassifier.set("dev") -@@ -71,7 +90,7 @@ tasks.jar { +@@ -100,14 +115,14 @@ tasks.jar { + val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper attributes( "Main-Class" to "org.bukkit.craftbukkit.Main", - "Implementation-Title" to "CraftBukkit", -- "Implementation-Version" to "git-Paper-$implementationVersion", -+ "Implementation-Version" to "git-Pufferfish-$implementationVersion", // Pufferfish +- "Implementation-Title" to "Paper", ++ "Implementation-Title" to "Pufferfish", // Pufferfish + "Implementation-Version" to implementationVersion, "Implementation-Vendor" to date, // Paper - "Specification-Title" to "Bukkit", +- "Specification-Title" to "Paper", ++ "Specification-Title" to "Pufferfish", // Pufferfish "Specification-Version" to project.version, -diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java -index 7620c72a4c243cbeea245203ce03a97cbfa7d922..b35a9f4c5f8960864c402ede8a51fb5ab9c4fcc0 100644 ---- a/src/main/java/co/aikar/timings/TimingsExport.java -+++ b/src/main/java/co/aikar/timings/TimingsExport.java -@@ -240,7 +240,8 @@ public class TimingsExport extends Thread { - parent.put("config", createObject( - pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), - pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), -- pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)) -+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Pufferfish -+ pair("pufferfish", mapAsJSON(gg.pufferfish.pufferfish.PufferfishConfig.getConfigCopy(), null)) // Pufferfish - )); +- "Specification-Vendor" to "Paper Team", +- "Brand-Id" to "papermc:paper", +- "Brand-Name" to "Paper", ++ "Specification-Vendor" to "Pufferfish Studios LLC", // Pufferfish ++ "Brand-Id" to "pufferfish:pufferfish", // Pufferfish ++ "Brand-Name" to "Pufferfish", // Pufferfish + "Build-Number" to (build ?: ""), + "Build-Time" to Instant.now().toString(), + "Git-Branch" to gitBranch, // Paper +diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java +index c21e00812f1aaa1279834a0562d360d6b89e146c..877d2095a066854939f260ca4b0b8c7b5abb620f 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java ++++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java +@@ -18,7 +18,7 @@ public final class IteratorSafeOrderedReferenceSet { + + private final double maxFragFactor; + +- private int iteratorCount; ++ private final java.util.concurrent.atomic.AtomicInteger iteratorCount = new java.util.concurrent.atomic.AtomicInteger(); // Pufferfish - async mob spawning + + public IteratorSafeOrderedReferenceSet() { + this(16, 0.75f, 16, 0.2); +@@ -79,7 +79,7 @@ public final class IteratorSafeOrderedReferenceSet { + } + + public int createRawIterator() { +- ++this.iteratorCount; ++ this.iteratorCount.incrementAndGet(); // Pufferfish - async mob spawning + if (this.indexMap.isEmpty()) { + return -1; + } else { +@@ -100,7 +100,7 @@ public final class IteratorSafeOrderedReferenceSet { + } + + public void finishRawIterator() { +- if (--this.iteratorCount == 0) { ++ if (this.iteratorCount.decrementAndGet() == 0) { // Pufferfish - async mob spawning + if (this.getFragFactor() >= this.maxFragFactor) { + this.defrag(); + } +@@ -117,7 +117,7 @@ public final class IteratorSafeOrderedReferenceSet { + throw new IllegalStateException(); + } + this.listElements[index] = null; +- if (this.iteratorCount == 0 && this.getFragFactor() >= this.maxFragFactor) { ++ if (this.iteratorCount.get() == 0 && this.getFragFactor() >= this.maxFragFactor) { // Pufferfish - async mob spawning + this.defrag(); + } + //this.check(); +@@ -219,7 +219,7 @@ public final class IteratorSafeOrderedReferenceSet { + } + + public IteratorSafeOrderedReferenceSet.Iterator iterator(final int flags) { +- ++this.iteratorCount; ++ this.iteratorCount.incrementAndGet(); // Pufferfish - async mob spawning + return new BaseIterator<>(this, true, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); + } - new TimingsExport(listeners, parent, history).start(); diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index 4b002e8b75d117b726b0de274a76d3596fce015b..692c962193cf9fcc6801fc93f3220bdc673d527b 100644 +index 8f62879582195d8ae4f64bd23f752fa133b1c973..8433c3ac440faa969069d1929b8b77fcb1080be7 100644 --- a/src/main/java/com/destroystokyo/paper/Metrics.java +++ b/src/main/java/com/destroystokyo/paper/Metrics.java -@@ -593,7 +593,7 @@ public class Metrics { +@@ -592,7 +592,7 @@ public class Metrics { boolean logFailedRequests = config.getBoolean("logFailedRequests", false); // Only start Metrics, if it's enabled in the config if (config.getBoolean("enabled", true)) { @@ -103,7 +143,7 @@ index 4b002e8b75d117b726b0de274a76d3596fce015b..692c962193cf9fcc6801fc93f3220bdc metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { String minecraftVersion = Bukkit.getVersion(); -@@ -607,11 +607,11 @@ public class Metrics { +@@ -606,11 +606,11 @@ public class Metrics { final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion(); if (implVersion != null) { final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1); @@ -117,429 +157,6 @@ index 4b002e8b75d117b726b0de274a76d3596fce015b..692c962193cf9fcc6801fc93f3220bdc metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { Map> map = new HashMap<>(); -diff --git a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java -index 41b9405d6759d865e0d14dd4f95163e9690e967d..091b1ae822e1c0517e59572e7a9bda11e998c0ee 100644 ---- a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java -+++ b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java -@@ -26,7 +26,7 @@ public abstract class AreaMap { - - // we use linked for better iteration. - // map of: coordinate to set of objects in coordinate -- protected final Long2ObjectOpenHashMap> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f); -+ protected Long2ObjectOpenHashMap> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f); // Pufferfish - not actually final - protected final PooledLinkedHashSets pooledHashSets; - - protected final ChangeCallback addCallback; -@@ -160,7 +160,8 @@ public abstract class AreaMap { - protected abstract PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getEmptySetFor(final E object); - - // expensive op, only for debug -- protected void validate(final E object, final int viewDistance) { -+ protected void validate0(final E object, final int viewDistance) { // Pufferfish - rename this thing just in case it gets used I'd rather a compile time error. -+ if (true) throw new UnsupportedOperationException(); // Pufferfish - not going to put in the effort to fix this if it doesn't ever get used. - int entiesGot = 0; - int expectedEntries = (2 * viewDistance + 1); - expectedEntries *= expectedEntries; -diff --git a/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java -index 46954db7ecd35ac4018fdf476df7c8020d7ce6c8..1ad890a244bdf6df48a8db68cb43450e08c788a6 100644 ---- a/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java -+++ b/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java -@@ -5,7 +5,7 @@ import net.minecraft.server.level.ServerPlayer; - /** - * @author Spottedleaf - */ --public final class PlayerAreaMap extends AreaMap { -+public class PlayerAreaMap extends AreaMap { // Pufferfish - not actually final - - public PlayerAreaMap() { - super(); -diff --git a/src/main/java/gg/airplane/structs/FluidDirectionCache.java b/src/main/java/gg/airplane/structs/FluidDirectionCache.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aa8467b9dda1f7707e41f50ac7b3e9d7343723ec ---- /dev/null -+++ b/src/main/java/gg/airplane/structs/FluidDirectionCache.java -@@ -0,0 +1,136 @@ -+package gg.airplane.structs; -+ -+import it.unimi.dsi.fastutil.HashCommon; -+ -+/** -+ * This is a replacement for the cache used in FluidTypeFlowing. -+ * The requirements for the previous cache were: -+ * - Store 200 entries -+ * - Look for the flag in the cache -+ * - If it exists, move to front of cache -+ * - If it doesn't exist, remove last entry in cache and insert in front -+ * -+ * This class accomplishes something similar, however has a few different -+ * requirements put into place to make this more optimize: -+ * -+ * - maxDistance is the most amount of entries to be checked, instead -+ * of having to check the entire list. -+ * - In combination with that, entries are all tracked by age and how -+ * frequently they're used. This enables us to remove old entries, -+ * without constantly shifting any around. -+ * -+ * Usage of the previous map would have to reset the head every single usage, -+ * shifting the entire map. Here, nothing happens except an increment when -+ * the cache is hit, and when it needs to replace an old element only a single -+ * element is modified. -+ */ -+public class FluidDirectionCache { -+ -+ private static class FluidDirectionEntry { -+ private final T data; -+ private final boolean flag; -+ private int uses = 0; -+ private int age = 0; -+ -+ private FluidDirectionEntry(T data, boolean flag) { -+ this.data = data; -+ this.flag = flag; -+ } -+ -+ public int getValue() { -+ return this.uses - (this.age >> 1); // age isn't as important as uses -+ } -+ -+ public void incrementUses() { -+ this.uses = this.uses + 1 & Integer.MAX_VALUE; -+ } -+ -+ public void incrementAge() { -+ this.age = this.age + 1 & Integer.MAX_VALUE; -+ } -+ } -+ -+ private final FluidDirectionEntry[] entries; -+ private final int mask; -+ private final int maxDistance; // the most amount of entries to check for a value -+ -+ public FluidDirectionCache(int size) { -+ int arraySize = HashCommon.nextPowerOfTwo(size); -+ this.entries = new FluidDirectionEntry[arraySize]; -+ this.mask = arraySize - 1; -+ this.maxDistance = Math.min(arraySize, 4); -+ } -+ -+ public Boolean getValue(T data) { -+ FluidDirectionEntry curr; -+ int pos; -+ -+ if ((curr = this.entries[pos = HashCommon.mix(data.hashCode()) & this.mask]) == null) { -+ return null; -+ } else if (data.equals(curr.data)) { -+ curr.incrementUses(); -+ return curr.flag; -+ } -+ -+ int checked = 1; // start at 1 because we already checked the first spot above -+ -+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) { -+ if (data.equals(curr.data)) { -+ curr.incrementUses(); -+ return curr.flag; -+ } else if (++checked >= this.maxDistance) { -+ break; -+ } -+ } -+ -+ return null; -+ } -+ -+ public void putValue(T data, boolean flag) { -+ FluidDirectionEntry curr; -+ int pos; -+ -+ if ((curr = this.entries[pos = HashCommon.mix(data.hashCode()) & this.mask]) == null) { -+ this.entries[pos] = new FluidDirectionEntry<>(data, flag); // add -+ return; -+ } else if (data.equals(curr.data)) { -+ curr.incrementUses(); -+ return; -+ } -+ -+ int checked = 1; // start at 1 because we already checked the first spot above -+ -+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) { -+ if (data.equals(curr.data)) { -+ curr.incrementUses(); -+ return; -+ } else if (++checked >= this.maxDistance) { -+ this.forceAdd(data, flag); -+ return; -+ } -+ } -+ -+ this.entries[pos] = new FluidDirectionEntry<>(data, flag); // add -+ } -+ -+ private void forceAdd(T data, boolean flag) { -+ int expectedPos = HashCommon.mix(data.hashCode()) & this.mask; -+ -+ int toRemovePos = expectedPos; -+ FluidDirectionEntry entryToRemove = this.entries[toRemovePos]; -+ -+ for (int i = expectedPos + 1; i < expectedPos + this.maxDistance; i++) { -+ int pos = i & this.mask; -+ FluidDirectionEntry entry = this.entries[pos]; -+ if (entry.getValue() < entryToRemove.getValue()) { -+ toRemovePos = pos; -+ entryToRemove = entry; -+ } -+ -+ entry.incrementAge(); // use this as a mechanism to age the other entries -+ } -+ -+ // remove the least used/oldest entry -+ this.entries[toRemovePos] = new FluidDirectionEntry(data, flag); -+ } -+} -diff --git a/src/main/java/gg/airplane/structs/ItemListWithBitset.java b/src/main/java/gg/airplane/structs/ItemListWithBitset.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1b7a4ee47f4445d7f2ac91d3a73ae113edbdddb2 ---- /dev/null -+++ b/src/main/java/gg/airplane/structs/ItemListWithBitset.java -@@ -0,0 +1,114 @@ -+package gg.airplane.structs; -+ -+import net.minecraft.core.NonNullList; -+import net.minecraft.world.item.ItemStack; -+import org.apache.commons.lang.Validate; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.AbstractList; -+import java.util.Arrays; -+import java.util.List; -+ -+public class ItemListWithBitset extends AbstractList { -+ public static ItemListWithBitset fromList(List list) { -+ if (list instanceof ItemListWithBitset ours) { -+ return ours; -+ } -+ return new ItemListWithBitset(list); -+ } -+ -+ private static ItemStack[] createArray(int size) { -+ ItemStack[] array = new ItemStack[size]; -+ Arrays.fill(array, ItemStack.EMPTY); -+ return array; -+ } -+ -+ private final ItemStack[] items; -+ -+ private long bitSet = 0; -+ private final long allBits; -+ -+ private static class OurNonNullList extends NonNullList { -+ protected OurNonNullList(List delegate) { -+ super(delegate, ItemStack.EMPTY); -+ } -+ } -+ -+ public final NonNullList nonNullList = new OurNonNullList(this); -+ -+ private ItemListWithBitset(List list) { -+ this(list.size()); -+ -+ for (int i = 0; i < list.size(); i++) { -+ this.set(i, list.get(i)); -+ } -+ } -+ -+ public ItemListWithBitset(int size) { -+ Validate.isTrue(size < Long.BYTES * 8, "size is too large"); -+ -+ this.items = createArray(size); -+ this.allBits = ((1L << size) - 1); -+ } -+ -+ public boolean isCompletelyEmpty() { -+ return this.bitSet == 0; -+ } -+ -+ public boolean hasFullStacks() { -+ return (this.bitSet & this.allBits) == allBits; -+ } -+ -+ @Override -+ public ItemStack set(int index, @NotNull ItemStack itemStack) { -+ ItemStack existing = this.items[index]; -+ -+ this.items[index] = itemStack; -+ -+ if (itemStack == ItemStack.EMPTY) { -+ this.bitSet &= ~(1L << index); -+ } else { -+ this.bitSet |= 1L << index; -+ } -+ -+ return existing; -+ } -+ -+ @NotNull -+ @Override -+ public ItemStack get(int var0) { -+ return this.items[var0]; -+ } -+ -+ @Override -+ public int size() { -+ return this.items.length; -+ } -+ -+ @Override -+ public void clear() { -+ Arrays.fill(this.items, ItemStack.EMPTY); -+ } -+ -+ // these are unsupported for block inventories which have a static size -+ @Override -+ public void add(int var0, ItemStack var1) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public ItemStack remove(int var0) { -+ throw new UnsupportedOperationException(); -+ } -+ -+ @Override -+ public String toString() { -+ return "ItemListWithBitset{" + -+ "items=" + Arrays.toString(items) + -+ ", bitSet=" + Long.toString(bitSet, 2) + -+ ", allBits=" + Long.toString(allBits, 2) + -+ ", size=" + this.items.length + -+ '}'; -+ } -+} -diff --git a/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java b/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a7f297ebb569f7c1f205e967ca485be70013a714 ---- /dev/null -+++ b/src/main/java/gg/airplane/structs/Long2FloatAgingCache.java -@@ -0,0 +1,119 @@ -+package gg.airplane.structs; -+ -+import it.unimi.dsi.fastutil.HashCommon; -+ -+/** -+ * A replacement for the cache used in Biome. -+ */ -+public class Long2FloatAgingCache { -+ -+ private static class AgingEntry { -+ private long data; -+ private float value; -+ private int uses = 0; -+ private int age = 0; -+ -+ private AgingEntry(long data, float value) { -+ this.data = data; -+ this.value = value; -+ } -+ -+ public void replace(long data, float flag) { -+ this.data = data; -+ this.value = flag; -+ } -+ -+ public int getValue() { -+ return this.uses - (this.age >> 1); // age isn't as important as uses -+ } -+ -+ public void incrementUses() { -+ this.uses = this.uses + 1 & Integer.MAX_VALUE; -+ } -+ -+ public void incrementAge() { -+ this.age = this.age + 1 & Integer.MAX_VALUE; -+ } -+ } -+ -+ private final AgingEntry[] entries; -+ private final int mask; -+ private final int maxDistance; // the most amount of entries to check for a value -+ -+ public Long2FloatAgingCache(int size) { -+ int arraySize = HashCommon.nextPowerOfTwo(size); -+ this.entries = new AgingEntry[arraySize]; -+ this.mask = arraySize - 1; -+ this.maxDistance = Math.min(arraySize, 4); -+ } -+ -+ public float getValue(long data) { -+ AgingEntry curr; -+ int pos; -+ -+ if ((curr = this.entries[pos = HashCommon.mix(HashCommon.long2int(data)) & this.mask]) == null) { -+ return Float.NaN; -+ } else if (data == curr.data) { -+ curr.incrementUses(); -+ return curr.value; -+ } -+ -+ int checked = 1; // start at 1 because we already checked the first spot above -+ -+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) { -+ if (data == curr.data) { -+ curr.incrementUses(); -+ return curr.value; -+ } else if (++checked >= this.maxDistance) { -+ break; -+ } -+ } -+ -+ return Float.NaN; -+ } -+ -+ public void putValue(long data, float value) { -+ AgingEntry curr; -+ int pos; -+ -+ if ((curr = this.entries[pos = HashCommon.mix(HashCommon.long2int(data)) & this.mask]) == null) { -+ this.entries[pos] = new AgingEntry(data, value); // add -+ return; -+ } else if (data == curr.data) { -+ curr.incrementUses(); -+ return; -+ } -+ -+ int checked = 1; // start at 1 because we already checked the first spot above -+ -+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) { -+ if (data == curr.data) { -+ curr.incrementUses(); -+ return; -+ } else if (++checked >= this.maxDistance) { -+ this.forceAdd(data, value); -+ return; -+ } -+ } -+ -+ this.entries[pos] = new AgingEntry(data, value); // add -+ } -+ -+ private void forceAdd(long data, float value) { -+ int expectedPos = HashCommon.mix(HashCommon.long2int(data)) & this.mask; -+ AgingEntry entryToRemove = this.entries[expectedPos]; -+ -+ for (int i = expectedPos + 1; i < expectedPos + this.maxDistance; i++) { -+ int pos = i & this.mask; -+ AgingEntry entry = this.entries[pos]; -+ if (entry.getValue() < entryToRemove.getValue()) { -+ entryToRemove = entry; -+ } -+ -+ entry.incrementAge(); // use this as a mechanism to age the other entries -+ } -+ -+ // remove the least used/oldest entry -+ entryToRemove.replace(data, value); -+ } -+} diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishCommand.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..020368da69b9a492155f6de6297f74732f4ab6ea @@ -616,10 +233,10 @@ index 0000000000000000000000000000000000000000..020368da69b9a492155f6de6297f7473 +} diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java new file mode 100644 -index 0000000000000000000000000000000000000000..6464682e2f93659e73aca491031c8051ab000033 +index 0000000000000000000000000000000000000000..f5a43a1e1a78b3eaabbcadc7af09750ee478eeb6 --- /dev/null +++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -@@ -0,0 +1,302 @@ +@@ -0,0 +1,280 @@ +package gg.pufferfish.pufferfish; + +import gg.pufferfish.pufferfish.simd.SIMDDetection; @@ -627,10 +244,7 @@ index 0000000000000000000000000000000000000000..6464682e2f93659e73aca491031c8051 +import java.io.IOException; +import java.util.Collections; +import net.minecraft.core.registries.BuiltInRegistries; -+import java.util.Locale; -+import java.util.Map; +import net.minecraft.server.MinecraftServer; -+import net.minecraft.tags.TagKey; +import org.apache.logging.log4j.Level; +import org.bukkit.configuration.ConfigurationSection; +import net.minecraft.world.entity.EntityType; @@ -708,7 +322,7 @@ index 0000000000000000000000000000000000000000..6464682e2f93659e73aca491031c8051 + // Attempt to detect vectorization + try { + SIMDDetection.isEnabled = SIMDDetection.canEnable(PufferfishLogger.LOGGER); -+ SIMDDetection.versionLimited = SIMDDetection.getJavaVersion() != 17 && SIMDDetection.getJavaVersion() != 18 && SIMDDetection.getJavaVersion() != 19; ++ SIMDDetection.versionLimited = SIMDDetection.getJavaVersion() < 17 || SIMDDetection.getJavaVersion() > 21; + } catch (NoClassDefFoundError | Exception ignored) { + ignored.printStackTrace(); + } @@ -716,7 +330,7 @@ index 0000000000000000000000000000000000000000..6464682e2f93659e73aca491031c8051 + if (SIMDDetection.isEnabled) { + PufferfishLogger.LOGGER.info("SIMD operations detected as functional. Will replace some operations with faster versions."); + } else if (SIMDDetection.versionLimited) { -+ PufferfishLogger.LOGGER.warning("Will not enable SIMD! These optimizations are only safely supported on Java 17, Java 18, and Java 19."); ++ PufferfishLogger.LOGGER.warning("Will not enable SIMD! These optimizations are only safely supported on Java 17-21."); + } else { + PufferfishLogger.LOGGER.warning("SIMD operations are available for your server, but are not configured!"); + PufferfishLogger.LOGGER.warning("To enable additional optimizations, add \"--add-modules=jdk.incubator.vector\" to your startup flags, BEFORE the \"-jar\"."); @@ -878,23 +492,6 @@ index 0000000000000000000000000000000000000000..6464682e2f93659e73aca491031c8051 + + setComment("dab", "Optimizes entity brains when", "they're far away from the player"); + } -+ -+ public static Map projectileTimeouts; -+ private static void projectileTimeouts() { -+ // Set some defaults -+ getInt("entity_timeouts.SNOWBALL", -1); -+ getInt("entity_timeouts.LLAMA_SPIT", -1); -+ setComment("entity_timeouts", -+ "These values define a entity's maximum lifespan. If an", -+ "entity is in this list and it has survived for longer than", -+ "that number of ticks, then it will be removed. Setting a value to", -+ "-1 disables this feature."); -+ -+ for (EntityType entityType : BuiltInRegistries.ENTITY_TYPE) { -+ String type = EntityType.getKey(entityType).getPath().toUpperCase(Locale.ROOT); -+ entityType.ttl = config.getInt("entity_timeouts." + type, -1); -+ } -+ } + + public static boolean throttleInactiveGoalSelectorTick; + private static void inactiveGoalSelectorThrottle() { @@ -914,10 +511,8 @@ index 0000000000000000000000000000000000000000..6464682e2f93659e73aca491031c8051 + + + public static boolean disableMethodProfiler; -+ public static boolean disableOutOfOrderChat; + private static void miscSettings() { -+ disableMethodProfiler = getBoolean("misc.disable-method-profiler", true); -+ disableOutOfOrderChat = getBoolean("misc.disable-out-of-order-chat", false); ++ disableMethodProfiler = getBoolean("misc.disable-method-profiler", true); + setComment("misc", "Settings for things that don't belong elsewhere"); + } + @@ -946,20 +541,24 @@ index 0000000000000000000000000000000000000000..53f2df00c6809618a9ee3d2ea72e85e8 +} diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishVersionFetcher.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishVersionFetcher.java new file mode 100644 -index 0000000000000000000000000000000000000000..893d8c0946ef71a0561221dd76bffff0dc940d56 +index 0000000000000000000000000000000000000000..06323dcc745aed16123980fc559d7b65c42f1e1c --- /dev/null +++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishVersionFetcher.java -@@ -0,0 +1,136 @@ +@@ -0,0 +1,132 @@ +package gg.pufferfish.pufferfish; + -+import static net.kyori.adventure.text.Component.text; -+import static net.kyori.adventure.text.format.NamedTextColor.GREEN; -+import static net.kyori.adventure.text.format.NamedTextColor.RED; -+ +import com.destroystokyo.paper.VersionHistoryManager; +import com.destroystokyo.paper.util.VersionFetcher; +import com.google.gson.Gson; +import com.google.gson.JsonObject; ++import io.papermc.paper.ServerBuildInfo; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.JoinConfiguration; ++import net.kyori.adventure.text.format.NamedTextColor; ++import net.kyori.adventure.text.format.TextDecoration; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; @@ -969,21 +568,18 @@ index 0000000000000000000000000000000000000000..893d8c0946ef71a0561221dd76bffff0 +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.JoinConfiguration; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.format.TextDecoration; -+import org.bukkit.craftbukkit.CraftServer; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; ++ ++import static net.kyori.adventure.text.Component.text; ++import static net.kyori.adventure.text.format.NamedTextColor.GREEN; ++import static net.kyori.adventure.text.format.NamedTextColor.RED; + +public class PufferfishVersionFetcher implements VersionFetcher { + + private static final Logger LOGGER = Logger.getLogger("PufferfishVersionFetcher"); + private static final HttpClient client = HttpClient.newHttpClient(); + -+ private static final URI JENKINS_URI = URI.create("https://ci.pufferfish.host/job/Pufferfish-1.20/lastSuccessfulBuild/buildNumber"); -+ private static final String GITHUB_FORMAT = "https://api.github.com/repos/pufferfish-gg/Pufferfish/compare/ver/1.20...%s"; ++ private static final URI JENKINS_URI = URI.create("https://ci.pufferfish.host/job/Pufferfish-1.21/lastSuccessfulBuild/buildNumber"); ++ private static final String GITHUB_FORMAT = "https://api.github.com/repos/pufferfish-gg/Pufferfish/compare/ver/1.21...%s"; + + private static final HttpResponse.BodyHandler JSON_OBJECT_BODY_HANDLER = responseInfo -> HttpResponse.BodySubscribers + .mapping( @@ -998,21 +594,16 @@ index 0000000000000000000000000000000000000000..893d8c0946ef71a0561221dd76bffff0 + + @Override + public @NotNull Component getVersionMessage(final @NotNull String serverVersion) { -+ final String[] parts = CraftServer.class.getPackage().getImplementationVersion().split("-"); + @NotNull Component component; -+ -+ if (parts.length != 3) { -+ component = text("Unknown server version.", RED); ++ ++ if (ServerBuildInfo.buildInfo().buildNumber().isPresent()) { ++ component = this.fetchJenkinsVersion(ServerBuildInfo.buildInfo().buildNumber().getAsInt()); ++ } else if (ServerBuildInfo.buildInfo().gitCommit().isPresent()) { ++ component = this.fetchGithubVersion(ServerBuildInfo.buildInfo().gitCommit().get()); + } else { -+ final String versionString = parts[2]; -+ -+ try { -+ component = this.fetchJenkinsVersion(Integer.parseInt(versionString)); -+ } catch (NumberFormatException e) { -+ component = this.fetchGithubVersion(versionString.substring(1, versionString.length() - 1)); -+ } ++ component = text("Unknown server version.", RED); + } -+ ++ + final @Nullable Component history = this.getHistory(); + return history != null ? Component + .join(JoinConfiguration.noSeparators(), component, Component.newline(), this.getHistory()) : component; @@ -1066,8 +657,8 @@ index 0000000000000000000000000000000000000000..893d8c0946ef71a0561221dd76bffff0 + return switch (Math.max(-1, Math.min(1, versionDiff))) { + case -1 -> text("You are running an unsupported version of Pufferfish.", RED); + case 0 -> text("You are on the latest version!", GREEN); -+ default -> text("You are running " + versionDiff + " version" + (versionDiff == 1 ? "" : "s") + " beyond. " + -+ "Please update your server when possible to maintain stability, security, and receive the latest optimizations.", ++ default -> text("You are running " + versionDiff + " version" + (versionDiff == 1 ? "" : "s") + " behind. " + ++ "Please update your server when possible to maintain stability and security, and to receive the latest optimizations.", + RED); + }; + } @@ -1353,43 +944,6 @@ index 0000000000000000000000000000000000000000..8e5323d5d9af25c8a85c4b34a6be76cf + } + +} -diff --git a/src/main/java/gg/pufferfish/pufferfish/util/AsyncPlayerAreaMap.java b/src/main/java/gg/pufferfish/pufferfish/util/AsyncPlayerAreaMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fdcb62d12164024a5f354d60cc863821a18d1b2a ---- /dev/null -+++ b/src/main/java/gg/pufferfish/pufferfish/util/AsyncPlayerAreaMap.java -@@ -0,0 +1,31 @@ -+package gg.pufferfish.pufferfish.util; -+ -+import com.destroystokyo.paper.util.misc.PlayerAreaMap; -+import com.destroystokyo.paper.util.misc.PooledLinkedHashSets; -+import java.util.concurrent.ConcurrentHashMap; -+import net.minecraft.server.level.ServerPlayer; -+ -+public final class AsyncPlayerAreaMap extends PlayerAreaMap { -+ -+ public AsyncPlayerAreaMap() { -+ super(); -+ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); -+ } -+ -+ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets) { -+ super(pooledHashSets); -+ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); -+ } -+ -+ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, -+ final ChangeCallback removeCallback) { -+ this(pooledHashSets, addCallback, removeCallback, null); -+ } -+ -+ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, -+ final ChangeCallback removeCallback, final ChangeSourceCallback changeSourceCallback) { -+ super(pooledHashSets, addCallback, removeCallback, changeSourceCallback); -+ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); -+ } -+ -+} diff --git a/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java b/src/main/java/gg/pufferfish/pufferfish/util/IterableWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..c1929840254a3e6d721816f4a20415bea1742580 @@ -1462,88 +1016,53 @@ index 0000000000000000000000000000000000000000..facd55463d44cb7e3d2ca6892982f549 + return backingMap.size(); + } +} -diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index e028353e0261310afc42ca0454b723d9f1ffc131..2222625a515d9ae6c3e9c92fc4d4a5bf974af5f8 100644 ---- a/src/main/java/io/papermc/paper/util/MCUtil.java -+++ b/src/main/java/io/papermc/paper/util/MCUtil.java -@@ -215,7 +215,7 @@ public final class MCUtil { - } - - public static long getCoordinateKey(final Entity entity) { -- return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); -+ return ((long)(entity.blockPosition.getZ() >> 4) << 32) | ((entity.blockPosition.getX() >> 4) & 0xFFFFFFFFL); // Pufferfish - eliminate double->long cast in hotpath - } - - public static long getCoordinateKey(final ChunkPos pair) { -diff --git a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -index 0af9ed92824ccf30814eceb6a2c2e5c12661c991..67eeb39aede6908d2756e49821ca350ebe916902 100644 ---- a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -+++ b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java -@@ -37,7 +37,7 @@ public class SignedMessageChain { - throw new SignedMessageChain.DecodeException(Component.translatable("chat.disabled.chain_broken"), false); // Paper - diff on change (if disconnects, need a new kick event cause) - } else if (playerPublicKey.data().hasExpired()) { - throw new SignedMessageChain.DecodeException(Component.translatable("chat.disabled.expiredProfileKey"), false, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes -- } else if (body.timeStamp().isBefore(this.lastTimeStamp)) { -+ } else if (!gg.pufferfish.pufferfish.PufferfishConfig.disableOutOfOrderChat && body.timeStamp().isBefore(this.lastTimeStamp)) { // Pufferfish - throw new SignedMessageChain.DecodeException(Component.translatable("multiplayer.disconnect.out_of_order_chat"), true, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes - } else { - this.lastTimeStamp = body.timeStamp(); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 2dc07e5ef249636e85ad9c78e3729e9e066a8fe8..b9e0a32f5829ca15f949effcafcbe2a975f6f690 100644 +index ae4ebf509837e8d44255781c61d02873f8b74be8..312edb4c47a404c1d20e6bdf748a4ccb49a330f4 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -312,6 +312,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { - AtomicReference atomicreference = new AtomicReference(); -@@ -1229,6 +1230,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Paper - } - - public SystemReport fillSystemReport(SystemReport details) { -@@ -2452,6 +2459,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + this.executeBlocking(() -> { diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 68d268b6fff126e8645b6deec3fb549ea2286b77..435b129c433704c24828d8fb57e14333c9423207 100644 +index 17a158ff6ce6520b69a5a0032ba4c05449dd0cf8..d62f7375394409a278bc565c8263506c598ceeba 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -221,6 +221,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -236,6 +236,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now - io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // Paper - init PaperBrigadierProvider + gg.pufferfish.pufferfish.PufferfishConfig.load(); // Pufferfish + gg.pufferfish.pufferfish.PufferfishCommand.init(); // Pufferfish this.setPvpAllowed(dedicatedserverproperties.pvp); this.setFlightAllowed(dedicatedserverproperties.allowFlight); -@@ -339,6 +341,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -356,6 +358,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface DedicatedServer.LOGGER.info("JMX monitoring enabled"); } @@ -1551,65 +1070,13 @@ index 68d268b6fff126e8645b6deec3fb549ea2286b77..435b129c433704c24828d8fb57e14333 return true; } } -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 12109446fc76a39faee6cda042ca48b3fd3809f4..1081e9df44bb24b2c51ebd9364c21c7b2a3a205a 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -243,7 +243,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper end - // Paper start - optimise chunk tick iteration - public final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet needsChangeBroadcasting = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets); -+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap = new gg.pufferfish.pufferfish.util.AsyncPlayerAreaMap(this.pooledLinkedPlayerHashSets); // Pufferfish - // Paper end - optimise chunk tick iteration - - public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { -@@ -1448,8 +1448,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - return ChunkMap.this.level.getServer().getScaledTrackingDistance(initialDistance); - } - -+ private static int getHighestRange(Entity parent, int highest) { -+ List passengers = parent.getPassengers(); -+ -+ for (int i = 0, size = passengers.size(); i < size; i++) { -+ Entity entity = passengers.get(i); -+ int range = entity.getType().clientTrackingRange() * 16; -+ range = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, range); // Paper -+ -+ if (range > highest) { // Paper - we need the lowest range thanks to the fact that our tracker doesn't account for passenger logic // Tuinity - not anymore! -+ highest = range; -+ } -+ -+ highest = getHighestRange(entity, highest); -+ } -+ -+ return highest; -+ } -+ - private int getEffectiveRange() { - int i = this.range; -+ // Pufferfish start - remove iterators and streams -+ /* - Iterator iterator = this.entity.getIndirectPassengers().iterator(); - - while (iterator.hasNext()) { -@@ -1461,6 +1481,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - i = j; - } - } -+ */ -+ i = getHighestRange(this.entity, i); -+ // Pufferfish end - - return this.scaledRange(i); - } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 366c0c9b45a819f7f94ebe3e49b8ab7f9edf9ce7..1cf8c819c0d7776c3b33d6594ca81abe3c2a719d 100644 +index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..aea9a45c0916501f71018d3250b56da435f5664e 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -77,6 +77,9 @@ public class ServerChunkCache extends ChunkSource { - private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4]; - // Paper end +@@ -183,6 +183,9 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + // Paper end - chunk tick iteration optimisations + + public boolean firstRunSpawnCounts = true; // Pufferfish + public final java.util.concurrent.atomic.AtomicBoolean _pufferfish_spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false); // Pufferfish - optimize countmobs @@ -1617,57 +1084,8 @@ index 366c0c9b45a819f7f94ebe3e49b8ab7f9edf9ce7..1cf8c819c0d7776c3b33d6594ca81abe public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory) { this.level = world; this.mainThreadProcessor = new ServerChunkCache.MainThreadExecutor(world); -@@ -513,6 +516,7 @@ public class ServerChunkCache extends ChunkSource { - - // Paper - optimise chunk tick iteration - -+ this.level.resetIceAndSnowTick(); // Pufferfish - reset ice & snow tick random - if (this.level.getServer().tickRateManager().runsNormally()) { - gameprofilerfiller.popPush("naturalSpawnCount"); - this.level.timings.countNaturalMobs.startTiming(); // Paper - timings -@@ -521,6 +525,7 @@ public class ServerChunkCache extends ChunkSource { - int naturalSpawnChunkCount = k; - NaturalSpawner.SpawnState spawnercreature_d; // moved down - if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled -+ if (!gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning) { // Pufferfish - moved down when async processing - // re-set mob counts - for (ServerPlayer player : this.level.players) { - // Paper start - per player mob spawning backoff -@@ -535,14 +540,18 @@ public class ServerChunkCache extends ChunkSource { - } - // Paper end - per player mob spawning backoff - } -- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); -+ lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); // Pufferfish - async mob spawning -+ } // Pufferfish - (endif) moved down when async processing - } else { -- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); -+ // Pufferfish start - async mob spawning -+ lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); -+ _pufferfish_spawnCountsReady.set(true); -+ // Pufferfish end - } - // Paper end - Optional per player mob spawns - this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings - -- this.lastSpawnState = spawnercreature_d; -+ // this.lastSpawnState = spawnercreature_d; // Pufferfish - this is managed asynchronously - gameprofilerfiller.popPush("spawnAndTick"); - boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit - -@@ -632,8 +641,8 @@ public class ServerChunkCache extends ChunkSource { - if (tick && chunk1.chunkStatus.isOrAfter(net.minecraft.server.level.FullChunkStatus.ENTITY_TICKING)) { - // Paper end - optimise chunk tick iteration - chunk1.incrementInhabitedTime(j); -- if (spawn && flag && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair)) { // Spigot // Paper - optimise chunk tick iteration -- NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1); -+ if (spawn && flag && (!gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning || _pufferfish_spawnCountsReady.get()) && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair)) { // Spigot // Paper - optimise chunk tick iteration // Pufferfish -+ NaturalSpawner.spawnForChunk(this.level, chunk1, lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag1); // Pufferfish - } - - if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - optimise chunk tick iteration -@@ -680,6 +689,40 @@ public class ServerChunkCache extends ChunkSource { - gameprofilerfiller.pop(); +@@ -511,6 +514,43 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + this.broadcastChangedChunks(gameprofilerfiller); gameprofilerfiller.pop(); } + @@ -1693,12 +1111,15 @@ index 366c0c9b45a819f7f94ebe3e49b8ab7f9edf9ce7..1cf8c819c0d7776c3b33d6594ca81abe + if (_pufferfish_spawnCountsReady.getAndSet(false)) { + net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> { + int mapped = distanceManager.getNaturalSpawnChunkCount(); -+ io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator objectiterator = -+ level.entityTickList.entities.iterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); -+ gg.pufferfish.pufferfish.util.IterableWrapper wrappedIterator = -+ new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator); -+ lastSpawnState = NaturalSpawner.createState(mapped, wrappedIterator, this::getFullChunk, null, true); -+ objectiterator.finishedIterating(); ++ ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator objectiterator = ++ level.entityTickList.entities.iterator(ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); ++ try { ++ gg.pufferfish.pufferfish.util.IterableWrapper wrappedIterator = ++ new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator); ++ lastSpawnState = NaturalSpawner.createState(mapped, wrappedIterator, this::getFullChunk, null, true); ++ } finally { ++ objectiterator.finishedIterating(); ++ } + _pufferfish_spawnCountsReady.set(true); + }); + } @@ -1706,42 +1127,89 @@ index 366c0c9b45a819f7f94ebe3e49b8ab7f9edf9ce7..1cf8c819c0d7776c3b33d6594ca81abe + // Pufferfish end } - private void getFullChunk(long pos, Consumer chunkConsumer) { + private void broadcastChangedChunks(ProfilerFiller profiler) { +@@ -560,6 +600,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + final int naturalSpawnChunkCount = j; + NaturalSpawner.SpawnState spawnercreature_d; // moved down + if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled ++ if (!gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning) { // Pufferfish - moved down when async processing + // re-set mob counts + for (ServerPlayer player : this.level.players) { + // Paper start - per player mob spawning backoff +@@ -574,13 +615,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + } + // Paper end - per player mob spawning backoff + } +- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); ++ lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); // Pufferfish - async mob spawning ++ } // Pufferfish - (endif) moved down when async processing + } else { +- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); ++ // Pufferfish start - async mob spawning ++ lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); ++ _pufferfish_spawnCountsReady.set(true); ++ // Pufferfish end + } + // Paper end - Optional per player mob spawns + +- this.lastSpawnState = spawnercreature_d; ++ // this.lastSpawnState = spawnercreature_d; // Pufferfish - this is managed asynchronously + profiler.popPush("spawnAndTick"); + boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit + int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); +@@ -597,7 +642,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + // Paper end - PlayerNaturallySpawnCreaturesEvent + boolean flag1 = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit + +- list1 = NaturalSpawner.getFilteredSpawningCategories(spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1, this.level); // CraftBukkit ++ list1 = NaturalSpawner.getFilteredSpawningCategories(lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag1, this.level); // CraftBukkit // Pufferfish + } else { + list1 = List.of(); + } +@@ -609,8 +654,8 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + ChunkPos chunkcoordintpair = chunk.getPos(); + + chunk.incrementInhabitedTime(timeDelta); +- if (!list1.isEmpty() && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot +- NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, list1); ++ if (!list1.isEmpty() && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && (!gg.pufferfish.pufferfish.PufferfishConfig.enableAsyncMobSpawning || _pufferfish_spawnCountsReady.get()) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot // Pufferfish ++ NaturalSpawner.spawnForChunk(this.level, chunk, lastSpawnState, list1); // Pufferfish + } + + if (true) { // Paper - rewrite chunk system diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 529ab44baaf573b97cf7e89560c548642733188f..db55ad9aaabfa1ea998754f3ac352d1698936696 100644 +index 103e2c414780be66324bcb9cd4ea539bbdfe12ad..c563326d3131bc726c7f43311c3eaa82131c6745 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java +++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -183,7 +183,8 @@ public class ServerEntity { - long i1 = this.positionCodec.encodeZ(vec3d); - boolean flag6 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L; +@@ -207,6 +207,7 @@ public class ServerEntity { + boolean flag5 = i < -32768L || i > 32767L || j < -32768L || j > 32767L || k < -32768L || k > 32767L; -- if (!flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()&& !(io.papermc.paper.configuration.GlobalConfiguration.get().collisions.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync -+ if (!flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround() && !(io.papermc.paper.configuration.GlobalConfiguration.get().collisions.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync + if (!this.forceStateResync && !flag5 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) { // Paper - fix desync when a player is added to the tracker + if (flag2 || flag3 || this.entity instanceof AbstractArrow) { // Pufferfish - if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) { + if ((!flag2 || !flag) && !(this.entity instanceof AbstractArrow)) { if (flag2) { - packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.onGround()); -@@ -197,6 +198,7 @@ public class ServerEntity { + packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) i), (short) ((int) j), (short) ((int) k), this.entity.onGround()); +@@ -220,6 +221,7 @@ public class ServerEntity { + flag3 = true; flag4 = true; - flag5 = true; } + } // Pufferfish } else { this.wasOnGround = this.entity.onGround(); this.teleportDelay = 0; diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 502bdc726b7890b00ee36871d905dea44e8719e3..fbffe3dab1b7812b50df5d6bddf4fbdb2e583339 100644 +index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..fe295515b8043d988eb87c2caf516a4ae4169451 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -894,6 +894,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -793,6 +793,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + org.spigotmc.ActivationRange.activateEntities(this); // Spigot - this.timings.entityTick.startTiming(); // Spigot this.entityTickList.forEach((entity) -> { + entity.activatedPriorityReset = false; // Pufferfish - DAB if (!entity.isRemoved()) { - if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed - entity.discard(); -@@ -913,7 +914,20 @@ public class ServerLevel extends Level implements WorldGenLevel { + if (!tickratemanager.isEntityFrozen(entity)) { + gameprofilerfiller.push("checkDespawn"); +@@ -810,7 +811,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } gameprofilerfiller.push("tick"); @@ -1749,7 +1217,6 @@ index 502bdc726b7890b00ee36871d905dea44e8719e3..fbffe3dab1b7812b50df5d6bddf4fbdb + // Pufferfish start - copied from this.guardEntityTick + try { + this.tickNonPassenger(entity); // Pufferfish - changed -+ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick + } catch (Throwable throwable) { + if (throwable instanceof ThreadDeath) throw throwable; // Paper + // Paper start - Prevent tile entity and entity crashes @@ -1759,335 +1226,73 @@ index 502bdc726b7890b00ee36871d905dea44e8719e3..fbffe3dab1b7812b50df5d6bddf4fbdb + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + // Paper end + } ++ this.moonrise$midTickTasks(); // Paper - rewrite chunk system + // Pufferfish end gameprofilerfiller.pop(); } } -@@ -978,9 +992,11 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - // Paper start - optimise random block ticking - private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); -- private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); -+ // private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); // Pufferfish - moved to super - // Paper end +@@ -931,7 +945,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ProfilerFiller gameprofilerfiller = Profiler.get(); -+ private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Pufferfish -+ - public void tickChunk(LevelChunk chunk, int randomTickSpeed) { - ChunkPos chunkcoordintpair = chunk.getPos(); - boolean flag = this.isRaining(); -@@ -991,7 +1007,7 @@ public class ServerLevel extends Level implements WorldGenLevel { gameprofilerfiller.push("thunder"); - final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change - -- if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder -+ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && /*this.random.nextInt(this.spigotConfig.thunderChance) == 0 &&*/ chunk.shouldDoLightning(this.random)) { // Spigot // Paper - Option to disable thunder // Pufferfish - replace random with shouldDoLightning - blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper +- if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && simpleRandom.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - Option to disable thunder // Paper - optimise random ticking ++ if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && /*simpleRandom.nextInt(this.spigotConfig.thunderChance) == 0*/ chunk.shouldDoLightning(this.simpleRandom)) { // Spigot // Paper - Option to disable thunder // Paper - optimise random ticking // Pufferfish - replace random with shouldDoLightning + BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15)); if (this.isRainingAt(blockposition)) { diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index fe2ef36ab5dc4b933abf24dbfd0e811c53239cf0..e725c1c0496383007ffb94c46fc18340666b5e29 100644 +index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..dedd8b3644699c4bdb33c9a7046342b620889b87 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -1135,6 +1135,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1226,6 +1226,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @Override public void handleEditBook(ServerboundEditBookPacket packet) { + if (!gg.pufferfish.pufferfish.PufferfishConfig.enableBooks && !this.player.getBukkitEntity().hasPermission("pufferfish.usebooks")) return; // Pufferfish // Paper start - Book size limits - if (!this.cserver.isPrimaryThread()) { - List pageList = packet.getPages(); -diff --git a/src/main/java/net/minecraft/world/CompoundContainer.java b/src/main/java/net/minecraft/world/CompoundContainer.java -index 241fec02e6869c638d3a160819b32173a081467b..6a8f9e8f5bf108674c47018def28906e2d0a729c 100644 ---- a/src/main/java/net/minecraft/world/CompoundContainer.java -+++ b/src/main/java/net/minecraft/world/CompoundContainer.java -@@ -1,5 +1,6 @@ - package net.minecraft.world; - -+import net.minecraft.core.Direction; // Pufferfish - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.ItemStack; - -@@ -64,6 +65,23 @@ public class CompoundContainer implements Container { - this.container2 = second; - } - -+ // Pufferfish start -+ @Override -+ public boolean hasEmptySlot(Direction enumdirection) { -+ return this.container1.hasEmptySlot(null) || this.container2.hasEmptySlot(null); -+ } -+ -+ @Override -+ public boolean isCompletelyFull(Direction enumdirection) { -+ return this.container1.isCompletelyFull(null) && this.container2.isCompletelyFull(null); -+ } -+ -+ @Override -+ public boolean isCompletelyEmpty(Direction enumdirection) { -+ return this.container1.isCompletelyEmpty(null) && this.container2.isCompletelyEmpty(null); -+ } -+ // Pufferfish end -+ - @Override - public int getContainerSize() { - return this.container1.getContainerSize() + this.container2.getContainerSize(); -diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java -index d6cbe98e67fdbf8db46338a88ab1356dd63b50a3..20dd3a63b2f955b05a75eb240e33ae4cf6aef28f 100644 ---- a/src/main/java/net/minecraft/world/Container.java -+++ b/src/main/java/net/minecraft/world/Container.java -@@ -3,6 +3,8 @@ package net.minecraft.world; - import java.util.Set; - import java.util.function.Predicate; - import net.minecraft.core.BlockPos; -+ -+import net.minecraft.core.Direction; // Pufferfish - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.Item; - import net.minecraft.world.item.ItemStack; -@@ -14,6 +16,63 @@ import org.bukkit.craftbukkit.entity.CraftHumanEntity; - // CraftBukkit end - - public interface Container extends Clearable { -+ // Pufferfish start - allow the inventory to override and optimize these frequent calls -+ default boolean hasEmptySlot(@org.jetbrains.annotations.Nullable Direction enumdirection) { // there is a slot with 0 items in it -+ if (this instanceof WorldlyContainer worldlyContainer) { -+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { -+ if (this.getItem(i).isEmpty()) { -+ return true; -+ } -+ } -+ } else { -+ int size = this.getContainerSize(); -+ for (int i = 0; i < size; i++) { -+ if (this.getItem(i).isEmpty()) { -+ return true; -+ } -+ } -+ } -+ return false; -+ } -+ -+ default boolean isCompletelyFull(@org.jetbrains.annotations.Nullable Direction enumdirection) { // every stack is maxed -+ if (this instanceof WorldlyContainer worldlyContainer) { -+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { -+ ItemStack itemStack = this.getItem(i); -+ if (itemStack.getCount() < itemStack.getMaxStackSize()) { -+ return false; -+ } -+ } -+ } else { -+ int size = this.getContainerSize(); -+ for (int i = 0; i < size; i++) { -+ ItemStack itemStack = this.getItem(i); -+ if (itemStack.getCount() < itemStack.getMaxStackSize()) { -+ return false; -+ } -+ } -+ } -+ return true; -+ } -+ -+ default boolean isCompletelyEmpty(@org.jetbrains.annotations.Nullable Direction enumdirection) { -+ if (this instanceof WorldlyContainer worldlyContainer) { -+ for (int i : worldlyContainer.getSlotsForFace(enumdirection)) { -+ if (!this.getItem(i).isEmpty()) { -+ return false; -+ } -+ } -+ } else { -+ int size = this.getContainerSize(); -+ for (int i = 0; i < size; i++) { -+ if (!this.getItem(i).isEmpty()) { -+ return false; -+ } -+ } -+ } -+ return true; -+ } -+ // Pufferfish end - - int LARGE_MAX_STACK_SIZE = 64; - int DEFAULT_DISTANCE_LIMIT = 8; + final io.papermc.paper.configuration.type.number.IntOr.Disabled pageMax = io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.pageMax; + if (!this.cserver.isPrimaryThread() && pageMax.enabled()) { diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 637478fd8a284e6833cf8f5fa17ccf9d73d1dd3f..1aa45e64e49ea011c2ba5e943b4e72c4f3a47176 100644 +index 1b547be0fe97119edf4f29666cfe0037e0c778e0..0348a458493c4fe22552ae2404272dd9b989d53e 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -309,7 +309,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - public double yo; - public double zo; - private Vec3 position; -- private BlockPos blockPosition; -+ public BlockPos blockPosition; // Pufferfish - private->public - private ChunkPos chunkPosition; - private Vec3 deltaMovement; - private float yRot; -@@ -424,6 +424,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - private UUID originWorld; +@@ -389,6 +389,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public boolean freezeLocked = false; // Paper - Freeze Tick Lock API public boolean fixedPose = false; // Paper - Expand Pose API + private final int despawnTime; // Paper - entity despawn time limit + public boolean activatedPriorityReset = false; // Pufferfish - DAB + public int activatedPriority = gg.pufferfish.pufferfish.PufferfishConfig.maximumActivationPrio; // Pufferfish - DAB (golf score) + public final BlockPos.MutableBlockPos cachedBlockPos = new BlockPos.MutableBlockPos(); // Pufferfish - reduce entity allocations public void setOrigin(@javax.annotation.Nonnull Location location) { this.origin = location.toVector(); -@@ -820,6 +823,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - } - - public void tick() { -+ // Pufferfish start - entity TTL -+ if (type != EntityType.PLAYER && type.ttl >= 0 && this.tickCount >= type.ttl) { -+ discard(); -+ return; -+ } -+ // Pufferfish end - entity TTL - this.baseTick(); - } - -@@ -4421,16 +4430,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - } - - public boolean updateFluidHeightAndDoFluidPushing(TagKey tag, double speed) { -- if (this.touchingUnloadedChunk()) { -+ if (false && this.touchingUnloadedChunk()) { // Pufferfish - cost of a lookup here is the same cost as below, so skip - return false; - } else { - AABB axisalignedbb = this.getBoundingBox().deflate(0.001D); -- int i = Mth.floor(axisalignedbb.minX); -- int j = Mth.ceil(axisalignedbb.maxX); -- int k = Mth.floor(axisalignedbb.minY); -- int l = Mth.ceil(axisalignedbb.maxY); -- int i1 = Mth.floor(axisalignedbb.minZ); -- int j1 = Mth.ceil(axisalignedbb.maxZ); -+ // Pufferfish start - rename -+ int minBlockX = Mth.floor(axisalignedbb.minX); -+ int maxBlockX = Mth.ceil(axisalignedbb.maxX); -+ int minBlockY = Mth.floor(axisalignedbb.minY); -+ int maxBlockY = Mth.ceil(axisalignedbb.maxY); -+ int minBlockZ = Mth.floor(axisalignedbb.minZ); -+ int maxBlockZ = Mth.ceil(axisalignedbb.maxZ); -+ // Pufferfish end - double d1 = 0.0D; - boolean flag = this.isPushedByFluid(); - boolean flag1 = false; -@@ -4438,14 +4449,61 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - int k1 = 0; - BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); - -- for (int l1 = i; l1 < j; ++l1) { -- for (int i2 = k; i2 < l; ++i2) { -- for (int j2 = i1; j2 < j1; ++j2) { -- blockposition_mutableblockposition.set(l1, i2, j2); -- FluidState fluid = this.level().getFluidState(blockposition_mutableblockposition); -+ // Pufferfish start - based off CollisionUtil.getCollisionsForBlocksOrWorldBorder -+ final int minSection = io.papermc.paper.util.WorldUtil.getMinSection(this.level()); -+ final int maxSection = io.papermc.paper.util.WorldUtil.getMaxSection(this.level()); -+ final int minBlock = minSection << 4; -+ final int maxBlock = (maxSection << 4) | 15; -+ -+ // special cases: -+ if (minBlockY > maxBlock || maxBlockY < minBlock) { -+ // no point in checking -+ return false; -+ } -+ -+ int minYIterate = Math.max(minBlock, minBlockY); -+ int maxYIterate = Math.min(maxBlock, maxBlockY); -+ -+ int minChunkX = minBlockX >> 4; -+ int maxChunkX = maxBlockX >> 4; -+ -+ int minChunkZ = minBlockZ >> 4; -+ int maxChunkZ = maxBlockZ >> 4; -+ -+ for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { -+ int minZ = currChunkZ == minChunkZ ? minBlockZ & 15 : 0; // coordinate in chunk -+ int maxZ = currChunkZ == maxChunkZ ? maxBlockZ & 15 : 16; // coordinate in chunk -+ -+ for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) { -+ int minX = currChunkX == minChunkX ? minBlockX & 15 : 0; // coordinate in chunk -+ int maxX = currChunkX == maxChunkX ? maxBlockX & 15 : 16; // coordinate in chunk -+ -+ net.minecraft.world.level.chunk.ChunkAccess chunk = this.level().getChunkIfLoadedImmediately(currChunkX, currChunkZ); -+ if (chunk == null) { -+ return false; // if we're touching an unloaded chunk then it's false -+ } -+ -+ net.minecraft.world.level.chunk.LevelChunkSection[] sections = chunk.getSections(); -+ -+ for (int currY = minYIterate; currY < maxYIterate; ++currY) { -+ net.minecraft.world.level.chunk.LevelChunkSection section = sections[(currY >> 4) - minSection]; -+ -+ if (section == null || section.hasOnlyAir() || section.fluidStateCount == 0) { // if no fluids, nothing in this section -+ // empty -+ // skip to next section -+ currY = (currY & ~(15)) + 15; // increment by 15: iterator loop increments by the extra one -+ continue; -+ } -+ -+ net.minecraft.world.level.chunk.PalettedContainer blocks = section.states; -+ -+ for (int currZ = minZ; currZ < maxZ; ++currZ) { -+ for (int currX = minX; currX < maxX; ++currX) { -+ FluidState fluid = blocks.get(currX & 15, currY & 15, currZ & 15).getFluidState(); - - if (fluid.is(tag)) { -- double d2 = (double) ((float) i2 + fluid.getHeight(this.level(), blockposition_mutableblockposition)); -+ blockposition_mutableblockposition.set((currChunkX << 4) + currX, currY, (currChunkZ << 4) + currZ); -+ double d2 = (double) ((float) currY + fluid.getHeight(this.level(), blockposition_mutableblockposition)); - - if (d2 >= axisalignedbb.minY) { - flag1 = true; -@@ -4467,9 +4525,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - // CraftBukkit end - } - } -+ } -+ } - } - } - } -+ // Pufferfish end - - if (vec3d.length() > 0.0D) { - if (k1 > 0) { diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index 09e8445a3f8c6b3ebc852a75a9a25b41a51ba659..dc11683ee4d8a6b7a1c42bcae36dc6e8105cd994 100644 +index d23914a3ab3723d532ae867db6b954c843030f75..8c1dad4b7f6461aca5ac37a25c880c550b0dcf5f 100644 --- a/src/main/java/net/minecraft/world/entity/EntityType.java +++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -305,6 +305,8 @@ public class EntityType implements FeatureElement, EntityTypeT - private final boolean canSpawnFarFromPlayer; +@@ -385,6 +385,7 @@ public class EntityType implements FeatureElement, EntityTypeT private final int clientTrackingRange; private final int updateInterval; + private final String descriptionId; + public boolean dabEnabled = false; // Pufferfish -+ public int ttl = -1; // Pufferfish - @Nullable - private String descriptionId; @Nullable + private Component description; + private final Optional> lootTable; diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index e9bb7feb591032904516d1b9374f486d8a7d066c..366121188c5abb550ed0a5f99d25c001628685bb 100644 +index 96b4fbe4a4655777ff10b32e3257e2fac2aba12a..ee2c88638f058172ef730de9b112ce6506211d3b 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -143,7 +143,6 @@ import org.bukkit.event.entity.EntityTeleportEvent; - import org.bukkit.event.player.PlayerItemConsumeEvent; - // CraftBukkit end +@@ -465,7 +465,7 @@ public abstract class LivingEntity extends Entity implements Attackable { --import co.aikar.timings.MinecraftTimings; // Paper - - public abstract class LivingEntity extends Entity implements Attackable { - -@@ -414,7 +413,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - boolean flag = this instanceof net.minecraft.world.entity.player.Player; - - if (!this.level().isClientSide) { + if (world1 instanceof ServerLevel) { + worldserver1 = (ServerLevel) world1; - if (this.isInWall()) { + if (shouldCheckForSuffocation() && this.isInWall()) { // Pufferfish - optimize suffocation - this.hurt(this.damageSources().inWall(), 1.0F); + this.hurtServer(worldserver1, this.damageSources().inWall(), 1.0F); } else if (flag && !this.level().getWorldBorder().isWithinBounds(this.getBoundingBox())) { - double d0 = this.level().getWorldBorder().getDistanceToBorder(this) + this.level().getWorldBorder().getDamageSafeZone(); -@@ -1418,6 +1417,19 @@ public abstract class LivingEntity extends Entity implements Attackable { - return this.getHealth() <= 0.0F; + double d1 = this.level().getWorldBorder().getDistanceToBorder(this) + this.level().getWorldBorder().getDamageSafeZone(); +@@ -564,6 +564,19 @@ public abstract class LivingEntity extends Entity implements Attackable { + gameprofilerfiller.pop(); } + // Pufferfish start - optimize suffocation @@ -2104,9 +1309,9 @@ index e9bb7feb591032904516d1b9374f486d8a7d066c..366121188c5abb550ed0a5f99d25c001 + // Pufferfish end + @Override - public boolean hurt(DamageSource source, float amount) { - if (this.isInvulnerableTo(source)) { -@@ -2024,6 +2036,20 @@ public abstract class LivingEntity extends Entity implements Attackable { + protected float getBlockSpeedFactor() { + return Mth.lerp((float) this.getAttributeValue(Attributes.MOVEMENT_EFFICIENCY), super.getBlockSpeedFactor(), 1.0F); +@@ -2135,6 +2148,20 @@ public abstract class LivingEntity extends Entity implements Attackable { return this.lastClimbablePos; } @@ -2128,10 +1333,10 @@ index e9bb7feb591032904516d1b9374f486d8a7d066c..366121188c5abb550ed0a5f99d25c001 if (this.isSpectator()) { return false; diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index d2c92df28475f0a32a0134324eb0a5609a9afb99..a6b48b4eab6e0e98205fd9cafc3cde5ad39651af 100644 +index 5a0b51342f4a646101f4588697bcae7d1ca8a010..8ebe26c46db485ee0bdf64a313681d465051f436 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -222,14 +222,16 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -231,14 +231,16 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab return this.lookControl; } @@ -2150,36 +1355,36 @@ index d2c92df28475f0a32a0134324eb0a5609a9afb99..a6b48b4eab6e0e98205fd9cafc3cde5a this.targetSelector.tick(); } } -@@ -913,16 +915,20 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -927,16 +929,20 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab if (i % 2 != 0 && this.tickCount > 1) { - this.level().getProfiler().push("targetSelector"); + gameprofilerfiller.push("targetSelector"); + if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking this.targetSelector.tickRunningGoals(false); - this.level().getProfiler().pop(); - this.level().getProfiler().push("goalSelector"); + gameprofilerfiller.pop(); + gameprofilerfiller.push("goalSelector"); + if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking this.goalSelector.tickRunningGoals(false); - this.level().getProfiler().pop(); + gameprofilerfiller.pop(); } else { - this.level().getProfiler().push("targetSelector"); + gameprofilerfiller.push("targetSelector"); + if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking this.targetSelector.tick(); - this.level().getProfiler().pop(); - this.level().getProfiler().push("goalSelector"); + gameprofilerfiller.pop(); + gameprofilerfiller.push("goalSelector"); + if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking this.goalSelector.tick(); - this.level().getProfiler().pop(); + gameprofilerfiller.pop(); } diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java -index b99a080ab27e24d8131fda931ca70d6d271bb01c..8d6954d05d2bf6d6c1c4953db3127b011a858cec 100644 +index fb967ac7b3e7828301f08a7fe9b039441cf7da30..b4cfae23709b7c3aed28317846e37c9311c948c1 100644 --- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java +++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java @@ -23,9 +23,11 @@ public class AttributeMap { - private final Map attributes = Maps.newHashMap(); - private final Set dirtyAttributes = Sets.newHashSet(); + private final Set attributesToSync = new ObjectOpenHashSet<>(); + private final Set attributesToUpdate = new ObjectOpenHashSet<>(); private final AttributeSupplier supplier; -+ private final java.util.function.Function createInstance; // Pufferfish ++ private final java.util.function.Function, AttributeInstance> createInstance; // Pufferfish public AttributeMap(AttributeSupplier defaultAttributes) { this.supplier = defaultAttributes; @@ -2187,18 +1392,18 @@ index b99a080ab27e24d8131fda931ca70d6d271bb01c..8d6954d05d2bf6d6c1c4953db3127b01 } private void onAttributeModified(AttributeInstance instance) { -@@ -42,9 +44,10 @@ public class AttributeMap { - return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().isClientSyncable()).collect(Collectors.toList()); +@@ -47,9 +49,10 @@ public class AttributeMap { + return this.attributes.values().stream().filter(attribute -> attribute.getAttribute().value().isClientSyncable()).collect(Collectors.toList()); } + @Nullable - public AttributeInstance getInstance(Attribute attribute) { + public AttributeInstance getInstance(Holder attribute) { - return this.attributes.computeIfAbsent(attribute, attributex -> this.supplier.createInstance(this::onAttributeModified, attributex)); + return this.attributes.computeIfAbsent(attribute, this.createInstance); // Pufferfish - cache lambda, as for some reason java allocates it anyways } - @Nullable + public boolean hasAttribute(Holder attribute) { diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java index 758f62416ca9c02351348ac0d41deeb4624abc0e..69130969c9a434ec2361e573c9a1ec9f462dfda2 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java @@ -2217,20 +1422,20 @@ index 758f62416ca9c02351348ac0d41deeb4624abc0e..69130969c9a434ec2361e573c9a1ec9f } } diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -index 38af5c7280366fd6ec077f3d914ea5f3ee77451a..d78e1f6191738d426968efc24e734f04b0fc7edb 100644 +index 29ae74339a4831ccef3d01e8054931715ba192ad..5a439e3b0fdc1010884634c1e046e49d8b9aee17 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -@@ -52,9 +52,12 @@ public class GoalSelector { +@@ -38,9 +38,12 @@ public class GoalSelector { } - // Paper start + // Paper start - EAR 2 - public boolean inactiveTick() { + public boolean inactiveTick(int tickRate, boolean inactive) { // Pufferfish start + if (inactive && !gg.pufferfish.pufferfish.PufferfishConfig.dearEnabled) tickRate = 4; // reset to Paper's -+ tickRate = Math.min(tickRate, this.newGoalRate); ++ tickRate = Math.min(tickRate, 3); this.curRate++; -- return this.curRate % this.newGoalRate == 0; -+ return this.curRate % tickRate == 0; +- return this.curRate % 3 == 0; // TODO newGoalRate was already unused in 1.20.4, check if this is correct ++ return this.curRate % tickRate == 0; // TODO newGoalRate was already unused in 1.20.4, check if this is correct + // Pufferfish end } public boolean hasTasks() { @@ -2247,36 +1452,11 @@ index aee0147649d458b87d92496eda0c1723ebe570d2..89e9ea999d2fbd81a1d74382ef3fcd67 if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) { this.blockPos = mutableBlockPos; this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : mutableBlockPos.immutable(); // Paper -diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -index d2f0c3b26d4beedb49d86e0242d843590d469d02..28cff997a1b263784e245f692adbff2a888a2d53 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java -@@ -76,9 +76,18 @@ public class TargetingConditions { - } - - if (this.range > 0.0) { -- double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0; -- double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0); // Paper - Fix MC-145656 -+ // Pufferfish start - check range before getting visibility -+ // d = invisibility percent, e = follow range adjusted for invisibility, f = distance - double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ()); -+ double followRangeRaw = this.useFollowRange ? this.getFollowRange(baseEntity) : this.range; -+ -+ if (f > followRangeRaw * followRangeRaw) { // the actual follow range will always be this value or smaller, so if the distance is larger then it never will return true after getting invis -+ return false; -+ } -+ -+ double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0; -+ double e = Math.max((followRangeRaw) * d, 2.0); // Paper - Fix MC-145656 -+ // Pufferfish end - if (f > e * e) { - return false; - } diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index 44fa2d4f90389f5526746bd94a2450c03340bd0b..4fba7c2f6ec363846a772ef2a63e9b3fc1037de5 100644 +index 60c2868f255d372226e0c1389caaa5477bbef41e..3de177a40649183b5b210e5f0c610a527287e9ec 100644 --- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java +++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -@@ -241,13 +241,22 @@ public class Bat extends AmbientCreature { +@@ -242,13 +242,22 @@ public class Bat extends AmbientCreature { } } @@ -2298,93 +1478,102 @@ index 44fa2d4f90389f5526746bd94a2450c03340bd0b..4fba7c2f6ec363846a772ef2a63e9b3f } + // Pufferfish end - @Override - protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { + private void setupAnimationStates() { + if (this.isResting()) { diff --git a/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java b/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java -index 5ad5f22e5aa26445e5eb229958e7bf356bdd460e..d241ca4d0295f9fce39c11197bd435cfac7f6e54 100644 +index b86f638390d386c838318a4d9b6571ac5514df8f..f4788104b1bb73810fdf0dc7f5311d5b078a81d5 100644 --- a/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java +++ b/src/main/java/net/minecraft/world/entity/animal/allay/Allay.java -@@ -221,9 +221,11 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS +@@ -223,11 +223,13 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS return 0.4F; } + private int behaviorTick = 0; // Pufferfish @Override - protected void customServerAiStep() { - this.level().getProfiler().push("allayBrain"); + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("allayBrain"); + if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("allayActivityUpdate"); + this.getBrain().tick(world, this); + gameprofilerfiller.pop(); + gameprofilerfiller.push("allayActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -index b21e180641d17438997a80e5bcb0ec7998d24a2e..33c160994f70f71446d665e7487913437c9f9db4 100644 +index 31b10cd404b672d7ce21c2107d8f83e32de26ef4..cb47876a13cb1990bb0ab4cff1bbe57b3b2d0a5e 100644 --- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java +++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -275,9 +275,11 @@ public class Axolotl extends Animal implements LerpingModel, VariantHolder, B return true; } + private int behaviorTick = 0; // Pufferfish @Override - protected void customServerAiStep() { - this.level().getProfiler().push("axolotlBrain"); + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("axolotlBrain"); + if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("axolotlActivityUpdate"); + this.getBrain().tick(world, this); + gameprofilerfiller.pop(); + gameprofilerfiller.push("axolotlActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -index a03fb7aa9f4528f4885db88eaf480202d5f54750..1767fd2df8cb37e9c36fa3008b5131ff4bdad12c 100644 +index ca04e5d829331551a2c2f44e223ff05c6ce04e76..db91b8018591fe248efda417fcde7fd2071c4cb6 100644 --- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -@@ -183,9 +183,11 @@ public class Frog extends Animal implements VariantHolder { - } +@@ -184,10 +184,12 @@ public class Frog extends Animal implements VariantHolder> { + .ifPresent(this::setVariant); } + private int behaviorTick = 0; // Pufferfish @Override - protected void customServerAiStep() { - this.level().getProfiler().push("frogBrain"); + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("frogBrain"); + if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("frogActivityUpdate"); + this.getBrain().tick(world, this); + profilerFiller.pop(); + profilerFiller.push("frogActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -index 958816ce2166248b542c96c10c398a52d769b4db..415afe3473d9f8a50b1edab8cfda6158e59836e6 100644 +index 48ac8c3f6e00c3c2dc67b6c994be7c0ac6dfcf81..cf326ef35bac732e7addf75537963593d5b268ae 100644 --- a/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java +++ b/src/main/java/net/minecraft/world/entity/animal/frog/Tadpole.java -@@ -80,9 +80,11 @@ public class Tadpole extends AbstractFish { +@@ -83,11 +83,13 @@ public class Tadpole extends AbstractFish { return SoundEvents.TADPOLE_FLOP; } + private int behaviorTick = 0; // Pufferfish @Override - protected void customServerAiStep() { - this.level().getProfiler().push("tadpoleBrain"); + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("tadpoleBrain"); + if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("tadpoleActivityUpdate"); + this.getBrain().tick(world, this); + gameprofilerfiller.pop(); + gameprofilerfiller.push("tadpoleActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -index 5d247ac38fe8a61603b3d934f3000bcda773142b..2e4177cfb02616ef6fa689f6d378976e39484cfb 100644 +index 76aca47d8638d5c37c57d3a59fa7f8ceaa5a53b4..fb92cd4b0c15b614c0c06d2867039aee1a6212a2 100644 --- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java -@@ -191,9 +191,11 @@ public class Goat extends Animal { +@@ -192,11 +192,13 @@ public class Goat extends Animal { return (Brain) super.getBrain(); // CraftBukkit - decompile error } + private int behaviorTick = 0; // Pufferfish @Override - protected void customServerAiStep() { - this.level().getProfiler().push("goatBrain"); + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("goatBrain"); + if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); - this.level().getProfiler().push("goatActivityUpdate"); + this.getBrain().tick(world, this); + gameprofilerfiller.pop(); + gameprofilerfiller.push("goatActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 12440ee2dccc0a697fb403765f2e1b987ccc0283..de2471cfa96a23944f229f33ffdff88b6b7756e4 100644 +index bd9e10f79eaf0d23908229b3ebc2227946a14843..2ce65ef77e4b28e1fd5ac7bd6a304cc115b8aca2 100644 --- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -151,6 +151,13 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -151,6 +151,13 @@ public class WitherBoss extends Monster implements RangedAttackMob { this.bossEvent.setName(this.getDisplayName()); } @@ -2399,21 +1588,21 @@ index 12440ee2dccc0a697fb403765f2e1b987ccc0283..de2471cfa96a23944f229f33ffdff88b protected SoundEvent getAmbientSound() { return SoundEvents.WITHER_AMBIENT; diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index f33c03e81b7ff643741f56eea055e6af260de618..6563e625ebae47fc68e5010d36bd4b4d327c07b7 100644 +index 2a394381a4ad46359359ba402b65c62b331480b4..4e4dab5bc202f6f421dcff98f0e36e8e70378b49 100644 --- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -@@ -333,11 +333,17 @@ public class EnderMan extends Monster implements NeutralMob { +@@ -306,11 +306,17 @@ public class EnderMan extends Monster implements NeutralMob { private boolean teleport(double x, double y, double z) { BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(x, y, z); -- while (blockposition_mutableblockposition.getY() > this.level().getMinBuildHeight() && !this.level().getBlockState(blockposition_mutableblockposition).blocksMotion()) { +- while (blockposition_mutableblockposition.getY() > this.level().getMinY() && !this.level().getBlockState(blockposition_mutableblockposition).blocksMotion()) { + // Pufferfish start - single chunk lookup + net.minecraft.world.level.chunk.LevelChunk chunk = this.level().getChunkIfLoaded(blockposition_mutableblockposition); + if (chunk == null) { + return false; + } + // Pufferfish end -+ while (blockposition_mutableblockposition.getY() > this.level().getMinBuildHeight() && !chunk.getBlockState(blockposition_mutableblockposition).blocksMotion()) { // Pufferfish ++ while (blockposition_mutableblockposition.getY() > this.level().getMinY() && !chunk.getBlockState(blockposition_mutableblockposition).blocksMotion()) { // Pufferfish blockposition_mutableblockposition.move(Direction.DOWN); } @@ -2423,60 +1612,64 @@ index f33c03e81b7ff643741f56eea055e6af260de618..6563e625ebae47fc68e5010d36bd4b4d boolean flag1 = iblockdata.getFluidState().is(FluidTags.WATER); diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -index 050ffa4a23feba29fdf4c6a175cdff4e5009027d..1299f93d4f983e6715e447add65df91ef9e9090a 100644 +index 92270912ef26924f611a1df7cb3d5b485b0a262d..9c20651b74157582e60793ceba8adde2c354f2a8 100644 --- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java -@@ -155,9 +155,11 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { - return (Brain)super.getBrain(); +@@ -138,11 +138,13 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + return (Brain) super.getBrain(); // CraftBukkit - decompile error } + private int behaviorTick; // Pufferfish @Override - protected void customServerAiStep() { - this.level().getProfiler().push("hoglinBrain"); + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("hoglinBrain"); + if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel)this.level(), this); - this.level().getProfiler().pop(); + this.getBrain().tick(world, this); + gameprofilerfiller.pop(); HoglinAi.updateActivity(this); diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -index a9813da7f2b248f98f22e0ad2e7842915025ec12..83d83e3f84bb6bd58761671c6cd4c8683545ff4c 100644 +index 2121d2a2e1aa1d0f0390cc515317096431f6dcb0..74ab50723056fef2a96dcc9e2de0e58526738011 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -300,9 +300,11 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento +@@ -307,11 +307,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento return !this.cannotHunt; } + private int behaviorTick; // Pufferfish @Override - protected void customServerAiStep() { - this.level().getProfiler().push("piglinBrain"); + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("piglinBrain"); + if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick((ServerLevel) this.level(), this); - this.level().getProfiler().pop(); + this.getBrain().tick(world, this); + gameprofilerfiller.pop(); PiglinAi.updateActivity(this); diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 937f81a859953498abe73bea560c86e6560e1c33..0a151c679b0dc943598180942d6d4b3886211688 100644 +index c47ed605f0822effd58df4f875297ed015e1e57e..4331ada8bed7ade7b53fd8ba000c1c1b34fa4331 100644 --- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java +++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -@@ -273,11 +273,13 @@ public class Warden extends Monster implements VibrationSystem { +@@ -275,11 +275,13 @@ public class Warden extends Monster implements VibrationSystem { } + private int behaviorTick = 0; // Pufferfish @Override - protected void customServerAiStep() { - ServerLevel worldserver = (ServerLevel) this.level(); + protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); - worldserver.getProfiler().push("wardenBrain"); + gameprofilerfiller.push("wardenBrain"); + if (this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish - this.getBrain().tick(worldserver, this); - this.level().getProfiler().pop(); - super.customServerAiStep(); + this.getBrain().tick(world, this); + gameprofilerfiller.pop(); + super.customServerAiStep(world); diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 24044795d8e0f1fb15a4f2f5401f44897092f2a3..96ca567af2d8fb2ba39f995be80b935344550124 100644 +index 2d8ba55906c8da16fde850e3412f4a6bda3d56e7..3fd86782134a674f58ef37288c8963a4a92f685c 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -143,6 +143,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -142,6 +142,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler return holder.is(PoiTypes.MEETING); }); @@ -2485,32 +1678,32 @@ index 24044795d8e0f1fb15a4f2f5401f44897092f2a3..96ca567af2d8fb2ba39f995be80b9353 public Villager(EntityType entityType, Level world) { this(entityType, world, VillagerType.PLAINS); } -@@ -246,6 +248,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -245,6 +247,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } // Spigot End + private int behaviorTick = 0; // Pufferfish @Override - @Deprecated // Paper - protected void customServerAiStep() { + protected void customServerAiStep(ServerLevel world) { + // Paper start - EAR 2 @@ -255,7 +258,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - protected void customServerAiStep(final boolean inactive) { - // Paper end - this.level().getProfiler().push("villagerBrain"); -- if (!inactive) this.getBrain().tick((ServerLevel) this.level(), this); // Paper + ProfilerFiller gameprofilerfiller = Profiler.get(); + + gameprofilerfiller.push("villagerBrain"); +- if (!inactive) this.getBrain().tick(world, this); + // Pufferfish start + if (!inactive && this.behaviorTick++ % this.activatedPriority == 0) { + this.getBrain().tick((ServerLevel) this.level(), this); // Paper + } + // Pufferfish end - this.level().getProfiler().pop(); + gameprofilerfiller.pop(); if (this.assignProfessionWhenSpawned) { this.assignProfessionWhenSpawned = false; diff --git a/src/main/java/net/minecraft/world/entity/player/Inventory.java b/src/main/java/net/minecraft/world/entity/player/Inventory.java -index 96c898086f35fd83f9b1ce7e3fe53d31b2fa4c31..c6a925cbd35eb33b27b90bfa8344ac7515d28b76 100644 +index 110456deaa662bc1c0f6ba7878bb3074869a4350..58c8e8f06f5cf028b158350327bf42984fcb4d38 100644 --- a/src/main/java/net/minecraft/world/entity/player/Inventory.java +++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java -@@ -687,6 +687,8 @@ public class Inventory implements Container, Nameable { +@@ -636,6 +636,8 @@ public class Inventory implements Container, Nameable { } public boolean contains(ItemStack stack) { @@ -2519,7 +1712,7 @@ index 96c898086f35fd83f9b1ce7e3fe53d31b2fa4c31..c6a925cbd35eb33b27b90bfa8344ac75 Iterator iterator = this.compartments.iterator(); while (iterator.hasNext()) { -@@ -701,6 +703,18 @@ public class Inventory implements Container, Nameable { +@@ -650,6 +652,18 @@ public class Inventory implements Container, Nameable { } } } @@ -2529,7 +1722,7 @@ index 96c898086f35fd83f9b1ce7e3fe53d31b2fa4c31..c6a925cbd35eb33b27b90bfa8344ac75 + for (int j = 0; j < list.size(); j++) { + ItemStack itemstack1 = list.get(j); + -+ if (!itemstack1.isEmpty() && ItemStack.isSameItemSameTags(itemstack1, stack)) { ++ if (!itemstack1.isEmpty() && ItemStack.isSameItemSameComponents(itemstack1, stack)) { + return true; + } + } @@ -2539,10 +1732,10 @@ index 96c898086f35fd83f9b1ce7e3fe53d31b2fa4c31..c6a925cbd35eb33b27b90bfa8344ac75 return false; } diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 156809090f1f83ad68e7e2477a3cfddac5757a8e..837f68825f601971f374be47952b23108bf66ba6 100644 +index 9a7b56b653848974e1194eb4f6d40cb99a96ff57..593b343b7cd5a24e34ad19a9e93eb9258f862357 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -45,6 +45,36 @@ public abstract class Projectile extends Entity implements TraceableEntity { +@@ -58,6 +58,36 @@ public abstract class Projectile extends Entity implements TraceableEntity { super(type, world); } @@ -2561,7 +1754,7 @@ index 156809090f1f83ad68e7e2477a3cfddac5757a8e..837f68825f601971f374be47952b2310 + int previousX = Mth.floor(this.getX()) >> 4, previousZ = Mth.floor(this.getZ()) >> 4; + int newX = Mth.floor(x) >> 4, newZ = Mth.floor(z) >> 4; + if (previousX != newX || previousZ != newZ) { -+ boolean isLoaded = ((net.minecraft.server.level.ServerChunkCache) this.level().getChunkSource()).getChunkAtIfLoadedMainThread(newX, newZ) != null; ++ boolean isLoaded = ((net.minecraft.server.level.ServerChunkCache) this.level().getChunkSource()).getChunkAtIfLoadedImmediately(newX, newZ) != null; + if (!isLoaded) { + if (Projectile.loadedThisTick > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerTick) { + if (++this.loadedLifetime > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerProjectile) { @@ -2579,59 +1772,12 @@ index 156809090f1f83ad68e7e2477a3cfddac5757a8e..837f68825f601971f374be47952b2310 public void setOwner(@Nullable Entity entity) { if (entity != null) { this.ownerUUID = entity.getUUID(); -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -index 756d0434472921992c9d84597d7c9c824e93614c..38c573d440946ca7ee6016ef92e9c1605031e611 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -@@ -28,7 +28,10 @@ import org.bukkit.inventory.InventoryHolder; - - public abstract class AbstractMinecartContainer extends AbstractMinecart implements ContainerEntity { - -+ // Pufferfish start - private NonNullList itemStacks; -+ private gg.airplane.structs.ItemListWithBitset itemStacksOptimized; -+ // Pufferfish end - @Nullable - public ResourceLocation lootTable; - public long lootTableSeed; -@@ -90,12 +93,18 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme - - protected AbstractMinecartContainer(EntityType type, Level world) { - super(type, world); -- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513 -+ // Pufferfish start -+ this.itemStacksOptimized = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // CraftBukkit - SPIGOT-3513 -+ this.itemStacks = this.itemStacksOptimized.nonNullList; -+ // Pufferfish end - } - - protected AbstractMinecartContainer(EntityType type, double x, double y, double z, Level world) { - super(type, world, x, y, z); -- this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513 -+ // Pufferfish start -+ this.itemStacksOptimized = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); // CraftBukkit - SPIGOT-3513 -+ this.itemStacks = this.itemStacksOptimized.nonNullList; -+ // Pufferfish end - } - - @Override -@@ -164,6 +173,10 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme - protected void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - this.lootableData.loadNbt(nbt); // Paper -+ // Pufferfish start -+ this.itemStacksOptimized = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); -+ this.itemStacks = this.itemStacksOptimized.nonNullList; -+ // Pufferfish end - this.readChestVehicleSaveData(nbt); - } - diff --git a/src/main/java/net/minecraft/world/item/EndCrystalItem.java b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -index e1696f6b77df4c8fceaece64701d4db78b0a4c42..faa3f62d22266a3c32d6c95c3ffebd4aa3880739 100644 +index b62db8c7c8c57e43869ee239ebf4b02f112355d9..2bee342e59e600426c8681a3ce641a12f22790be 100644 --- a/src/main/java/net/minecraft/world/item/EndCrystalItem.java +++ b/src/main/java/net/minecraft/world/item/EndCrystalItem.java -@@ -55,7 +55,7 @@ public class EndCrystalItem extends Item { - world.gameEvent((Entity) context.getPlayer(), GameEvent.ENTITY_PLACE, blockposition1); +@@ -57,7 +57,7 @@ public class EndCrystalItem extends Item { + world.gameEvent((Entity) context.getPlayer(), (Holder) GameEvent.ENTITY_PLACE, blockposition1); EndDragonFight enderdragonbattle = ((ServerLevel) world).getDragonFight(); - if (enderdragonbattle != null) { @@ -2640,33 +1786,33 @@ index e1696f6b77df4c8fceaece64701d4db78b0a4c42..faa3f62d22266a3c32d6c95c3ffebd4a } } diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java -index 27b0a79f7a7c47047216aae42944bac2a2151181..a097cfc528f709c80575f35483b6878314ea2717 100644 +index 12f95bee2a69fd5df7c4a165537e01299e60c5f6..4b3769020a92124bd5677cf75e268b8bc5ba2031 100644 --- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java +++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java -@@ -26,8 +26,13 @@ public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBoo - final CraftingBookCategory category; - final ItemStack result; - final NonNullList ingredients; +@@ -31,8 +31,13 @@ public class ShapelessRecipe implements CraftingRecipe { + final List ingredients; + @Nullable + private PlacementInfo placementInfo; + private final boolean isBukkit; // Pufferfish + // Pufferfish start - public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, NonNullList ingredients) { + public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, List ingredients) { + this(group, category, result, ingredients, false); + } -+ public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, NonNullList ingredients, boolean isBukkit) { this.isBukkit = isBukkit; // Pufferfish end ++ public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, List ingredients, boolean isBukkit) { this.isBukkit = isBukkit; // Pufferfish end this.group = group; this.category = category; this.result = result; -@@ -77,6 +82,28 @@ public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBoo +@@ -80,6 +85,27 @@ public class ShapelessRecipe implements CraftingRecipe { } - public boolean matches(CraftingContainer inventory, Level world) { + public boolean matches(CraftingInput input, Level world) { + // Pufferfish start + if (!this.isBukkit) { + java.util.List ingredients = com.google.common.collect.Lists.newArrayList(this.ingredients.toArray(new Ingredient[0])); + -+ inventory: for (int index = 0; index < inventory.getContainerSize(); index++) { -+ ItemStack itemStack = inventory.getItem(index); ++ inventory: for (int index = 0; index < input.size(); index++) { ++ ItemStack itemStack = input.getItem(index); + + if (!itemStack.isEmpty()) { + for (int i = 0; i < ingredients.size(); i++) { @@ -2682,27 +1828,17 @@ index 27b0a79f7a7c47047216aae42944bac2a2151181..a097cfc528f709c80575f35483b68783 + return ingredients.isEmpty(); + } + // Pufferfish end -+ - StackedContents autorecipestackmanager = new StackedContents(); - autorecipestackmanager.initialize(this); // Paper - better exact choice recipes - int i = 0; + // Paper start - Improve exact choice recipe ingredients & unwrap ternary + if (input.ingredientCount() != this.ingredients.size()) { + return false; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index ca89d1593bf1b46c79a882db528cbca1359dc9d4..a82de7111915b19cdc3f065910465a5e7e843aff 100644 +index 27f9d167b5ae9ce5117798ea44324107df59425f..6470f145e2470574a40ddce6ca5bf924c1bb094c 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -215,6 +215,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // Paper end - - public abstract ResourceKey getTypeKey(); -+ -+ protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - move thread unsafe random initialization // Pufferfish - getter - - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config; Async-Anti-Xray: Pass executor - this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot -@@ -1317,13 +1319,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1488,16 +1488,16 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + public void guardEntityTick(Consumer tickConsumer, T entity) { try { tickConsumer.accept(entity); - MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick - } catch (Throwable throwable) { + } catch (Throwable throwable) { // Pufferfish - diff on change ServerLevel.tick if (throwable instanceof ThreadDeath) throw throwable; // Paper @@ -2714,282 +1850,18 @@ index ca89d1593bf1b46c79a882db528cbca1359dc9d4..a82de7111915b19cdc3f065910465a5e + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Pufferfish - diff on change ServerLevel.tick // Paper end - Prevent block entity and entity crashes } +- this.moonrise$midTickTasks(); // Paper - rewrite chunk system ++ this.moonrise$midTickTasks(); // Paper - rewrite chunk system // Pufferfish - diff on change ServerLevel.tick } -@@ -1797,6 +1799,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - - public ProfilerFiller getProfiler() { -+ if (gg.pufferfish.pufferfish.PufferfishConfig.disableMethodProfiler) return net.minecraft.util.profiling.InactiveProfiler.INSTANCE; // Pufferfish - return (ProfilerFiller) this.profiler.get(); - } - -diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index da7489986848316fed029b71d1bc4e1248c9c9a8..661acdf4b1f33d150b0caf179e925d3162d7be35 100644 ---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java -+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -425,12 +425,12 @@ public final class NaturalSpawner { - } - } - -- private static BlockPos getRandomPosWithin(Level world, LevelChunk chunk) { -+ private static BlockPos getRandomPosWithin(ServerLevel world, LevelChunk chunk) { // Pufferfish - accept serverlevel - ChunkPos chunkcoordintpair = chunk.getPos(); -- int i = chunkcoordintpair.getMinBlockX() + world.random.nextInt(16); -- int j = chunkcoordintpair.getMinBlockZ() + world.random.nextInt(16); -+ int i = chunkcoordintpair.getMinBlockX() + world.getThreadUnsafeRandom().nextInt(16); // Pufferfish - use thread unsafe random -+ int j = chunkcoordintpair.getMinBlockZ() + world.getThreadUnsafeRandom().nextInt(16); // Pufferfish - int k = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, j) + 1; -- int l = Mth.randomBetweenInclusive(world.random, world.getMinBuildHeight(), k); -+ int l = Mth.randomBetweenInclusive(world.getThreadUnsafeRandom(), world.getMinBuildHeight(), k); // Pufferfish - - return new BlockPos(i, l, j); - } -diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java -index 64076a452a315090d299a7a58a43fd3b5c1b4e0a..0c317b0147a73a8075e0883f0c132f4db0bdfea7 100644 ---- a/src/main/java/net/minecraft/world/level/biome/Biome.java -+++ b/src/main/java/net/minecraft/world/level/biome/Biome.java -@@ -63,13 +63,18 @@ public final class Biome { - private final BiomeGenerationSettings generationSettings; - private final MobSpawnSettings mobSettings; - private final BiomeSpecialEffects specialEffects; -- private final ThreadLocal temperatureCache = ThreadLocal.withInitial(() -> Util.make(() -> { -+ // Pufferfish start - use our cache -+ private final ThreadLocal temperatureCache = ThreadLocal.withInitial(() -> Util.make(() -> { -+ /* - Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = new Long2FloatLinkedOpenHashMap(1024, 0.25F) { - protected void rehash(int i) { - } - }; - long2FloatLinkedOpenHashMap.defaultReturnValue(Float.NaN); - return long2FloatLinkedOpenHashMap; -+ */ -+ return new gg.airplane.structs.Long2FloatAgingCache(TEMPERATURE_CACHE_SIZE); -+ // Pufferfish end - })); - - Biome(Biome.ClimateSettings weather, BiomeSpecialEffects effects, BiomeGenerationSettings generationSettings, MobSpawnSettings spawnSettings) { -@@ -112,17 +117,15 @@ public final class Biome { - @Deprecated - public float getTemperature(BlockPos blockPos) { - long l = blockPos.asLong(); -- Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = this.temperatureCache.get(); -- float f = long2FloatLinkedOpenHashMap.get(l); -+ // Pufferfish start -+ gg.airplane.structs.Long2FloatAgingCache cache = this.temperatureCache.get(); -+ float f = cache.getValue(l); - if (!Float.isNaN(f)) { - return f; - } else { - float g = this.getHeightAdjustedTemperature(blockPos); -- if (long2FloatLinkedOpenHashMap.size() == 1024) { -- long2FloatLinkedOpenHashMap.removeFirstFloat(); -- } -- -- long2FloatLinkedOpenHashMap.put(l, g); -+ cache.putValue(l, g); -+ // Pufferfish end - return g; - } - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -index 9b1243d96e0694c62fc9e82e9be540bce0d2b3ad..3514022d898a24052c917ebf55dcef3e757d6836 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -@@ -31,7 +31,10 @@ import org.bukkit.entity.HumanEntity; - public class ChestBlockEntity extends RandomizableContainerBlockEntity implements LidBlockEntity { - - private static final int EVENT_SET_OPEN_COUNT = 1; -+ // Pufferfish start - private NonNullList items; -+ private gg.airplane.structs.ItemListWithBitset optimizedItems; -+ // Pufferfish end - public final ContainerOpenersCounter openersCounter; - private final ChestLidController chestLidController; - -@@ -65,9 +68,13 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - } - // CraftBukkit end - -+ private final boolean isNative = getClass().equals(ChestBlockEntity.class); // Pufferfish - protected ChestBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); -- this.items = NonNullList.withSize(27, ItemStack.EMPTY); -+ // Pufferfish start -+ this.optimizedItems = new gg.airplane.structs.ItemListWithBitset(27); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - this.openersCounter = new ContainerOpenersCounter() { - @Override - protected void onOpen(Level world, BlockPos pos, BlockState state) { -@@ -98,6 +105,23 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - this.chestLidController = new ChestLidController(); - } - -+ // Pufferfish start -+ @Override -+ public boolean hasEmptySlot(Direction enumdirection) { -+ return isNative ? !this.optimizedItems.hasFullStacks() : super.hasEmptySlot(enumdirection); -+ } -+ -+ @Override -+ public boolean isCompletelyFull(Direction enumdirection) { -+ return isNative ? this.optimizedItems.hasFullStacks() && super.isCompletelyFull(enumdirection) : super.isCompletelyFull(enumdirection); -+ } -+ -+ @Override -+ public boolean isCompletelyEmpty(Direction enumdirection) { -+ return isNative && this.optimizedItems.isCompletelyEmpty() || super.isCompletelyEmpty(enumdirection); -+ } -+ // Pufferfish end -+ - public ChestBlockEntity(BlockPos pos, BlockState state) { - this(BlockEntityType.CHEST, pos, state); - } -@@ -115,7 +139,10 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement + // Paper start - Option to prevent armor stands from doing entity lookups @Override - public void load(CompoundTag nbt) { - super.load(nbt); -- this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); -+ // Pufferfish start -+ this.optimizedItems = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - if (!this.tryLoadLootTable(nbt)) { - ContainerHelper.loadAllItems(nbt, this.items); - } -@@ -187,7 +214,10 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - - @Override - protected void setItems(NonNullList list) { -- this.items = list; -+ // Pufferfish start -+ this.optimizedItems = gg.airplane.structs.ItemListWithBitset.fromList(list); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index cdb739df2a285032d25d84f4464f202a7a3fa578..6b9cd8543a5bfc2b936ba18f66ffd60f2f792e43 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -48,7 +48,10 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - public static final int MOVE_ITEM_SPEED = 8; - public static final int HOPPER_CONTAINER_SIZE = 5; -+ // Pufferfish start - private NonNullList items; -+ private gg.airplane.structs.ItemListWithBitset optimizedItems; // Pufferfish -+ // Pufferfish end - public int cooldownTime; - private long tickedGameTime; - -@@ -84,14 +87,37 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - public HopperBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.HOPPER, pos, state); -- this.items = NonNullList.withSize(5, ItemStack.EMPTY); -+ // Pufferfish start -+ this.optimizedItems = new gg.airplane.structs.ItemListWithBitset(5); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - this.cooldownTime = -1; - } - -+ // Pufferfish start -+ @Override -+ public boolean hasEmptySlot(Direction enumdirection) { -+ return !this.optimizedItems.hasFullStacks(); -+ } -+ -+ @Override -+ public boolean isCompletelyFull(Direction enumdirection) { -+ return this.optimizedItems.hasFullStacks() && super.isCompletelyFull(enumdirection); -+ } -+ -+ @Override -+ public boolean isCompletelyEmpty(Direction enumdirection) { -+ return this.optimizedItems.isCompletelyEmpty() || super.isCompletelyEmpty(enumdirection); -+ } -+ // Pufferfish end -+ - @Override - public void load(CompoundTag nbt) { - super.load(nbt); -- this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); -+ // Pufferfish start -+ this.optimizedItems = new gg.airplane.structs.ItemListWithBitset(this.getContainerSize()); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - if (!this.tryLoadLootTable(nbt)) { - ContainerHelper.loadAllItems(nbt, this.items); - } -@@ -492,6 +518,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - } - - private static boolean isFullContainer(Container inventory, Direction direction) { -+ if (true) return inventory.isCompletelyFull(direction); // Pufferfish - use bitsets - // Paper start - Perf: Optimize Hoppers - if (inventory instanceof WorldlyContainer worldlyContainer) { - for (final int slot : worldlyContainer.getSlotsForFace(direction)) { -@@ -514,7 +541,10 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - } - - private static boolean isEmptyContainer(Container inv, Direction facing) { -- return allMatch(inv, facing, IS_EMPTY_TEST); // Paper - Perf: Optimize Hoppers -+ // Pufferfish start - use bitsets -+ //return allMatch(inv, facing, IS_EMPTY_TEST); // Paper - Perf: Optimize Hoppers -+ return inv.isCompletelyEmpty(facing); -+ // Pufferfish end - } - - public static boolean suckInItems(Level world, Hopper hopper) { -@@ -714,7 +744,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - if (HopperBlockEntity.canPlaceItemInContainer(to, stack, slot, side)) { - boolean flag = false; -- boolean flag1 = to.isEmpty(); -+ boolean flag1 = to.isCompletelyEmpty(side); // Pufferfish - - if (itemstack1.isEmpty()) { - // Spigot start - SPIGOT-6693, InventorySubcontainer#setItem -@@ -909,7 +939,10 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - @Override - protected void setItems(NonNullList list) { -- this.items = list; -+ // Pufferfish start -+ this.optimizedItems = gg.airplane.structs.ItemListWithBitset.fromList(list); -+ this.items = this.optimizedItems.nonNullList; -+ // Pufferfish end - } - - public static void entityInside(Level world, BlockPos pos, BlockState state, Entity entity, HopperBlockEntity blockEntity) { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java -index dfd1246b735fe64c5beae83567a013861eb00822..fa64bf5ad13c278438039b663ea3134e72108411 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java -@@ -94,12 +94,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc - public boolean isEmpty() { - this.unpackLootTable(null); - // Paper start - Perf: Optimize Hoppers -- for (final ItemStack itemStack : this.getItems()) { -- if (!itemStack.isEmpty()) { -- return false; -- } -- } -- return true; -+ return this.isCompletelyEmpty(null); // Pufferfish - use super - // Paper end - Perf: Optimize Hoppers - } - diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 465458e8a7dbaf9afb32709a71c7b2620d1e1fd2..270a892373ecbb3982990d6201d79c8a66de4f60 100644 +index 97937e3bd211997f0a0a3e9e671a1c59712d0003..99a95d77f44dddfd7be6c2ebd60e827d9de956b7 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -86,6 +86,18 @@ public class LevelChunk extends ChunkAccess { +@@ -89,6 +89,18 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p private final LevelChunkTicks fluidTicks; - public volatile FullChunkStatus chunkStatus = FullChunkStatus.INACCESSIBLE; // Paper - rewrite chunk system + private LevelChunk.UnsavedListener unsavedListener; + // Pufferfish start - instead of using a random every time the chunk is ticked, define when lightning strikes preemptively + private int lightningTick; @@ -3006,306 +1878,46 @@ index 465458e8a7dbaf9afb32709a71c7b2620d1e1fd2..270a892373ecbb3982990d6201d79c8a public LevelChunk(Level world, ChunkPos pos) { this(world, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, (LevelChunkSection[]) null, (LevelChunk.PostLoadProcessor) null, (BlendingData) null); } -@@ -109,6 +121,8 @@ public class LevelChunk extends ChunkAccess { - this.postLoad = entityLoader; - this.blockTicks = blockTickScheduler; - this.fluidTicks = fluidTickScheduler; +@@ -122,6 +134,8 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + this.debug = !empty && this.level.isDebug(); + this.defaultBlockState = empty ? VOID_AIR_BLOCKSTATE : AIR_BLOCKSTATE; + // Paper end - get block chunk optimisation + -+ this.lightningTick = this.level.getThreadUnsafeRandom().nextInt(100000) << 1; // Pufferfish - initialize lightning tick ++ this.lightningTick = new java.util.Random().nextInt(100000) << 1; // Pufferfish - initialize lightning tick } // CraftBukkit start -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -index 796bbef3544e06b8e7aac7e8ac5f740a2613f4bd..2422ca3ffc6ab7178cacf933b8013f85e7de4bd9 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -25,6 +25,7 @@ public class LevelChunkSection { - public final PalettedContainer states; - // CraftBukkit start - read/write - private PalettedContainer> biomes; -+ public short fluidStateCount; // Pufferfish - public final com.destroystokyo.paper.util.maplist.IBlockDataList tickingList = new com.destroystokyo.paper.util.maplist.IBlockDataList(); // Paper - // Paper start - optimise collisions - private int specialCollidingBlocks; -@@ -102,6 +103,7 @@ public class LevelChunkSection { - - if (!fluid.isEmpty()) { - --this.tickingFluidCount; -+ --this.fluidStateCount; // Pufferfish - } - - if (!state.isAir()) { -@@ -116,6 +118,7 @@ public class LevelChunkSection { - - if (!fluid1.isEmpty()) { - ++this.tickingFluidCount; -+ ++this.fluidStateCount; // Pufferfish - } - - this.updateBlockCallback(x, y, z, iblockdata1, state); // Paper - optimise collisions -@@ -162,6 +165,7 @@ public class LevelChunkSection { - if (fluid.isRandomlyTicking()) { - this.tickingFluidCount = (short) (this.tickingFluidCount + 1); - } -+ this.fluidStateCount++; // Pufferfish - } - - // Paper start - optimise collisions diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java -index 83a39f900551e39d5af6f17a339a386ddee4feef..0c8c534fc69172387f188af5282accfed7597ac7 100644 +index d8b4196adf955f8d414688dc451caac2d9c609d9..80a43def4912a3228cd95117d5c2aac68798b4ec 100644 --- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java +++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java @@ -9,7 +9,7 @@ import javax.annotation.Nullable; import net.minecraft.world.entity.Entity; public class EntityTickList { -- private final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? -+ public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? // Pufferfish - private->public +- private final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system ++ public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system // Pufferfish - private->public private void ensureActiveIsNotIterated() { - // Paper - replace with better logic, do not delay removals -diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -index 6d8ff6c06af5545634f255ed17dc1e489ece2548..6411aa4ff6bd4cabb25c426fa8f4a7eedb969c03 100644 ---- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java -@@ -45,6 +45,8 @@ public abstract class FlowingFluid extends Fluid { - public static final BooleanProperty FALLING = BlockStateProperties.FALLING; - public static final IntegerProperty LEVEL = BlockStateProperties.LEVEL_FLOWING; - private static final int CACHE_SIZE = 200; -+ // Pufferfish start - use our own cache -+ /* - private static final ThreadLocal> OCCLUSION_CACHE = ThreadLocal.withInitial(() -> { - Object2ByteLinkedOpenHashMap object2bytelinkedopenhashmap = new Object2ByteLinkedOpenHashMap(200) { - protected void rehash(int i) {} -@@ -53,6 +55,14 @@ public abstract class FlowingFluid extends Fluid { - object2bytelinkedopenhashmap.defaultReturnValue((byte) 127); - return object2bytelinkedopenhashmap; - }); -+ */ -+ -+ private static final ThreadLocal> localFluidDirectionCache = ThreadLocal.withInitial(() -> { -+ // Pufferfish todo - mess with this number for performance -+ // with 2048 it seems very infrequent on a small world that it has to remove old entries -+ return new gg.airplane.structs.FluidDirectionCache<>(2048); -+ }); -+ // Pufferfish end - private final Map shapes = Maps.newIdentityHashMap(); - - public FlowingFluid() {} -@@ -251,6 +261,8 @@ public abstract class FlowingFluid extends Fluid { - return false; - } - // Paper end - optimise collisions -+ // Pufferfish start - modify to use our cache -+ /* - Object2ByteLinkedOpenHashMap object2bytelinkedopenhashmap; - - if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) { -@@ -258,9 +270,16 @@ public abstract class FlowingFluid extends Fluid { - } else { - object2bytelinkedopenhashmap = null; - } -+ */ -+ gg.airplane.structs.FluidDirectionCache cache = null; -+ -+ if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) { -+ cache = localFluidDirectionCache.get(); -+ } - - Block.BlockStatePairKey block_a; - -+ /* - if (object2bytelinkedopenhashmap != null) { - block_a = new Block.BlockStatePairKey(state, fromState, face); - byte b0 = object2bytelinkedopenhashmap.getAndMoveToFirst(block_a); -@@ -271,11 +290,22 @@ public abstract class FlowingFluid extends Fluid { - } else { - block_a = null; - } -+ */ -+ if (cache != null) { -+ block_a = new Block.BlockStatePairKey(state, fromState, face); -+ Boolean flag = cache.getValue(block_a); -+ if (flag != null) { -+ return flag; -+ } -+ } else { -+ block_a = null; -+ } - - VoxelShape voxelshape = state.getCollisionShape(world, pos); - VoxelShape voxelshape1 = fromState.getCollisionShape(world, fromPos); - boolean flag = !Shapes.mergedFaceOccludes(voxelshape, voxelshape1, face); - -+ /* - if (object2bytelinkedopenhashmap != null) { - if (object2bytelinkedopenhashmap.size() == 200) { - object2bytelinkedopenhashmap.removeLastByte(); -@@ -283,6 +313,11 @@ public abstract class FlowingFluid extends Fluid { - - object2bytelinkedopenhashmap.putAndMoveToFirst(block_a, (byte) (flag ? 1 : 0)); - } -+ */ -+ if (cache != null) { -+ cache.putValue(block_a, flag); -+ } -+ // Pufferfish end - - return flag; - } -diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootParams.java b/src/main/java/net/minecraft/world/level/storage/loot/LootParams.java -index 37a0002bbe6539648db5219bb373e0404ae48dc0..ca0571d232e102c4b177a1ea44b96f5f0f440211 100644 ---- a/src/main/java/net/minecraft/world/level/storage/loot/LootParams.java -+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootParams.java -@@ -21,8 +21,10 @@ public class LootParams { - - public LootParams(ServerLevel world, Map, Object> parameters, Map dynamicDrops, float luck) { - this.level = world; -- this.params = parameters; -- this.dynamicDrops = dynamicDrops; -+ // Pufferfish start - use unmodifiable maps instead of immutable ones to skip the copy -+ this.params = java.util.Collections.unmodifiableMap(parameters); -+ this.dynamicDrops = java.util.Collections.unmodifiableMap(dynamicDrops); -+ // Pufferfish end - this.luck = luck; - } - -diff --git a/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java b/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java -index 88a4a72bb390947dc17e5da09a99b2d1b3ac4621..284c76ddb9724b44bb2e93f590685c728e843e6d 100644 ---- a/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java -+++ b/src/main/java/net/minecraft/world/phys/shapes/EntityCollisionContext.java -@@ -17,50 +17,69 @@ public class EntityCollisionContext implements CollisionContext { - return defaultValue; - } - }; -- private final boolean descending; -- private final double entityBottom; -- private final ItemStack heldItem; -- private final Predicate canStandOnFluid; -+ // Pufferfish start - remove these and pray no plugin uses them -+ // private final boolean descending; -+ // private final double entityBottom; -+ // private final ItemStack heldItem; -+ // private final Predicate canStandOnFluid; -+ // Pufferfish end - @Nullable - private final Entity entity; - - protected EntityCollisionContext(boolean descending, double minY, ItemStack heldItem, Predicate walkOnFluidPredicate, @Nullable Entity entity) { -- this.descending = descending; -- this.entityBottom = minY; -- this.heldItem = heldItem; -- this.canStandOnFluid = walkOnFluidPredicate; -+ // Pufferfish start - remove these -+ // this.descending = descending; -+ // this.entityBottom = minY; -+ // this.heldItem = heldItem; -+ // this.canStandOnFluid = walkOnFluidPredicate; -+ // Pufferfish end - this.entity = entity; - } - - @Deprecated - protected EntityCollisionContext(Entity entity) { -- this( -- entity.isDescending(), -- entity.getY(), -- entity instanceof LivingEntity ? ((LivingEntity)entity).getMainHandItem() : ItemStack.EMPTY, -- entity instanceof LivingEntity ? ((LivingEntity)entity)::canStandOnFluid : fluidState -> false, -- entity -- ); -+ // Pufferfish start - remove this -+ // this( -+ // entity.isDescending(), -+ // entity.getY(), -+ // entity instanceof LivingEntity ? ((LivingEntity)entity).getMainHandItem() : ItemStack.EMPTY, -+ // entity instanceof LivingEntity ? ((LivingEntity)entity)::canStandOnFluid : fluidState -> false, -+ // entity -+ // ); -+ // Pufferfish end -+ this.entity = entity; - } - - @Override - public boolean isHoldingItem(Item item) { -- return this.heldItem.is(item); -+ // Pufferfish start -+ Entity entity = this.entity; -+ if (entity instanceof LivingEntity livingEntity) { -+ return livingEntity.getMainHandItem().is(item); -+ } -+ return ItemStack.EMPTY.is(item); -+ // Pufferfish end - } - - @Override - public boolean canStandOnFluid(FluidState stateAbove, FluidState state) { -- return this.canStandOnFluid.test(state) && !stateAbove.getType().isSame(state.getType()); -+ // Pufferfish start -+ Entity entity = this.entity; -+ if (entity instanceof LivingEntity livingEntity) { -+ return livingEntity.canStandOnFluid(state) && !stateAbove.getType().isSame(state.getType()); -+ } -+ return false; -+ // Pufferfish end - } - - @Override - public boolean isDescending() { -- return this.descending; -+ return this.entity != null && this.entity.isDescending(); // Pufferfish - } - - @Override - public boolean isAbove(VoxelShape shape, BlockPos pos, boolean defaultValue) { -- return this.entityBottom > (double)pos.getY() + shape.max(Direction.Axis.Y) - 1.0E-5F; -+ return (this.entity == null ? -Double.MAX_VALUE : entity.getY()) > (double)pos.getY() + shape.max(Direction.Axis.Y) - 1.0E-5F; // Pufferfish - } - - @Nullable -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index c490a29bcf7410bc54959ee71375605964379ed5..18bfe2fb7efad66f5fae07a30593d640c597bf77 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -266,7 +266,7 @@ import javax.annotation.Nullable; // Paper - import javax.annotation.Nonnull; // Paper - - public final class CraftServer implements Server { -- private final String serverName = "Paper"; // Paper -+ private final String serverName = "Pufferfish"; // Paper // Pufferfish - private final String serverVersion; - private final String bukkitVersion = Versioning.getBukkitVersion(); - private final Logger logger = Logger.getLogger("Minecraft"); -@@ -1137,6 +1137,11 @@ public final class CraftServer implements Server { - plugin.getPluginMeta().getDisplayName(), - "This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies." - )); -+ getLogger().log(Level.SEVERE, String.format("%s Stacktrace", worker.getThread().getName())); -+ StackTraceElement[] stackTrace = worker.getThread().getStackTrace(); -+ for (StackTraceElement element : stackTrace) { -+ getLogger().log(Level.SEVERE, " " + element.toString()); -+ } - } - } - // Paper end - Wait for Async Tasks during shutdown + // Paper - rewrite chunk system diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java -index 96d772eb02f79f8c478f5e6f065e387aa7665b18..c5ce412f321b8b4f31cc042893659e213b081f29 100644 +index 7c989318dc7ad89bb0d9143fcaac1e4bba6f5907..143a4d4efcc989ed4a4c73cc304e1978ad8f0699 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java -@@ -45,6 +45,6 @@ public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe - data.set(i, this.toNMS(ingred.get(i), true)); +@@ -44,6 +44,6 @@ public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe + data.add(this.toNMS(i, true)); } -- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data))); -+ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data, true))); // Pufferfish +- MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data))); ++ MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftRecipe.toMinecraft(this.getKey()), new net.minecraft.world.item.crafting.ShapelessRecipe(this.getGroup(), CraftRecipe.getCategory(this.getCategory()), CraftItemStack.asNMSCopy(this.getResult()), data, true))); // Pufferfish } } diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 3c7a771c48cc2732cc038ca11bb93ec5f8c2d667..94681c5d807019be5caf0b5d5156c0d670f45f8f 100644 +index 15892c7769caa15f3d52a1ee2147cf9615aa0e25..6ef651e6dc16bad45aeb76f8e17b97871c506a64 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -502,7 +502,7 @@ public final class CraftMagicNumbers implements UnsafeValues { - +@@ -505,7 +505,7 @@ public final class CraftMagicNumbers implements UnsafeValues { + // Paper start @Override public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { - return new com.destroystokyo.paper.PaperVersionFetcher(); @@ -3327,11 +1939,11 @@ index 774556a62eb240da42e84db4502e2ed43495be17..80553face9c70c2a3d897681e7761df8 if (stream != null) { diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 3283ed99c35ffed6805567705e0518d9f84feedc..d7c7e12c0b8f77e59d94de130972f762ed227726 100644 +index 1d438ef44cbe4d1eedfba36d8fe5d2ad53464921..bc525c7843b9cc0f7705c0dc6795c05f4e5b4bb1 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -38,6 +38,10 @@ import co.aikar.timings.MinecraftTimings; - import net.minecraft.world.entity.schedule.Activity; +@@ -37,6 +37,10 @@ import net.minecraft.world.entity.projectile.ThrownTrident; + import net.minecraft.world.entity.raid.Raider; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; +// Pufferfish start @@ -3341,7 +1953,7 @@ index 3283ed99c35ffed6805567705e0518d9f84feedc..d7c7e12c0b8f77e59d94de130972f762 public class ActivationRange { -@@ -223,6 +227,25 @@ public class ActivationRange +@@ -221,6 +225,25 @@ public class ActivationRange } // Paper end - Configurable marker ticking ActivationRange.activateEntity(entity); @@ -3367,7 +1979,7 @@ index 3283ed99c35ffed6805567705e0518d9f84feedc..d7c7e12c0b8f77e59d94de130972f762 } // Paper end } -@@ -239,12 +262,12 @@ public class ActivationRange +@@ -236,12 +259,12 @@ public class ActivationRange if ( MinecraftServer.currentTick > entity.activatedTick ) { if ( entity.defaultActivationState ) @@ -3382,7 +1994,7 @@ index 3283ed99c35ffed6805567705e0518d9f84feedc..d7c7e12c0b8f77e59d94de130972f762 entity.activatedTick = MinecraftServer.currentTick; } } -@@ -298,7 +321,7 @@ public class ActivationRange +@@ -295,7 +318,7 @@ public class ActivationRange if ( entity instanceof LivingEntity ) { LivingEntity living = (LivingEntity) entity; diff --git a/patches/unapplied-server/0002-Fix-pufferfish-issues.patch b/patches/unapplied-server/0002-Fix-pufferfish-issues.patch new file mode 100644 index 000000000..def3bace7 --- /dev/null +++ b/patches/unapplied-server/0002-Fix-pufferfish-issues.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 4 Jan 2022 23:05:41 -0600 +Subject: [PATCH] Fix pufferfish issues + + +diff --git a/build.gradle.kts b/build.gradle.kts +index 96d831791edbe6ae07325008b760f70f75c4d713..83e2c8784eaa77851e9efc6b889d673c1fd046d0 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -63,7 +63,7 @@ dependencies { + + // Pufferfish start + implementation("org.yaml:snakeyaml:1.32") +- implementation ("me.carleslc.Simple-YAML:Simple-Yaml:1.8.4") { ++ implementation ("com.github.carleslc.Simple-YAML:Simple-Yaml:1.8.4") { // Purpur - Fix pufferfish issues + exclude(group="org.yaml", module="snakeyaml") + } + // Pufferfish end +diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java +index f5a43a1e1a78b3eaabbcadc7af09750ee478eeb6..3ff4f092a59242a8cb930c084915a774db881652 100644 +--- a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java ++++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java +@@ -25,6 +25,7 @@ public class PufferfishConfig { + + private static final YamlFile config = new YamlFile(); + private static int updates = 0; ++ public static File pufferfishFile; // Purpur - Fix pufferfish issues + + private static ConfigurationSection convertToBukkit(org.simpleyaml.configuration.ConfigurationSection section) { + ConfigurationSection newSection = new MemoryConfiguration(); +@@ -47,7 +48,7 @@ public class PufferfishConfig { + } + + public static void load() throws IOException { +- File configFile = new File("pufferfish.yml"); ++ File configFile = pufferfishFile; // Purpur - Fix pufferfish issues + + if (configFile.exists()) { + try { +@@ -229,7 +230,7 @@ public class PufferfishConfig { + public static int activationDistanceMod; + + private static void dynamicActivationOfBrains() throws IOException { +- dearEnabled = getBoolean("dab.enabled", "activation-range.enabled", true); ++ dearEnabled = getBoolean("dab.enabled", "activation-range.enabled", false); // Purpur - Fix pufferfish issues + startDistance = getInt("dab.start-distance", "activation-range.start-distance", 12, + "This value determines how far away an entity has to be", + "from the player to start being effected by DEAR."); +@@ -256,7 +257,7 @@ public class PufferfishConfig { + + public static boolean throttleInactiveGoalSelectorTick; + private static void inactiveGoalSelectorThrottle() { +- throttleInactiveGoalSelectorTick = getBoolean("inactive-goal-selector-throttle", "inactive-goal-selector-disable", true, ++ throttleInactiveGoalSelectorTick = getBoolean("inactive-goal-selector-throttle", "inactive-goal-selector-disable", false, // Purpur - Fix pufferfish issues + "Throttles the AI goal selector in entity inactive ticks.", + "This can improve performance by a few percent, but has minor gameplay implications."); + } +diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java +index 790bad0494454ca12ee152e3de6da3da634d9b20..19d602e4e6fa5abf59559eab4132677b09a967a1 100644 +--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java ++++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java +@@ -31,6 +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_PUFFERFISH_NAME = "Pufferfish"; // Purpur - Fix pufferfish issues + + private static final String BUILD_DEV = "DEV"; + +@@ -42,9 +43,9 @@ public record ServerBuildInfoImpl( + this( + getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID) + .map(Key::key) +- .orElse(BRAND_PAPER_ID), ++ .orElse(BRAND_PUFFERFISH_ID), // Purpur - Fix pufferfish issues + getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME) +- .orElse(BRAND_PAPER_NAME), ++ .orElse(BRAND_PUFFERFISH_NAME), // Purpur - Fix pufferfish issues + SharedConstants.getCurrentVersion().getId(), + SharedConstants.getCurrentVersion().getName(), + getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER) +@@ -61,7 +62,7 @@ public record ServerBuildInfoImpl( + + @Override + public boolean isBrandCompatible(final @NotNull Key brandId) { +- return brandId.equals(this.brandId); ++ return brandId.equals(this.brandId) || brandId.equals(BRAND_PAPER_ID); // Purpur - Fix pufferfish issues + } + + @Override +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index d62f7375394409a278bc565c8263506c598ceeba..8ccf355a2541c8fb725c312c6955bb6cf624ff0f 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -236,6 +236,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark + com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics + com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now ++ gg.pufferfish.pufferfish.PufferfishConfig.pufferfishFile = (java.io.File) options.valueOf("pufferfish-settings"); // Purpur - Fix pufferfish issues + gg.pufferfish.pufferfish.PufferfishConfig.load(); // Pufferfish + gg.pufferfish.pufferfish.PufferfishCommand.init(); // Pufferfish + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +index 593b343b7cd5a24e34ad19a9e93eb9258f862357..80ff364514d071d1862c4b3aa5d01b9c39062946 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +@@ -77,7 +77,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { + if (!isLoaded) { + if (Projectile.loadedThisTick > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerTick) { + if (++this.loadedLifetime > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerProjectile) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Purpur - Fix pufferfish issues + } + return; + } +diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +index 99a95d77f44dddfd7be6c2ebd60e827d9de956b7..00ea1c2037c7c7780764bfcc3e07b6554e910db2 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -135,7 +135,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + this.defaultBlockState = empty ? VOID_AIR_BLOCKSTATE : AIR_BLOCKSTATE; + // Paper end - get block chunk optimisation + +- this.lightningTick = new java.util.Random().nextInt(100000) << 1; // Pufferfish - initialize lightning tick ++ this.lightningTick = java.util.concurrent.ThreadLocalRandom.current().nextInt(100000) << 1; // Pufferfish - initialize lightning tick // Purpur - any random will do - Fix pufferfish issues + } + + // CraftBukkit start +diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java +index 1c2439ffc1e407ff69286817d22f127470ce07ba..d74f885fcdf686359f761aa7356fe03cf293ee59 100644 +--- a/src/main/java/org/bukkit/craftbukkit/Main.java ++++ b/src/main/java/org/bukkit/craftbukkit/Main.java +@@ -176,6 +176,13 @@ public class Main { + .describedAs("Jar file"); + // Paper end + ++ // Purpur start - Fix pufferfish issues ++ acceptsAll(asList("pufferfish", "pufferfish-settings"), "File for pufferfish settings") ++ .withRequiredArg() ++ .ofType(File.class) ++ .defaultsTo(new File("pufferfish.yml")) ++ .describedAs("Yml file"); ++ // Purpur end - Fix pufferfish issues + // Paper start + acceptsAll(asList("server-name"), "Name of the server") + .withRequiredArg() diff --git a/patches/unapplied-server/0003-Fix-pufferfish-issues.patch b/patches/unapplied-server/0003-Fix-pufferfish-issues.patch deleted file mode 100644 index cae584b75..000000000 --- a/patches/unapplied-server/0003-Fix-pufferfish-issues.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 12 Jun 2022 09:18:57 -0500 -Subject: [PATCH] Fix pufferfish issues - - -diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -index 6464682e2f93659e73aca491031c8051ab000033..5a73aa17a963ae2d57e9bd5b5e3e5b0030d06216 100644 ---- a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -+++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -@@ -86,7 +86,7 @@ public class PufferfishConfig { - // Attempt to detect vectorization - try { - SIMDDetection.isEnabled = SIMDDetection.canEnable(PufferfishLogger.LOGGER); -- SIMDDetection.versionLimited = SIMDDetection.getJavaVersion() != 17 && SIMDDetection.getJavaVersion() != 18 && SIMDDetection.getJavaVersion() != 19; -+ SIMDDetection.versionLimited = SIMDDetection.getJavaVersion() < 17 || SIMDDetection.getJavaVersion() > 21; - } catch (NoClassDefFoundError | Exception ignored) { - ignored.printStackTrace(); - } -@@ -94,7 +94,7 @@ public class PufferfishConfig { - if (SIMDDetection.isEnabled) { - PufferfishLogger.LOGGER.info("SIMD operations detected as functional. Will replace some operations with faster versions."); - } else if (SIMDDetection.versionLimited) { -- PufferfishLogger.LOGGER.warning("Will not enable SIMD! These optimizations are only safely supported on Java 17, Java 18, and Java 19."); -+ PufferfishLogger.LOGGER.warning("Will not enable SIMD! These optimizations are only safely supported on Java 17 through Java 21."); - } else { - PufferfishLogger.LOGGER.warning("SIMD operations are available for your server, but are not configured!"); - PufferfishLogger.LOGGER.warning("To enable additional optimizations, add \"--add-modules=jdk.incubator.vector\" to your startup flags, BEFORE the \"-jar\"."); -@@ -232,7 +232,7 @@ public class PufferfishConfig { - public static int activationDistanceMod; - - private static void dynamicActivationOfBrains() throws IOException { -- dearEnabled = getBoolean("dab.enabled", "activation-range.enabled", true); -+ dearEnabled = getBoolean("dab.enabled", "activation-range.enabled", false); // Purpur - startDistance = getInt("dab.start-distance", "activation-range.start-distance", 12, - "This value determines how far away an entity has to be", - "from the player to start being effected by DEAR."); -@@ -276,7 +276,7 @@ public class PufferfishConfig { - - public static boolean throttleInactiveGoalSelectorTick; - private static void inactiveGoalSelectorThrottle() { -- throttleInactiveGoalSelectorTick = getBoolean("inactive-goal-selector-throttle", "inactive-goal-selector-disable", true, -+ throttleInactiveGoalSelectorTick = getBoolean("inactive-goal-selector-throttle", "inactive-goal-selector-disable", false, // Purpur - "Throttles the AI goal selector in entity inactive ticks.", - "This can improve performance by a few percent, but has minor gameplay implications."); - } -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index fbffe3dab1b7812b50df5d6bddf4fbdb2e583339..881ba370b098a4a202fbfb9c5c3d9304719d155e 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -992,7 +992,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - // Paper start - optimise random block ticking - private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); -- // private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); // Pufferfish - moved to super -+ private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - moved to super // Purpur - dont break ABI - // Paper end - - private int currentIceAndSnowTick = 0; protected void resetIceAndSnowTick() { this.currentIceAndSnowTick = this.randomTickRandom.nextInt(16); } // Pufferfish -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 1aa45e64e49ea011c2ba5e943b4e72c4f3a47176..6f7b34357788faecf8368cc9a27d26585935f789 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -825,7 +825,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - public void tick() { - // Pufferfish start - entity TTL - if (type != EntityType.PLAYER && type.ttl >= 0 && this.tickCount >= type.ttl) { -- discard(); -+ discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Purpur - return; - } - // Pufferfish end - entity TTL -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 837f68825f601971f374be47952b23108bf66ba6..2a8a8030feefae84e394460612405887e63f2ac7 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -64,7 +64,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { - if (!isLoaded) { - if (Projectile.loadedThisTick > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerTick) { - if (++this.loadedLifetime > gg.pufferfish.pufferfish.PufferfishConfig.maxProjectileLoadsPerProjectile) { -- this.discard(); -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Purpur - } - return; - } -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index a82de7111915b19cdc3f065910465a5e7e843aff..fc32b6342b7553265f2a012f91f4dd9c0386f8f2 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -215,8 +215,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // Paper end - - public abstract ResourceKey getTypeKey(); -- -- protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - move thread unsafe random initialization // Pufferfish - getter -+ -+ //protected final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(java.util.concurrent.ThreadLocalRandom.current().nextLong()); public net.minecraft.util.RandomSource getThreadUnsafeRandom() { return this.randomTickRandom; } // Pufferfish - move thread unsafe random initialization // Pufferfish - getter // Purpur - dont break ABI - - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config; Async-Anti-Xray: Pass executor - this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 270a892373ecbb3982990d6201d79c8a66de4f60..d087c8271dbdfe3dc6d805539a710d37ed6d7f21 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -122,7 +122,7 @@ public class LevelChunk extends ChunkAccess { - this.blockTicks = blockTickScheduler; - this.fluidTicks = fluidTickScheduler; - -- this.lightningTick = this.level.getThreadUnsafeRandom().nextInt(100000) << 1; // Pufferfish - initialize lightning tick -+ this.lightningTick = java.util.concurrent.ThreadLocalRandom.current().nextInt(100000) << 1; // Pufferfish - initialize lightning tick // Purpur - any random will do - } - - // CraftBukkit start diff --git a/patches/unapplied-server/0269-Make-pufferfish-config-relocatable.patch b/patches/unapplied-server/0269-Make-pufferfish-config-relocatable.patch deleted file mode 100644 index c81d41c1e..000000000 --- a/patches/unapplied-server/0269-Make-pufferfish-config-relocatable.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Sun, 12 Jun 2022 09:18:57 -0500 -Subject: [PATCH] Make pufferfish config relocatable - - -diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -index 5a73aa17a963ae2d57e9bd5b5e3e5b0030d06216..8afc58f35deb49084a20b803e91ce4692ce6e4d6 100644 ---- a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -+++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java -@@ -28,6 +28,7 @@ public class PufferfishConfig { - - private static final YamlFile config = new YamlFile(); - private static int updates = 0; -+ public static File pufferfishFile; // Purpur - - private static ConfigurationSection convertToBukkit(org.simpleyaml.configuration.ConfigurationSection section) { - ConfigurationSection newSection = new MemoryConfiguration(); -@@ -50,7 +51,7 @@ public class PufferfishConfig { - } - - public static void load() throws IOException { -- File configFile = new File("pufferfish.yml"); -+ File configFile = pufferfishFile; // Purpur - - if (configFile.exists()) { - try { -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 6a9bd431e9c2e1fc1e51d394eaccba864bbeac89..85b861e21d8798a883ecbd0a09cc25f87e801b7b 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -230,6 +230,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - // Purpur end - com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now - io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // Paper - init PaperBrigadierProvider -+ gg.pufferfish.pufferfish.PufferfishConfig.pufferfishFile = (java.io.File) options.valueOf("pufferfish-settings"); // Purpur - gg.pufferfish.pufferfish.PufferfishConfig.load(); // Pufferfish - gg.pufferfish.pufferfish.PufferfishCommand.init(); // Pufferfish - -diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 1dd676ad37c68e3fce71306d7e05cb2c377a32b4..409c0e81571e23c9d535b541c61538424259d60a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/Main.java -+++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -180,6 +180,12 @@ public class Main { - .ofType(File.class) - .defaultsTo(new File("purpur.yml")) - .describedAs("Yml file"); -+ -+ acceptsAll(asList("pufferfish", "pufferfish-settings"), "File for pufferfish settings") -+ .withRequiredArg() -+ .ofType(File.class) -+ .defaultsTo(new File("pufferfish.yml")) -+ .describedAs("Yml file"); - // Purpur end - - // Paper start diff --git a/purpur-api/build.gradle.kts.patch b/purpur-api/build.gradle.kts.patch new file mode 100644 index 000000000..5f295dd9c --- /dev/null +++ b/purpur-api/build.gradle.kts.patch @@ -0,0 +1,56 @@ +--- a/paper-api/build.gradle.kts ++++ b/paper-api/build.gradle.kts +@@ -93,7 +_,7 @@ + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + } + +-val generatedApiPath: java.nio.file.Path = layout.projectDirectory.dir("src/generated/java").asFile.toPath() ++val generatedApiPath: java.nio.file.Path = rootProject.layout.projectDirectory.dir("paper-api/src/generated/java").asFile.toPath() + idea { + module { + generatedSourceDirs.add(generatedApiPath.toFile()) +@@ -103,6 +_,18 @@ + main { + java { + srcDir(generatedApiPath) ++ srcDir(file("../paper-api/src/main/java")) ++ } ++ resources { ++ srcDir(file("../paper-api/src/main/resources")) ++ } ++ } ++ test { ++ java { ++ srcDir(file("../paper-api/src/test/java")) ++ } ++ resources { ++ srcDir(file("../paper-api/src/test/resources")) + } + } + } +@@ -168,8 +_,10 @@ + val services = objects.newInstance() + + tasks.withType { ++ //(options as StandardJavadocDocletOptions).addStringOption("-add-modules", "jdk.incubator.vector") // Purpur - our javadocs need this for pufferfish's SIMD patch ++ (options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet") // Purpur - silence Paper's bajillion javadoc warnings + val options = options as StandardJavadocDocletOptions +- options.overview = "src/main/javadoc/overview.html" ++ options.overview = "../paper-api/src/main/javadoc/overview.html" + options.use() + options.isDocFilesSubDirs = true + options.links( +@@ -202,11 +_,11 @@ + } + + // workaround for https://github.com/gradle/gradle/issues/4046 +- inputs.dir("src/main/javadoc").withPropertyName("javadoc-sourceset") ++ inputs.dir("../paper-api/src/main/javadoc").withPropertyName("javadoc-sourceset") + val fsOps = services.fileSystemOperations + doLast { + fsOps.copy { +- from("src/main/javadoc") { ++ from("../paper-api/src/main/javadoc") { + include("**/doc-files/**") + } + into("build/docs/javadoc") diff --git a/purpur-api/paper-patches/features/0001-Rebrand.patch b/purpur-api/paper-patches/features/0001-Rebrand.patch new file mode 100644 index 000000000..9153a5d0c --- /dev/null +++ b/purpur-api/paper-patches/features/0001-Rebrand.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: granny +Date: Thu, 16 May 2024 19:11:29 -0700 +Subject: [PATCH] Rebrand + + +diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java +index 652ff54e7c50412503725d628bfe72ed03059790..fb1fe2651e53a9bf46b3632c638e13eea9dcda93 100644 +--- a/src/main/java/io/papermc/paper/ServerBuildInfo.java ++++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java +@@ -19,6 +19,12 @@ public interface ServerBuildInfo { + */ + Key BRAND_PAPER_ID = Key.key("papermc", "paper"); + ++ // Purpur start ++ /** ++ * The brand id for Purpur. ++ */ ++ Key BRAND_PURPUR_ID = Key.key("purpurmc", "purpur"); ++ // Purpur end + /** + * Gets the {@code ServerBuildInfo}. + * diff --git a/patches/api/0001-Purpur-config-files.patch b/purpur-api/paper-patches/features/0002-Purpur-config-files.patch similarity index 85% rename from patches/api/0001-Purpur-config-files.patch rename to purpur-api/paper-patches/features/0002-Purpur-config-files.patch index d175ac5a8..e3535a398 100644 --- a/patches/api/0001-Purpur-config-files.patch +++ b/purpur-api/paper-patches/features/0002-Purpur-config-files.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Purpur config files diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 30cbe3bdc7142769019765b03cc4fe1f9ba1ddb4..f5c3c1a0c11dd3518981ce3b86dba8ced8578d9c 100644 +index 365368983a25f7ccbd3c8b7b572a5173a4c868a0..594bcedd823acc87ed429ad8ef17b66e9dc15beb 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -2257,6 +2257,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2330,6 +2330,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi } // Paper end diff --git a/purpur-api/paper-patches/files/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java.patch b/purpur-api/paper-patches/files/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java.patch new file mode 100644 index 000000000..b21f25fa2 --- /dev/null +++ b/purpur-api/paper-patches/files/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java.patch @@ -0,0 +1,29 @@ +--- a/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java ++++ b/src/generated/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +@@ -441,6 +_,26 @@ + + GoalKey ZOMBIE_ATTACK_TURTLE_EGG = create("zombie_attack_turtle_egg", Zombie.class); + ++ // Purpur start - Ridables ++ GoalKey MOB_HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider")); ++ GoalKey HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider")); ++ GoalKey LLAMA_HAS_RIDER = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_has_rider")); ++ // Purpur end - Ridables ++ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms ++ GoalKey FIND_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal")); ++ GoalKey ORBIT_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal")); ++ // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms ++ // Purpur start - Add option to disable zombie aggressiveness towards villagers when lagging ++ GoalKey DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); ++ GoalKey ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager")); ++ // Purpur end - Add option to disable zombie aggressiveness towards villagers when lagging ++ // Purpur start - Configurable chance for wolves to spawn rabid ++ GoalKey AVOID_RABID_WOLF = GoalKey.of(Wolf.class, NamespacedKey.minecraft("avoid_rabid_wolf")); ++ // Purpur end - Configurable chance for wolves to spawn rabid ++ // Purpur start - Iron golem poppy calms anger ++ GoalKey RECEIVE_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("receive_flower")); ++ // Purpur end - Iron golem poppy calms anger ++ + private static GoalKey create(final String key, final Class type) { + return GoalKey.of(type, NamespacedKey.minecraft(key)); + } diff --git a/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/TimedEventExecutor.java.patch b/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/TimedEventExecutor.java.patch new file mode 100644 index 000000000..382cc7915 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/TimedEventExecutor.java.patch @@ -0,0 +1,14 @@ +--- a/src/main/java/co/aikar/timings/TimedEventExecutor.java ++++ b/src/main/java/co/aikar/timings/TimedEventExecutor.java +@@ -80,9 +_,9 @@ + executor.execute(listener, event); + return; + } +- try (Timing ignored = timings.startTiming()){ ++ //try (Timing ignored = timings.startTiming()){ // Purpur - Remove Timings + executor.execute(listener, event); +- } ++ //} // Purpur - Remove Timings + } + + @Override diff --git a/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/Timing.java.patch b/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/Timing.java.patch new file mode 100644 index 000000000..d971ba0c2 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/Timing.java.patch @@ -0,0 +1,48 @@ +--- a/src/main/java/co/aikar/timings/Timing.java ++++ b/src/main/java/co/aikar/timings/Timing.java +@@ -39,6 +_,7 @@ + * @return Timing + */ + @NotNull ++ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings + Timing startTiming(); + + /** +@@ -46,6 +_,7 @@ + * + * Will automatically be called when this Timing is used with try-with-resources + */ ++ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings + void stopTiming(); + + /** +@@ -56,6 +_,7 @@ + * @return Timing + */ + @NotNull ++ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings + Timing startTimingIfSync(); + + /** +@@ -65,12 +_,14 @@ + * + * But only if we are on the primary thread. + */ ++ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings + void stopTimingIfSync(); + + /** + * @deprecated Doesn't do anything - Removed + */ + @Deprecated ++ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings + void abort(); + + /** +@@ -82,5 +_,6 @@ + TimingHandler getTimingHandler(); + + @Override ++ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings + void close(); + } diff --git a/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/Timings.java.patch b/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/Timings.java.patch new file mode 100644 index 000000000..beab0b68d --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/Timings.java.patch @@ -0,0 +1,25 @@ +--- a/src/main/java/co/aikar/timings/Timings.java ++++ b/src/main/java/co/aikar/timings/Timings.java +@@ -124,7 +_,7 @@ + @NotNull + public static Timing ofStart(@NotNull Plugin plugin, @NotNull String name, @Nullable Timing groupHandler) { + Timing timing = of(plugin, name, groupHandler); +- timing.startTiming(); ++ //timing.startTiming(); // Purpur - Remove Timings + return timing; + } + +@@ -146,7 +_,7 @@ + */ + public static void setTimingsEnabled(boolean enabled) { + if (enabled && !warnedAboutDeprecationOnEnable) { +- Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage())); ++ //Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage())); // Purpur - Remove Timings + warnedAboutDeprecationOnEnable = true; + } + } +@@ -322,4 +_,3 @@ + return TimingsManager.getHandler(groupName, name, groupHandler); + } + } +- diff --git a/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/TimingsCommand.java.patch b/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/TimingsCommand.java.patch new file mode 100644 index 000000000..96b13d99c --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/co/aikar/timings/TimingsCommand.java.patch @@ -0,0 +1,34 @@ +--- a/src/main/java/co/aikar/timings/TimingsCommand.java ++++ b/src/main/java/co/aikar/timings/TimingsCommand.java +@@ -47,7 +_,7 @@ + public TimingsCommand(@NotNull String name) { + super(name); + this.description = "Manages Spigot Timings data to see performance of the server."; +- this.usageMessage = "/timings "; ++ this.usageMessage = "/timings";// "; // Purpur - Remove Timings + this.setPermission("bukkit.command.timings"); + } + +@@ -57,7 +_,12 @@ + return true; + } + if (true) { +- sender.sendMessage(Timings.deprecationMessage()); ++ // Purpur start - Remove Timings ++ net.kyori.adventure.text.minimessage.MiniMessage mm = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage(); ++ sender.sendMessage(mm.deserialize("Purpur has removed timings to save your performance. Please use /spark instead")); ++ sender.sendMessage(mm.deserialize("For more information, view its documentation at")); ++ sender.sendMessage(mm.deserialize("https://spark.lucko.me/docs/Command-Usage")); ++ // Purpur end - Remove Timings + return true; + } + if (args.length < 1) { +@@ -118,7 +_,7 @@ + Preconditions.checkNotNull(args, "Arguments cannot be null"); + Preconditions.checkNotNull(alias, "Alias cannot be null"); + +- if (args.length == 1) { ++ if (false && args.length == 1) { // Purpur - Remove Timings + return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS, + new ArrayList(TIMINGS_SUBCOMMANDS.size())); + } diff --git a/purpur-api/paper-patches/files/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java.patch b/purpur-api/paper-patches/files/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java.patch new file mode 100644 index 000000000..4264eea11 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java.patch @@ -0,0 +1,15 @@ +--- a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java ++++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java +@@ -28,6 +_,12 @@ + */ + Component getVersionMessage(String serverVersion); + ++ // Purpur start ++ default int distance() { ++ return 0; ++ } ++ // Purpur end ++ + @ApiStatus.Internal + class DummyVersionFetcher implements VersionFetcher { + diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Bukkit.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Bukkit.java.patch new file mode 100644 index 000000000..7bdf2cf76 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Bukkit.java.patch @@ -0,0 +1,136 @@ +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2980,4 +_,133 @@ + public static Server.Spigot spigot() { + return server.spigot(); + } ++ ++ // Purpur start - Bring back server name ++ /** ++ * Get the name of this server ++ * @return the name of the server ++ */ ++ @NotNull ++ public static String getServerName() { ++ return server.getServerName(); ++ } ++ // Purpur end - Bring back server name ++ ++ // Purpur start - Lagging threshold ++ /** ++ * Check if server is lagging according to laggy threshold setting ++ * ++ * @return True if lagging ++ */ ++ public static boolean isLagging() { ++ return server.isLagging(); ++ } ++ // Purpur end - Lagging threshold ++ ++ // Purpur start - Added the ability to add combustible items ++ /** ++ * Add an Item as fuel for furnaces ++ * ++ * @param material The material that will be the fuel ++ * @param burnTime The time (in ticks) this item will burn for ++ */ ++ public static void addFuel(@NotNull Material material, int burnTime) { ++ server.addFuel(material, burnTime); ++ } ++ ++ /** ++ * Remove an item as fuel for furnaces ++ * ++ * @param material The material that will no longer be a fuel ++ */ ++ public static void removeFuel(@NotNull Material material) { ++ server.removeFuel(material); ++ } ++ // Purpur end - Added the ability to add combustible items ++ ++ // Purpur start - Debug Marker API ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ */ ++ public static void sendBlockHighlight(@NotNull Location location, int duration) { ++ server.sendBlockHighlight(location, duration); ++ } ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client ++ */ ++ public static void sendBlockHighlight(@NotNull Location location, int duration, int argb) { ++ server.sendBlockHighlight(location, duration, argb); ++ } ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ */ ++ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text) { ++ server.sendBlockHighlight(location, duration, text); ++ } ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client ++ */ ++ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb) { ++ server.sendBlockHighlight(location, duration, text, argb); ++ } ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param color Color of the highlight. Will be ignored on some versions of vanilla client ++ * @param transparency Transparency of the highlight ++ * @throws IllegalArgumentException If transparency is outside 0-255 range ++ */ ++ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency) { ++ server.sendBlockHighlight(location, duration, color, transparency); ++ } ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ * @param color Color of the highlight. Will be ignored on some versions of vanilla client ++ * @param transparency Transparency of the highlight ++ * @throws IllegalArgumentException If transparency is outside 0-255 range ++ */ ++ public static void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency) { ++ server.sendBlockHighlight(location, duration, text, color, transparency); ++ } ++ ++ /** ++ * Clears all debug block highlights for all players on the server. ++ */ ++ public static void clearBlockHighlights() { ++ server.clearBlockHighlights(); ++ } ++ // Purpur end - Debug Marker API + } diff --git a/patches/api/0016-ChatColor-conveniences.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/ChatColor.java.patch similarity index 76% rename from patches/api/0016-ChatColor-conveniences.patch rename to purpur-api/paper-patches/files/src/main/java/org/bukkit/ChatColor.java.patch index 1cbcc2653..a9da296b0 100644 --- a/patches/api/0016-ChatColor-conveniences.patch +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/ChatColor.java.patch @@ -1,27 +1,11 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Fri, 10 Jul 2020 12:43:25 -0500 -Subject: [PATCH] ChatColor conveniences - - -diff --git a/src/main/java/org/bukkit/ChatColor.java b/src/main/java/org/bukkit/ChatColor.java -index 918a045165cdcde264bc24082b7afebb407271de..687d11619379aead7f665d4a5f8f8bcc857cb8e9 100644 --- a/src/main/java/org/bukkit/ChatColor.java +++ b/src/main/java/org/bukkit/ChatColor.java -@@ -3,6 +3,7 @@ package org.bukkit; - import com.google.common.base.Preconditions; - import com.google.common.collect.Maps; - import java.util.Map; -+import java.util.regex.Matcher; - import java.util.regex.Pattern; - import org.jetbrains.annotations.Contract; - import org.jetbrains.annotations.NotNull; -@@ -456,4 +457,77 @@ public enum ChatColor { +@@ -456,4 +_,77 @@ BY_CHAR.put(color.code, color); } } + -+ // Purpur start ++ // Purpur start - ChatColor conveniences + /** + * Convert legacy string into a string ready to be parsed by MiniMessage + * @@ -31,7 +15,7 @@ index 918a045165cdcde264bc24082b7afebb407271de..687d11619379aead7f665d4a5f8f8bcc + @NotNull + public static String toMM(@NotNull String str) { + StringBuilder sb = new StringBuilder(str); -+ Matcher m = STRIP_COLOR_PATTERN.matcher(sb); ++ java.util.regex.Matcher m = STRIP_COLOR_PATTERN.matcher(sb); + while (m.find()) { + sb.replace(m.start(), m.end(), sb.substring(m.start(), m.end()).toLowerCase()); + } @@ -92,5 +76,5 @@ index 918a045165cdcde264bc24082b7afebb407271de..687d11619379aead7f665d4a5f8f8bcc + public static String color(@Nullable String str, boolean parseHex) { + return str != null ? net.md_5.bungee.api.ChatColor.translateAlternateColorCodes('&', parseHex ? replaceHex(str) : str) : str; + } -+ // Purpur end ++ // Purpur end - ChatColor conveniences } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Material.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Material.java.patch new file mode 100644 index 000000000..48bef86e4 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Material.java.patch @@ -0,0 +1,43 @@ +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -5812,4 +_,40 @@ + return this.asItemType().getDefaultDataTypes(); + } + // Paper end - data component API ++ ++ // Purpur start - ItemStack convenience methods ++ public boolean isArmor() { ++ switch (this) { ++ // ++ case LEATHER_BOOTS: ++ case LEATHER_CHESTPLATE: ++ case LEATHER_HELMET: ++ case LEATHER_LEGGINGS: ++ case CHAINMAIL_BOOTS: ++ case CHAINMAIL_CHESTPLATE: ++ case CHAINMAIL_HELMET: ++ case CHAINMAIL_LEGGINGS: ++ case IRON_BOOTS: ++ case IRON_CHESTPLATE: ++ case IRON_HELMET: ++ case IRON_LEGGINGS: ++ case GOLDEN_BOOTS: ++ case GOLDEN_CHESTPLATE: ++ case GOLDEN_HELMET: ++ case GOLDEN_LEGGINGS: ++ case DIAMOND_BOOTS: ++ case DIAMOND_CHESTPLATE: ++ case DIAMOND_HELMET: ++ case DIAMOND_LEGGINGS: ++ case NETHERITE_BOOTS: ++ case NETHERITE_CHESTPLATE: ++ case NETHERITE_HELMET: ++ case NETHERITE_LEGGINGS: ++ case TURTLE_HELMET: ++ return true; ++ default: ++ return false; ++ } ++ } ++ // Purpur end - ItemStack convenience methods + } diff --git a/patches/api/0029-Extended-OfflinePlayer-API.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch similarity index 86% rename from patches/api/0029-Extended-OfflinePlayer-API.patch rename to purpur-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch index af97d3dd0..5048818d2 100644 --- a/patches/api/0029-Extended-OfflinePlayer-API.patch +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/OfflinePlayer.java.patch @@ -1,17 +1,9 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: YouHaveTrouble -Date: Sun, 22 Aug 2021 05:11:09 +0200 -Subject: [PATCH] Extended OfflinePlayer API - - -diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java -index 30298a629b39bd43ce14b414fc697b2dfcbea89c..ce00af9121de7a910aaea4e0685a06d4cf31b4e3 100644 --- a/src/main/java/org/bukkit/OfflinePlayer.java +++ b/src/main/java/org/bukkit/OfflinePlayer.java -@@ -557,4 +557,106 @@ public interface OfflinePlayer extends ServerOperator, AnimalTamer, Configuratio - */ - @Nullable - public Location getLocation(); +@@ -573,4 +_,106 @@ + @Override + io.papermc.paper.persistence.@NotNull PersistentDataContainerView getPersistentDataContainer(); + // Paper end - add pdc to offline player + + // Purpur start - OfflinePlayer API + /** diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch new file mode 100644 index 000000000..b149d0c27 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch @@ -0,0 +1,114 @@ +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2654,4 +_,111 @@ + */ + void allowPausing(@NotNull org.bukkit.plugin.Plugin plugin, boolean value); + // Paper end - API to check if the server is sleeping ++ ++ // Purpur start - Bring back server name ++ /** ++ * Get the name of this server ++ * @return the name of the server ++ */ ++ @NotNull ++ String getServerName(); ++ // Purpur end - Bring back server name ++ ++ // Purpur start - Lagging threshold ++ /** ++ * Check if server is lagging according to laggy threshold setting ++ * ++ * @return True if lagging ++ */ ++ boolean isLagging(); ++ // Purpur end - Lagging threshold ++ ++ // Purpur start - Added the ability to add combustible items ++ /** ++ * Add an Item as fuel for furnaces ++ * ++ * @param material The material that will be the fuel ++ * @param burnTime The time (in ticks) this item will burn for ++ */ ++ public void addFuel(@NotNull Material material, int burnTime); ++ ++ /** ++ * Remove an item as fuel for furnaces ++ * ++ * @param material The material that will no longer be a fuel ++ */ ++ public void removeFuel(@NotNull Material material); ++ // Purpur end - Added the ability to add combustible items ++ ++ // Purpur start - Debug Marker API ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, int argb); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param color Color of the highlight. Will be ignored on some versions of vanilla client ++ * @param transparency Transparency of the highlight ++ * @throws IllegalArgumentException If transparency is outside 0-255 range ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on the server. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ * @param color Color of the highlight. Will be ignored on some versions of vanilla client ++ * @param transparency Transparency of the highlight ++ * @throws IllegalArgumentException If transparency is outside 0-255 range ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency); ++ ++ /** ++ * Clears all debug block highlights for all players on the server. ++ */ ++ void clearBlockHighlights(); ++ // Purpur end - Debug Marker API + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch new file mode 100644 index 000000000..eaa0ae079 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/World.java.patch @@ -0,0 +1,89 @@ +--- a/src/main/java/org/bukkit/World.java ++++ b/src/main/java/org/bukkit/World.java +@@ -4253,6 +_,86 @@ + @Nullable + public DragonBattle getEnderDragonBattle(); + ++ // Purpur start ++ /** ++ * Gets the local difficulty (based on inhabited time) at a location ++ * ++ * @param location Location to check ++ * @return The local difficulty ++ */ ++ public float getLocalDifficultyAt(@NotNull Location location); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on this world. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on this world. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, int argb); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on this world. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on this world. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on this world. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param color Color of the highlight. Will be ignored on some versions of vanilla client ++ * @param transparency Transparency of the highlight ++ * @throws IllegalArgumentException If transparency is outside 0-255 range ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to all players on this world. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ * @param color Color of the highlight. Will be ignored on some versions of vanilla client ++ * @param transparency Transparency of the highlight ++ * @throws IllegalArgumentException If transparency is outside 0-255 range ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency); ++ ++ /** ++ * Clears all debug block highlights for all players on this world. ++ */ ++ void clearBlockHighlights(); ++ // Purpur end ++ + /** + * Get all {@link FeatureFlag} enabled in this world. + * diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/block/EntityBlockStorage.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/block/EntityBlockStorage.java.patch new file mode 100644 index 000000000..94b62abaa --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/block/EntityBlockStorage.java.patch @@ -0,0 +1,28 @@ +--- a/src/main/java/org/bukkit/block/EntityBlockStorage.java ++++ b/src/main/java/org/bukkit/block/EntityBlockStorage.java +@@ -47,6 +_,25 @@ + @NotNull + List releaseEntities(); + ++ // Purpur start - Stored Bee API ++ /** ++ * Releases a stored entity, and returns the entity in the world. ++ * ++ * @param entity Entity to release ++ * @return The entity which was released, or null if the stored entity is not in the hive ++ */ ++ @org.jetbrains.annotations.Nullable ++ T releaseEntity(@NotNull org.purpurmc.purpur.entity.StoredEntity entity); ++ ++ /** ++ * Gets all the entities currently stored in the block. ++ * ++ * @return List of all entities which are stored in the block ++ */ ++ @NotNull ++ List> getEntities(); ++ // Purpur end - Stored Bee API ++ + /** + * Add an entity to the block. + * diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch new file mode 100644 index 000000000..83f75df21 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch @@ -0,0 +1,36 @@ +--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java ++++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java +@@ -153,6 +_,19 @@ + return false; + } + ++ // Purpur start - ExecuteCommandEvent ++ String[] parsedArgs = Arrays.copyOfRange(args, 1, args.length); ++ org.purpurmc.purpur.event.ExecuteCommandEvent event = new org.purpurmc.purpur.event.ExecuteCommandEvent(sender, target, sentCommandLabel, parsedArgs); ++ if (!event.callEvent()) { ++ return true; // cancelled ++ } ++ ++ sender = event.getSender(); ++ target = event.getCommand(); ++ sentCommandLabel = event.getLabel(); ++ parsedArgs = event.getArgs(); ++ // Purpur end - ExecuteCommandEvent ++ + // Paper start - Plugins do weird things to workaround normal registration + if (target.timings == null) { + target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target); +@@ -160,10 +_,10 @@ + // Paper end + + try { +- try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources ++ //try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources // Purpur - Remove Timings + // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) +- target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length)); +- } // target.timings.stopTiming(); // Spigot // Paper ++ target.execute(sender, sentCommandLabel, parsedArgs); // Purpur - ExecuteCommandEvent ++ //} // target.timings.stopTiming(); // Spigot // Paper // Purpur - Remove Timings + } catch (CommandException ex) { + server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper + //target.timings.stopTiming(); // Spigot // Paper diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch new file mode 100644 index 000000000..b424f2eb9 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch @@ -0,0 +1,26 @@ +--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java +@@ -215,7 +_,7 @@ + String version = Bukkit.getVersion(); + // Paper start + if (version.startsWith("null")) { // running from ide? +- setVersionMessage(Component.text("Unknown version, custom build?", NamedTextColor.YELLOW)); ++ setVersionMessage(Component.text("* Unknown version, custom build?", NamedTextColor.RED)); // Purpur + return; + } + setVersionMessage(getVersionFetcher().getVersionMessage(version)); +@@ -256,9 +_,11 @@ + // Paper start + private void setVersionMessage(final @NotNull Component msg) { + lastCheck = System.currentTimeMillis(); +- final Component message = Component.textOfChildren( +- Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE), +- Component.newline(), ++ // Purpur start ++ int distance = getVersionFetcher().distance(); ++ final Component message = Component.join(net.kyori.adventure.text.JoinConfiguration.separator(Component.newline()), ++ ChatColor.parseMM("Current Purpur Version: %s%s*", distance == 0 ? "" : distance > 0 ? "" : "", Bukkit.getVersion()), ++ // Purpur end + msg + ); + this.versionMessage = Component.text() diff --git a/patches/api/0023-Add-enchantment-target-for-bows-and-crossbows.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java.patch similarity index 53% rename from patches/api/0023-Add-enchantment-target-for-bows-and-crossbows.patch rename to purpur-api/paper-patches/files/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java.patch index d9680f160..45b679507 100644 --- a/patches/api/0023-Add-enchantment-target-for-bows-and-crossbows.patch +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java.patch @@ -1,18 +1,10 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Tue, 23 Mar 2021 15:01:03 -0500 -Subject: [PATCH] Add enchantment target for bows and crossbows - - -diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java -index 455ff52d90565838fe7640c3f045b27082a6c2f1..5831ffe24eed01311c71989dcb1830dbc395607b 100644 --- a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java +++ b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java -@@ -227,6 +227,18 @@ public enum EnchantmentTarget { +@@ -227,6 +_,30 @@ public boolean includes(@NotNull Material item) { return BREAKABLE.includes(item) || (WEARABLE.includes(item) && !item.equals(Material.ELYTRA)) || item.equals(Material.COMPASS); } -+ // Purpur start ++ // Purpur start - Add enchantment target for bows and crossbows + }, + + /** @@ -23,7 +15,19 @@ index 455ff52d90565838fe7640c3f045b27082a6c2f1..5831ffe24eed01311c71989dcb1830db + public boolean includes(@NotNull Material item) { + return item.equals(Material.BOW) || item.equals(Material.CROSSBOW); + } -+ // Purpur end ++ // Purpur end - Add enchantment target for bows and crossbows ++ // Purpur start - Shears can have looting enchantment ++ }, ++ ++ /** ++ * Allow the Enchantment to be placed on shears. ++ */ ++ WEAPON_AND_SHEARS { ++ @Override ++ public boolean includes(@NotNull Material item) { ++ return WEAPON.includes(item) || item.equals(Material.SHEARS); ++ } ++ // Purpur end - Shears can have looting enchantment }; /** diff --git a/patches/api/0025-Add-back-player-spawned-endermite-API.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Endermite.java.patch similarity index 70% rename from patches/api/0025-Add-back-player-spawned-endermite-API.patch rename to purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Endermite.java.patch index 1a57eb065..218b3659e 100644 --- a/patches/api/0025-Add-back-player-spawned-endermite-API.patch +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Endermite.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 26 Jun 2021 22:08:57 -0500 -Subject: [PATCH] Add back player spawned endermite API - - -diff --git a/src/main/java/org/bukkit/entity/Endermite.java b/src/main/java/org/bukkit/entity/Endermite.java -index 138d2530de2410f4a9424dabd3e5ce0cd1c1dcd2..10a8d64ad2da0be2c14f34c3e7d1957c6f2883d1 100644 --- a/src/main/java/org/bukkit/entity/Endermite.java +++ b/src/main/java/org/bukkit/entity/Endermite.java -@@ -3,25 +3,21 @@ package org.bukkit.entity; +@@ -3,25 +_,21 @@ public interface Endermite extends Monster { /** @@ -21,7 +13,7 @@ index 138d2530de2410f4a9424dabd3e5ce0cd1c1dcd2..10a8d64ad2da0be2c14f34c3e7d1957c * @return player spawned status - * @deprecated this functionality no longer exists */ -- @Deprecated +- @Deprecated(since = "1.17") boolean isPlayerSpawned(); /** @@ -34,7 +26,7 @@ index 138d2530de2410f4a9424dabd3e5ce0cd1c1dcd2..10a8d64ad2da0be2c14f34c3e7d1957c * @param playerSpawned player spawned status - * @deprecated this functionality no longer exists */ -- @Deprecated +- @Deprecated(since = "1.17") void setPlayerSpawned(boolean playerSpawned); // Paper start /** diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch new file mode 100644 index 000000000..2ee29df0c --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch @@ -0,0 +1,62 @@ +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -1196,4 +_,59 @@ + */ + void broadcastHurtAnimation(@NotNull java.util.Collection players); + // Paper end - broadcast hurt animation ++ ++ // Purpur start - Ridables ++ /** ++ * Get the riding player ++ * ++ * @return Riding player ++ */ ++ @Nullable ++ Player getRider(); ++ ++ /** ++ * Check if entity is being ridden ++ * ++ * @return True if being ridden ++ */ ++ boolean hasRider(); ++ ++ /** ++ * Check if entity is ridable ++ * ++ * @return True if ridable ++ */ ++ boolean isRidable(); ++ ++ /** ++ * Check if entity is ridable in water ++ * ++ * @return True if ridable in water ++ */ ++ boolean isRidableInWater(); ++ // Purpur end - Ridables ++ ++ // Purpur start - API for any mob to burn daylight ++ /** ++ * Checks if the entity is in daylight ++ * ++ * @return True if in daylight ++ */ ++ boolean isInDaylight(); ++ // Purpur end - API for any mob to burn daylight ++ ++ // Purpur start - Fire Immunity API ++ /** ++ * Checks if the entity is fire immune ++ * ++ * @return True if fire immune ++ */ ++ boolean isImmuneToFire(); ++ ++ /** ++ * Sets if the entity is fire immune ++ * Set this to null to restore the entity type default ++ */ ++ void setImmuneToFire(@Nullable Boolean fireImmune); ++ // Purpur end - Fire Immunity API + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/IronGolem.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/IronGolem.java.patch new file mode 100644 index 000000000..8a25a65b2 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/IronGolem.java.patch @@ -0,0 +1,23 @@ +--- a/src/main/java/org/bukkit/entity/IronGolem.java ++++ b/src/main/java/org/bukkit/entity/IronGolem.java +@@ -19,4 +_,20 @@ + * player created, false if you want it to be a natural village golem. + */ + public void setPlayerCreated(boolean playerCreated); ++ ++ // Purpur start ++ /** ++ * Get the player that summoned this iron golem ++ * ++ * @return UUID of summoner ++ */ ++ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner(); ++ ++ /** ++ * Set the player that summoned this iron golem ++ * ++ * @param summoner UUID of summoner ++ */ ++ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner); ++ // Purpur end + } diff --git a/patches/api/0017-Item-entity-immunities.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Item.java.patch similarity index 76% rename from patches/api/0017-Item-entity-immunities.patch rename to purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Item.java.patch index dd689e3cd..294924ed9 100644 --- a/patches/api/0017-Item-entity-immunities.patch +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Item.java.patch @@ -1,14 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sat, 22 Aug 2020 17:42:08 -0500 -Subject: [PATCH] Item entity immunities - - -diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java -index bcc6ba95bd21c7972865838c636a03f50b6c1f1a..c3fcd8dd7dbb1e1a18e17c014c1e641149ea5960 100644 --- a/src/main/java/org/bukkit/entity/Item.java +++ b/src/main/java/org/bukkit/entity/Item.java -@@ -153,4 +153,62 @@ public interface Item extends Entity, io.papermc.paper.entity.Frictional { // Pa +@@ -153,4 +_,62 @@ */ public void setHealth(int health); // Paper end diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/LivingEntity.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/LivingEntity.java.patch new file mode 100644 index 000000000..2ec452396 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/LivingEntity.java.patch @@ -0,0 +1,23 @@ +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -1468,4 +_,20 @@ + */ + boolean canUseEquipmentSlot(org.bukkit.inventory.@NotNull EquipmentSlot slot); + // Paper end - Expose canUseSlot ++ ++ // Purpur start - API for any mob to burn daylight ++ /** ++ * If this mob will burn in the sunlight ++ * ++ * @return True if mob will burn in sunlight ++ */ ++ boolean shouldBurnInDay(); ++ ++ /** ++ * Set if this mob should burn in the sunlight ++ * ++ * @param shouldBurnInDay True to burn in sunlight ++ */ ++ void setShouldBurnInDay(boolean shouldBurnInDay); ++ // Purpur end - API for any mob to burn daylight + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Llama.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Llama.java.patch new file mode 100644 index 000000000..43e170b4b --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Llama.java.patch @@ -0,0 +1,23 @@ +--- a/src/main/java/org/bukkit/entity/Llama.java ++++ b/src/main/java/org/bukkit/entity/Llama.java +@@ -119,4 +_,20 @@ + @org.jetbrains.annotations.Nullable + Llama getCaravanTail(); + // Paper end ++ ++ // Purpur start ++ /** ++ * Check if this Llama should attempt to join a caravan ++ * ++ * @return True if Llama is allowed to join a caravan ++ */ ++ boolean shouldJoinCaravan(); ++ ++ /** ++ * Set if this Llama should attempt to join a caravan ++ * ++ * @param shouldJoinCaravan True to allow joining a caravan ++ */ ++ void setShouldJoinCaravan(boolean shouldJoinCaravan); ++ // Purpur end + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch new file mode 100644 index 000000000..efdb19897 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch @@ -0,0 +1,126 @@ +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -3928,4 +_,123 @@ + * @return the result of this method, holding leftovers and spawned items. + */ + @NotNull PlayerGiveResult give(@NotNull Collection<@NotNull ItemStack> items, boolean dropIfFull); ++ ++ // Purpur start ++ /** ++ * Allows you to get if player uses PurpurClient ++ * ++ * @return true if player uses PurpurClient ++ */ ++ public boolean usesPurpurClient(); ++ ++ /** ++ * Check if player is AFK ++ * ++ * @return True if AFK ++ */ ++ boolean isAfk(); ++ ++ /** ++ * Set player as AFK ++ * ++ * @param setAfk Whether to set AFK or not ++ */ ++ void setAfk(boolean setAfk); ++ ++ /** ++ * Reset the idle timer back to 0 ++ * @deprecated Use {@link #resetIdleDuration()} instead ++ */ ++ void resetIdleTimer(); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to this player. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to this player. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, int argb); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to this player. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to this player. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ * @param argb Color of the highlight. ARGB int. Will be ignored on some versions of vanilla client ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, int argb); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to this player. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param color Color of the highlight. Will be ignored on some versions of vanilla client ++ * @param transparency Transparency of the highlight ++ * @throws IllegalArgumentException If transparency is outside 0-255 range ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull org.bukkit.Color color, int transparency); ++ ++ /** ++ * Creates debug block highlight on specified block location and show it to this player. ++ *

++ * Clients may be inconsistent in displaying it. ++ * @param location Location to highlight ++ * @param duration Duration for highlight to show in milliseconds ++ * @param text Text to show above the highlight ++ * @param color Color of the highlight. Will be ignored on some versions of vanilla client ++ * @param transparency Transparency of the highlight ++ * @throws IllegalArgumentException If transparency is outside 0-255 range ++ */ ++ void sendBlockHighlight(@NotNull Location location, int duration, @NotNull String text, @NotNull org.bukkit.Color color, int transparency); ++ ++ /** ++ * Clears all debug block highlights ++ */ ++ void clearBlockHighlights(); ++ ++ /** ++ * Sends a player the death screen with a specified death message. ++ * ++ * @param message The death message to show the player ++ */ ++ void sendDeathScreen(@NotNull net.kyori.adventure.text.Component message); ++ ++ /** ++ * Sends a player the death screen with a specified death message, ++ * along with the entity that caused the death. ++ * ++ * @param message The death message to show the player ++ * @param killer The entity that killed the player ++ * @deprecated Use {@link #sendDeathScreen(net.kyori.adventure.text.Component)} instead, as 1.20 removed the killer ID from the packet. ++ */ ++ @Deprecated(since = "1.20") ++ default void sendDeathScreen(@NotNull net.kyori.adventure.text.Component message, @Nullable Entity killer) { ++ sendDeathScreen(message); ++ } ++ // Purpur end + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Snowman.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Snowman.java.patch new file mode 100644 index 000000000..a24330d2d --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Snowman.java.patch @@ -0,0 +1,23 @@ +--- a/src/main/java/org/bukkit/entity/Snowman.java ++++ b/src/main/java/org/bukkit/entity/Snowman.java +@@ -23,4 +_,20 @@ + * @param derpMode True to remove the pumpkin, false to add a pumpkin + */ + void setDerp(boolean derpMode); ++ ++ // Purpur start ++ /** ++ * Get the player that summoned this snowman ++ * ++ * @return UUID of summoner ++ */ ++ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner(); ++ ++ /** ++ * Set the player that summoned this snowman ++ * ++ * @param summoner UUID of summoner ++ */ ++ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner); ++ // Purpur end + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Villager.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Villager.java.patch new file mode 100644 index 000000000..90aac0f52 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Villager.java.patch @@ -0,0 +1,17 @@ +--- a/src/main/java/org/bukkit/entity/Villager.java ++++ b/src/main/java/org/bukkit/entity/Villager.java +@@ -367,4 +_,14 @@ + */ + public void clearReputations(); + // Paper end ++ ++ // Purpur start ++ ++ /** ++ * Check if villager is currently lobotomized ++ * ++ * @return True if lobotomized ++ */ ++ boolean isLobotomized(); ++ // Purpur end + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wither.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wither.java.patch new file mode 100644 index 000000000..1080c3d6d --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wither.java.patch @@ -0,0 +1,23 @@ +--- a/src/main/java/org/bukkit/entity/Wither.java ++++ b/src/main/java/org/bukkit/entity/Wither.java +@@ -107,4 +_,20 @@ + */ + void enterInvulnerabilityPhase(); + // Paper end ++ ++ // Purpur start ++ /** ++ * Get the player that summoned this wither ++ * ++ * @return UUID of summoner ++ */ ++ @org.jetbrains.annotations.Nullable java.util.UUID getSummoner(); ++ ++ /** ++ * Set the player that summoned this wither ++ * ++ * @param summoner UUID of summoner ++ */ ++ void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner); ++ // Purpur end + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wolf.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wolf.java.patch new file mode 100644 index 000000000..f3ac2ef4a --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/entity/Wolf.java.patch @@ -0,0 +1,23 @@ +--- a/src/main/java/org/bukkit/entity/Wolf.java ++++ b/src/main/java/org/bukkit/entity/Wolf.java +@@ -110,4 +_,20 @@ + return RegistryAccess.registryAccess().getRegistry(RegistryKey.WOLF_VARIANT).getOrThrow(NamespacedKey.minecraft(key)); + } + } ++ ++ // Purpur start ++ /** ++ * Checks if this wolf is rabid ++ * ++ * @return whether the wolf is rabid ++ */ ++ public boolean isRabid(); ++ ++ /** ++ * Sets this wolf to be rabid or not ++ * ++ * @param rabid whether the wolf should be rabid ++ */ ++ public void setRabid(boolean rabid); ++ // Purpur end + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java.patch new file mode 100644 index 000000000..0d86a78ae --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java.patch @@ -0,0 +1,12 @@ +--- a/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityDamageEvent.java +@@ -308,7 +_,8 @@ + WORLD_BORDER, + /** + * Damage caused when an entity contacts a block such as a Cactus, +- * Dripstone (Stalagmite) or Berry Bush. ++ * Dripstone (Stalagmite) or Berry Bush. (Stonecutters too if you ++ * have the Stonecutter damage Purpur feature enabled) + *

+ * Damage: variable + */ diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java.patch new file mode 100644 index 000000000..24085dc5d --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java.patch @@ -0,0 +1,15 @@ +--- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +@@ -216,6 +_,12 @@ + * When all effects are removed due to a bucket of milk. + */ + MILK, ++ // Purpur start ++ /** ++ * When a player wears full netherite armor ++ */ ++ NETHERITE_ARMOR, ++ // Purpur end + /** + * When a player gets bad omen after killing a patrol captain. + * diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryType.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryType.java.patch new file mode 100644 index 000000000..ec2e9aabe --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/event/inventory/InventoryType.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java +@@ -164,7 +_,7 @@ + SMITHING_NEW(4, "Upgrade Gear", MenuType.SMITHING), + ; + +- private final int size; ++ private int size; @ApiStatus.Internal public void setDefaultSize(int size) { this.size = size; } // Purpur - remove final and add setter + private final String title; + private final MenuType menuType; + private final boolean isCreatable; diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/AnvilInventory.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/AnvilInventory.java.patch new file mode 100644 index 000000000..34a114418 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/AnvilInventory.java.patch @@ -0,0 +1,45 @@ +--- a/src/main/java/org/bukkit/inventory/AnvilInventory.java ++++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java +@@ -138,4 +_,42 @@ + setItem(2, result); + } + // Paper end ++ ++ // Purpur start ++ /** ++ * Gets if the player viewing the anvil inventory can bypass experience cost ++ * ++ * @return whether the player viewing the anvil inventory can bypass the experience cost ++ * @deprecated use {@link AnvilView#canBypassCost()}. ++ */ ++ @Deprecated(forRemoval = true, since = "1.21") ++ boolean canBypassCost(); ++ ++ /** ++ * Set if the player viewing the anvil inventory can bypass the experience cost ++ * ++ * @param bypassCost whether the player viewing the anvil inventory can bypass the experience cost ++ * @deprecated use {@link AnvilView#setBypassCost(boolean)}. ++ */ ++ @Deprecated(forRemoval = true, since = "1.21") ++ void setBypassCost(boolean bypassCost); ++ ++ /** ++ * Gets if the player viewing the anvil inventory can do unsafe enchants ++ * ++ * @return whether the player viewing the anvil inventory can do unsafe enchants ++ * @deprecated use {@link AnvilView#canDoUnsafeEnchants()}. ++ */ ++ @Deprecated(forRemoval = true, since = "1.21") ++ boolean canDoUnsafeEnchants(); ++ ++ /** ++ * Set if the player viewing the anvil inventory can do unsafe enchants ++ * ++ * @param canDoUnsafeEnchants whether the player viewing the anvil inventory can do unsafe enchants ++ * @deprecated use {@link AnvilView#setDoUnsafeEnchants(boolean)}. ++ */ ++ @Deprecated(forRemoval = true, since = "1.21") ++ void setDoUnsafeEnchants(boolean canDoUnsafeEnchants); ++ // Purpur end + } diff --git a/patches/api/0014-ItemStack-convenience-methods.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/ItemStack.java.patch similarity index 63% rename from patches/api/0014-ItemStack-convenience-methods.patch rename to purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/ItemStack.java.patch index 979571e73..02c8dfc89 100644 --- a/patches/api/0014-ItemStack-convenience-methods.patch +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/ItemStack.java.patch @@ -1,82 +1,25 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 15 Mar 2020 20:52:12 -0500 -Subject: [PATCH] ItemStack convenience methods - - -diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 7a337fe908915f8ea487a0b9236c511cb07d5e66..1dd02e2782364bf25521088cf8858d3443643447 100644 ---- a/src/main/java/org/bukkit/Material.java -+++ b/src/main/java/org/bukkit/Material.java -@@ -11657,4 +11657,40 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla - public boolean isEnabledByFeature(@NotNull World world) { - return Bukkit.getDataPackManager().isEnabledByFeature(this, world); - } -+ -+ // Purpur start -+ public boolean isArmor() { -+ switch (this) { -+ // -+ case LEATHER_BOOTS: -+ case LEATHER_CHESTPLATE: -+ case LEATHER_HELMET: -+ case LEATHER_LEGGINGS: -+ case CHAINMAIL_BOOTS: -+ case CHAINMAIL_CHESTPLATE: -+ case CHAINMAIL_HELMET: -+ case CHAINMAIL_LEGGINGS: -+ case IRON_BOOTS: -+ case IRON_CHESTPLATE: -+ case IRON_HELMET: -+ case IRON_LEGGINGS: -+ case GOLDEN_BOOTS: -+ case GOLDEN_CHESTPLATE: -+ case GOLDEN_HELMET: -+ case GOLDEN_LEGGINGS: -+ case DIAMOND_BOOTS: -+ case DIAMOND_CHESTPLATE: -+ case DIAMOND_HELMET: -+ case DIAMOND_LEGGINGS: -+ case NETHERITE_BOOTS: -+ case NETHERITE_CHESTPLATE: -+ case NETHERITE_HELMET: -+ case NETHERITE_LEGGINGS: -+ case TURTLE_HELMET: -+ return true; -+ default: -+ return false; -+ } -+ } -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db534286d267b05 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -17,6 +17,17 @@ import org.bukkit.inventory.meta.ItemMeta; +@@ -21,6 +_,13 @@ import org.bukkit.material.MaterialData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -+// Purpur start ++// Purpur start - ItemStack convenience methods +import com.google.common.collect.Multimap; +import java.util.Collection; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.data.BlockData; -+import org.bukkit.inventory.meta.BlockDataMeta; -+import org.bukkit.inventory.meta.Repairable; -+import org.bukkit.persistence.PersistentDataContainer; -+import org.bukkit.persistence.PersistentDataHolder; -+// Purpur end ++// Purpur end - ItemStack convenience methods /** * Represents a stack of items. -@@ -1073,4 +1084,565 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat - return Bukkit.getUnsafe().computeTooltipLines(this, tooltipContext, player); +@@ -1329,4 +_,482 @@ + return this.craftDelegate.matchesWithoutData(item, excludeTypes, ignoreCount); } - // Paper end - expose itemstack tooltip lines + // Paper end - data component API + -+ // Purpur start ++ // Purpur start - ItemStack convenience methods + /** + * Gets the display name that is set. + *

@@ -87,7 +30,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + */ + @NotNull + public String getDisplayName() { -+ return getItemMeta().getDisplayName(); ++ return this.craftDelegate.getDisplayName(); + } + + /** @@ -96,9 +39,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @param name the name to set + */ + public void setDisplayName(@Nullable String name) { -+ ItemMeta itemMeta = getItemMeta(); -+ itemMeta.setDisplayName(name); -+ setItemMeta(itemMeta); ++ this.craftDelegate.setDisplayName(name); + } + + /** @@ -107,7 +48,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if this has a display name + */ + public boolean hasDisplayName() { -+ return hasItemMeta() && getItemMeta().hasDisplayName(); ++ return this.craftDelegate.hasDisplayName(); + } + + /** @@ -120,7 +61,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + */ + @NotNull + public String getLocalizedName() { -+ return getItemMeta().getLocalizedName(); ++ return this.craftDelegate.getLocalizedName(); + } + + /** @@ -129,9 +70,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @param name the name to set + */ + public void setLocalizedName(@Nullable String name) { -+ ItemMeta itemMeta = getItemMeta(); -+ itemMeta.setLocalizedName(name); -+ setItemMeta(itemMeta); ++ this.craftDelegate.setLocalizedName(name); + } + + /** @@ -140,7 +79,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if this has a localized name + */ + public boolean hasLocalizedName() { -+ return hasItemMeta() && getItemMeta().hasLocalizedName(); ++ return this.craftDelegate.hasLocalizedName(); + } + + /** @@ -149,7 +88,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if this has lore + */ + public boolean hasLore() { -+ return hasItemMeta() && getItemMeta().hasLore(); ++ return this.craftDelegate.hasLore(); + } + + /** @@ -159,7 +98,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if this enchantment exists for this meta + */ + public boolean hasEnchant(@NotNull Enchantment ench) { -+ return hasItemMeta() && getItemMeta().hasEnchant(ench); ++ return this.craftDelegate.hasEnchant(ench); + } + + /** @@ -169,7 +108,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return The level that the specified enchantment has, or 0 if none + */ + public int getEnchantLevel(@NotNull Enchantment ench) { -+ return getItemMeta().getEnchantLevel(ench); ++ return this.craftDelegate.getEnchantLevel(ench); + } + + /** @@ -180,7 +119,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + */ + @NotNull + public Map getEnchants() { -+ return getItemMeta().getEnchants(); ++ return this.craftDelegate.getEnchants(); + } + + /** @@ -194,10 +133,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * otherwise + */ + public boolean addEnchant(@NotNull Enchantment ench, int level, boolean ignoreLevelRestriction) { -+ ItemMeta itemMeta = getItemMeta(); -+ boolean result = itemMeta.addEnchant(ench, level, ignoreLevelRestriction); -+ setItemMeta(itemMeta); -+ return result; ++ return this.craftDelegate.addEnchant(ench, level, ignoreLevelRestriction); + } + + /** @@ -208,10 +144,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * otherwise + */ + public boolean removeEnchant(@NotNull Enchantment ench) { -+ ItemMeta itemMeta = getItemMeta(); -+ boolean result = itemMeta.removeEnchant(ench); -+ setItemMeta(itemMeta); -+ return result; ++ return this.craftDelegate.removeEnchant(ench); + } + + /** @@ -220,7 +153,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if an enchantment exists on this meta + */ + public boolean hasEnchants() { -+ return hasItemMeta() && getItemMeta().hasEnchants(); ++ return this.craftDelegate.hasEnchants(); + } + + /** @@ -231,7 +164,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if the enchantment conflicts, false otherwise + */ + public boolean hasConflictingEnchant(@NotNull Enchantment ench) { -+ return hasItemMeta() && getItemMeta().hasConflictingEnchant(ench); ++ return this.craftDelegate.hasConflictingEnchant(ench); + } + + /** @@ -243,9 +176,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @param data the data to set, or null to clear + */ + public void setCustomModelData(@Nullable Integer data) { -+ ItemMeta itemMeta = getItemMeta(); -+ itemMeta.setCustomModelData(data); -+ setItemMeta(itemMeta); ++ this.craftDelegate.setCustomModelData(data); + } + + /** @@ -260,7 +191,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return the localized name that is set + */ + public int getCustomModelData() { -+ return getItemMeta().getCustomModelData(); ++ return this.craftDelegate.getCustomModelData(); + } + + /** @@ -272,7 +203,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if this has custom model data + */ + public boolean hasCustomModelData() { -+ return hasItemMeta() && getItemMeta().hasCustomModelData(); ++ return this.craftDelegate.hasCustomModelData(); + } + + /** @@ -281,7 +212,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return whether block data is already attached + */ + public boolean hasBlockData() { -+ return hasItemMeta() && ((BlockDataMeta) getItemMeta()).hasBlockData(); ++ return this.craftDelegate.hasBlockData(); + } + + /** @@ -296,7 +227,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + */ + @NotNull + public BlockData getBlockData(@NotNull Material material) { -+ return ((BlockDataMeta) getItemMeta()).getBlockData(material); ++ return this.craftDelegate.getBlockData(material); + } + + /** @@ -307,9 +238,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * this item. + */ + public void setBlockData(@NotNull BlockData blockData) { -+ ItemMeta itemMeta = getItemMeta(); -+ ((BlockDataMeta) itemMeta).setBlockData(blockData); -+ setItemMeta(itemMeta); ++ this.craftDelegate.setBlockData(blockData); + } + + /** @@ -318,7 +247,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return the repair penalty + */ + public int getRepairCost() { -+ return ((Repairable) getItemMeta()).getRepairCost(); ++ return this.craftDelegate.getRepairCost(); + } + + /** @@ -327,9 +256,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @param cost repair penalty + */ + public void setRepairCost(int cost) { -+ ItemMeta itemMeta = getItemMeta(); -+ ((Repairable) itemMeta).setRepairCost(cost); -+ setItemMeta(itemMeta); ++ this.craftDelegate.setRepairCost(cost); + } + + /** @@ -338,7 +265,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if this has a repair penalty + */ + public boolean hasRepairCost() { -+ return hasItemMeta() && ((Repairable) getItemMeta()).hasRepairCost(); ++ return this.craftDelegate.hasRepairCost(); + } + + /** @@ -348,7 +275,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if the unbreakable tag is true + */ + public boolean isUnbreakable() { -+ return hasItemMeta() && getItemMeta().isUnbreakable(); ++ return this.craftDelegate.isUnbreakable(); + } + + /** @@ -357,9 +284,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @param unbreakable true if set unbreakable + */ + public void setUnbreakable(boolean unbreakable) { -+ ItemMeta itemMeta = getItemMeta(); -+ itemMeta.setUnbreakable(unbreakable); -+ setItemMeta(itemMeta); ++ this.craftDelegate.setUnbreakable(unbreakable); + } + + /** @@ -368,7 +293,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if any AttributeModifiers exist + */ + public boolean hasAttributeModifiers() { -+ return hasItemMeta() && getItemMeta().hasAttributeModifiers(); ++ return this.craftDelegate.hasAttributeModifiers(); + } + + /** @@ -381,7 +306,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + */ + @Nullable + public Multimap getAttributeModifiers() { -+ return getItemMeta().getAttributeModifiers(); ++ return this.craftDelegate.getAttributeModifiers(); + } + + /** @@ -400,7 +325,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + */ + @NotNull + public Multimap getAttributeModifiers(@Nullable EquipmentSlot slot) { -+ return getItemMeta().getAttributeModifiers(slot); ++ return this.craftDelegate.getAttributeModifiers(slot); + } + + /** @@ -414,7 +339,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + */ + @Nullable + public Collection getAttributeModifiers(@NotNull Attribute attribute) { -+ return getItemMeta().getAttributeModifiers(attribute); ++ return this.craftDelegate.getAttributeModifiers(attribute); + } + + /** @@ -434,10 +359,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @throws IllegalArgumentException if AttributeModifier already exists + */ + public boolean addAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) { -+ ItemMeta itemMeta = getItemMeta(); -+ boolean result = itemMeta.addAttributeModifier(attribute, modifier); -+ setItemMeta(itemMeta); -+ return result; ++ return this.craftDelegate.addAttributeModifier(attribute, modifier); + } + + /** @@ -451,9 +373,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * and their AttributeModifiers + */ + public void setAttributeModifiers(@Nullable Multimap attributeModifiers) { -+ ItemMeta itemMeta = getItemMeta(); -+ itemMeta.setAttributeModifiers(attributeModifiers); -+ setItemMeta(itemMeta); ++ this.craftDelegate.setAttributeModifiers(attributeModifiers); + } + + /** @@ -468,10 +388,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @throws NullPointerException if Attribute is null + */ + public boolean removeAttributeModifier(@NotNull Attribute attribute) { -+ ItemMeta itemMeta = getItemMeta(); -+ boolean result = itemMeta.removeAttributeModifier(attribute); -+ setItemMeta(itemMeta); -+ return result; ++ return this.craftDelegate.removeAttributeModifier(attribute); + } + + /** @@ -486,10 +403,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * EquipmentSlot. + */ + public boolean removeAttributeModifier(@Nullable EquipmentSlot slot) { -+ ItemMeta itemMeta = getItemMeta(); -+ boolean result = itemMeta.removeAttributeModifier(slot); -+ setItemMeta(itemMeta); -+ return result; ++ return this.craftDelegate.removeAttributeModifier(slot); + } + + /** @@ -506,24 +420,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @see AttributeModifier#getUniqueId() + */ + public boolean removeAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) { -+ ItemMeta itemMeta = getItemMeta(); -+ boolean result = itemMeta.removeAttributeModifier(attribute, modifier); -+ setItemMeta(itemMeta); -+ return result; -+ } -+ -+ /** -+ * Returns a custom tag container capable of storing tags on the object. -+ * -+ * Note that the tags stored on this container are all stored under their -+ * own custom namespace therefore modifying default tags using this -+ * {@link PersistentDataHolder} is impossible. -+ * -+ * @return the persistent metadata container -+ */ -+ @NotNull -+ public PersistentDataContainer getPersistentDataContainer() { -+ return getItemMeta().getPersistentDataContainer(); ++ return this.craftDelegate.removeAttributeModifier(attribute, modifier); + } + + /** @@ -532,7 +429,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return true if this has damage + */ + public boolean hasDamage() { -+ return hasItemMeta() && ((Damageable) getItemMeta()).hasDamage(); ++ return this.craftDelegate.hasDamage(); + } + + /** @@ -541,7 +438,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return the damage + */ + public int getDamage() { -+ return ((Damageable) getItemMeta()).getDamage(); ++ return this.craftDelegate.getDamage(); + } + + /** @@ -550,9 +447,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @param damage item damage + */ + public void setDamage(int damage) { -+ ItemMeta itemMeta = getItemMeta(); -+ ((Damageable) itemMeta).setDamage(damage); -+ setItemMeta(itemMeta); ++ this.craftDelegate.setDamage(damage); + } + + /** @@ -598,42 +493,7 @@ index 84a7bf0936d35bf42b5ed038d295d5c31740f472..6e9b4cbc81878616b1c48add5db53428 + * @return True if damage broke the item + */ + public boolean damage(int amount, boolean ignoreUnbreaking) { -+ Damageable damageable = (Damageable) getItemMeta(); -+ if (amount > 0) { -+ int unbreaking = getEnchantLevel(Enchantment.UNBREAKING); -+ int reduce = 0; -+ for (int i = 0; unbreaking > 0 && i < amount; ++i) { -+ if (reduceDamage(java.util.concurrent.ThreadLocalRandom.current(), unbreaking)) { -+ ++reduce; -+ } -+ } -+ amount -= reduce; -+ if (amount <= 0) { -+ return isBroke(damageable.getDamage()); -+ } -+ } -+ int damage = damageable.getDamage() + amount; -+ damageable.setDamage(damage); -+ setItemMeta((ItemMeta) damageable); -+ return isBroke(damage); ++ return this.craftDelegate.damage(amount, ignoreUnbreaking); + } -+ -+ public boolean isBroke(int damage) { -+ if (damage > getType().getMaxDurability()) { -+ if (getAmount() > 0) { -+ // ensure it "breaks" -+ setAmount(0); -+ } -+ return true; -+ } -+ return false; -+ } -+ -+ private boolean reduceDamage(java.util.Random random, int unbreaking) { -+ if (getType().isArmor()) { -+ return random.nextFloat() < 0.6F; -+ } -+ return random.nextInt(unbreaking + 1) > 0; -+ } -+ // Purpur end ++ // Purpur end - ItemStack convenience methods } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/RecipeChoice.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/RecipeChoice.java.patch new file mode 100644 index 000000000..177eef71b --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/RecipeChoice.java.patch @@ -0,0 +1,36 @@ +--- a/src/main/java/org/bukkit/inventory/RecipeChoice.java ++++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java +@@ -191,6 +_,7 @@ + public static class ExactChoice implements RecipeChoice { + + private List choices; ++ private Predicate predicate; // Purpur - Add predicate to recipe's ExactChoice ingredient + + public ExactChoice(@NotNull ItemStack stack) { + this(Arrays.asList(stack)); +@@ -241,6 +_,7 @@ + + @Override + public boolean test(@NotNull ItemStack t) { ++ if (predicate != null) return predicate.test(t); // Purpur - Add predicate to recipe's ExactChoice ingredient + for (ItemStack match : choices) { + if (t.isSimilar(match)) { + return true; +@@ -249,6 +_,17 @@ + + return false; + } ++ ++ // Purpur start - Add predicate to recipe's ExactChoice ingredient ++ @org.jetbrains.annotations.Nullable ++ public Predicate getPredicate() { ++ return predicate; ++ } ++ ++ public void setPredicate(@org.jetbrains.annotations.Nullable Predicate predicate) { ++ this.predicate = predicate; ++ } ++ // Purpur end - Add predicate to recipe's ExactChoice ingredient + + @Override + public int hashCode() { diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/view/AnvilView.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/view/AnvilView.java.patch new file mode 100644 index 000000000..3a63aa786 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/view/AnvilView.java.patch @@ -0,0 +1,37 @@ +--- a/src/main/java/org/bukkit/inventory/view/AnvilView.java ++++ b/src/main/java/org/bukkit/inventory/view/AnvilView.java +@@ -89,4 +_,34 @@ + */ + void bypassEnchantmentLevelRestriction(boolean bypassEnchantmentLevelRestriction); + // Paper end - bypass anvil level restrictions ++ ++ // Purpur start - Anvil API ++ /** ++ * Gets if the player viewing the anvil inventory can bypass experience cost ++ * ++ * @return whether the player viewing the anvil inventory can bypass the experience cost ++ */ ++ boolean canBypassCost(); ++ ++ /** ++ * Set if the player viewing the anvil inventory can bypass the experience cost ++ * ++ * @param bypassCost whether the player viewing the anvil inventory can bypass the experience cost ++ */ ++ void setBypassCost(boolean bypassCost); ++ ++ /** ++ * Gets if the player viewing the anvil inventory can do unsafe enchants ++ * ++ * @return whether the player viewing the anvil inventory can do unsafe enchants ++ */ ++ boolean canDoUnsafeEnchants(); ++ ++ /** ++ * Set if the player viewing the anvil inventory can do unsafe enchants ++ * ++ * @param canDoUnsafeEnchants whether the player viewing the anvil inventory can do unsafe enchants ++ */ ++ void setDoUnsafeEnchants(boolean canDoUnsafeEnchants); ++ // Purpur end - Anvil API + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/map/MapRenderer.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/map/MapRenderer.java.patch new file mode 100644 index 000000000..80ffd257a --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/map/MapRenderer.java.patch @@ -0,0 +1,15 @@ +--- a/src/main/java/org/bukkit/map/MapRenderer.java ++++ b/src/main/java/org/bukkit/map/MapRenderer.java +@@ -54,4 +_,12 @@ + */ + public abstract void render(@NotNull MapView map, @NotNull MapCanvas canvas, @NotNull Player player); + ++ // Purpur - start - Explorer Map API ++ /** ++ * Check if this is an explorer (aka treasure) map. ++ * ++ * @return True if explorer map ++ */ ++ public abstract boolean isExplorerMap(); ++ // Purpur - end - Explorer Map API + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/permissions/PermissibleBase.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/permissions/PermissibleBase.java.patch new file mode 100644 index 000000000..e83156fc3 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/permissions/PermissibleBase.java.patch @@ -0,0 +1,20 @@ +--- a/src/main/java/org/bukkit/permissions/PermissibleBase.java ++++ b/src/main/java/org/bukkit/permissions/PermissibleBase.java +@@ -169,7 +_,7 @@ + + for (Permission perm : defaults) { + String name = perm.getName().toLowerCase(Locale.ROOT); +- permissions.put(name, new PermissionAttachmentInfo(parent, name, null, true)); ++ permissions.put(name, new PermissionAttachmentInfo(parent, name, null, perm.getDefault().getValue(isOp()))); // Purpur - Fix default permission system + Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent); + calculateChildPermissions(perm.getChildren(), false, null); + } +@@ -197,7 +_,7 @@ + String name = entry.getKey(); + + Permission perm = Bukkit.getServer().getPluginManager().getPermission(name); +- boolean value = entry.getValue() ^ invert; ++ boolean value = (entry.getValue() == null && perm != null ? perm.getDefault().getValue(isOp()) : entry.getValue()) ^ invert; // Purpur - Fix default permission system + String lname = name.toLowerCase(Locale.ROOT); + + permissions.put(lname, new PermissionAttachmentInfo(parent, lname, attachment, value)); diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch new file mode 100644 index 000000000..d4cb6a9fd --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch @@ -0,0 +1,10 @@ +--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +@@ -55,6 +_,7 @@ + private final Pattern[] fileFilters = new Pattern[]{Pattern.compile("\\.jar$")}; + private final List loaders = new CopyOnWriteArrayList(); + private final LibraryLoader libraryLoader; ++ public static boolean SuppressLibraryLoaderLogger = false; // Purpur - Add log suppression for LibraryLoader + + /** + * This class was not meant to be constructed explicitly diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/LibraryLoader.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/LibraryLoader.java.patch new file mode 100644 index 000000000..f8702315d --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/LibraryLoader.java.patch @@ -0,0 +1,26 @@ +--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +@@ -68,6 +_,7 @@ + @Override + public void transferStarted(@NotNull TransferEvent event) throws TransferCancelledException + { ++ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader + logger.log( Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName() ); + } + } ); +@@ -94,6 +_,7 @@ + { + return null; + } ++ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader + logger.log( Level.INFO, "[{0}] Loading {1} libraries... please wait", new Object[] + { + java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), desc.getLibraries().size() // Paper - use configured log prefix +@@ -144,6 +_,7 @@ + } + + jarFiles.add( url ); ++ if (!JavaPluginLoader.SuppressLibraryLoaderLogger) // Purpur - Add log suppression for LibraryLoader + logger.log( Level.INFO, "[{0}] Loaded library {1}", new Object[] + { + java.util.Objects.requireNonNullElseGet(desc.getPrefix(), desc::getName), file // Paper - use configured log prefix diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/util/permissions/CommandPermissions.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/util/permissions/CommandPermissions.java.patch new file mode 100644 index 000000000..1b18651ec --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/util/permissions/CommandPermissions.java.patch @@ -0,0 +1,10 @@ +--- a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java ++++ b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java +@@ -18,6 +_,7 @@ + DefaultPermissions.registerPermission(PREFIX + "plugins", "Allows the user to view the list of plugins running on this server", PermissionDefault.TRUE, commands); + DefaultPermissions.registerPermission(PREFIX + "reload", "Allows the user to reload the server settings", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "version", "Allows the user to view the version of the server", PermissionDefault.TRUE, commands); ++ DefaultPermissions.registerPermission(PREFIX + "purpur", "Allows the user to use the purpur command", PermissionDefault.OP, commands); // Purpur - Default permissions + + commands.recalculatePermissibles(); + return commands; diff --git a/purpur-api/paper-patches/files/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java.patch b/purpur-api/paper-patches/files/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java.patch new file mode 100644 index 000000000..4cf992931 --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java.patch @@ -0,0 +1,56 @@ +--- a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java ++++ b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java +@@ -31,7 +_,7 @@ + + if (withLegacy) { + Permission legacy = new Permission(LEGACY_PREFIX + result.getName(), result.getDescription(), PermissionDefault.FALSE); +- legacy.getChildren().put(result.getName(), true); ++ legacy.getChildren().put(result.getName(), null); // Purpur - Fix default permission system + registerPermission(perm, false); + } + +@@ -40,7 +_,7 @@ + + @NotNull + public static Permission registerPermission(@NotNull Permission perm, @NotNull Permission parent) { +- parent.getChildren().put(perm.getName(), true); ++ parent.getChildren().put(perm.getName(), null); // Purpur - Fix default permission system + return registerPermission(perm); + } + +@@ -53,7 +_,7 @@ + @NotNull + public static Permission registerPermission(@NotNull String name, @Nullable String desc, @NotNull Permission parent) { + Permission perm = registerPermission(name, desc); +- parent.getChildren().put(perm.getName(), true); ++ parent.getChildren().put(perm.getName(), null); // Purpur - Fix default permission system + return perm; + } + +@@ -66,7 +_,7 @@ + @NotNull + public static Permission registerPermission(@NotNull String name, @Nullable String desc, @Nullable PermissionDefault def, @NotNull Permission parent) { + Permission perm = registerPermission(name, desc, def); +- parent.getChildren().put(perm.getName(), true); ++ parent.getChildren().put(perm.getName(), null); // Purpur - Fix default permission system + return perm; + } + +@@ -79,7 +_,7 @@ + @NotNull + public static Permission registerPermission(@NotNull String name, @Nullable String desc, @Nullable PermissionDefault def, @Nullable Map children, @NotNull Permission parent) { + Permission perm = registerPermission(name, desc, def, children); +- parent.getChildren().put(perm.getName(), true); ++ parent.getChildren().put(perm.getName(), null); // Purpur - Fix default permission system + return perm; + } + +@@ -88,6 +_,8 @@ + + CommandPermissions.registerPermissions(parent); + BroadcastPermissions.registerPermissions(parent); ++ ++ org.purpurmc.purpur.util.permissions.PurpurPermissions.registerPermissions(); // Purpur - Default permissions + + parent.recalculatePermissibles(); + } diff --git a/purpur-api/paper-patches/files/src/main/java/org/spigotmc/CustomTimingsHandler.java.patch b/purpur-api/paper-patches/files/src/main/java/org/spigotmc/CustomTimingsHandler.java.patch new file mode 100644 index 000000000..6d4395fbf --- /dev/null +++ b/purpur-api/paper-patches/files/src/main/java/org/spigotmc/CustomTimingsHandler.java.patch @@ -0,0 +1,12 @@ +--- a/src/main/java/org/spigotmc/CustomTimingsHandler.java ++++ b/src/main/java/org/spigotmc/CustomTimingsHandler.java +@@ -61,7 +_,7 @@ + handler = timing; + } + +- public void startTiming() { handler.startTiming(); } +- public void stopTiming() { handler.stopTiming(); } ++ public void startTiming() { /*handler.startTiming();*/ } // Purpur - Remove Timings ++ public void stopTiming() { /*handler.stopTiming();*/ } // Purpur - Remove Timings + + } diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java b/purpur-api/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java new file mode 100644 index 000000000..29540d555 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/entity/StoredEntity.java @@ -0,0 +1,52 @@ +package org.purpurmc.purpur.entity; + +import org.bukkit.Nameable; +import org.bukkit.block.EntityBlockStorage; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.persistence.PersistentDataHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Represents an entity stored in a block + * + * @see org.bukkit.block.EntityBlockStorage + */ +public interface StoredEntity extends PersistentDataHolder, Nameable { + /** + * Checks if this entity has been released yet + * + * @return if this entity has been released + */ + boolean hasBeenReleased(); + + /** + * Releases the entity from its stored block + * + * @return the released entity, or null if unsuccessful (including if this entity has already been released) + */ + @Nullable + T release(); + + /** + * Returns the block in which this entity is stored + * + * @return the EntityBlockStorage in which this entity is stored, or null if it has been released + */ + @Nullable + EntityBlockStorage getBlockStorage(); + + /** + * Gets the entity type of this stored entity + * + * @return the type of entity this stored entity represents + */ + @NotNull + EntityType getType(); + + /** + * Writes data to the block entity snapshot. {@link EntityBlockStorage#update()} must be run in order to update the block in game. + */ + void update(); +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java new file mode 100644 index 000000000..55feef232 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/ExecuteCommandEvent.java @@ -0,0 +1,127 @@ +package org.purpurmc.purpur.event; + +import com.google.common.base.Preconditions; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * This event is called whenever someone runs a command + */ +@NullMarked +public class ExecuteCommandEvent extends Event implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancel = false; + private CommandSender sender; + private Command command; + private String label; + private @Nullable String[] args; + + @ApiStatus.Internal + public ExecuteCommandEvent(CommandSender sender, Command command, String label, @Nullable String[] args) { + this.sender = sender; + this.command = command; + this.label = label; + this.args = args; + } + + /** + * Gets the command that the player is attempting to execute. + * + * @return Command the player is attempting to execute + */ + public Command getCommand() { + return command; + } + + /** + * Sets the command that the player will execute. + * + * @param command New command that the player will execute + * @throws IllegalArgumentException if command is null or empty + */ + public void setCommand(Command command) throws IllegalArgumentException { + Preconditions.checkArgument(command != null, "Command cannot be null"); + this.command = command; + } + + /** + * Gets the sender that this command will be executed as. + * + * @return Sender this command will be executed as + */ + public CommandSender getSender() { + return sender; + } + + /** + * Sets the sender that this command will be executed as. + * + * @param sender New sender which this event will execute as + * @throws IllegalArgumentException if the sender provided is null + */ + public void setSender(final CommandSender sender) throws IllegalArgumentException { + Preconditions.checkArgument(sender != null, "Sender cannot be null"); + this.sender = sender; + } + + /** + * Get the label used to execute this command + * + * @return Label used to execute this command + */ + public String getLabel() { + return label; + } + + /** + * Set the label used to execute this command + * + * @param label Label used + */ + public void setLabel(String label) { + this.label = label; + } + + /** + * Get the args passed to the command + * + * @return Args passed to the command + */ + public String[] getArgs() { + return args; + } + + /** + * Set the args passed to the command + * + * @param args Args passed to the command + */ + public void setArgs(String[] args) { + this.args = args; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java new file mode 100644 index 000000000..e9637b820 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerAFKEvent.java @@ -0,0 +1,71 @@ +package org.purpurmc.purpur.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +public class PlayerAFKEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final boolean setAfk; + private boolean shouldKick; + private @Nullable String broadcast; + private boolean cancel; + + @ApiStatus.Internal + public PlayerAFKEvent(Player player, boolean setAfk, boolean shouldKick, @Nullable String broadcast, boolean async) { + super(player, async); + this.setAfk = setAfk; + this.shouldKick = shouldKick; + this.broadcast = broadcast; + } + + /** + * Whether player is going afk or coming back + * + * @return True if going afk. False is coming back + */ + public boolean isGoingAfk() { + return setAfk; + } + + public boolean shouldKick() { + return shouldKick; + } + + public void setShouldKick(boolean shouldKick) { + this.shouldKick = shouldKick; + } + + @Nullable + public String getBroadcastMsg() { + return broadcast; + } + + public void setBroadcastMsg(@Nullable String broadcast) { + this.broadcast = broadcast; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java new file mode 100644 index 000000000..795c558b4 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java @@ -0,0 +1,83 @@ +package org.purpurmc.purpur.event; + +import org.bukkit.block.Block; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public class PlayerSetSpawnerTypeWithEggEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final Block block; + private final CreatureSpawner spawner; + private EntityType type; + private boolean cancel; + + @ApiStatus.Internal + public PlayerSetSpawnerTypeWithEggEvent(Player player, Block block, CreatureSpawner spawner, EntityType type) { + super(player); + this.block = block; + this.spawner = spawner; + this.type = type; + } + + /** + * Get the spawner Block in the world + * + * @return Spawner Block + */ + public Block getBlock() { + return block; + } + + /** + * Get the spawner state + * + * @return Spawner state + */ + public CreatureSpawner getSpawner() { + return spawner; + } + + /** + * Gets the EntityType being set on the spawner + * + * @return EntityType being set + */ + public EntityType getEntityType() { + return type; + } + + /** + * Sets the EntityType being set on the spawner + * + * @param type EntityType to set + */ + public void setEntityType(EntityType type) { + this.type = type; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerSetTrialSpawnerTypeWithEggEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerSetTrialSpawnerTypeWithEggEvent.java new file mode 100644 index 000000000..1d4dbf60a --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/PlayerSetTrialSpawnerTypeWithEggEvent.java @@ -0,0 +1,83 @@ +package org.purpurmc.purpur.event; + +import org.bukkit.block.Block; +import org.bukkit.block.TrialSpawner; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public class PlayerSetTrialSpawnerTypeWithEggEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final Block block; + private final TrialSpawner spawner; + private EntityType type; + private boolean cancel; + + @ApiStatus.Internal + public PlayerSetTrialSpawnerTypeWithEggEvent(Player player, Block block, TrialSpawner spawner, EntityType type) { + super(player); + this.block = block; + this.spawner = spawner; + this.type = type; + } + + /** + * Get the spawner Block in the world + * + * @return Spawner Block + */ + public Block getBlock() { + return block; + } + + /** + * Get the spawner state + * + * @return Spawner state + */ + public TrialSpawner getSpawner() { + return spawner; + } + + /** + * Gets the EntityType being set on the spawner + * + * @return EntityType being set + */ + public EntityType getEntityType() { + return type; + } + + /** + * Sets the EntityType being set on the spawner + * + * @param type EntityType to set + */ + public void setEntityType(EntityType type) { + this.type = type; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java new file mode 100644 index 000000000..4b4d32c58 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/PreBlockExplodeEvent.java @@ -0,0 +1,56 @@ +package org.purpurmc.purpur.event; + +import org.bukkit.ExplosionResult; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.block.BlockExplodeEvent; +import org.jetbrains.annotations.ApiStatus; +import java.util.Collections; +import org.jspecify.annotations.NullMarked; + +/** + * Called before a block's explosion is processed + */ +@NullMarked +public class PreBlockExplodeEvent extends BlockExplodeEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final float yield; + + @ApiStatus.Internal + public PreBlockExplodeEvent(final Block what, final float yield, BlockState explodedBlockState, ExplosionResult result) { + super(what, explodedBlockState, Collections.emptyList(), yield, result); + this.yield = yield; + this.cancelled = false; + } + + /** + * Returns the percentage of blocks to drop from this explosion + * + * @return The yield. + */ + public float getYield() { + return yield; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java new file mode 100644 index 000000000..7f631a41a --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeFoundFlowerEvent.java @@ -0,0 +1,48 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.Location; +import org.bukkit.entity.Bee; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Called when a bee targets a flower + */ +@NullMarked +public class BeeFoundFlowerEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + private final Location location; + + @ApiStatus.Internal + public BeeFoundFlowerEvent(Bee bee, @Nullable Location location) { + super(bee); + this.location = location; + } + + @Override + public Bee getEntity() { + return (Bee) super.getEntity(); + } + + /** + * Returns the location of the flower that the bee targets + * + * @return The location of the flower + */ + @Nullable + public Location getLocation() { + return location; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java new file mode 100644 index 000000000..e260145d6 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeStartedPollinatingEvent.java @@ -0,0 +1,46 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.Location; +import org.bukkit.entity.Bee; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a bee starts pollinating + */ +@NullMarked +public class BeeStartedPollinatingEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + private final Location location; + + @ApiStatus.Internal + public BeeStartedPollinatingEvent(Bee bee, Location location) { + super(bee); + this.location = location; + } + + @Override + public Bee getEntity() { + return (Bee) super.getEntity(); + } + + /** + * Returns the location of the flower that the bee pollinates + * + * @return The location of the flower + */ + public Location getLocation() { + return this.location; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java new file mode 100644 index 000000000..8b2b351d6 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/BeeStopPollinatingEvent.java @@ -0,0 +1,60 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.Location; +import org.bukkit.entity.Bee; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Called when a bee stops pollinating + */ +@NullMarked +public class BeeStopPollinatingEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + private final Location location; + private final boolean success; + + @ApiStatus.Internal + public BeeStopPollinatingEvent(Bee bee, @Nullable Location location, boolean success) { + super(bee); + this.location = location; + this.success = success; + } + + @Override + public Bee getEntity() { + return (Bee) super.getEntity(); + } + + /** + * Returns the location of the flower that the bee stopped pollinating + * + * @return The location of the flower + */ + @Nullable + public Location getLocation() { + return location; + } + + /** + * Returns whether the bee successfully pollinated the flower + * + * @return True if the pollination was successful + */ + public boolean wasSuccessful() { + return success; + } + + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java new file mode 100644 index 000000000..daf3bbf83 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/EntityTeleportHinderedEvent.java @@ -0,0 +1,114 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Fired when an entity is hindered from teleporting. + */ +@NullMarked +public class EntityTeleportHinderedEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + + private final Reason reason; + + private final @Nullable TeleportCause teleportCause; + + private boolean retry = false; + + @ApiStatus.Internal + public EntityTeleportHinderedEvent(Entity what, Reason reason, @Nullable TeleportCause teleportCause) { + super(what); + this.reason = reason; + this.teleportCause = teleportCause; + } + + /** + * @return why the teleport was hindered. + */ + public Reason getReason() { + return reason; + } + + /** + * @return why the teleport occurred if cause was given, otherwise {@code null}. + */ + @Nullable + public TeleportCause getTeleportCause() { + return teleportCause; + } + + /** + * Whether the teleport should be retried. + *

+ * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack + * overflow. Do not retry more than necessary. + *

+ * + * @return whether the teleport should be retried. + */ + public boolean shouldRetry() { + return retry; + } + + /** + * Sets whether the teleport should be retried. + *

+ * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack + * overflow. Do not retry more than necessary. + *

+ * + * @param retry whether the teleport should be retried. + */ + public void setShouldRetry(boolean retry) { + this.retry = retry; + } + + /** + * Calls the event and tests if should retry. + * + * @return whether the teleport should be retried. + */ + @Override + public boolean callEvent() { + super.callEvent(); + return shouldRetry(); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + /** + * Reason for hindrance in teleports. + */ + public enum Reason { + /** + * The teleported entity is a passenger of another entity. + */ + IS_PASSENGER, + + /** + * The teleported entity has passengers. + */ + IS_VEHICLE, + + /** + * The teleport event was cancelled. + *

+ * This is only caused by players teleporting. + *

+ */ + EVENT_CANCELLED, + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java new file mode 100644 index 000000000..f0a7fe694 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/GoatRamEntityEvent.java @@ -0,0 +1,58 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.entity.Goat; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a goat rams an entity + */ +@NullMarked +public class GoatRamEntityEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private final LivingEntity rammedEntity; + private boolean cancelled; + + @ApiStatus.Internal + public GoatRamEntityEvent(Goat goat, LivingEntity rammedEntity) { + super(goat); + this.rammedEntity = rammedEntity; + } + + /** + * Returns the entity that was rammed by the goat + * + * @return The rammed entity + */ + public LivingEntity getRammedEntity() { + return this.rammedEntity; + } + + @Override + public Goat getEntity() { + return (Goat) super.getEntity(); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java new file mode 100644 index 000000000..e34c37579 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/LlamaJoinCaravanEvent.java @@ -0,0 +1,60 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.entity.Llama; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a Llama tries to join a caravan. + *

+ * Cancelling the event will not let the Llama join. To prevent future attempts + * at joining a caravan use {@link Llama#setShouldJoinCaravan(boolean)}. + */ +@NullMarked +public class LlamaJoinCaravanEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean canceled; + private final Llama head; + + @ApiStatus.Internal + public LlamaJoinCaravanEvent(Llama llama, Llama head) { + super(llama); + this.head = head; + } + + @Override + public Llama getEntity() { + return (Llama) entity; + } + + /** + * Get the Llama that this Llama is about to follow + * + * @return Llama about to be followed + */ + public Llama getHead() { + return head; + } + + @Override + public boolean isCancelled() { + return canceled; + } + + @Override + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java new file mode 100644 index 000000000..23ea41ff5 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/LlamaLeaveCaravanEvent.java @@ -0,0 +1,34 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.entity.Llama; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a Llama leaves a caravan + */ +@NullMarked +public class LlamaLeaveCaravanEvent extends EntityEvent { + private static final HandlerList handlers = new HandlerList(); + + @ApiStatus.Internal + public LlamaLeaveCaravanEvent(Llama llama) { + super(llama); + } + + @Override + public Llama getEntity() { + return (Llama) entity; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java new file mode 100644 index 000000000..d56fb0664 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/PreEntityExplodeEvent.java @@ -0,0 +1,66 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.ExplosionResult; +import org.bukkit.Location; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.jetbrains.annotations.ApiStatus; +import java.util.Collections; +import org.jspecify.annotations.NullMarked; + +/** + * Called before an entity's explosion is processed + */ +@NullMarked +public class PreEntityExplodeEvent extends EntityExplodeEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final float yield; + private final Location location; + + @ApiStatus.Internal + public PreEntityExplodeEvent(org.bukkit.entity.Entity what, final Location location, final float yield, ExplosionResult result) { + super(what, location, Collections.emptyList(), yield, result); + this.cancelled = false; + this.yield = yield; + this.location = location; + } + + /** + * Returns the percentage of blocks to drop from this explosion + * + * @return The yield. + */ + public float getYield() { + return yield; + } + + /** + * Returns the location where the explosion happened. + * + * @return The location of the explosion + */ + public Location getLocation() { + return location; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java new file mode 100644 index 000000000..c31a656da --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/RidableMoveEvent.java @@ -0,0 +1,100 @@ +package org.purpurmc.purpur.event.entity; + +import com.google.common.base.Preconditions; +import org.bukkit.Location; +import org.bukkit.entity.Mob; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Triggered when a ridable mob moves with a rider + */ +@NullMarked +public class RidableMoveEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean canceled; + private final Player rider; + private Location from; + private Location to; + + @ApiStatus.Internal + public RidableMoveEvent(Mob entity, Player rider, Location from, Location to) { + super(entity); + this.rider = rider; + this.from = from; + this.to = to; + } + + @Override + public Mob getEntity() { + return (Mob) entity; + } + + public Player getRider() { + return rider; + } + + public boolean isCancelled() { + return canceled; + } + + public void setCancelled(boolean cancel) { + canceled = cancel; + } + + /** + * Gets the location this entity moved from + * + * @return Location the entity moved from + */ + public Location getFrom() { + return from; + } + + /** + * Sets the location to mark as where the entity moved from + * + * @param from New location to mark as the entity's previous location + */ + public void setFrom(Location from) { + validateLocation(from); + this.from = from; + } + + /** + * Gets the location this entity moved to + * + * @return Location the entity moved to + */ + public Location getTo() { + return to; + } + + /** + * Sets the location that this entity will move to + * + * @param to New Location this entity will move to + */ + public void setTo(Location to) { + validateLocation(to); + this.to = to; + } + + private void validateLocation(Location loc) { + Preconditions.checkArgument(loc != null, "Cannot use null location!"); + Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!"); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java new file mode 100644 index 000000000..02de629f0 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/entity/RidableSpacebarEvent.java @@ -0,0 +1,38 @@ +package org.purpurmc.purpur.event.entity; + +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public class RidableSpacebarEvent extends EntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + + @ApiStatus.Internal + public RidableSpacebarEvent(Entity entity) { + super(entity); + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java new file mode 100644 index 000000000..b2199854b --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java @@ -0,0 +1,50 @@ +package org.purpurmc.purpur.event.inventory; + +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.inventory.InventoryEvent; +import org.bukkit.inventory.AnvilInventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a player takes the result item out of an anvil + */ +@NullMarked +public class AnvilTakeResultEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); + private final Player player; + private final ItemStack result; + + @ApiStatus.Internal + public AnvilTakeResultEvent(HumanEntity player, InventoryView view, ItemStack result) { + super(view); + this.player = (Player) player; + this.result = result; + } + + public Player getPlayer() { + return player; + } + + public ItemStack getResult() { + return result; + } + + @Override + public AnvilInventory getInventory() { + return (AnvilInventory) super.getInventory(); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java new file mode 100644 index 000000000..4293c4a57 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java @@ -0,0 +1,35 @@ +package org.purpurmc.purpur.event.inventory; + +import org.bukkit.event.HandlerList; +import org.bukkit.event.inventory.InventoryEvent; +import org.bukkit.inventory.AnvilInventory; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when anvil slots change, triggering the result slot to be updated + */ +@NullMarked +public class AnvilUpdateResultEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); + + @ApiStatus.Internal + public AnvilUpdateResultEvent(InventoryView view) { + super(view); + } + + @Override + public AnvilInventory getInventory() { + return (AnvilInventory) super.getInventory(); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java new file mode 100644 index 000000000..d6db2d355 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/GrindstoneTakeResultEvent.java @@ -0,0 +1,72 @@ +package org.purpurmc.purpur.event.inventory; + +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.inventory.InventoryEvent; +import org.bukkit.inventory.GrindstoneInventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a player takes the result item out of a Grindstone + */ +@NullMarked +public class GrindstoneTakeResultEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); + private final Player player; + private final ItemStack result; + private int experienceAmount; + + @ApiStatus.Internal + public GrindstoneTakeResultEvent(HumanEntity player, InventoryView view, ItemStack result, int experienceAmount) { + super(view); + this.player = (Player) player; + this.result = result; + this.experienceAmount = experienceAmount; + } + + public Player getPlayer() { + return player; + } + + public ItemStack getResult() { + return result; + } + + @Override + public GrindstoneInventory getInventory() { + return (GrindstoneInventory) super.getInventory(); + } + + /** + * Get the amount of experience this transaction will give + * (takes priority over and uses result from {@link org.bukkit.event.block.BlockExpEvent}) + * + * @return Amount of experience to give + */ + public int getExperienceAmount() { + return this.experienceAmount; + } + + /** + * Set the amount of experience this transaction will give + * (takes priority over {@link org.bukkit.event.block.BlockExpEvent}) + * + * @param experienceAmount Amount of experience to give + */ + public void setExperienceAmount(int experienceAmount) { + this.experienceAmount = experienceAmount; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java b/purpur-api/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java new file mode 100644 index 000000000..31cce9f4e --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/event/player/PlayerBookTooLargeEvent.java @@ -0,0 +1,65 @@ +package org.purpurmc.purpur.event.player; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a player tries to bypass book limitations + */ +@NullMarked +public class PlayerBookTooLargeEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); + private final ItemStack book; + private boolean kickPlayer = true; + + /** + * @param player The player + * @param book The book + */ + @ApiStatus.Internal + public PlayerBookTooLargeEvent(Player player, ItemStack book) { + super(player, !Bukkit.isPrimaryThread()); + this.book = book; + } + + /** + * Get the book containing the wanted edits + * + * @return The book + */ + public ItemStack getBook() { + return book; + } + + /** + * Whether server should kick the player or not + * + * @return True to kick player + */ + public boolean shouldKickPlayer() { + return kickPlayer; + } + + /** + * Whether server should kick the player or not + * + * @param kickPlayer True to kick player + */ + public void setShouldKickPlayer(boolean kickPlayer) { + this.kickPlayer = kickPlayer; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/language/Language.java b/purpur-api/src/main/java/org/purpurmc/purpur/language/Language.java new file mode 100644 index 000000000..cbdad4cf0 --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/language/Language.java @@ -0,0 +1,60 @@ +package org.purpurmc.purpur.language; + +import net.kyori.adventure.translation.Translatable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Represents a language that can translate translation keys + */ +@NullMarked +public abstract class Language { + private static @Nullable Language language; + + /** + * Returns the default language of the server + */ + @Nullable + public static Language getLanguage() { + return language; + } + + public static void setLanguage(Language language) { + if (Language.language != null) { + throw new UnsupportedOperationException("Cannot redefine singleton Language"); + } + Language.language = language; + } + + /** + * Checks if a certain translation key is translatable with this language + * @param key The translation key + * @return Whether this language can translate the key + */ + abstract public boolean has(String key); + + /** + * Checks if a certain translation key is translatable with this language + * @param key The translation key + * @return Whether this language can translate the key + */ + public boolean has(Translatable key) { + return has(key.translationKey()); + } + + /** + * Translates a translation key to this language + * @param key The translation key + * @return The translated key, or the translation key if it couldn't be translated + */ + abstract public String getOrDefault(String key); + + /** + * Translates a translation key to this language + * @param key The translation key + * @return The translated key, or the translation key if it couldn't be translated + */ + public String getOrDefault(Translatable key) { + return getOrDefault(key.translationKey()); + } +} diff --git a/purpur-api/src/main/java/org/purpurmc/purpur/util/permissions/PurpurPermissions.java b/purpur-api/src/main/java/org/purpurmc/purpur/util/permissions/PurpurPermissions.java new file mode 100644 index 000000000..50647252e --- /dev/null +++ b/purpur-api/src/main/java/org/purpurmc/purpur/util/permissions/PurpurPermissions.java @@ -0,0 +1,87 @@ +package org.purpurmc.purpur.util.permissions; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Mob; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; +import org.bukkit.util.permissions.DefaultPermissions; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +public final class PurpurPermissions { + private static final String ROOT = "purpur"; + private static final String PREFIX = ROOT + "."; + private static final Set mobs = new HashSet<>(); + + static { + for (EntityType mob : EntityType.values()) { + Class clazz = mob.getEntityClass(); + if (clazz != null && Mob.class.isAssignableFrom(clazz)) { + mobs.add(mob.getName()); + } + } + } + + @NotNull + public static Permission registerPermissions() { + Permission purpur = DefaultPermissions.registerPermission(ROOT, "Gives the user the ability to use all Purpur utilities and commands", PermissionDefault.FALSE); + + DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.six", "Gives the user six rows of enderchest space", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.five", "Gives the user five rows of enderchest space", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.four", "Gives the user four rows of enderchest space", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.three", "Gives the user three rows of enderchest space", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.two", "Gives the user two rows of enderchest space", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.one", "Gives the user one row of enderchest space", PermissionDefault.FALSE, purpur); + + DefaultPermissions.registerPermission(PREFIX + "debug.f3n", "Allows the user to use F3+N keybind to swap gamemodes", PermissionDefault.FALSE, purpur); + + DefaultPermissions.registerPermission(PREFIX + "joinfullserver", "Allows the user to join a full server", PermissionDefault.OP, purpur); + + DefaultPermissions.registerPermission(PREFIX + "bypassIdleKick", "Allows the user to bypass being kicked while idle", PermissionDefault.FALSE, purpur); + + DefaultPermissions.registerPermission(PREFIX + "inventory_totem", "Allows the user to use totem of undying anywhere in their inventory", PermissionDefault.FALSE, purpur); + + Permission anvil = DefaultPermissions.registerPermission(PREFIX + "anvil", "Allows the user to use all anvil color and format abilities", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "anvil.color", "Allows the user to use color codes in an anvil", PermissionDefault.FALSE, anvil); + DefaultPermissions.registerPermission(PREFIX + "anvil.minimessage", "Allows the user to use minimessage tags in an anvil", PermissionDefault.FALSE, anvil); + DefaultPermissions.registerPermission(PREFIX + "anvil.remove_italics", "Allows the user to remove italics in an anvil", PermissionDefault.FALSE, anvil); + DefaultPermissions.registerPermission(PREFIX + "anvil.format", "Allows the user to use format codes in an anvil", PermissionDefault.FALSE, anvil); + anvil.recalculatePermissibles(); + + Permission book = DefaultPermissions.registerPermission(PREFIX + "book", "Allows the user to use color codes on books", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "book.color.edit", "Allows the user to use color codes on books when editing", PermissionDefault.FALSE, book); + DefaultPermissions.registerPermission(PREFIX + "book.color.sign", "Allows the user to use color codes on books when signing", PermissionDefault.FALSE, book); + book.recalculatePermissibles(); + + Permission sign = DefaultPermissions.registerPermission(PREFIX + "sign", "Allows the user to use all sign abilities", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission(PREFIX + "sign.edit", "Allows the user to click signs to open sign editor", PermissionDefault.TRUE, sign); + DefaultPermissions.registerPermission(PREFIX + "sign.color", "Allows the user to use color codes on signs", PermissionDefault.FALSE, sign); + DefaultPermissions.registerPermission(PREFIX + "sign.style", "Allows the user to use style codes on signs", PermissionDefault.FALSE, sign); + DefaultPermissions.registerPermission(PREFIX + "sign.magic", "Allows the user to use magic/obfuscate code on signs", PermissionDefault.FALSE, sign); + sign.recalculatePermissibles(); + + Permission ride = DefaultPermissions.registerPermission("allow.ride", "Allows the user to ride all mobs", PermissionDefault.FALSE, purpur); + for (String mob : mobs) { + DefaultPermissions.registerPermission("allow.ride." + mob, "Allows the user to ride " + mob, PermissionDefault.FALSE, ride); + } + ride.recalculatePermissibles(); + + Permission special = DefaultPermissions.registerPermission("allow.special", "Allows the user to use all mobs special abilities", PermissionDefault.FALSE, purpur); + for (String mob : mobs) { + DefaultPermissions.registerPermission("allow.special." + mob, "Allows the user to use " + mob + " special ability", PermissionDefault.FALSE, special); + } + special.recalculatePermissibles(); + + Permission powered = DefaultPermissions.registerPermission("allow.powered", "Allows the user to toggle all mobs powered state", PermissionDefault.FALSE, purpur); + DefaultPermissions.registerPermission("allow.powered.creeper", "Allows the user to toggle creeper powered state", PermissionDefault.FALSE, powered); + powered.recalculatePermissibles(); + + DefaultPermissions.registerPermission(PREFIX + "portal.instant", "Allows the user to bypass portal wait time", PermissionDefault.FALSE, purpur); + + purpur.recalculatePermissibles(); + return purpur; + } +} diff --git a/purpur-server/build.gradle.kts.patch b/purpur-server/build.gradle.kts.patch new file mode 100644 index 000000000..59cc82d61 --- /dev/null +++ b/purpur-server/build.gradle.kts.patch @@ -0,0 +1,81 @@ +--- a/paper-server/build.gradle.kts ++++ b/paper-server/build.gradle.kts +@@ -21,6 +_,16 @@ + // macheOldPath = file("F:\\Projects\\PaperTooling\\mache\\versions\\1.21.4\\src\\main\\java") + // gitFilePatches = true + ++ val purpur = forks.register("purpur") { ++ upstream.patchDir("paperServer") { ++ upstreamPath = "paper-server" ++ excludes = setOf("src/minecraft", "patches", "build.gradle.kts") ++ patchesDir = rootDirectory.dir("purpur-server/paper-patches") ++ outputDir = rootDirectory.dir("paper-server") ++ } ++ } ++ activeFork = purpur ++ + spigot { + buildDataRef = "3edaf46ec1eed4115ce1b18d2846cded42577e42" + packageVersion = "v1_21_R3" // also needs to be updated in MappingEnvironment +@@ -101,7 +_,20 @@ + } + } + +-val log4jPlugins = sourceSets.create("log4jPlugins") ++sourceSets { ++ main { ++ java { srcDir("../paper-server/src/main/java") } ++ resources { srcDir("../paper-server/src/main/resources") } ++ } ++ test { ++ java { srcDir("../paper-server/src/test/java") } ++ resources { srcDir("../paper-server/src/test/resources") } ++ } ++} ++ ++val log4jPlugins = sourceSets.create("log4jPlugins") { ++ java { srcDir("../paper-server/src/log4jPlugins/java") } ++} + configurations.named(log4jPlugins.compileClasspathConfigurationName) { + extendsFrom(configurations.compileClasspath.get()) + } +@@ -119,7 +_,7 @@ + } + + dependencies { +- implementation(project(":paper-api")) ++ implementation(project(":purpur-api")) + implementation("ca.spottedleaf:concurrentutil:0.0.3") + implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ + implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21 +@@ -149,6 +_,10 @@ + runtimeOnly("com.mysql:mysql-connector-j:9.1.0") + runtimeOnly("com.lmax:disruptor:3.4.4") + ++ implementation("org.mozilla:rhino-runtime:1.7.14") // Purpur ++ implementation("org.mozilla:rhino-engine:1.7.14") // Purpur ++ implementation("dev.omega24:upnp4j:1.0") // Purpur ++ + runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6") + runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") + runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") +@@ -188,14 +_,14 @@ + val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim() + attributes( + "Main-Class" to "org.bukkit.craftbukkit.Main", +- "Implementation-Title" to "Paper", ++ "Implementation-Title" to "Purpur", // Purpur + "Implementation-Version" to implementationVersion, + "Implementation-Vendor" to date, +- "Specification-Title" to "Paper", ++ "Specification-Title" to "Purpur", // Purpur + "Specification-Version" to project.version, +- "Specification-Vendor" to "Paper Team", +- "Brand-Id" to "papermc:paper", +- "Brand-Name" to "Paper", ++ "Specification-Vendor" to "Purpur Team", // Purpur ++ "Brand-Id" to "purpurmc:purpur", // Purpur ++ "Brand-Name" to "Purpur", // Purpur + "Build-Number" to (build ?: ""), + "Build-Time" to buildTime.toString(), + "Git-Branch" to gitBranch, diff --git a/purpur-server/minecraft-patches/features/0001-Ridables.patch b/purpur-server/minecraft-patches/features/0001-Ridables.patch new file mode 100644 index 000000000..f6921b145 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0001-Ridables.patch @@ -0,0 +1,5108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 5 Jul 2020 22:19:49 -0500 +Subject: [PATCH] Ridables + + +diff --git a/net/minecraft/gametest/framework/GameTestHelper.java b/net/minecraft/gametest/framework/GameTestHelper.java +index 29d402620d2e1cbed94f941f933ae8eb5d786e7f..ec0998369158286fccb38c8e10c3cfa2a653a8aa 100644 +--- a/net/minecraft/gametest/framework/GameTestHelper.java ++++ b/net/minecraft/gametest/framework/GameTestHelper.java +@@ -281,6 +281,8 @@ public class GameTestHelper { + + public void setAfk(final boolean afk) {} // Purpur - AFK API + ++ public void resetLastActionTime() {} // Purpur - Ridables ++ + @Override + public boolean isLocalPlayer() { + return true; +diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java +index 121b57c7f5345f5d8884eaa1d36dac79fb7d42ef..9afbfe9bf493e09ca1963e8956ab7573964479b4 100644 +--- a/net/minecraft/server/MinecraftServer.java ++++ b/net/minecraft/server/MinecraftServer.java +@@ -1745,6 +1745,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - Add EntityMoveEvent + serverLevel.updateLagCompensationTick(); // Paper - lag compensation + net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers ++ serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables + profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location()); + /* Drop global time updates + if (this.tickCount % 20 == 0) { +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index 5cf2c7f8fb05a91ed17f1d9c07f7d3e748738058..3770dc90d9412c6378c0bd57a651b9c3e62b9a72 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -217,6 +217,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent + public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent + private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current) ++ public boolean hasRidableMoveEvent = false; // Purpur - Ridables + + public LevelChunk getChunkIfLoaded(int x, int z) { + return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately +diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java +index a6f771cbee878eb383b67c61fa2469f2916413b5..d77381237f8a7d1b2f280a5032f5e1c8f0ab8f94 100644 +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -848,6 +848,15 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + this.trackEnteredOrExitedLavaOnVehicle(); + this.updatePlayerAttributes(); + this.advancements.flushDirty(this); ++ ++ // Purpur start - Ridables ++ if (this.level().purpurConfig.useNightVisionWhenRiding && this.getVehicle() != null && this.getVehicle().getRider() == this && this.level().getGameTime() % 100 == 0) { // 5 seconds ++ MobEffectInstance nightVision = this.getEffect(MobEffects.NIGHT_VISION); ++ if (nightVision == null || nightVision.getDuration() <= 300) { // 15 seconds ++ this.addEffect(new MobEffectInstance(MobEffects.NIGHT_VISION, 400, 0)); // 20 seconds ++ } ++ } ++ // Purpur end - Ridables + } + + private void updatePlayerAttributes() { +diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index d681e14d33a8de6ca2c7f0a2e1ff9bb9d55adbbb..ee002c2cef9d4810fdacac71de77e948f5b0e89d 100644 +--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -2835,6 +2835,8 @@ public class ServerGamePacketListenerImpl + + ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); + ++ player.processClick(hand); // Purpur - Ridables ++ + // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a + if ((target instanceof Bucketable && target instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) { + target.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it +diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java +index 43a4427a8f327fbb224cb25e63a5c6b244eb9b09..62a38ecedbd579b32a8fd9cff5a433bfe635fc62 100644 +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -3151,6 +3151,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.passengers = ImmutableList.copyOf(list); + } + ++ // Purpur start - Ridables ++ if (isRidable() && this.passengers.get(0) == passenger && passenger instanceof Player player) { ++ onMount(player); ++ this.rider = player; ++ } ++ // Purpur end - Ridables ++ + this.gameEvent(GameEvent.ENTITY_MOUNT, passenger); + } + } +@@ -3192,6 +3199,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return false; + } + // CraftBukkit end ++ ++ // Purpur start - Ridables ++ if (this.rider != null && this.passengers.get(0) == this.rider) { ++ onDismount(this.rider); ++ this.rider = null; ++ } ++ // Purpur end - Ridables ++ + if (this.passengers.size() == 1 && this.passengers.get(0) == passenger) { + this.passengers = ImmutableList.of(); + } else { +@@ -5115,4 +5130,44 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return ((ServerLevel) this.level).isPositionEntityTicking(this.blockPosition()); + } + // Paper end - Expose entity id counter ++ // Purpur start - Ridables ++ @Nullable ++ private Player rider = null; ++ ++ @Nullable ++ public Player getRider() { ++ return rider; ++ } ++ ++ public boolean isRidable() { ++ return false; ++ } ++ ++ public boolean isControllable() { ++ return true; ++ } ++ ++ public void onMount(Player rider) { ++ if (this instanceof Mob) { ++ ((Mob) this).setTarget(null, null, false); ++ ((Mob) this).getNavigation().stop(); ++ } ++ rider.setJumping(false); // fixes jump on mount ++ } ++ ++ public void onDismount(Player player) { ++ } ++ ++ public boolean onSpacebar() { ++ return false; ++ } ++ ++ public boolean onClick(InteractionHand hand) { ++ return false; ++ } ++ ++ public boolean processClick(InteractionHand hand) { ++ return false; ++ } ++ // Purpur end - Ridables + } +diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java +index 95d78dcdb6777df73898694367ee17b1cb76d7a2..d0313fd5368baa53ec511c8c07fc78a1f1ecec4e 100644 +--- a/net/minecraft/world/entity/GlowSquid.java ++++ b/net/minecraft/world/entity/GlowSquid.java +@@ -32,6 +32,19 @@ public class GlowSquid extends Squid { + } + // Purpur end - Flying squids! Oh my! + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.glowSquidRidable; ++ } ++ ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.glowSquidControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected ParticleOptions getInkParticle() { + return ParticleTypes.GLOW_SQUID_INK; +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index f41d5ffe83e3cfb4c30d150f8b66f8f2568ae20c..8c2bdb1775f7c4110c5f967b1052eba6a8fcbbfa 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -250,9 +250,9 @@ public abstract class LivingEntity extends Entity implements Attackable { + protected float rotOffs; + public float lastHurt; + public boolean jumping; +- public float xxa; +- public float yya; +- public float zza; ++ public float xxa; public float getStrafeMot() { return xxa; } public void setStrafeMot(float strafe) { xxa = strafe; } // Purpur - OBFHELPER ++ public float yya; public float getVerticalMot() { return yya; } public void setVerticalMot(float vertical) { yya = vertical; } // Purpur - OBFHELPER ++ public float zza; public float getForwardMot() { return zza; } public void setForwardMot(float forward) { zza = forward; } // Purpur - OBFHELPER + protected int lerpSteps; + protected double lerpX; + protected double lerpY; +@@ -310,7 +310,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + + protected LivingEntity(EntityType entityType, Level level) { + super(entityType, level); +- this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType)); ++ this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType), this); // Purpur - Ridables + this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit + // CraftBukkit - this.setHealth(this.getMaxHealth()) inlined and simplified to skip the instanceof check for Player, as getBukkitEntity() is not initialized in constructor + this.entityData.set(LivingEntity.DATA_HEALTH_ID, this.getMaxHealth()); +@@ -377,6 +377,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + .add(Attributes.MOVEMENT_EFFICIENCY) + .add(Attributes.ATTACK_KNOCKBACK); + } ++ public boolean shouldSendAttribute(Attribute attribute) { return true; } // Purpur - Ridables + + @Override + protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) { +@@ -3537,8 +3538,10 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.pushEntities(); + profilerFiller.pop(); + // Paper start - Add EntityMoveEvent +- if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof Player)) { +- if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { ++ // Purpur start - Ridables ++ if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { ++ if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof Player)) { ++ // Purpur end - Ridables + Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO); + Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); + io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone()); +@@ -3548,6 +3551,21 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch()); + } + } ++ // Purpur start - Ridables ++ if (getRider() != null) { ++ getRider().resetLastActionTime(); ++ if (((ServerLevel) level()).hasRidableMoveEvent && this instanceof Mob) { ++ Location from = new Location(level().getWorld(), xo, yo, zo, this.yRotO, this.xRotO); ++ Location to = new Location(level().getWorld(), getX(), getY(), getZ(), this.getYRot(), this.getXRot()); ++ org.purpurmc.purpur.event.entity.RidableMoveEvent event = new org.purpurmc.purpur.event.entity.RidableMoveEvent((org.bukkit.entity.Mob) getBukkitLivingEntity(), (org.bukkit.entity.Player) getRider().getBukkitEntity(), from, to.clone()); ++ if (!event.callEvent()) { ++ absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch()); ++ } else if (!to.equals(event.getTo())) { ++ absMoveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); ++ } ++ } ++ } ++ // Purpur end - Ridables + } + // Paper end - Add EntityMoveEvent + if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { +diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java +index 26f7cd5ddacf5f908702adbf55b56dcc6fcbe162..c431f28c3f4f6cec946048f5752c364429af5ba1 100644 +--- a/net/minecraft/world/entity/Mob.java ++++ b/net/minecraft/world/entity/Mob.java +@@ -151,8 +151,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + super(entityType, level); + this.goalSelector = new GoalSelector(); + this.targetSelector = new GoalSelector(); +- this.lookControl = new LookControl(this); +- this.moveControl = new MoveControl(this); ++ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this); // Purpur - Ridables ++ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this); // Purpur - Ridables + this.jumpControl = new JumpControl(this); + this.bodyRotationControl = this.createBodyControl(); + this.navigation = this.createNavigation(level); +@@ -1405,7 +1405,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + } + + protected InteractionResult mobInteract(Player player, InteractionHand hand) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur - Ridables + } + + public boolean isWithinRestriction() { +@@ -1723,4 +1723,58 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + public float[] getArmorDropChances() { + return this.armorDropChances; + } ++ ++ // Purpur start - Ridables ++ public double getMaxY() { ++ return level().getHeight(); ++ } ++ ++ public InteractionResult tryRide(Player player, InteractionHand hand) { ++ return tryRide(player, hand, InteractionResult.PASS); ++ } ++ ++ public InteractionResult tryRide(Player player, InteractionHand hand, InteractionResult result) { ++ if (!isRidable()) { ++ return result; ++ } ++ if (hand != InteractionHand.MAIN_HAND) { ++ return InteractionResult.PASS; ++ } ++ if (player.isShiftKeyDown()) { ++ return InteractionResult.PASS; ++ } ++ if (!player.getItemInHand(hand).isEmpty()) { ++ return InteractionResult.PASS; ++ } ++ if (!passengers.isEmpty() || player.isPassenger()) { ++ return InteractionResult.PASS; ++ } ++ if (this instanceof TamableAnimal tamable) { ++ if (tamable.isTame() && !tamable.isOwnedBy(player)) { ++ return InteractionResult.PASS; ++ } ++ if (!tamable.isTame() && !level().purpurConfig.untamedTamablesAreRidable) { ++ return InteractionResult.PASS; ++ } ++ } ++ if (this instanceof AgeableMob ageable) { ++ if (ageable.isBaby() && !level().purpurConfig.babiesAreRidable) { ++ return InteractionResult.PASS; ++ } ++ } ++ if (!player.getBukkitEntity().hasPermission("allow.ride." + net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getKey(getType()).getPath())) { ++ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { ++ serverPlayer.sendMiniMessage(org.purpurmc.purpur.PurpurConfig.cannotRideMob); ++ } ++ return InteractionResult.PASS; ++ } ++ player.setYRot(this.getYRot()); ++ player.setXRot(this.getXRot()); ++ if (player.startRiding(this)) { ++ return InteractionResult.SUCCESS; ++ } else { ++ return InteractionResult.PASS; ++ } ++ } ++ // Purpur end - Ridables + } +diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java +index 4c808c7ef336de74048f40bd1cc8b14131a9325d..a25d74592e89e3d6339479c6dc2b6f45d1932cfc 100644 +--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java ++++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java +@@ -23,14 +23,21 @@ public class AttributeMap { + private final Set attributesToSync = new ObjectOpenHashSet<>(); + private final Set attributesToUpdate = new ObjectOpenHashSet<>(); + private final AttributeSupplier supplier; ++ private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables + + public AttributeMap(AttributeSupplier supplier) { +- this.supplier = supplier; ++ // Purpur start - Ridables ++ this(supplier, null); ++ } ++ public AttributeMap(AttributeSupplier defaultAttributes, net.minecraft.world.entity.LivingEntity entity) { ++ this.entity = entity; ++ // Purpur end - Ridables ++ this.supplier = defaultAttributes; + } + + private void onAttributeModified(AttributeInstance instance) { + this.attributesToUpdate.add(instance); +- if (instance.getAttribute().value().isClientSyncable()) { ++ if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - Ridables + this.attributesToSync.add(instance); + } + } +@@ -44,7 +51,7 @@ public class AttributeMap { + } + + public Collection getSyncableAttributes() { +- return this.attributes.values().stream().filter(instance -> instance.getAttribute().value().isClientSyncable()).collect(Collectors.toList()); ++ return this.attributes.values().stream().filter(instance -> instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))).collect(Collectors.toList()); // Purpur - Ridables + } + + @Nullable +diff --git a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java +index 33527a1825119f3667fb3c7ccec318f2c7328ec9..61ed4d687120fcbb7b91863e400f3657ebcde687 100644 +--- a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java ++++ b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java +@@ -131,7 +131,7 @@ public class DefaultAttributes { + .put(EntityType.OCELOT, Ocelot.createAttributes().build()) + .put(EntityType.PANDA, Panda.createAttributes().build()) + .put(EntityType.PARROT, Parrot.createAttributes().build()) +- .put(EntityType.PHANTOM, Monster.createMonsterAttributes().build()) ++ .put(EntityType.PHANTOM, net.minecraft.world.entity.monster.Phantom.createAttributes().build()) // Purpur - Ridables + .put(EntityType.PIG, Pig.createAttributes().build()) + .put(EntityType.PIGLIN, Piglin.createAttributes().build()) + .put(EntityType.PIGLIN_BRUTE, PiglinBrute.createAttributes().build()) +diff --git a/net/minecraft/world/entity/ai/control/MoveControl.java b/net/minecraft/world/entity/ai/control/MoveControl.java +index 0f9bf0cb0655a6ed449a86e99b17f89b4e3264df..1860b4ab2314f5da017313977c6423e735a4f96b 100644 +--- a/net/minecraft/world/entity/ai/control/MoveControl.java ++++ b/net/minecraft/world/entity/ai/control/MoveControl.java +@@ -29,6 +29,20 @@ public class MoveControl implements Control { + this.mob = mob; + } + ++ // Purpur start - Ridables ++ public void setSpeedModifier(double speed) { ++ this.speedModifier = speed; ++ } ++ ++ public void setForward(float forward) { ++ this.strafeForwards = forward; ++ } ++ ++ public void setStrafe(float strafe) { ++ this.strafeRight = strafe; ++ } ++ // Purpur end - Ridables ++ + public boolean hasWanted() { + return this.operation == MoveControl.Operation.MOVE_TO; + } +diff --git a/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java b/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java +index d7f9b3b2b1077ea10e8f64b87c8f4c4354e90858..713f62b34a91fa76f40e49a5e390145f70755e58 100644 +--- a/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java ++++ b/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java +@@ -3,7 +3,7 @@ package net.minecraft.world.entity.ai.control; + import net.minecraft.util.Mth; + import net.minecraft.world.entity.Mob; + +-public class SmoothSwimmingLookControl extends LookControl { ++public class SmoothSwimmingLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables + private final int maxYRotFromCenter; + private static final int HEAD_TILT_X = 10; + private static final int HEAD_TILT_Y = 20; +@@ -14,7 +14,7 @@ public class SmoothSwimmingLookControl extends LookControl { + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (this.lookAtCooldown > 0) { + this.lookAtCooldown--; + this.getYRotD().ifPresent(rotationWanted -> this.mob.yHeadRot = this.rotateTowards(this.mob.yHeadRot, rotationWanted + 20.0F, this.yMaxRotSpeed)); +diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java +index 4d715a29f1ad31e87977562bd0e2aeddb54ee082..e7ea944e77175ee4051b8e7361c502d0cc2115d5 100644 +--- a/net/minecraft/world/entity/ambient/Bat.java ++++ b/net/minecraft/world/entity/ambient/Bat.java +@@ -42,11 +42,58 @@ public class Bat extends AmbientCreature { + + public Bat(EntityType entityType, Level level) { + super(entityType, level); ++ this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.075F); // Purpur - Ridables + if (!level.isClientSide) { + this.setResting(true); + } + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean shouldSendAttribute(net.minecraft.world.entity.ai.attributes.Attribute attribute) { return attribute != Attributes.FLYING_SPEED.value(); } // Fixes log spam on clients ++ ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.batRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.batRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.batControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.batMaxY; ++ } ++ ++ @Override ++ public void onMount(net.minecraft.world.entity.player.Player rider) { ++ super.onMount(rider); ++ if (isResting()) { ++ setResting(false); ++ level().levelEvent(null, 1025, new BlockPos(this).above(), 0); ++ } ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && this.isControllable() && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ // Purpur end - Ridables ++ + @Override + public boolean isFlapping() { + return !this.isResting() && this.tickCount % 10.0F == 0.0F; +@@ -98,7 +145,7 @@ public class Bat extends AmbientCreature { + } + + public static AttributeSupplier.Builder createAttributes() { +- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0); ++ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - Ridables + } + + public boolean isResting() { +@@ -129,6 +176,14 @@ public class Bat extends AmbientCreature { + + @Override + protected void customServerAiStep(ServerLevel level) { ++ // Purpur start - Ridables ++ if (getRider() != null && this.isControllable()) { ++ Vec3 mot = getDeltaMovement(); ++ setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); ++ return; ++ } ++ // Purpur end - Ridables ++ + super.customServerAiStep(level); + BlockPos blockPos = this.blockPosition(); + BlockPos blockPos1 = blockPos.above(); +diff --git a/net/minecraft/world/entity/animal/AbstractFish.java b/net/minecraft/world/entity/animal/AbstractFish.java +index c0997c8c0f8ee4474d3acdd5938b1879c4e589a2..28ae152125ed83d8917674b6068f227f87890f30 100644 +--- a/net/minecraft/world/entity/animal/AbstractFish.java ++++ b/net/minecraft/world/entity/animal/AbstractFish.java +@@ -87,6 +87,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { + @Override + protected void registerGoals() { + super.registerGoals(); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(0, new PanicGoal(this, 1.25)); + this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6, 1.4, EntitySelector.NO_SPECTATORS::test)); + this.goalSelector.addGoal(4, new AbstractFish.FishSwimGoal(this)); +@@ -100,7 +101,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { + @Override + public void travel(Vec3 travelVector) { + if (this.isControlledByLocalInstance() && this.isInWater()) { +- this.moveRelative(0.01F, travelVector); ++ this.moveRelative(getRider() != null ? getSpeed() : 0.01F, travelVector); // Purpur - Ridables + this.move(MoverType.SELF, this.getDeltaMovement()); + this.setDeltaMovement(this.getDeltaMovement().scale(0.9)); + if (this.getTarget() == null) { +@@ -160,7 +161,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { + protected void playStepSound(BlockPos pos, BlockState block) { + } + +- static class FishMoveControl extends MoveControl { ++ static class FishMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur - Ridables + private final AbstractFish fish; + + FishMoveControl(AbstractFish mob) { +@@ -168,14 +169,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { + this.fish = mob; + } + ++ // Purpur start - Ridables + @Override +- public void tick() { ++ public void purpurTick(Player rider) { ++ super.purpurTick(rider); ++ fish.setDeltaMovement(fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); ++ } ++ // Purpur end - Ridables ++ ++ @Override ++ public void vanillaTick() { // Purpur - Ridables + if (this.fish.isEyeInFluid(FluidTags.WATER)) { + this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0, 0.005, 0.0)); + } + + if (this.operation == MoveControl.Operation.MOVE_TO && !this.fish.getNavigation().isDone()) { +- float f = (float)(this.speedModifier * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); ++ float f = (float)(this.getSpeedModifier() * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables + this.fish.setSpeed(Mth.lerp(0.125F, this.fish.getSpeed(), f)); + double d = this.wantedX - this.fish.getX(); + double d1 = this.wantedY - this.fish.getY(); +diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java +index 3793570827eb6ca21c6b990d76c679c00ad100f4..af0cf64b4c74d290dec8032f8a6127867e301130 100644 +--- a/net/minecraft/world/entity/animal/Bee.java ++++ b/net/minecraft/world/entity/animal/Bee.java +@@ -145,6 +145,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + + public Bee(EntityType entityType, Level level) { + super(entityType, level); ++ final org.purpurmc.purpur.controller.FlyingMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.25F, 1.0F, false); // Purpur - Ridables + // Paper start - Fix MC-167279 + class BeeFlyingMoveControl extends FlyingMoveControl { + public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) { +@@ -153,11 +154,24 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + + @Override + public void tick() { ++ // Purpur start - Ridables ++ if (mob.getRider() != null && mob.isControllable()) { ++ flyingController.purpurTick(mob.getRider()); ++ return; ++ } ++ // Purpur end - Ridables + if (this.mob.getY() <= Bee.this.level().getMinY()) { + this.mob.setNoGravity(false); + } + super.tick(); + } ++ ++ // Purpur start - Ridables ++ @Override ++ public boolean hasWanted() { ++ return mob.getRider() != null || !mob.isControllable() || super.hasWanted(); ++ } ++ // Purpur end - Ridables + } + this.moveControl = new BeeFlyingMoveControl(this, 20, true); + // Paper end - Fix MC-167279 +@@ -169,6 +183,40 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + this.setPathfindingMalus(PathType.FENCE, -1.0F); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.beeRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.beeRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.beeControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.beeMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && this.isControllable() && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ // Purpur end - Ridables ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +@@ -183,6 +231,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.4F, true)); + this.goalSelector.addGoal(1, new Bee.BeeEnterHiveGoal()); + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); +@@ -200,6 +249,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + this.goalSelector.addGoal(7, new Bee.BeeGrowCropGoal()); + this.goalSelector.addGoal(8, new Bee.BeeWanderGoal()); + this.goalSelector.addGoal(9, new FloatGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new Bee.BeeHurtByOtherGoal(this).setAlertOthers(new Class[0])); + this.targetSelector.addGoal(2, new Bee.BeeBecomeAngryTargetGoal(this)); + this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); +@@ -1084,15 +1134,15 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + } + } + +- class BeeLookControl extends LookControl { ++ class BeeLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables + BeeLookControl(final Mob mob) { + super(mob); + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (!Bee.this.isAngry()) { +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + } + +diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java +index 618f184ce9fed4d9b01f2df4d9a4476d20a55546..f066b0acfa0e954f6d71e62962c76afa1f05a4a5 100644 +--- a/net/minecraft/world/entity/animal/Cat.java ++++ b/net/minecraft/world/entity/animal/Cat.java +@@ -93,10 +93,36 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true); + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new TamableAnimal.TamableAnimalPanicGoal(1.5)); + this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); + this.goalSelector.addGoal(3, new Cat.CatRelaxOnOwnerGoal(this)); +@@ -109,6 +135,7 @@ public class Cat extends TamableAnimal implements VariantHolder(this, Rabbit.class, false, null)); + this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR)); + } +@@ -360,6 +387,7 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CHICKEN_FOOD), false)); +diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java +index 708bcc39e7242292d5d5bfcaf599e3738628df9b..6a19086e272363701260801f3c6db9b5c91b8ef5 100644 +--- a/net/minecraft/world/entity/animal/Cod.java ++++ b/net/minecraft/world/entity/animal/Cod.java +@@ -13,6 +13,18 @@ public class Cod extends AbstractSchoolingFish { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.codRidable; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.codControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + public ItemStack getBucketItemStack() { + return new ItemStack(Items.COD_BUCKET); +diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java +index 8c1f74c6be53cbf48bd6b5641511359578801c08..656babc0c8810a85eb9f78ced1f3ad9551fdc286 100644 +--- a/net/minecraft/world/entity/animal/Cow.java ++++ b/net/minecraft/world/entity/animal/Cow.java +@@ -38,9 +38,27 @@ public class Cow extends Animal { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.cowRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.cowRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.cowControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new PanicGoal(this, 2.0)); + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); + this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, itemStack -> level().purpurConfig.cowFeedMushrooms > 0 && (itemStack.is(net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem()) || itemStack.is(net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem())) || itemStack.is(ItemTags.COW_FOOD), false)); // Purpur - Cows eat mushrooms +@@ -86,13 +104,14 @@ public class Cow extends Animal { + + @Override + public InteractionResult mobInteract(Player player, InteractionHand hand) { ++ if (getRider() != null) return InteractionResult.PASS; // Purpur - Ridables + ItemStack itemInHand = player.getItemInHand(hand); + if (itemInHand.is(Items.BUCKET) && !this.isBaby()) { + // CraftBukkit start - Got milk? + org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemInHand, Items.MILK_BUCKET, hand); + if (event.isCancelled()) { + player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur - Ridables + } + // CraftBukkit end + player.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F); +diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java +index 8be0dd148d88dfdfb9efab91124c829e60b5dea5..35bce598bb5857356823594d2a001006ce19f835 100644 +--- a/net/minecraft/world/entity/animal/Dolphin.java ++++ b/net/minecraft/world/entity/animal/Dolphin.java +@@ -72,14 +72,82 @@ public class Dolphin extends AgeableWaterCreature { + public static final Predicate ALLOWED_ITEMS = itemEntity -> !itemEntity.hasPickUpDelay() && itemEntity.isAlive() && itemEntity.isInWater(); + public static final float BABY_SCALE = 0.65F; + private boolean isNaturallyAggressiveToPlayers; // Purpur - Dolphins naturally aggressive to players chance ++ private int spitCooldown; // Purpur - Ridables + + public Dolphin(EntityType entityType, Level level) { + super(entityType, level); +- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); ++ // Purpur start - Ridables ++ class DolphinMoveControl extends SmoothSwimmingMoveControl { ++ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterMoveControllerWASD; ++ private final Dolphin dolphin; ++ ++ public DolphinMoveControl(Dolphin dolphin, int pitchChange, int yawChange, float speedInWater, float speedInAir, boolean buoyant) { ++ super(dolphin, pitchChange, yawChange, speedInWater, speedInAir, buoyant); ++ this.dolphin = dolphin; ++ this.waterMoveControllerWASD = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(dolphin); ++ } ++ ++ @Override ++ public void tick() { ++ if (dolphin.getRider() != null && dolphin.isControllable()) { ++ purpurTick(dolphin.getRider()); ++ } else { ++ super.tick(); ++ } ++ } ++ ++ public void purpurTick(Player rider) { ++ if (dolphin.getAirSupply() < 150) { ++ // if drowning override player WASD controls to find air ++ super.tick(); ++ } else { ++ waterMoveControllerWASD.purpurTick(rider); ++ dolphin.setDeltaMovement(dolphin.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); ++ } ++ } ++ }; ++ this.moveControl = new DolphinMoveControl(this, 85, 10, 0.02F, 0.1F, true); ++ // Purpur end - Ridables + this.lookControl = new SmoothSwimmingLookControl(this, 10); + this.setCanPickUpLoot(true); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.dolphinRidable; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.dolphinControllable; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (spitCooldown == 0 && getRider() != null) { ++ spitCooldown = level().purpurConfig.dolphinSpitCooldown; ++ ++ org.bukkit.craftbukkit.entity.CraftPlayer player = (org.bukkit.craftbukkit.entity.CraftPlayer) getRider().getBukkitEntity(); ++ if (!player.hasPermission("allow.special.dolphin")) { ++ return false; ++ } ++ ++ org.bukkit.Location loc = player.getEyeLocation(); ++ loc.setPitch(loc.getPitch() - 10); ++ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(10).add(loc.toVector()); ++ ++ org.purpurmc.purpur.entity.projectile.DolphinSpit spit = new org.purpurmc.purpur.entity.projectile.DolphinSpit(level(), this); ++ spit.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), level().purpurConfig.dolphinSpitSpeed, 5.0F); ++ ++ level().addFreshEntity(spit); ++ playSound(SoundEvents.DOLPHIN_ATTACK, 1.0F, 1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F); ++ return true; ++ } ++ return false; ++ } ++ // Purpur end - Ridables ++ + @Nullable + @Override + public SpawnGroupData finalizeSpawn( +@@ -172,6 +240,7 @@ public class Dolphin extends AgeableWaterCreature { + this.goalSelector.addGoal(0, new BreathAirGoal(this)); + this.goalSelector.addGoal(0, new TryFindWaterGoal(this)); + this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - Dolphins naturally aggressive to players chance ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this)); + this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0)); + this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0, 10)); +@@ -182,6 +251,7 @@ public class Dolphin extends AgeableWaterCreature { + this.goalSelector.addGoal(8, new Dolphin.PlayWithItemsGoal()); + this.goalSelector.addGoal(8, new FollowBoatGoal(this)); + this.goalSelector.addGoal(9, new AvoidEntityGoal<>(this, Guardian.class, 8.0F, 1.0, 1.0)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Guardian.class).setAlertOthers()); + this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur - Dolphins naturally aggressive to players chance + } +@@ -227,7 +297,7 @@ public class Dolphin extends AgeableWaterCreature { + + @Override + protected boolean canRide(Entity entity) { +- return true; ++ return boardingCooldown <= 0; // Purpur - make dolphin honor ride cooldown like all other non-boss mobs; + } + + @Override +@@ -256,6 +326,11 @@ public class Dolphin extends AgeableWaterCreature { + @Override + public void tick() { + super.tick(); ++ // Purpur start - Ridables ++ if (spitCooldown > 0) { ++ spitCooldown--; ++ } ++ // Purpur end - Ridables + if (this.isNoAi()) { + this.setAirSupply(this.getMaxAirSupply()); + } else { +diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java +index ddc252c76cedec0a0e9e268d8a874015a5ad52fe..8b0a813f9dd001c6dd108ba7aac04d134a20fbc1 100644 +--- a/net/minecraft/world/entity/animal/Fox.java ++++ b/net/minecraft/world/entity/animal/Fox.java +@@ -129,6 +129,44 @@ public class Fox extends Animal implements VariantHolder { + this.getNavigation().setRequiredPathLength(32.0F); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.foxRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.foxRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.foxControllable; ++ } ++ ++ @Override ++ public float getJumpPower() { ++ return getRider() != null && this.isControllable() ? 0.5F : super.getJumpPower(); ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ setCanPickUpLoot(false); ++ clearStates(); ++ setIsPouncing(false); ++ spitOutItem(getItemBySlot(EquipmentSlot.MAINHAND)); ++ setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); ++ } ++ ++ @Override ++ public void onDismount(Player rider) { ++ super.onDismount(rider); ++ setCanPickUpLoot(true); ++ } ++ // Purpur end - Ridables ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +@@ -148,6 +186,7 @@ public class Fox extends Animal implements VariantHolder { + this, AbstractFish.class, 20, false, false, (entity, level) -> entity instanceof AbstractSchoolingFish + ); + this.goalSelector.addGoal(0, new Fox.FoxFloatGoal()); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(0, new ClimbOnTopOfPowderSnowGoal(this, this.level())); + this.goalSelector.addGoal(1, new Fox.FaceplantGoal()); + this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2)); +@@ -175,6 +214,7 @@ public class Fox extends Animal implements VariantHolder { + this.goalSelector.addGoal(11, new Fox.FoxSearchForItemsGoal()); + this.goalSelector.addGoal(12, new Fox.FoxLookAtPlayerGoal(this, Player.class, 24.0F)); + this.goalSelector.addGoal(13, new Fox.PerchAndSearchGoal()); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector + .addGoal( + 3, +@@ -1095,15 +1135,15 @@ public class Fox extends Animal implements VariantHolder { + } + } + +- public class FoxLookControl extends LookControl { ++ public class FoxLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables + public FoxLookControl() { + super(Fox.this); + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (!Fox.this.isSleeping()) { +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + } + +@@ -1139,15 +1179,15 @@ public class Fox extends Animal implements VariantHolder { + } + } + +- class FoxMoveControl extends MoveControl { ++ class FoxMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables + public FoxMoveControl() { + super(Fox.this); + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (Fox.this.canMove()) { +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + } + } +diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java +index 46921562c9c5caf7e04ee180325a638273d6bad2..223c4796f659a24062a719045e484a22d31ab2f0 100644 +--- a/net/minecraft/world/entity/animal/IronGolem.java ++++ b/net/minecraft/world/entity/animal/IronGolem.java +@@ -73,9 +73,28 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + } + // Purpur end - Summoner API + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.ironGolemRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ironGolemRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.ironGolemControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options ++ if (level().purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur - Ridables ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true)); + this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9, 32.0F)); + this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6, false)); +@@ -83,6 +102,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + this.goalSelector.addGoal(5, new OfferFlowerGoal(this)); + this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new DefendVillageTargetGoal(this)); + this.targetSelector.addGoal(2, new HurtByTargetGoal(this)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); +@@ -271,12 +291,12 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + protected InteractionResult mobInteract(Player player, InteractionHand hand) { + ItemStack itemInHand = player.getItemInHand(hand); + if (!itemInHand.is(Items.IRON_INGOT)) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur - Ridables + } else { + float health = this.getHealth(); + this.heal(25.0F); + if (this.getHealth() == health) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur - Ridables + } else { + float f = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F; + this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f); +diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java +index a8aeb79b1c1413d74a5d18a57bd4ba4beca6039c..1292146341022483f78a9128ef9d7a88089274a0 100644 +--- a/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/net/minecraft/world/entity/animal/MushroomCow.java +@@ -55,6 +55,23 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder drops = this.generateDefaultDrops(serverLevel, itemInHand); + org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); + if (event != null) { +- if (event.isCancelled()) return InteractionResult.PASS; ++ if (event.isCancelled()) return tryRide(player, hand); // Purpur - Ridables + drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); + // Paper end - custom shear drops + } +diff --git a/net/minecraft/world/entity/animal/Ocelot.java b/net/minecraft/world/entity/animal/Ocelot.java +index e193696b2e3eb1c1c689c05592ab4318a98772ad..d26a8658c8c56c3b0df4e5908de1ac23ac2dd351 100644 +--- a/net/minecraft/world/entity/animal/Ocelot.java ++++ b/net/minecraft/world/entity/animal/Ocelot.java +@@ -62,6 +62,23 @@ public class Ocelot extends Animal { + this.reassessTrustingGoals(); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.ocelotRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ocelotRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.ocelotControllable; ++ } ++ // Purpur end - Ridables ++ + public boolean isTrusting() { + return this.entityData.get(DATA_TRUSTING); + } +@@ -93,12 +110,14 @@ public class Ocelot extends Animal { + protected void registerGoals() { + this.temptGoal = new Ocelot.OcelotTemptGoal(this, 0.6, itemStack -> itemStack.is(ItemTags.OCELOT_FOOD), true); + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(3, this.temptGoal); + this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3F)); + this.goalSelector.addGoal(8, new OcelotAttackGoal(this)); + this.goalSelector.addGoal(9, new BreedGoal(this, 0.8)); + this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8, 1.0000001E-5F)); + this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0F)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Chicken.class, false)); + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR)); + } +diff --git a/net/minecraft/world/entity/animal/Panda.java b/net/minecraft/world/entity/animal/Panda.java +index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f4fa1a515 100644 +--- a/net/minecraft/world/entity/animal/Panda.java ++++ b/net/minecraft/world/entity/animal/Panda.java +@@ -105,6 +105,32 @@ public class Panda extends Animal { + } + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.pandaRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pandaRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.pandaControllable; ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ setForwardMot(0.0F); ++ sit(false); ++ eat(false); ++ setOnBack(false); ++ } ++ // Purpur end - Ridables ++ + @Override + protected boolean canDispenserEquipIntoSlot(EquipmentSlot slot) { + return slot == EquipmentSlot.MAINHAND && this.canPickUpLoot(); +@@ -258,6 +284,7 @@ public class Panda extends Animal { + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(2, new Panda.PandaPanicGoal(this, 2.0)); + this.goalSelector.addGoal(2, new Panda.PandaBreedGoal(this, 1.0)); + this.goalSelector.addGoal(3, new Panda.PandaAttackGoal(this, 1.2F, true)); +@@ -273,6 +300,7 @@ public class Panda extends Animal { + this.goalSelector.addGoal(12, new Panda.PandaRollGoal(this)); + this.goalSelector.addGoal(13, new FollowParentGoal(this, 1.25)); + this.goalSelector.addGoal(14, new WaterAvoidingRandomStrollGoal(this, 1.0)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new Panda.PandaHurtByTargetGoal(this).setAlertOthers(new Class[0])); + } + +@@ -616,7 +644,7 @@ public class Panda extends Animal { + public InteractionResult mobInteract(Player player, InteractionHand hand) { + ItemStack itemInHand = player.getItemInHand(hand); + if (this.isScared()) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur - Ridables + } else if (this.isOnBack()) { + this.setOnBack(false); + return InteractionResult.SUCCESS; +@@ -652,7 +680,7 @@ public class Panda extends Animal { + + return InteractionResult.SUCCESS_SERVER; + } else { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur - Ridables + } + } + +@@ -964,7 +992,7 @@ public class Panda extends Animal { + } + } + +- static class PandaMoveControl extends MoveControl { ++ static class PandaMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables + private final Panda panda; + + public PandaMoveControl(Panda mob) { +@@ -973,9 +1001,9 @@ public class Panda extends Animal { + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (this.panda.canPerformAction()) { +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + } + } +diff --git a/net/minecraft/world/entity/animal/Parrot.java b/net/minecraft/world/entity/animal/Parrot.java +index 1d840fe1c718ea4431c471e3cbbdee074ed53179..445614d09d2364daee5245c217baeb31e186c168 100644 +--- a/net/minecraft/world/entity/animal/Parrot.java ++++ b/net/minecraft/world/entity/animal/Parrot.java +@@ -124,12 +124,68 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder entityType, Level level) { + super(entityType, level); +- this.moveControl = new FlyingMoveControl(this, 10, false); ++ // Purpur start - Ridables ++ final org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); ++ class ParrotMoveControl extends FlyingMoveControl { ++ public ParrotMoveControl(Mob entity, int maxPitchChange, boolean noGravity) { ++ super(entity, maxPitchChange, noGravity); ++ } ++ ++ @Override ++ public void tick() { ++ if (mob.getRider() != null && mob.isControllable()) { ++ flyingController.purpurTick(mob.getRider()); ++ } else { ++ super.tick(); ++ } ++ } ++ ++ @Override ++ public boolean hasWanted() { ++ return mob.getRider() != null && mob.isControllable() ? getForwardMot() != 0 || getStrafeMot() != 0 : super.hasWanted(); ++ } ++ } ++ this.moveControl = new ParrotMoveControl(this, 10, false); ++ // Purpur end - Ridables + this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F); + this.setPathfindingMalus(PathType.DAMAGE_FIRE, -1.0F); + this.setPathfindingMalus(PathType.COCOA, -1.0F); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.parrotRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.parrotRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.parrotControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.parrotMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && this.isControllable() && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ // Purpur end - Ridables ++ + @Nullable + @Override + public SpawnGroupData finalizeSpawn( +@@ -150,9 +206,11 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder itemStack.is(Items.CARROT_ON_A_STICK), false)); +diff --git a/net/minecraft/world/entity/animal/PolarBear.java b/net/minecraft/world/entity/animal/PolarBear.java +index fbd35f074a3045d483aabd9bc7e1c9c4f10a3167..711ed0d753494a92a003fc683146f289505ed7f6 100644 +--- a/net/minecraft/world/entity/animal/PolarBear.java ++++ b/net/minecraft/world/entity/animal/PolarBear.java +@@ -59,6 +59,7 @@ public class PolarBear extends Animal implements NeutralMob { + private int remainingPersistentAngerTime; + @Nullable + private UUID persistentAngerTarget; ++ private int standTimer = 0; // Purpur - Ridables + + public PolarBear(EntityType entityType, Level level) { + super(entityType, level); +@@ -87,6 +88,34 @@ public class PolarBear extends Animal implements NeutralMob { + } + // Purpur end - Breedable Polar Bears + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.polarBearRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.polarBearRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.polarBearControllable; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (!isStanding()) { ++ if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0) { ++ setStanding(true); ++ playSound(SoundEvents.POLAR_BEAR_WARNING, 1.0F, 1.0F); ++ } ++ } ++ return false; ++ } ++ // Purpur end - Ridables ++ + @Nullable + @Override + public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) { +@@ -102,6 +131,7 @@ public class PolarBear extends Animal implements NeutralMob { + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal()); + this.goalSelector.addGoal(1, new PanicGoal(this, 2.0, mob -> mob.isBaby() ? DamageTypeTags.PANIC_CAUSES : DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES)); + // Purpur start - Breedable Polar Bears +@@ -114,6 +144,7 @@ public class PolarBear extends Animal implements NeutralMob { + this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new PolarBear.PolarBearHurtByTargetGoal()); + this.targetSelector.addGoal(2, new PolarBear.PolarBearAttackPlayersGoal()); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); +@@ -232,6 +263,12 @@ public class PolarBear extends Animal implements NeutralMob { + if (!this.level().isClientSide) { + this.updatePersistentAnger((ServerLevel)this.level(), true); + } ++ ++ // Purpur start - Ridables ++ if (isStanding() && --standTimer <= 0) { ++ setStanding(false); ++ } ++ // Purpur end - Ridables + } + + @Override +@@ -251,6 +288,7 @@ public class PolarBear extends Animal implements NeutralMob { + + public void setStanding(boolean standing) { + this.entityData.set(DATA_STANDING_ID, standing); ++ standTimer = standing ? 20 : -1; // Purpur - Ridables + } + + public float getStandingAnimationScale(float partialTick) { +diff --git a/net/minecraft/world/entity/animal/Pufferfish.java b/net/minecraft/world/entity/animal/Pufferfish.java +index d94a7cfcd0f7a15ce97d3b12daa8b2c71acf997a..f7e9abf778186ad1c78dbe411980a83c5e68792e 100644 +--- a/net/minecraft/world/entity/animal/Pufferfish.java ++++ b/net/minecraft/world/entity/animal/Pufferfish.java +@@ -45,6 +45,18 @@ public class Pufferfish extends AbstractFish { + this.refreshDimensions(); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.pufferfishRidable; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.pufferfishControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java +index b2cbe9f7a771dbfc381effa0821d44421c98b33e..8cac46951938c80fae3499e8b53709c25d86e9bd 100644 +--- a/net/minecraft/world/entity/animal/Rabbit.java ++++ b/net/minecraft/world/entity/animal/Rabbit.java +@@ -83,6 +83,7 @@ public class Rabbit extends Animal implements VariantHolder { + private boolean wasOnGround; + private int jumpDelayTicks; + public int moreCarrotTicks; ++ private boolean actualJump; // Purpur - Ridables + + public Rabbit(EntityType entityType, Level level) { + super(entityType, level); +@@ -91,9 +92,55 @@ public class Rabbit extends Animal implements VariantHolder { + //this.setSpeedModifier(0.0); // CraftBukkit + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.rabbitRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.rabbitRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.rabbitControllable; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (onGround) { ++ actualJump = true; ++ jumpFromGround(); ++ actualJump = false; ++ } ++ return true; ++ } ++ ++ private void handleJumping() { ++ if (onGround) { ++ RabbitJumpControl jumpController = (RabbitJumpControl) jumpControl; ++ if (!wasOnGround) { ++ setJumping(false); ++ jumpController.setCanJump(false); ++ } ++ if (!jumpController.wantJump()) { ++ if (moveControl.hasWanted()) { ++ startJumping(); ++ } ++ } else if (!jumpController.canJump()) { ++ jumpController.setCanJump(true); ++ } ++ } ++ wasOnGround = onGround; ++ } ++ // Purpur end - Ridables ++ + @Override + public void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level())); + this.goalSelector.addGoal(1, new Rabbit.RabbitPanicGoal(this, 2.2)); + this.goalSelector.addGoal(2, new BreedGoal(this, 0.8)); +@@ -108,6 +155,14 @@ public class Rabbit extends Animal implements VariantHolder { + + @Override + protected float getJumpPower() { ++ // Purpur start - Ridables ++ if (getRider() != null && this.isControllable()) { ++ if (getForwardMot() < 0) { ++ setSpeed(getForwardMot() * 2F); ++ } ++ return actualJump ? 0.5F : 0.3F; ++ } ++ // Purpur end - Ridables + float f = 0.3F; + if (this.moveControl.getSpeedModifier() <= 0.6) { + f = 0.2F; +@@ -175,6 +230,12 @@ public class Rabbit extends Animal implements VariantHolder { + + @Override + public void customServerAiStep(ServerLevel level) { ++ // Purpur start - Ridables ++ if (getRider() != null && this.isControllable()) { ++ handleJumping(); ++ return; ++ } ++ // Purpur end - Ridables + if (this.jumpDelayTicks > 0) { + this.jumpDelayTicks--; + } +@@ -483,7 +544,7 @@ public class Rabbit extends Animal implements VariantHolder { + } + } + +- static class RabbitMoveControl extends MoveControl { ++ static class RabbitMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables + private final Rabbit rabbit; + private double nextJumpSpeed; + +@@ -493,14 +554,14 @@ public class Rabbit extends Animal implements VariantHolder { + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (this.rabbit.onGround() && !this.rabbit.jumping && !((Rabbit.RabbitJumpControl)this.rabbit.jumpControl).wantJump()) { + this.rabbit.setSpeedModifier(0.0); + } else if (this.hasWanted() || this.operation == MoveControl.Operation.JUMPING) { + this.rabbit.setSpeedModifier(this.nextJumpSpeed); + } + +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + + @Override +diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java +index 41366f7b9af176a33b20ea26dd53d50994d2c600..ebbd6d39c3f5d6c66445c2c743785ed369408389 100644 +--- a/net/minecraft/world/entity/animal/Salmon.java ++++ b/net/minecraft/world/entity/animal/Salmon.java +@@ -35,6 +35,18 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder stack.is(ItemTags.SHEEP_FOOD), false)); +diff --git a/net/minecraft/world/entity/animal/SnowGolem.java b/net/minecraft/world/entity/animal/SnowGolem.java +index 29427515b648b84248f486c156c5cd7a0995ba14..52de92b118b613217b8f92ff672c01ddf798a1fc 100644 +--- a/net/minecraft/world/entity/animal/SnowGolem.java ++++ b/net/minecraft/world/entity/animal/SnowGolem.java +@@ -61,12 +61,31 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + } + // Purpur end - Summoner API + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.snowGolemRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.snowGolemRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.snowGolemControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new RangedAttackGoal(this, level().purpurConfig.snowGolemAttackDistance, level().purpurConfig.snowGolemSnowBallMin, level().purpurConfig.snowGolemSnowBallMax, level().purpurConfig.snowGolemSnowBallModifier)); // Purpur - Snow Golem rate of fire config + this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F)); + this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entity, level) -> entity instanceof Enemy)); + } + +@@ -113,6 +132,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + return; + } + ++ if (getRider() != null && this.isControllable() && !level().purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden + BlockState blockState = Blocks.SNOW.defaultBlockState(); + + for (int i = 0; i < 4; i++) { +@@ -155,7 +175,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); + if (event != null) { + if (event.isCancelled()) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur - Ridables + } + drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); + // Paper end - custom shear drops +@@ -176,7 +196,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + return InteractionResult.SUCCESS; + // Purpur end - Snowman drop and put back pumpkin + } else { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur - Ridables + } + } + +diff --git a/net/minecraft/world/entity/animal/Squid.java b/net/minecraft/world/entity/animal/Squid.java +index c776d40896a6514ab9c66df206c93469ec682b23..e3f43e8c6ddbae289a82157cab4beb18f682dd75 100644 +--- a/net/minecraft/world/entity/animal/Squid.java ++++ b/net/minecraft/world/entity/animal/Squid.java +@@ -69,9 +69,32 @@ public class Squid extends AgeableWaterCreature { + } + // Purpur end - Flying squids! Oh my! + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.squidRidable; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.squidControllable; ++ } ++ ++ protected static void rotateVectorAroundY(org.bukkit.util.Vector vector, double degrees) { ++ double rad = Math.toRadians(degrees); ++ double cos = Math.cos(rad); ++ double sine = Math.sin(rad); ++ double x = vector.getX(); ++ double z = vector.getZ(); ++ vector.setX(cos * x - sine * z); ++ vector.setZ(sine * x + cos * z); ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new Squid.SquidFleeGoal()); + } + +@@ -327,6 +350,37 @@ public class Squid extends AgeableWaterCreature { + + @Override + public void tick() { ++ // Purpur start - Ridables ++ net.minecraft.world.entity.player.Player rider = squid.getRider(); ++ if (rider != null && squid.isControllable()) { ++ if (rider.jumping) { ++ squid.onSpacebar(); ++ } ++ float forward = rider.getForwardMot(); ++ float strafe = rider.getStrafeMot(); ++ float speed = (float) squid.getAttributeValue(Attributes.MOVEMENT_SPEED) * 10F; ++ if (forward < 0.0F) { ++ speed *= -0.5; ++ } ++ org.bukkit.util.Vector dir = rider.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(speed / 20.0F); ++ if (strafe != 0.0F) { ++ if (forward == 0.0F) { ++ dir.setY(0); ++ rotateVectorAroundY(dir, strafe > 0.0F ? -90 : 90); ++ } else if (forward < 0.0F) { ++ rotateVectorAroundY(dir, strafe > 0.0F ? 45 : -45); ++ } else { ++ rotateVectorAroundY(dir, strafe > 0.0F ? -45 : 45); ++ } ++ } ++ if (forward != 0.0F || strafe != 0.0F) { ++ squid.movementVector = new Vec3((float) dir.getX(), (float) dir.getY(), (float) dir.getZ()); ++ } else { ++ squid.movementVector = Vec3.ZERO; ++ } ++ return; ++ } ++ // Purpur end - Ridables + int noActionTime = this.squid.getNoActionTime(); + if (noActionTime > 100) { + this.squid.movementVector = Vec3.ZERO; +diff --git a/net/minecraft/world/entity/animal/TropicalFish.java b/net/minecraft/world/entity/animal/TropicalFish.java +index fa5f7f7d54083f9ea2095dd44362069d00e0b9a5..1e31a39b276e1c5ae767da7af0b536007c87189e 100644 +--- a/net/minecraft/world/entity/animal/TropicalFish.java ++++ b/net/minecraft/world/entity/animal/TropicalFish.java +@@ -67,6 +67,18 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.tropicalFishRidable; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.tropicalFishControllable; ++ } ++ // Purpur end - Ridables ++ + public static String getPredefinedName(int variantId) { + return "entity.minecraft.tropical_fish.predefined." + variantId; + } +diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java +index 354ec2b987882d8f40ef4ac5257183d2fda73bb8..98cb91574c8d2bdb6d180256f657ecc67987a6fe 100644 +--- a/net/minecraft/world/entity/animal/Turtle.java ++++ b/net/minecraft/world/entity/animal/Turtle.java +@@ -84,6 +84,23 @@ public class Turtle extends Animal { + this.moveControl = new Turtle.TurtleMoveControl(this); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.turtleRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.turtleRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.turtleControllable; ++ } ++ // Purpur end - Ridables ++ + public void setHomePos(BlockPos homePos) { + this.entityData.set(HOME_POS, homePos); + } +@@ -188,6 +205,7 @@ public class Turtle extends Animal { + + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(0, new Turtle.TurtlePanicGoal(this, 1.2)); + this.goalSelector.addGoal(1, new Turtle.TurtleBreedGoal(this, 1.0)); + this.goalSelector.addGoal(1, new Turtle.TurtleLayEggGoal(this, 1.0)); +@@ -539,12 +557,14 @@ public class Turtle extends Animal { + } + } + +- static class TurtleMoveControl extends MoveControl { ++ static class TurtleMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables + private final Turtle turtle; ++ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur - Ridables + + TurtleMoveControl(Turtle mob) { + super(mob); + this.turtle = mob; ++ waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(turtle, 0.25D); // Purpur - Ridables + } + + private void updateSpeed() { +@@ -563,7 +583,7 @@ public class Turtle extends Animal { + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + this.updateSpeed(); + if (this.operation == MoveControl.Operation.MOVE_TO && !this.turtle.getNavigation().isDone()) { + double d = this.wantedX - this.turtle.getX(); +@@ -577,7 +597,7 @@ public class Turtle extends Animal { + float f = (float)(Mth.atan2(d2, d) * 180.0F / (float)Math.PI) - 90.0F; + this.turtle.setYRot(this.rotlerp(this.turtle.getYRot(), f, 90.0F)); + this.turtle.yBodyRot = this.turtle.getYRot(); +- float f1 = (float)(this.speedModifier * this.turtle.getAttributeValue(Attributes.MOVEMENT_SPEED)); ++ float f1 = (float)(this.getSpeedModifier() * this.turtle.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables + this.turtle.setSpeed(Mth.lerp(0.125F, this.turtle.getSpeed(), f1)); + this.turtle.setDeltaMovement(this.turtle.getDeltaMovement().add(0.0, this.turtle.getSpeed() * d1 * 0.1, 0.0)); + } +diff --git a/net/minecraft/world/entity/animal/Wolf.java b/net/minecraft/world/entity/animal/Wolf.java +index 6cc3893742b443ec84942252910cf444cdbf0c96..90609ff3060322110ece27630de0abae1a6370a8 100644 +--- a/net/minecraft/world/entity/animal/Wolf.java ++++ b/net/minecraft/world/entity/animal/Wolf.java +@@ -180,9 +180,32 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder(this, Llama.class, 24.0F, 1.5, 1.5)); +@@ -195,6 +218,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder entityType, Level level) { + super(entityType, level); +- this.moveControl = new FlyingMoveControl(this, 20, true); ++ // Purpur start - Ridables ++ this.purpurController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.1F, 0.5F); ++ this.moveControl = new FlyingMoveControl(this, 20, true) { ++ @Override ++ public void tick() { ++ if (mob.getRider() != null && mob.isControllable()) { ++ purpurController.purpurTick(mob.getRider()); ++ } else { ++ super.tick(); ++ } ++ } ++ }; ++ // Purpur end - Ridables + this.setCanPickUpLoot(this.canPickUpLoot()); + this.vibrationUser = new Allay.VibrationUser(); + this.vibrationData = new VibrationSystem.Data(); +@@ -138,6 +151,28 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS + } + // CraftBukkit end + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.allayRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.allayRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.allayControllable; ++ } ++ ++ @Override ++ protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ } ++ // Purpur end - Ridables ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +@@ -247,6 +282,7 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("allayBrain"); ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + profilerFiller.push("allayActivityUpdate"); +diff --git a/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/net/minecraft/world/entity/animal/armadillo/Armadillo.java +index dfdbcb31458095a71c187efc2774ecc4945dd11b..87a190d8646d8bbed8c182f9f0f7d8c398e63d26 100644 +--- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java ++++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java +@@ -80,6 +80,23 @@ public class Armadillo extends Animal { + return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 12.0).add(Attributes.MOVEMENT_SPEED, 0.14); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.armadilloRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.armadilloRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.armadilloControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/net/minecraft/world/entity/animal/axolotl/Axolotl.java +index 9faa929734035c167e54569ce34d841291856589..2054e4624da0c9b04ea69b9bf39443c4574d48be 100644 +--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java ++++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java +@@ -115,6 +115,23 @@ public class Axolotl extends Animal implements VariantHolder, B + this.lookControl = new Axolotl.AxolotlLookControl(this, 20); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.axolotlRidable; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.axolotlControllable; ++ } ++ ++ @Override ++ protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ } ++ // Purpur end - Ridables ++ + @Override + public float getWalkTargetValue(BlockPos pos, LevelReader level) { + return 0.0F; +@@ -304,6 +321,7 @@ public class Axolotl extends Animal implements VariantHolder, B + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("axolotlBrain"); ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + profilerFiller.push("axolotlActivityUpdate"); +@@ -555,23 +573,31 @@ public class Axolotl extends Animal implements VariantHolder, B + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (!Axolotl.this.isPlayingDead()) { +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + } + } + + static class AxolotlMoveControl extends SmoothSwimmingMoveControl { + private final Axolotl axolotl; ++ private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur - Ridables + + public AxolotlMoveControl(Axolotl axolotl) { + super(axolotl, 85, 10, 0.1F, 0.5F, false); + this.axolotl = axolotl; ++ waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(axolotl, 0.5D); // Purpur - Ridables + } + + @Override + public void tick() { ++ // Purpur start - Ridables ++ if (axolotl.getRider() != null && axolotl.isControllable()) { ++ waterController.purpurTick(axolotl.getRider()); ++ return; ++ } ++ // Purpur end - Ridables + if (!this.axolotl.isPlayingDead()) { + super.tick(); + } +diff --git a/net/minecraft/world/entity/animal/camel/Camel.java b/net/minecraft/world/entity/animal/camel/Camel.java +index 3ac169f83c5619b5c00c866354a2e066a0a738cc..11311d2ec37d825e73e2218e60e2606dd3a25a1d 100644 +--- a/net/minecraft/world/entity/animal/camel/Camel.java ++++ b/net/minecraft/world/entity/animal/camel/Camel.java +@@ -83,6 +83,13 @@ public class Camel extends AbstractHorse { + groundPathNavigation.setCanWalkOverFences(true); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.camelRidableInWater; ++ } ++ // Purpur end - Ridables ++ + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); +diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java +index 12c655b60087a2f6122ffa508b3224159d8777b0..9a400c8bf2b54aa5fbcbe65b61670cac5fbebf05 100644 +--- a/net/minecraft/world/entity/animal/frog/Frog.java ++++ b/net/minecraft/world/entity/animal/frog/Frog.java +@@ -106,6 +106,8 @@ public class Frog extends Animal implements VariantHolder> { + public final AnimationState croakAnimationState = new AnimationState(); + public final AnimationState tongueAnimationState = new AnimationState(); + public final AnimationState swimIdleAnimationState = new AnimationState(); ++ private org.purpurmc.purpur.controller.MoveControllerWASD purpurLandController; // Purpur - Ridables ++ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurWaterController; // Purpur - Ridables + + public Frog(EntityType entityType, Level level) { + super(entityType, level); +@@ -113,7 +115,55 @@ public class Frog extends Animal implements VariantHolder> { + this.setPathfindingMalus(PathType.WATER, 4.0F); + this.setPathfindingMalus(PathType.TRAPDOOR, -1.0F); + this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); ++ // Purpur start - Ridables ++ this.purpurLandController = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.2F); ++ this.purpurWaterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F); ++ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) { ++ @Override ++ public void tick() { ++ net.minecraft.world.entity.player.Player rider = mob.getRider(); ++ if (rider != null && mob.isControllable()) { ++ if (mob.isInWater()) { ++ purpurWaterController.purpurTick(rider); ++ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, -0.005D, 0.0D)); ++ } else { ++ purpurLandController.purpurTick(rider); ++ } ++ } else { ++ super.tick(); ++ } ++ } ++ }; ++ // Purpur end - Ridables ++ } ++ ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.frogRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.frogRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.frogControllable; ++ } ++ ++ @Override ++ protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ } ++ ++ @Override ++ public float getJumpPower() { ++ return (getRider() != null && isControllable()) ? level().purpurConfig.frogRidableJumpHeight * this.getBlockJumpFactor() : super.getJumpPower(); + } ++ // Purpur end - Ridables + + @Override + protected Brain.Provider brainProvider() { +@@ -188,6 +238,7 @@ public class Frog extends Animal implements VariantHolder> { + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("frogBrain"); ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + profilerFiller.push("frogActivityUpdate"); +@@ -380,7 +431,7 @@ public class Frog extends Animal implements VariantHolder> { + return level.getBlockState(pos.below()).is(BlockTags.FROGS_SPAWNABLE_ON) && isBrightEnoughToSpawn(level, pos); + } + +- class FrogLookControl extends LookControl { ++ class FrogLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables + FrogLookControl(final Mob mob) { + super(mob); + } +diff --git a/net/minecraft/world/entity/animal/frog/Tadpole.java b/net/minecraft/world/entity/animal/frog/Tadpole.java +index 97adf8142cdd322c4873c420ed760e9dee34da23..e888e606b4b14fa6485de7426bc146b6005962af 100644 +--- a/net/minecraft/world/entity/animal/frog/Tadpole.java ++++ b/net/minecraft/world/entity/animal/frog/Tadpole.java +@@ -63,13 +63,50 @@ public class Tadpole extends AbstractFish { + MemoryModuleType.IS_PANICKING + ); + public boolean ageLocked; // Paper ++ private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurController; // Purpur - Ridables + + public Tadpole(EntityType entityType, Level level) { + super(entityType, level); +- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); ++ // Purpur start - Ridables ++ this.purpurController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F); ++ this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) { ++ @Override ++ public void tick() { ++ Player rider = mob.getRider(); ++ if (rider != null && mob.isControllable()) { ++ purpurController.purpurTick(rider); ++ mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, 0.002D, 0.0D)); ++ } else { ++ super.tick(); ++ } ++ } ++ }; ++ // Purpur end - Ridables + this.lookControl = new SmoothSwimmingLookControl(this, 10); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.tadpoleRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.tadpoleRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.tadpoleControllable; ++ } ++ ++ @Override ++ protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ } ++ // Purpur end - Ridables ++ + @Override + protected PathNavigation createNavigation(Level level) { + return new WaterBoundPathNavigation(this, level); +@@ -99,6 +136,7 @@ public class Tadpole extends AbstractFish { + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("tadpoleBrain"); ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + profilerFiller.push("tadpoleActivityUpdate"); +diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java +index 7b73d4134d30ba8edb69785a2e2eb2d89b2341a7..302208b566038a3a352ca867dd70a61887bac104 100644 +--- a/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/net/minecraft/world/entity/animal/goat/Goat.java +@@ -111,6 +111,23 @@ public class Goat extends Animal { + .orElseGet(() -> new ItemStack(Items.GOAT_HORN)); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.goatRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.goatRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.goatControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +@@ -188,6 +205,7 @@ public class Goat extends Animal { + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("goatBrain"); ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + profilerFiller.push("goatActivityUpdate"); +diff --git a/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/net/minecraft/world/entity/animal/horse/AbstractHorse.java +index d52a8315f1e6876c26c732f4c4caa47bc6bebf6e..828406060e50ff62586929371aafb46ef7d81f92 100644 +--- a/net/minecraft/world/entity/animal/horse/AbstractHorse.java ++++ b/net/minecraft/world/entity/animal/horse/AbstractHorse.java +@@ -206,11 +206,21 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + + protected AbstractHorse(EntityType entityType, Level level) { + super(entityType, level); ++ this.moveControl = new net.minecraft.world.entity.ai.control.MoveControl(this); // Purpur - use vanilla controller ++ this.lookControl = new net.minecraft.world.entity.ai.control.LookControl(this); // Purpur - use vanilla controller + this.createInventory(); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return false; // vanilla handles ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new PanicGoal(this, 1.2)); + this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2)); + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0, AbstractHorse.class)); +@@ -221,6 +231,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + if (this.canPerformRearing()) { + this.goalSelector.addGoal(9, new RandomStandGoal(this)); + } ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables + + this.addBehaviourGoals(); + } +diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java +index 9b97f3d3675f5051b18a68ff7fa056d859a283e9..ee3fa710e95f2e84f7f9bdce1159d1136815172d 100644 +--- a/net/minecraft/world/entity/animal/horse/Donkey.java ++++ b/net/minecraft/world/entity/animal/horse/Donkey.java +@@ -16,6 +16,13 @@ public class Donkey extends AbstractChestedHorse { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.donkeyRidableInWater; ++ } ++ // Purpur end - Ridables ++ + @Override + protected SoundEvent getAmbientSound() { + return SoundEvents.DONKEY_AMBIENT; +diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java +index c6d0700f29d6c8123e96efe225faf2d99202ac81..361bf346153912bcbfcf962d7f716dfe12ae2a7b 100644 +--- a/net/minecraft/world/entity/animal/horse/Horse.java ++++ b/net/minecraft/world/entity/animal/horse/Horse.java +@@ -43,6 +43,13 @@ public class Horse extends AbstractHorse implements VariantHolder { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.horseRidableInWater; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void randomizeAttributes(RandomSource random) { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt)); +diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java +index 7d4aad3c45d710488aba540ee5a535098ddd27ee..164a429d432badcb315e8ece406e29e576a11265 100644 +--- a/net/minecraft/world/entity/animal/horse/Llama.java ++++ b/net/minecraft/world/entity/animal/horse/Llama.java +@@ -78,7 +78,51 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entityType, Level level) { + super(EntityType.ENDER_DRAGON, level); +@@ -106,6 +107,37 @@ public class EnderDragon extends Mob implements Enemy { + this.noPhysics = true; + this.phaseManager = new EnderDragonPhaseManager(this); + this.explosionSource = new net.minecraft.world.level.ServerExplosion(level.getMinecraftWorld(), this, null, null, new Vec3(Double.NaN, Double.NaN, Double.NaN), Float.NaN, true, net.minecraft.world.level.Explosion.BlockInteraction.DESTROY); // Paper ++ ++ // Purpur start - Ridables ++ this.moveControl = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this) { ++ @Override ++ public void vanillaTick() { ++ // dragon doesn't use the controller. do nothing ++ } ++ }; ++ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) { ++ @Override ++ public void vanillaTick() { ++ // dragon doesn't use the controller. do nothing ++ } ++ ++ @Override ++ public void purpurTick(Player rider) { ++ setYawPitch(rider.getYRot() - 180F, rider.xRotO * 0.5F); ++ } ++ }; ++ // Purpur end - Ridables ++ } ++ ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.enderDragonRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.enderDragonRidableInWater; + } + + public void setDragonFight(EndDragonFight dragonFight) { +@@ -120,6 +152,17 @@ public class EnderDragon extends Mob implements Enemy { + return this.fightOrigin; + } + ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.enderDragonControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.enderDragonMaxY; ++ } ++ // Purpur end - Ridables ++ + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0); + } +@@ -169,6 +212,37 @@ public class EnderDragon extends Mob implements Enemy { + + @Override + public void aiStep() { ++ // Purpur start - Ridables ++ boolean hasRider = getRider() != null && this.isControllable(); ++ if (hasRider) { ++ if (!hadRider) { ++ hadRider = true; ++ noPhysics = false; ++ this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(4.0F, 2.0F); ++ } ++ ++ // dragon doesn't use controllers, so must tick manually ++ moveControl.tick(); ++ lookControl.tick(); ++ ++ moveRelative((float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F, new Vec3(-getStrafeMot(), getVerticalMot(), -getForwardMot())); ++ Vec3 mot = getDeltaMovement(); ++ setDeltaMovement(mot); ++ move(MoverType.PLAYER, mot); ++ ++ mot = mot.multiply(0.9F, 0.9F, 0.9F); ++ setDeltaMovement(mot); ++ ++ // control wing flap speed on client ++ phaseManager.setPhase(mot.x() * mot.x() + mot.z() * mot.z() < 0.005F ? EnderDragonPhase.HOVERING : EnderDragonPhase.HOLDING_PATTERN); ++ } else if (hadRider) { ++ hadRider = false; ++ noPhysics = true; ++ this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(16.0F, 8.0F); ++ phaseManager.setPhase(EnderDragonPhase.HOLDING_PATTERN); // HoldingPattern ++ } ++ // Purpur end - Ridables ++ + this.processFlappingMovement(); + if (this.level().isClientSide) { + this.setHealth(this.getHealth()); +@@ -197,6 +271,8 @@ public class EnderDragon extends Mob implements Enemy { + + this.oFlapTime = this.flapTime; + if (this.isDeadOrDying()) { ++ if (hasRider) ejectPassengers(); // Purpur - Ridables ++ + float f = (this.random.nextFloat() - 0.5F) * 8.0F; + float f1 = (this.random.nextFloat() - 0.5F) * 4.0F; + float f2 = (this.random.nextFloat() - 0.5F) * 8.0F; +@@ -206,9 +282,9 @@ public class EnderDragon extends Mob implements Enemy { + Vec3 deltaMovement = this.getDeltaMovement(); + float f1 = 0.2F / ((float)deltaMovement.horizontalDistance() * 10.0F + 1.0F); + f1 *= (float)Math.pow(2.0, deltaMovement.y); +- if (this.phaseManager.getCurrentPhase().isSitting()) { ++ if (!hasRider && this.phaseManager.getCurrentPhase().isSitting()) { // Purpur - Ridables + this.flapTime += 0.1F; +- } else if (this.inWall) { ++ } else if (!hasRider && this.inWall) { // Purpur - Ridables + this.flapTime += f1 * 0.5F; + } else { + this.flapTime += f1; +@@ -219,7 +295,7 @@ public class EnderDragon extends Mob implements Enemy { + this.flapTime = 0.5F; + } else { + this.flightHistory.record(this.getY(), this.getYRot()); +- if (this.level() instanceof ServerLevel serverLevel1) { ++ if (this.level() instanceof ServerLevel serverLevel1 && !hasRider) { // Purpur - Ridables + DragonPhaseInstance currentPhase = this.phaseManager.getCurrentPhase(); + currentPhase.doServerTick(serverLevel1); + if (this.phaseManager.getCurrentPhase() != currentPhase) { +@@ -298,7 +374,7 @@ public class EnderDragon extends Mob implements Enemy { + this.tickPart(this.body, sin1 * 0.5F, 0.0, -cos1 * 0.5F); + this.tickPart(this.wing1, cos1 * 4.5F, 2.0, sin1 * 4.5F); + this.tickPart(this.wing2, cos1 * -4.5F, 2.0, sin1 * -4.5F); +- if (this.level() instanceof ServerLevel serverLevel2 && this.hurtTime == 0) { ++ if (this.level() instanceof ServerLevel serverLevel2 && this.hurtTime == 0 && !hasRider) { // Purpur - Ridables + this.knockBack( + serverLevel2, + serverLevel2.getEntities( +@@ -348,9 +424,9 @@ public class EnderDragon extends Mob implements Enemy { + } + + if (this.level() instanceof ServerLevel serverLevel3) { +- this.inWall = this.checkWalls(serverLevel3, this.head.getBoundingBox()) ++ this.inWall = !hasRider && this.checkWalls(serverLevel3, this.head.getBoundingBox()) + | this.checkWalls(serverLevel3, this.neck.getBoundingBox()) +- | this.checkWalls(serverLevel3, this.body.getBoundingBox()); ++ | this.checkWalls(serverLevel3, this.body.getBoundingBox()); // Purpur - Ridables + if (this.dragonFight != null) { + this.dragonFight.updateDragon(this); + } +diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java +index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc508815a3 100644 +--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java ++++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -69,6 +69,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { + private final int[] nextHeadUpdate = new int[2]; + private final int[] idleHeadUpdates = new int[2]; + private int destroyBlocksTick; ++ private int shootCooldown = 0; // Purpur - Ridables + private boolean canPortal = false; // Paper + public final ServerBossEvent bossEvent = (ServerBossEvent)new ServerBossEvent( + this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS +@@ -78,9 +79,23 @@ public class WitherBoss extends Monster implements RangedAttackMob { + && entity.attackable(); + private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0).selector(LIVING_ENTITY_SELECTOR); + @Nullable private java.util.UUID summoner; // Purpur - Summoner API ++ private org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD purpurController; // Purpur - Ridables + + public WitherBoss(EntityType entityType, Level level) { + super(entityType, level); ++ // Purpur start - Ridables ++ this.purpurController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.1F); ++ this.moveControl = new FlyingMoveControl(this, 10, false) { ++ @Override ++ public void tick() { ++ if (mob.getRider() != null && mob.isControllable()) { ++ purpurController.purpurTick(mob.getRider()); ++ } else { ++ super.tick(); ++ } ++ } ++ }; ++ // Purpur end - Ridables + this.moveControl = new FlyingMoveControl(this, 10, false); + this.setHealth(this.getMaxHealth()); + this.xpReward = 50; +@@ -97,6 +112,105 @@ public class WitherBoss extends Monster implements RangedAttackMob { + } + // Purpur end - Summoner API + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.witherRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.witherControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.witherMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && this.isControllable() && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 5F; ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.5, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ this.entityData.set(DATA_TARGETS.get(0), 0); ++ this.entityData.set(DATA_TARGETS.get(1), 0); ++ this.entityData.set(DATA_TARGETS.get(2), 0); ++ getNavigation().stop(); ++ shootCooldown = 20; ++ } ++ ++ @Override ++ public boolean onClick(net.minecraft.world.InteractionHand hand) { ++ return shoot(getRider(), hand == net.minecraft.world.InteractionHand.MAIN_HAND ? new int[]{1} : new int[]{2}); ++ } ++ ++ public boolean shoot(@Nullable Player rider, int[] heads) { ++ if (shootCooldown > 0) { ++ return false; ++ } ++ ++ shootCooldown = 20; ++ if (rider == null) { ++ return false; ++ } ++ ++ org.bukkit.craftbukkit.entity.CraftHumanEntity player = rider.getBukkitEntity(); ++ if (!player.hasPermission("allow.special.wither")) { ++ return false; ++ } ++ ++ net.minecraft.world.phys.HitResult rayTrace = getRayTrace(120, net.minecraft.world.level.ClipContext.Fluid.NONE); ++ if (rayTrace == null) { ++ return false; ++ } ++ ++ Vec3 loc; ++ if (rayTrace.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK) { ++ BlockPos pos = ((net.minecraft.world.phys.BlockHitResult) rayTrace).getBlockPos(); ++ loc = new Vec3(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D); ++ } else if (rayTrace.getType() == net.minecraft.world.phys.HitResult.Type.ENTITY) { ++ Entity target = ((net.minecraft.world.phys.EntityHitResult) rayTrace).getEntity(); ++ loc = new Vec3(target.getX(), target.getY() + (target.getEyeHeight() / 2), target.getZ()); ++ } else { ++ org.bukkit.block.Block block = player.getTargetBlock(null, 120); ++ loc = new Vec3(block.getX() + 0.5D, block.getY() + 0.5D, block.getZ() + 0.5D); ++ } ++ ++ for (int head : heads) { ++ shoot(head, loc.x(), loc.y(), loc.z(), rider); ++ } ++ ++ return true; // handled ++ } ++ ++ public void shoot(int head, double x, double y, double z, Player rider) { ++ level().levelEvent(null, 1024, blockPosition(), 0); ++ double headX = getHeadX(head); ++ double headY = getHeadY(head); ++ double headZ = getHeadZ(head); ++ Vec3 vec3d = new Vec3(x - headX, y - headY, z - headZ); ++ WitherSkull skull = new WitherSkull(level(), this, vec3d.normalize()); ++ skull.setPosRaw(headX, headY, headZ); ++ level().addFreshEntity(skull); ++ } ++ // Purpur end - Ridables ++ + @Override + protected PathNavigation createNavigation(Level level) { + FlyingPathNavigation flyingPathNavigation = new FlyingPathNavigation(this, level); +@@ -107,11 +221,13 @@ public class WitherBoss extends Monster implements RangedAttackMob { + + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(0, new WitherBoss.WitherDoNothingGoal()); + this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0, 40, 20.0F)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomFlyingGoal(this, 1.0)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 0, false, false, LIVING_ENTITY_SELECTOR)); + } +@@ -271,6 +387,15 @@ public class WitherBoss extends Monster implements RangedAttackMob { + + @Override + protected void customServerAiStep(ServerLevel level) { ++ // Purpur start - Ridables ++ if (getRider() != null && this.isControllable()) { ++ Vec3 mot = getDeltaMovement(); ++ setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); ++ } ++ if (shootCooldown > 0) { ++ shootCooldown--; ++ } ++ // Purpur end - Ridables + if (this.getInvulnerableTicks() > 0) { + int i = this.getInvulnerableTicks() - 1; + this.bossEvent.setProgress(1.0F - i / 220.0F); +@@ -577,11 +702,11 @@ public class WitherBoss extends Monster implements RangedAttackMob { + } + + public int getAlternativeTarget(int head) { +- return this.entityData.get(DATA_TARGETS.get(head)); ++ return getRider() != null && this.isControllable() ? 0 : this.entityData.get(DATA_TARGETS.get(head)); // Purpur - Ridables + } + + public void setAlternativeTarget(int targetOffset, int newId) { +- this.entityData.set(DATA_TARGETS.get(targetOffset), newId); ++ if (getRider() == null || !this.isControllable()) this.entityData.set(DATA_TARGETS.get(targetOffset), newId); // Purpur - Ridables + } + + public boolean isPowered() { +diff --git a/net/minecraft/world/entity/monster/AbstractSkeleton.java b/net/minecraft/world/entity/monster/AbstractSkeleton.java +index 1e97cb34aa22ad3150b598232dd339213b236f5c..e186aee80b052b7fc4bfe02763010bfb2d55ea35 100644 +--- a/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -73,12 +73,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(2, new RestrictSunGoal(this)); + this.goalSelector.addGoal(3, new FleeSunGoal(this, 1.0)); + this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Wolf.class, 6.0F, 1.0, 1.2)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); +diff --git a/net/minecraft/world/entity/monster/Blaze.java b/net/minecraft/world/entity/monster/Blaze.java +index 419c729502ee708bba9e750f1b951450eca82695..201b08a75c42d90e657c3d56fc6691839e87199c 100644 +--- a/net/minecraft/world/entity/monster/Blaze.java ++++ b/net/minecraft/world/entity/monster/Blaze.java +@@ -33,6 +33,7 @@ public class Blaze extends Monster { + + public Blaze(EntityType entityType, Level level) { + super(entityType, level); ++ this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur - Ridables + this.setPathfindingMalus(PathType.WATER, -1.0F); + this.setPathfindingMalus(PathType.LAVA, 8.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); +@@ -40,19 +41,55 @@ public class Blaze extends Monster { + this.xpReward = 10; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.blazeRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.blazeRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.blazeControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.blazeMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && this.isControllable() && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(4, new Blaze.BlazeAttackGoal(this)); + this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 0.0F)); + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers()); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); + } + + public static AttributeSupplier.Builder createAttributes() { +- return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0); ++ return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - Ridables + } + + @Override +@@ -117,6 +154,13 @@ public class Blaze extends Monster { + + @Override + protected void customServerAiStep(ServerLevel level) { ++ // Purpur start - Ridables ++ if (getRider() != null && this.isControllable()) { ++ Vec3 mot = getDeltaMovement(); ++ setDeltaMovement(mot.x(), getVerticalMot() > 0 ? 0.07D : -0.07D, mot.z()); ++ return; ++ } ++ // Purpur end - Ridables + this.nextHeightOffsetChangeTick--; + if (this.nextHeightOffsetChangeTick <= 0) { + this.nextHeightOffsetChangeTick = 100; +diff --git a/net/minecraft/world/entity/monster/Bogged.java b/net/minecraft/world/entity/monster/Bogged.java +index f01670f7106a39957c9b37839fcca0d9f29208f0..2b603c1242aac307f28bae5a85bcaad309f929f5 100644 +--- a/net/minecraft/world/entity/monster/Bogged.java ++++ b/net/minecraft/world/entity/monster/Bogged.java +@@ -41,6 +41,23 @@ public class Bogged extends AbstractSkeleton implements Shearable { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.boggedRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.boggedRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.boggedControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/monster/CaveSpider.java b/net/minecraft/world/entity/monster/CaveSpider.java +index 2e32567fca7a2a4cd87bc078a6eeb30e3ffabfce..4873a3d8dd9c160ecdbda594ee546c35ec03a1e7 100644 +--- a/net/minecraft/world/entity/monster/CaveSpider.java ++++ b/net/minecraft/world/entity/monster/CaveSpider.java +@@ -26,6 +26,23 @@ public class CaveSpider extends Spider { + return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.caveSpiderRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.caveSpiderRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.caveSpiderControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + public boolean doHurtTarget(ServerLevel level, Entity source) { + if (super.doHurtTarget(level, source)) { +diff --git a/net/minecraft/world/entity/monster/Creeper.java b/net/minecraft/world/entity/monster/Creeper.java +index 9aff3c911a56885ab3c34bb34bb05e7b1c00d3bd..cdcee233ed0c272e4a68a2a709fe92b21bc6c22c 100644 +--- a/net/minecraft/world/entity/monster/Creeper.java ++++ b/net/minecraft/world/entity/monster/Creeper.java +@@ -51,21 +51,98 @@ public class Creeper extends Monster { + private int droppedSkulls; + public Entity entityIgniter; // CraftBukkit + private boolean exploding = false; // Purpur - Config to make Creepers explode on death ++ // Purpur start - Ridables ++ private int spacebarCharge = 0; ++ private int prevSpacebarCharge = 0; ++ private int powerToggleDelay = 0; ++ // Purpur end - Ridables + + public Creeper(EntityType entityType, Level level) { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.creeperRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.creeperRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.creeperControllable; ++ } ++ ++ @Override ++ protected void customServerAiStep(ServerLevel world) { ++ if (powerToggleDelay > 0) { ++ powerToggleDelay--; ++ } ++ if (getRider() != null && this.isControllable()) { ++ if (getRider().getForwardMot() != 0 || getRider().getStrafeMot() != 0) { ++ spacebarCharge = 0; ++ setIgnited(false); ++ setSwellDir(-1); ++ } ++ if (spacebarCharge == prevSpacebarCharge) { ++ spacebarCharge = 0; ++ } ++ prevSpacebarCharge = spacebarCharge; ++ } ++ super.customServerAiStep(world); ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ setIgnited(false); ++ setSwellDir(-1); ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (powerToggleDelay > 0) { ++ return true; // just toggled power, do not jump or ignite ++ } ++ spacebarCharge++; ++ if (spacebarCharge > maxSwell - 2) { ++ spacebarCharge = 0; ++ if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.powered.creeper")) { ++ powerToggleDelay = 20; ++ setPowered(!isPowered()); ++ setIgnited(false); ++ setSwellDir(-1); ++ return true; ++ } ++ } ++ if (!isIgnited()) { ++ if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0 && ++ getRider().getBukkitEntity().hasPermission("allow.special.creeper")) { ++ setIgnited(true); ++ setSwellDir(1); ++ return true; ++ } ++ } ++ return getForwardMot() == 0 && getStrafeMot() == 0; // do not jump if standing still ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(2, new SwellGoal(this)); ++ this.goalSelector.addGoal(3, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Ocelot.class, 6.0F, 1.0, 1.2)); + this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Cat.class, 6.0F, 1.0, 1.2)); + this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, false)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true)); + this.targetSelector.addGoal(2, new HurtByTargetGoal(this)); + } +@@ -312,6 +389,7 @@ public class Creeper extends Monster { + com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited); + if (event.callEvent()) { + this.entityData.set(DATA_IS_IGNITED, event.isIgnited()); ++ if (!event.isIgnited()) setSwellDir(-1); // Purpur - Ridables + } + } + } +diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java +index 6c1e816356243686f7d0bfa031badc75b54b215d..c1da9ebee7e870a9143e6224be9e9f4e62232459 100644 +--- a/net/minecraft/world/entity/monster/Drowned.java ++++ b/net/minecraft/world/entity/monster/Drowned.java +@@ -75,6 +75,23 @@ public class Drowned extends Zombie implements RangedAttackMob { + return Zombie.createAttributes().add(Attributes.STEP_HEIGHT, 1.0); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.drownedRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.drownedRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.drownedControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void addBehaviourGoals() { + this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0)); +@@ -408,7 +425,7 @@ public class Drowned extends Zombie implements RangedAttackMob { + } + } + +- static class DrownedMoveControl extends MoveControl { ++ static class DrownedMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables + private final Drowned drowned; + + public DrownedMoveControl(Drowned mob) { +@@ -417,7 +434,7 @@ public class Drowned extends Zombie implements RangedAttackMob { + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + LivingEntity target = this.drowned.getTarget(); + if (this.drowned.wantsToSwim() && this.drowned.isInWater()) { + if (target != null && target.getY() > this.drowned.getY() || this.drowned.searchingForLand) { +@@ -437,7 +454,7 @@ public class Drowned extends Zombie implements RangedAttackMob { + float f = (float)(Mth.atan2(d2, d) * 180.0F / (float)Math.PI) - 90.0F; + this.drowned.setYRot(this.rotlerp(this.drowned.getYRot(), f, 90.0F)); + this.drowned.yBodyRot = this.drowned.getYRot(); +- float f1 = (float)(this.speedModifier * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); ++ float f1 = (float)(this.getSpeedModifier() * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables + float f2 = Mth.lerp(0.125F, this.drowned.getSpeed(), f1); + this.drowned.setSpeed(f2); + this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(f2 * d * 0.005, f2 * d1 * 0.1, f2 * d2 * 0.005)); +@@ -446,7 +463,7 @@ public class Drowned extends Zombie implements RangedAttackMob { + this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(0.0, -0.008, 0.0)); + } + +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + } + } +diff --git a/net/minecraft/world/entity/monster/ElderGuardian.java b/net/minecraft/world/entity/monster/ElderGuardian.java +index 4585b7c867685f8419c4d2b5b90af5946d337f90..c6eeaf7b460408acfdf89d988b47b08eab7df4c5 100644 +--- a/net/minecraft/world/entity/monster/ElderGuardian.java ++++ b/net/minecraft/world/entity/monster/ElderGuardian.java +@@ -31,6 +31,18 @@ public class ElderGuardian extends Guardian { + } + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.elderGuardianRidable; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.elderGuardianControllable; ++ } ++ // Purpur end - Ridables ++ + public static AttributeSupplier.Builder createAttributes() { + return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.ATTACK_DAMAGE, 8.0).add(Attributes.MAX_HEALTH, 80.0); + } +diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java +index 8709588083fd5ca6a31d9a8d4096475d117915a1..cf511c78638e0d7aa652d1c880b3cd8172d5b3cf 100644 +--- a/net/minecraft/world/entity/monster/EnderMan.java ++++ b/net/minecraft/world/entity/monster/EnderMan.java +@@ -90,9 +90,27 @@ public class EnderMan extends Monster implements NeutralMob { + this.setPathfindingMalus(PathType.WATER, -1.0F); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.endermanRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.endermanRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.endermanControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new EnderMan.EndermanFreezeWhenLookedAt(this)); + this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0, false)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 0.0F)); +@@ -100,6 +118,7 @@ public class EnderMan extends Monster implements NeutralMob { + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.goalSelector.addGoal(10, new EnderMan.EndermanLeaveBlockGoal(this)); + this.goalSelector.addGoal(11, new EnderMan.EndermanTakeBlockGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt)); + this.targetSelector.addGoal(2, new HurtByTargetGoal(this)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, 10, true, false, (entityliving, ignored) -> entityliving.level().purpurConfig.endermanAggroEndermites && entityliving instanceof Endermite endermite && (!entityliving.level().purpurConfig.endermanAggroEndermitesOnlyIfPlayerSpawned || endermite.isPlayerSpawned()))); // Purpur +@@ -272,7 +291,7 @@ public class EnderMan extends Monster implements NeutralMob { + + @Override + protected void customServerAiStep(ServerLevel level) { +- if (level.isDay() && this.tickCount >= this.targetChangeTime + 600) { ++ if ((getRider() == null || !this.isControllable()) && level.isDay() && this.tickCount >= this.targetChangeTime + 600) { // Purpur - Ridables - no random teleporting + float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue(); + if (lightLevelDependentMagicValue > 0.5F + && level.canSeeSky(this.blockPosition()) +@@ -385,6 +404,7 @@ public class EnderMan extends Monster implements NeutralMob { + public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { + if (this.isInvulnerableTo(level, damageSource)) { + return false; ++ } else if (getRider() != null && this.isControllable()) { return super.hurtServer(level, damageSource, amount); // Purpur - no teleporting on damage + } else if (org.purpurmc.purpur.PurpurConfig.endermanShortHeight && damageSource.is(net.minecraft.world.damagesource.DamageTypes.IN_WALL)) { return false; // Purpur - no suffocation damage if short height - Short enderman height + } else { + boolean flag = damageSource.getDirectEntity() instanceof ThrownPotion; +diff --git a/net/minecraft/world/entity/monster/Endermite.java b/net/minecraft/world/entity/monster/Endermite.java +index 4e00daa6ece386f70502c074084b7b1b64caac2f..f4ab2e984dd87d2372aa10d2cbfd03a3f6fb1249 100644 +--- a/net/minecraft/world/entity/monster/Endermite.java ++++ b/net/minecraft/world/entity/monster/Endermite.java +@@ -45,14 +45,33 @@ public class Endermite extends Monster { + } + // Purpur end - Add back player spawned endermite API + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.endermiteRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.endermiteRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.endermiteControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level())); + this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0, false)); + this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers()); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); + } +diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java +index b70ea1af39cada6bb17001c6b65502510e34c4b2..2eaeb0c0c0cb917506443ed1380b81f317961d53 100644 +--- a/net/minecraft/world/entity/monster/Evoker.java ++++ b/net/minecraft/world/entity/monster/Evoker.java +@@ -50,10 +50,28 @@ public class Evoker extends SpellcasterIllager { + this.xpReward = 10; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.evokerRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.evokerRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.evokerControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new Evoker.EvokerCastingSpellGoal()); + this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6, 1.0)); + this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 0.6, 1.0)); +@@ -63,6 +81,7 @@ public class Evoker extends SpellcasterIllager { + this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6)); + this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); + this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true).setUnseenMemoryTicks(300)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false).setUnseenMemoryTicks(300)); +diff --git a/net/minecraft/world/entity/monster/Ghast.java b/net/minecraft/world/entity/monster/Ghast.java +index b97bbfbbc8c1a4f38b4b858ef4915b637cc8a627..00c05fb5736c90c94f6fe51793acf8b65b1d0505 100644 +--- a/net/minecraft/world/entity/monster/Ghast.java ++++ b/net/minecraft/world/entity/monster/Ghast.java +@@ -42,11 +42,47 @@ public class Ghast extends FlyingMob implements Enemy { + this.moveControl = new Ghast.GhastMoveControl(this); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.ghastRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ghastRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.ghastControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.ghastMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && this.isControllable() && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(5, new Ghast.RandomFloatAroundGoal(this)); + this.goalSelector.addGoal(7, new Ghast.GhastLookGoal(this)); + this.goalSelector.addGoal(7, new Ghast.GhastShootFireballGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector + .addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> Math.abs(entity.getY() - this.getY()) <= 4.0)); + } +@@ -101,7 +137,7 @@ public class Ghast extends FlyingMob implements Enemy { + } + + public static AttributeSupplier.Builder createAttributes() { +- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.FOLLOW_RANGE, 100.0); ++ return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.FOLLOW_RANGE, 100.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - Ridables + } + + @Override +@@ -191,7 +227,7 @@ public class Ghast extends FlyingMob implements Enemy { + } + } + +- static class GhastMoveControl extends MoveControl { ++ static class GhastMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables + private final Ghast ghast; + private int floatDuration; + +@@ -201,7 +237,7 @@ public class Ghast extends FlyingMob implements Enemy { + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (this.operation == MoveControl.Operation.MOVE_TO) { + if (this.floatDuration-- <= 0) { + this.floatDuration = this.floatDuration + this.ghast.getRandom().nextInt(5) + 2; +diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java +index 969eb604851d1cce50f0f99ed479189061d5de0c..135f83484ac31db7dcc225ba6f94e2e4ca27eea8 100644 +--- a/net/minecraft/world/entity/monster/Giant.java ++++ b/net/minecraft/world/entity/monster/Giant.java +@@ -12,6 +12,29 @@ public class Giant extends Monster { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.giantRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.giantRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.giantControllable; ++ } ++ ++ @Override ++ protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); ++ } ++ // Purpur end - Ridables ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0); + } +diff --git a/net/minecraft/world/entity/monster/Guardian.java b/net/minecraft/world/entity/monster/Guardian.java +index c8e249b8f7ee8e9c075169ec988f5a0d459a3767..c20c744522459d938c772077e542ba433bc4c80e 100644 +--- a/net/minecraft/world/entity/monster/Guardian.java ++++ b/net/minecraft/world/entity/monster/Guardian.java +@@ -66,14 +66,35 @@ public class Guardian extends Monster { + this.xpReward = 10; + this.setPathfindingMalus(PathType.WATER, 0.0F); + this.moveControl = new Guardian.GuardianMoveControl(this); ++ // Purpur start - Ridables ++ this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) { ++ @Override ++ public void setYawPitch(float yaw, float pitch) { ++ super.setYawPitch(yaw, pitch * 0.35F); ++ } ++ }; ++ // Purpur end - Ridables + this.clientSideTailAnimation = this.random.nextFloat(); + this.clientSideTailAnimationO = this.clientSideTailAnimation; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.guardianRidable; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.guardianControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + MoveTowardsRestrictionGoal moveTowardsRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0); + this.randomStrollGoal = new RandomStrollGoal(this, 1.0, 80); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(4, this.guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field + this.goalSelector.addGoal(5, moveTowardsRestrictionGoal); + this.goalSelector.addGoal(7, this.randomStrollGoal); +@@ -82,6 +103,7 @@ public class Guardian extends Monster { + this.goalSelector.addGoal(9, new RandomLookAroundGoal(this)); + this.randomStrollGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); + moveTowardsRestrictionGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 10, true, false, new Guardian.GuardianAttackSelector(this))); + } + +@@ -344,7 +366,7 @@ public class Guardian extends Monster { + @Override + public void travel(Vec3 travelVector) { + if (this.isControlledByLocalInstance() && this.isInWater()) { +- this.moveRelative(0.1F, travelVector); ++ this.moveRelative(getRider() != null && this.isControllable() ? getSpeed() : 0.1F, travelVector); // Purpur - Ridables + this.move(MoverType.SELF, this.getDeltaMovement()); + this.setDeltaMovement(this.getDeltaMovement().scale(0.9)); + if (!this.isMoving() && this.getTarget() == null) { +@@ -452,7 +474,7 @@ public class Guardian extends Monster { + } + } + +- static class GuardianMoveControl extends MoveControl { ++ static class GuardianMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur - Ridables + private final Guardian guardian; + + public GuardianMoveControl(Guardian mob) { +@@ -460,8 +482,17 @@ public class Guardian extends Monster { + this.guardian = mob; + } + ++ // Purpur start - Ridables + @Override +- public void tick() { ++ public void purpurTick(Player rider) { ++ super.purpurTick(rider); ++ guardian.setDeltaMovement(guardian.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); ++ guardian.setMoving(guardian.getForwardMot() > 0.0F); // control tail speed ++ } ++ // Purpur end - Ridables ++ ++ @Override ++ public void vanillaTick() { // Purpur - Ridables + if (this.operation == MoveControl.Operation.MOVE_TO && !this.guardian.getNavigation().isDone()) { + Vec3 vec3 = new Vec3(this.wantedX - this.guardian.getX(), this.wantedY - this.guardian.getY(), this.wantedZ - this.guardian.getZ()); + double len = vec3.length(); +@@ -471,7 +502,7 @@ public class Guardian extends Monster { + float f = (float)(Mth.atan2(vec3.z, vec3.x) * 180.0F / (float)Math.PI) - 90.0F; + this.guardian.setYRot(this.rotlerp(this.guardian.getYRot(), f, 90.0F)); + this.guardian.yBodyRot = this.guardian.getYRot(); +- float f1 = (float)(this.speedModifier * this.guardian.getAttributeValue(Attributes.MOVEMENT_SPEED)); ++ float f1 = (float)(this.getSpeedModifier() * this.guardian.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables + float f2 = Mth.lerp(0.125F, this.guardian.getSpeed(), f1); + this.guardian.setSpeed(f2); + double d3 = Math.sin((this.guardian.tickCount + this.guardian.getId()) * 0.5) * 0.05; +diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java +index 6155c544ad2722a49c5e41dd7d7b02fedc56474e..23936305045299352561e866b6a28aa515cd614a 100644 +--- a/net/minecraft/world/entity/monster/Husk.java ++++ b/net/minecraft/world/entity/monster/Husk.java +@@ -21,6 +21,23 @@ public class Husk extends Zombie { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.huskRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.huskRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.huskControllable; ++ } ++ // Purpur end - Ridables ++ + public static boolean checkHuskSpawnRules( + EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java +index 40ca12e391b2adac6b132f1832b1427acb3748bc..bd0f4d77260f5b123856fc7e72d5f8e74bb45321 100644 +--- a/net/minecraft/world/entity/monster/Illusioner.java ++++ b/net/minecraft/world/entity/monster/Illusioner.java +@@ -57,10 +57,28 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { + } + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.illusionerRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.illusionerRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.illusionerControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new SpellcasterIllager.SpellcasterCastingSpellGoal()); + this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2)); + this.goalSelector.addGoal(4, new Illusioner.IllusionerMirrorSpellGoal()); +@@ -69,6 +87,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { + this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6)); + this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); + this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true).setUnseenMemoryTicks(300)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false).setUnseenMemoryTicks(300)); +diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java +index 905ecbd8b22c785ee4ea18004ac50eb1b7005d3f..f10b204c18b88e9110cebf050b60c23367ea3aa0 100644 +--- a/net/minecraft/world/entity/monster/MagmaCube.java ++++ b/net/minecraft/world/entity/monster/MagmaCube.java +@@ -24,6 +24,28 @@ public class MagmaCube extends Slime { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.magmaCubeRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.magmaCubeRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.magmaCubeControllable; ++ } ++ ++ @Override ++ public float getJumpPower() { ++ return 0.42F * this.getBlockJumpFactor(); // from EntityLiving ++ } ++ // Purpur end - Ridables ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); + } +@@ -71,6 +93,7 @@ public class MagmaCube extends Slime { + float f = this.getSize() * 0.1F; + this.setDeltaMovement(deltaMovement.x, this.getJumpPower() + f, deltaMovement.z); + this.hasImpulse = true; ++ this.actualJump = false; // Purpur - Ridables + } + + @Override +diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java +index 9ea3acd5ff3d7751875d61861aa5f6c717d0b5e2..75c6a43a3ab4851a47990402bee49f7e8305cd60 100644 +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -60,6 +60,64 @@ public class Phantom extends FlyingMob implements Enemy { + this.lookControl = new Phantom.PhantomLookControl(this); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.phantomRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.phantomRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.phantomControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.phantomMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && this.isControllable() && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ ++ public static net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder createAttributes() { ++ return Monster.createMonsterAttributes().add(Attributes.FLYING_SPEED, 3.0D); ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.special.phantom")) { ++ shoot(); ++ } ++ return false; ++ } ++ ++ public boolean shoot() { ++ org.bukkit.Location loc = ((org.bukkit.entity.LivingEntity) getBukkitEntity()).getEyeLocation(); ++ loc.setPitch(-loc.getPitch()); ++ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(100).add(loc.toVector()); ++ ++ org.purpurmc.purpur.entity.projectile.PhantomFlames flames = new org.purpurmc.purpur.entity.projectile.PhantomFlames(level(), this); ++ flames.canGrief = level().purpurConfig.phantomAllowGriefing; ++ flames.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), 1.0F, 5.0F); ++ level().addFreshEntity(flames); ++ return true; ++ } ++ // Purpur end - Ridables ++ + @Override + public boolean isFlapping() { + return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0; +@@ -72,9 +130,11 @@ public class Phantom extends FlyingMob implements Enemy { + + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new Phantom.PhantomAttackStrategyGoal()); + this.goalSelector.addGoal(2, new Phantom.PhantomSweepAttackGoal()); + this.goalSelector.addGoal(3, new Phantom.PhantomCircleAroundAnchorGoal()); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal()); + } + +@@ -90,6 +150,7 @@ public class Phantom extends FlyingMob implements Enemy { + + private void updatePhantomSizeInfo() { + this.refreshDimensions(); ++ if (level().purpurConfig.phantomFlamesOnSwoop && attackPhase == AttackPhase.SWOOP) shoot(); // Purpur - Ridables - Phantom flames on swoop + this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(6 + this.getPhantomSize()); + } + +@@ -147,6 +208,7 @@ public class Phantom extends FlyingMob implements Enemy { + @Override + public void aiStep() { + if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API ++ if (getRider() == null || !this.isControllable()) // Purpur - Ridables + this.igniteForSeconds(8.0F); + } + +@@ -411,25 +473,42 @@ public class Phantom extends FlyingMob implements Enemy { + } + } + +- static class PhantomLookControl extends LookControl { ++ static class PhantomLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables + public PhantomLookControl(Mob mob) { + super(mob); + } + ++ // Purpur start - Ridables ++ public void purpurTick(Player rider) { ++ setYawPitch(rider.getYRot(), -rider.xRotO * 0.75F); ++ } ++ // Purpur end - Ridables ++ + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + } + } + +- class PhantomMoveControl extends MoveControl { ++ class PhantomMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables + private float speed = 0.1F; + + public PhantomMoveControl(final Mob mob) { + super(mob); + } + ++ // Purpur start - Ridables ++ public void purpurTick(Player rider) { ++ if (!Phantom.this.onGround) { ++ // phantom is always in motion when flying ++ // TODO - FIX THIS ++ // rider.setForward(1.0F); ++ } ++ super.purpurTick(rider); ++ } ++ // Purpur end - Ridables ++ + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (Phantom.this.horizontalCollision) { + Phantom.this.setYRot(Phantom.this.getYRot() + 180.0F); + this.speed = 0.1F; +diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java +index e855ebc5be2cef3b96e2c01a8c1d388e433c0d52..4e799981f04cd17a34f043dda82869adcf16ea98 100644 +--- a/net/minecraft/world/entity/monster/Pillager.java ++++ b/net/minecraft/world/entity/monster/Pillager.java +@@ -63,16 +63,35 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.pillagerRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pillagerRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.pillagerControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2)); + this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F)); + this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0, 8.0F)); + this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6)); + this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0F, 1.0F)); + this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 15.0F)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); +diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java +index 6f0fad37a05e9cd53b6e15c119127da492737c95..fb4e91c4f37619ce273ada0909932b32ba3b53f5 100644 +--- a/net/minecraft/world/entity/monster/Ravager.java ++++ b/net/minecraft/world/entity/monster/Ravager.java +@@ -66,15 +66,40 @@ public class Ravager extends Raider { + this.setPathfindingMalus(PathType.LEAVES, 0.0F); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.ravagerRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ravagerRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.ravagerControllable; ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ getNavigation().stop(); ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); + if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur - option to make ravagers afraid of rabbits ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, true)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(2, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true)); + this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true, (entity, level) -> !entity.isBaby())); +@@ -131,7 +156,7 @@ public class Ravager extends Raider { + @Override + public void aiStep() { + super.aiStep(); +- if (this.isAlive()) { ++ if (this.isAlive() && (getRider() == null || !this.isControllable())) { // Purpur - Ridables + if (this.isImmobile()) { + this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.0); + } else { +diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java +index 3f2668c79dd3d9e7973c1bba3e424b8220749682..e0a496a0c584e1f90967a8528a73536fd991e774 100644 +--- a/net/minecraft/world/entity/monster/Shulker.java ++++ b/net/minecraft/world/entity/monster/Shulker.java +@@ -104,12 +104,31 @@ public class Shulker extends AbstractGolem implements VariantHolder(this, Player.class, true)); + } +diff --git a/net/minecraft/world/entity/monster/Skeleton.java b/net/minecraft/world/entity/monster/Skeleton.java +index f0022458e3e01f6d01df0f8d69b2db73c77fb914..d4426daf3b8079a7e769013d43f44c72b0fce697 100644 +--- a/net/minecraft/world/entity/monster/Skeleton.java ++++ b/net/minecraft/world/entity/monster/Skeleton.java +@@ -25,6 +25,23 @@ public class Skeleton extends AbstractSkeleton { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.skeletonRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.skeletonRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.skeletonControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/monster/Slime.java b/net/minecraft/world/entity/monster/Slime.java +index 8db4cba1be6d7a5538295ba8da1fdaf7a77a16d0..7d31d68ac0fce102af480a47db73409926611428 100644 +--- a/net/minecraft/world/entity/monster/Slime.java ++++ b/net/minecraft/world/entity/monster/Slime.java +@@ -57,6 +57,7 @@ public class Slime extends Mob implements Enemy { + public float oSquish; + private boolean wasOnGround; + private boolean canWander = true; // Paper - Slime pathfinder events ++ protected boolean actualJump; // Purpur - Ridables + + public Slime(EntityType entityType, Level level) { + super(entityType, level); +@@ -64,12 +65,48 @@ public class Slime extends Mob implements Enemy { + this.moveControl = new Slime.SlimeMoveControl(this); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.slimeRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.slimeRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.slimeControllable; ++ } ++ ++ @Override ++ public float getJumpPower() { ++ float height = super.getJumpPower(); ++ return getRider() != null && this.isControllable() && actualJump ? height * 1.5F : height; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (onGround && getRider() != null && this.isControllable()) { ++ actualJump = true; ++ if (getRider().getForwardMot() == 0 || getRider().getStrafeMot() == 0) { ++ jumpFromGround(); // jump() here if not moving ++ } ++ } ++ return true; // do not jump() in wasd controller, let vanilla controller handle ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new Slime.SlimeFloatGoal(this)); + this.goalSelector.addGoal(2, new Slime.SlimeAttackGoal(this)); + this.goalSelector.addGoal(3, new Slime.SlimeRandomDirectionGoal(this)); + this.goalSelector.addGoal(5, new Slime.SlimeKeepOnJumpingGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector + .addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> Math.abs(entity.getY() - this.getY()) <= 4.0)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); +@@ -371,6 +408,7 @@ public class Slime extends Mob implements Enemy { + Vec3 deltaMovement = this.getDeltaMovement(); + this.setDeltaMovement(deltaMovement.x, this.getJumpPower(), deltaMovement.z); + this.hasImpulse = true; ++ this.actualJump = false; // Purpur - Ridables + } + + @Nullable +@@ -535,7 +573,7 @@ public class Slime extends Mob implements Enemy { + } + } + +- static class SlimeMoveControl extends MoveControl { ++ static class SlimeMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables + private float yRot; + private int jumpDelay; + private final Slime slime; +@@ -553,21 +591,33 @@ public class Slime extends Mob implements Enemy { + } + + public void setWantedMovement(double speed) { +- this.speedModifier = speed; ++ this.setSpeedModifier(speed); // Purpur - Ridables + this.operation = MoveControl.Operation.MOVE_TO; + } + + @Override + public void tick() { ++ // Purpur start - Ridables ++ if (slime.getRider() != null && slime.isControllable()) { ++ purpurTick(slime.getRider()); ++ if (slime.getForwardMot() != 0 || slime.getStrafeMot() != 0) { ++ if (jumpDelay > 10) { ++ jumpDelay = 6; ++ } ++ } else { ++ jumpDelay = 20; ++ } ++ } else { ++ // Purpur end - Ridables + this.mob.setYRot(this.rotlerp(this.mob.getYRot(), this.yRot, 90.0F)); + this.mob.yHeadRot = this.mob.getYRot(); + this.mob.yBodyRot = this.mob.getYRot(); +- if (this.operation != MoveControl.Operation.MOVE_TO) { ++ } if ((slime.getRider() == null || !slime.isControllable()) && this.operation != MoveControl.Operation.MOVE_TO) { // Purpur - Ridables + this.mob.setZza(0.0F); + } else { + this.operation = MoveControl.Operation.WAIT; + if (this.mob.onGround()) { +- this.mob.setSpeed((float)(this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); ++ this.mob.setSpeed((float)(this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (slime.getRider() != null && slime.isControllable() && (slime.getRider().getForwardMot() != 0 || slime.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur - Ridables + if (this.jumpDelay-- <= 0) { + this.jumpDelay = this.slime.getJumpDelay(); + if (this.isAggressive) { +@@ -584,7 +634,7 @@ public class Slime extends Mob implements Enemy { + this.mob.setSpeed(0.0F); + } + } else { +- this.mob.setSpeed((float)(this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); ++ this.mob.setSpeed((float)(this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (slime.getRider() != null && slime.isControllable() && (slime.getRider().getForwardMot() != 0 || slime.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur - Ridables + } + } + } +diff --git a/net/minecraft/world/entity/monster/Spider.java b/net/minecraft/world/entity/monster/Spider.java +index af0305079a367899708ee2bbac82aefaa9129d2f..ea83335dd0d128b32d2fe513eab82e642b533b4c 100644 +--- a/net/minecraft/world/entity/monster/Spider.java ++++ b/net/minecraft/world/entity/monster/Spider.java +@@ -50,15 +50,34 @@ public class Spider extends Monster { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.spiderRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.spiderRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.spiderControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Armadillo.class, 6.0F, 1.0, 1.2, livingEntity -> !((Armadillo)livingEntity).isScared())); + this.goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4F)); + this.goalSelector.addGoal(4, new Spider.SpiderAttackGoal(this)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); + this.targetSelector.addGoal(2, new Spider.SpiderTargetGoal<>(this, Player.class)); + this.targetSelector.addGoal(3, new Spider.SpiderTargetGoal<>(this, IronGolem.class)); +diff --git a/net/minecraft/world/entity/monster/Stray.java b/net/minecraft/world/entity/monster/Stray.java +index 5fa2b7920a233afb3659b02cbd7ab82307ea9aaf..ed7ba19870a09ac78c1f069040a25e47c4b19d3a 100644 +--- a/net/minecraft/world/entity/monster/Stray.java ++++ b/net/minecraft/world/entity/monster/Stray.java +@@ -22,6 +22,23 @@ public class Stray extends AbstractSkeleton { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.strayRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.strayRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.strayControllable; ++ } ++ // Purpur end - Ridables ++ + public static boolean checkStraySpawnRules( + EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java +index ce690b564ea8ee055823928169fe605893498f3d..78671f02ef28f4a3b796b357d21fb4c9b64c153e 100644 +--- a/net/minecraft/world/entity/monster/Strider.java ++++ b/net/minecraft/world/entity/monster/Strider.java +@@ -94,6 +94,23 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { + this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.striderRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.striderRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.striderControllable; ++ } ++ // Purpur end - Ridables ++ + public static boolean checkStriderSpawnRules( + EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +@@ -156,6 +173,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new PanicGoal(this, 1.65)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); + this.temptGoal = new TemptGoal(this, 1.4, itemStack -> itemStack.is(ItemTags.STRIDER_TEMPT_ITEMS), false); + this.goalSelector.addGoal(3, this.temptGoal); +@@ -437,7 +455,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { + InteractionResult interactionResult = super.mobInteract(player, hand); + if (!interactionResult.consumesAction()) { + ItemStack itemInHand = player.getItemInHand(hand); +- return (InteractionResult)(itemInHand.is(Items.SADDLE) ? itemInHand.interactLivingEntity(player, this, hand) : InteractionResult.PASS); ++ return (InteractionResult)(itemInHand.is(Items.SADDLE) ? itemInHand.interactLivingEntity(player, this, hand) : tryRide(player, hand)); // Purpur - Ridables + } else { + if (isFood && !this.isSilent()) { + this.level() +diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java +index 7f1cdea810db24182f8f87076c42a19b1b43e98a..26528bc9a9cffb68f82917a3e70900cfb65304d7 100644 +--- a/net/minecraft/world/entity/monster/Vex.java ++++ b/net/minecraft/world/entity/monster/Vex.java +@@ -58,6 +58,50 @@ public class Vex extends Monster implements TraceableEntity { + this.xpReward = 3; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.vexRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vexRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.vexControllable; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level().purpurConfig.vexMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && this.isControllable()) { ++ float speed; ++ if (onGround) { ++ speed = (float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F; ++ } else { ++ speed = (float) getAttributeValue(Attributes.FLYING_SPEED); ++ } ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ ++ @Override ++ public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { ++ return false; // no fall damage please ++ } ++ // Purpur end - Ridables ++ + @Override + public boolean isFlapping() { + return this.tickCount % TICKS_PER_FLAP == 0; +@@ -70,7 +114,7 @@ public class Vex extends Monster implements TraceableEntity { + + @Override + public void tick() { +- this.noPhysics = true; ++ this.noPhysics = getRider() == null || !this.isControllable(); // Purpur - Ridables + super.tick(); + this.noPhysics = false; + this.setNoGravity(true); +@@ -84,17 +128,19 @@ public class Vex extends Monster implements TraceableEntity { + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(4, new Vex.VexChargeAttackGoal()); + this.goalSelector.addGoal(8, new Vex.VexRandomMoveGoal()); + this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); + this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); + this.targetSelector.addGoal(2, new Vex.VexCopyOwnerTargetGoal(this)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true)); + } + + public static AttributeSupplier.Builder createAttributes() { +- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0).add(Attributes.ATTACK_DAMAGE, 4.0); ++ return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0).add(Attributes.ATTACK_DAMAGE, 4.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur; + } + + @Override +@@ -301,13 +347,13 @@ public class Vex extends Monster implements TraceableEntity { + } + } + +- class VexMoveControl extends MoveControl { ++ class VexMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables + public VexMoveControl(final Vex mob) { + super(mob); + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (this.operation == MoveControl.Operation.MOVE_TO) { + Vec3 vec3 = new Vec3(this.wantedX - Vex.this.getX(), this.wantedY - Vex.this.getY(), this.wantedZ - Vex.this.getZ()); + double len = vec3.length(); +@@ -315,7 +361,7 @@ public class Vex extends Monster implements TraceableEntity { + this.operation = MoveControl.Operation.WAIT; + Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().scale(0.5)); + } else { +- Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3.scale(this.speedModifier * 0.05 / len))); ++ Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3.scale(this.getSpeedModifier() * 0.05 / len))); // Purpur - Ridables + if (Vex.this.getTarget() == null) { + Vec3 deltaMovement = Vex.this.getDeltaMovement(); + Vex.this.setYRot(-((float)Mth.atan2(deltaMovement.x, deltaMovement.z)) * (180.0F / (float)Math.PI)); +diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java +index 5e7506f64159ac4838eee8594c995387e2fceed0..c1a1bb0be8bc77a1c0f771924f3bb8b4936d367b 100644 +--- a/net/minecraft/world/entity/monster/Vindicator.java ++++ b/net/minecraft/world/entity/monster/Vindicator.java +@@ -55,15 +55,34 @@ public class Vindicator extends AbstractIllager { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.vindicatorRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vindicatorRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.vindicatorControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2)); + this.goalSelector.addGoal(2, new Vindicator.VindicatorBreakDoorGoal(this)); + this.goalSelector.addGoal(3, new AbstractIllager.RaiderOpenDoorGoal(this)); + this.goalSelector.addGoal(4, new Raider.HoldGroundAttackGoal(this, 10.0F)); + this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0, false)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); +diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java +index 9f5676b5fa0f369adb8643391738c5ae33911df7..0b3c78e646d68ef57a7cf5d7eb77a07c497bd216 100644 +--- a/net/minecraft/world/entity/monster/Witch.java ++++ b/net/minecraft/world/entity/monster/Witch.java +@@ -56,6 +56,23 @@ public class Witch extends Raider implements RangedAttackMob { + super(entityType, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.witchRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witchRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.witchControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + super.registerGoals(); +@@ -64,10 +81,12 @@ public class Witch extends Raider implements RangedAttackMob { + ); + this.attackPlayersGoal = new NearestAttackableWitchTargetGoal<>(this, Player.class, 10, true, false, null); + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0, 60, 10.0F)); + this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(3, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class)); + this.targetSelector.addGoal(2, this.healRaidersGoal); + this.targetSelector.addGoal(3, this.attackPlayersGoal); +diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java +index eed8dbefd4d04082dc4e091c858e50309ed5c49b..b0f155564b11ff5fd2430694b937b7826df104ea 100644 +--- a/net/minecraft/world/entity/monster/WitherSkeleton.java ++++ b/net/minecraft/world/entity/monster/WitherSkeleton.java +@@ -34,6 +34,23 @@ public class WitherSkeleton extends AbstractSkeleton { + this.setPathfindingMalus(PathType.LAVA, 8.0F); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.witherSkeletonRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherSkeletonRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.witherSkeletonControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); +diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java +index 9b94e74f6317f835500225b087fe93487a7a0b22..b279e33bb14dfea4813bba770daf950f5343419d 100644 +--- a/net/minecraft/world/entity/monster/Zoglin.java ++++ b/net/minecraft/world/entity/monster/Zoglin.java +@@ -85,6 +85,23 @@ public class Zoglin extends Monster implements HoglinBase { + this.xpReward = 5; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.zoglinRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zoglinRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.zoglinControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +@@ -250,6 +267,7 @@ public class Zoglin extends Monster implements HoglinBase { + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("zoglinBrain"); ++ if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + this.updateActivity(); +diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java +index a60c7b828332fc214caea10be9bc1505e2b5d0a9..6c6806fd7204e3610142f0365d158aee33ef8b2c 100644 +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -100,11 +100,30 @@ public class Zombie extends Monster { + this(EntityType.ZOMBIE, level); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.zombieRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.zombieControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0, 3)); // Paper - Add zombie targets turtle egg config + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.addBehaviourGoals(); + } + +diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java +index 3608fbcd1998ddcdec8ec501dd5f6b80911104ee..33bb29bc03bce90750b3b9376a6ed848208a569d 100644 +--- a/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -78,6 +78,23 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + .ifPresent(profession -> this.setVillagerData(this.getVillagerData().setProfession(profession.value()))); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.zombieVillagerRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieVillagerRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.zombieVillagerControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +index f1e25786ef687b4680db1cca96a5ae6068e93946..369f1224ea787ae034d86d0e92696882304cb271 100644 +--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -63,6 +63,23 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + this.setPathfindingMalus(PathType.LAVA, 8.0F); + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.zombifiedPiglinRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombifiedPiglinRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.zombifiedPiglinControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + public void setPersistentAngerTarget(@Nullable UUID target) { + this.persistentAngerTarget = target; +diff --git a/net/minecraft/world/entity/monster/creaking/Creaking.java b/net/minecraft/world/entity/monster/creaking/Creaking.java +index eba1e78352f956618b2796ce7cbe5d6f7e6591b6..57ac66c2de97c9b5940c1f0af663a1a26d2c8b73 100644 +--- a/net/minecraft/world/entity/monster/creaking/Creaking.java ++++ b/net/minecraft/world/entity/monster/creaking/Creaking.java +@@ -102,6 +102,29 @@ public class Creaking extends Monster { + return this.getHomePos() != null; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.creakingRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.creakingRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.creakingControllable; ++ } ++ ++ @Override ++ protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ } ++ // Purpur end - Ridables ++ + @Override + protected BodyRotationControl createBodyControl() { + return new Creaking.CreakingBodyRotationControl(this); +@@ -580,28 +603,28 @@ public class Creaking extends Monster { + } + } + +- class CreakingLookControl extends LookControl { ++ class CreakingLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables { + public CreakingLookControl(final Creaking mob) { + super(mob); + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (Creaking.this.canMove()) { +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + } + } + +- class CreakingMoveControl extends MoveControl { ++ class CreakingMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables + public CreakingMoveControl(final Creaking mob) { + super(mob); + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur - Ridables + if (Creaking.this.canMove()) { +- super.tick(); ++ super.vanillaTick(); // Purpur - Ridables + } + } + } +diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +index 0ddc0fe06a1b701f88ed8f8041ecd68f7da6c86d..028e09e1d8a14d989b2c19ca62e6544a93e1f1c4 100644 +--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java ++++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +@@ -92,6 +92,23 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + this.xpReward = 5; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.hoglinRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.hoglinRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.hoglinControllable; ++ } ++ // Purpur end - Ridables ++ + @VisibleForTesting + public void setTimeInOverworld(int timeInOverworld) { + this.timeInOverworld = timeInOverworld; +@@ -160,6 +177,7 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("hoglinBrain"); ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + HoglinAi.updateActivity(this); +diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java +index 0257eada48b35ea024520afe30596beae8a7ef1e..02d748ecb10c3e20aafc0c449b99ca5b6cd80e04 100644 +--- a/net/minecraft/world/entity/monster/piglin/Piglin.java ++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java +@@ -151,6 +151,23 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + this.xpReward = 5; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.piglinRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.piglinRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.piglinControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); +@@ -346,6 +363,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("piglinBrain"); ++ //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + PiglinAi.updateActivity(this); +diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +index 0964b138e87357b7601ddfe937a2b9132afd5478..97241682311797faa93927e0477a7646ce53b2c8 100644 +--- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java ++++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +@@ -65,6 +65,23 @@ public class PiglinBrute extends AbstractPiglin { + this.xpReward = 20; + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.piglinBruteRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.piglinBruteRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.piglinBruteControllable; ++ } ++ // Purpur end - Ridables ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes() + .add(Attributes.MAX_HEALTH, 50.0) +@@ -117,6 +134,7 @@ public class PiglinBrute extends AbstractPiglin { + protected void customServerAiStep(ServerLevel level) { + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("piglinBruteBrain"); ++ if (getRider() == null || this.isControllable()) // Purpur - only use brain if no rider + this.getBrain().tick(level, this); + profilerFiller.pop(); + PiglinBruteAi.updateActivity(this); +diff --git a/net/minecraft/world/entity/monster/warden/Warden.java b/net/minecraft/world/entity/monster/warden/Warden.java +index 9f476e587d7df797129e49738f101cccca7e10b7..f968e5c99bdb23b268bc34ea1ba5d54ae9ad0ff9 100644 +--- a/net/minecraft/world/entity/monster/warden/Warden.java ++++ b/net/minecraft/world/entity/monster/warden/Warden.java +@@ -129,8 +129,32 @@ public class Warden extends Monster implements VibrationSystem { + this.setPathfindingMalus(PathType.LAVA, 8.0F); + this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); ++ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.5F); // Purpur - Ridables + } + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.wardenRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wardenRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.wardenControllable; ++ } ++ ++ @Override ++ protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables ++ } ++ // Purpur end - Ridables ++ + @Override + public Packet getAddEntityPacket(ServerEntity entity) { + return new ClientboundAddEntityPacket(this, entity, this.hasPose(Pose.EMERGING) ? 1 : 0); +@@ -394,6 +418,7 @@ public class Warden extends Monster implements VibrationSystem { + + @Contract("null->false") + public boolean canTargetEntity(@Nullable Entity entity) { ++ if (getRider() != null && isControllable()) return false; // Purpur - Ridables + return entity instanceof LivingEntity livingEntity + && this.level() == entity.level() + && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity) +diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java +index 7eb291323dfc71189ac4a160d3cb43506957aa9e..a7424ad414b72d2adaf0863bf1055f3eff5e2989 100644 +--- a/net/minecraft/world/entity/npc/Villager.java ++++ b/net/minecraft/world/entity/npc/Villager.java +@@ -246,6 +246,28 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + } + // Purpur end - Lobotomize stuck villagers + ++ // Purpur start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.villagerRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.villagerRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.villagerControllable; ++ } ++ ++ @Override ++ protected void registerGoals() { ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); ++ } ++ // Purpur end - Ridables ++ + @Override + public Brain getBrain() { + return (Brain)super.getBrain(); +@@ -355,7 +377,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + } + // Purpur end - Lobotomize stuck villagers + // Pufferfish start +- if (!inactive /*&& this.behaviorTick++ % this.activatedPriority == 0*/) { ++ if (!inactive && (getRider() == null || !this.isControllable()) /*&& this.behaviorTick++ % this.activatedPriority == 0*/) { // Purpur - Ridables + this.getBrain().tick(level, this); // Paper - EAR 2 + } + else if (this.isLobotomized && shouldRestock()) restock(); // Purpur - Lobotomize stuck villagers +@@ -415,7 +437,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + return super.mobInteract(player, hand); + } else if (this.isBaby()) { + this.setUnhappy(); +- return InteractionResult.SUCCESS; ++ return tryRide(player, hand, InteractionResult.SUCCESS); // Purpur - Ridables + } else { + if (!this.level().isClientSide) { + boolean isEmpty = this.getOffers().isEmpty(); +@@ -428,9 +450,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + } + + if (isEmpty) { +- return InteractionResult.CONSUME; ++ return tryRide(player, hand, InteractionResult.CONSUME); // Purpur - Ridables + } + ++ if (level().purpurConfig.villagerRidable && itemInHand.isEmpty()) return tryRide(player, hand); // Purpur - Ridables ++ + if (this.level().purpurConfig.villagerAllowTrading) // Purpur - Add config for villager trading + this.startTrading(player); + } +diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java +index fab309dc34eb88f2b9c844078f167885121675c1..0f8ec3abead11c46205cd21290c65ec2b859efdc 100644 +--- a/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -76,6 +76,23 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + } + // Purpur end - Allow leashing villagers + ++ // Purpur - start - Ridables ++ @Override ++ public boolean isRidable() { ++ return level().purpurConfig.wanderingTraderRidable; ++ } ++ ++ @Override ++ public boolean dismountsUnderwater() { ++ return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wanderingTraderRidableInWater; ++ } ++ ++ @Override ++ public boolean isControllable() { ++ return level().purpurConfig.wanderingTraderControllable; ++ } ++ // Purpur end - Ridables ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +@@ -137,8 +154,9 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + + if (!this.level().isClientSide) { + if (this.getOffers().isEmpty()) { +- return InteractionResult.CONSUME; ++ return tryRide(player, hand, InteractionResult.CONSUME); // Purpur - Ridables + } ++ if (level().purpurConfig.wanderingTraderRidable && itemInHand.isEmpty()) return tryRide(player, hand); // Purpur - Ridables + + if (this.level().purpurConfig.wanderingTraderAllowTrading) { // Purpur - Add config for villager trading + this.setTradingPlayer(player); +diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java +index 3ca4dd7fdb3b8205d72593c13a0fe76e86f76095..ca998a8a480af63d4a5f58a1f4490528a7b33c69 100644 +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -220,6 +220,19 @@ public abstract class Player extends LivingEntity { + } + // CraftBukkit end + ++ // Purpur start - Ridables ++ public abstract void resetLastActionTime(); ++ ++ @Override ++ public boolean processClick(InteractionHand hand) { ++ Entity vehicle = getRootVehicle(); ++ if (vehicle != null && vehicle.getRider() == this) { ++ return vehicle.onClick(hand); ++ } ++ return false; ++ } ++ // Purpur end - Ridables ++ + public Player(Level level, BlockPos pos, float yRot, GameProfile gameProfile) { + super(EntityType.PLAYER, level); + this.setUUID(gameProfile.getId()); +diff --git a/net/minecraft/world/entity/projectile/LlamaSpit.java b/net/minecraft/world/entity/projectile/LlamaSpit.java +index 4880db97135d54fa72f64c108b2bd4ded096438b..bc102b049047d6e2a1d29e10f92cdf5ae2c140bd 100644 +--- a/net/minecraft/world/entity/projectile/LlamaSpit.java ++++ b/net/minecraft/world/entity/projectile/LlamaSpit.java +@@ -33,6 +33,12 @@ public class LlamaSpit extends Projectile { + ); + } + ++ // Purpur start - Ridables ++ public void projectileTick() { ++ super.tick(); ++ } ++ // Purpur end - Ridables ++ + @Override + protected double getDefaultGravity() { + return 0.06; +diff --git a/net/minecraft/world/entity/projectile/WitherSkull.java b/net/minecraft/world/entity/projectile/WitherSkull.java +index c7a76d45b5749cf054607808610eb710493f80ea..9af37bd40649f602d700fc7b683c646ae9189eb9 100644 +--- a/net/minecraft/world/entity/projectile/WitherSkull.java ++++ b/net/minecraft/world/entity/projectile/WitherSkull.java +@@ -110,6 +110,14 @@ public class WitherSkull extends AbstractHurtingProjectile { + } + // Purpur end - Add canSaveToDisk to Entity + ++ // Purpur start - Ridables ++ @Override ++ public boolean canHitEntity(Entity target) { ++ // do not hit rider ++ return target != this.getRider() && super.canHitEntity(target); ++ } ++ // Purpur end - Ridables ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(DATA_DANGEROUS, false); diff --git a/purpur-server/minecraft-patches/features/0002-Configurable-entity-base-attributes.patch b/purpur-server/minecraft-patches/features/0002-Configurable-entity-base-attributes.patch new file mode 100644 index 000000000..c1b6fbad3 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0002-Configurable-entity-base-attributes.patch @@ -0,0 +1,1788 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 10 Dec 2020 16:44:54 -0600 +Subject: [PATCH] Configurable entity base attributes + + +diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java +index d0313fd5368baa53ec511c8c07fc78a1f1ecec4e..898b1e01026ec1f44cfe60e9f18a997c86e30594 100644 +--- a/net/minecraft/world/entity/GlowSquid.java ++++ b/net/minecraft/world/entity/GlowSquid.java +@@ -45,6 +45,13 @@ public class GlowSquid extends Squid { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.glowSquidMaxHealth); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected ParticleOptions getInkParticle() { + return ParticleTypes.GLOW_SQUID_INK; +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index 8c2bdb1775f7c4110c5f967b1052eba6a8fcbbfa..d1f7da0f4adc4609247c349d7ccdb0e6bba9b8f8 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -311,6 +311,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + protected LivingEntity(EntityType entityType, Level level) { + super(entityType, level); + this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType), this); // Purpur - Ridables ++ this.initAttributes(); // Purpur - Configurable entity base attributes + this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit + // CraftBukkit - this.setHealth(this.getMaxHealth()) inlined and simplified to skip the instanceof check for Player, as getBukkitEntity() is not initialized in constructor + this.entityData.set(LivingEntity.DATA_HEALTH_ID, this.getMaxHealth()); +@@ -324,6 +325,8 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.brain = this.makeBrain(new Dynamic<>(nbtOps, nbtOps.createMap(ImmutableMap.of(nbtOps.createString("memories"), nbtOps.emptyMap())))); + } + ++ protected void initAttributes() {}// Purpur - Configurable entity base attributes ++ + public Brain getBrain() { + return this.brain; + } +diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java +index e7ea944e77175ee4051b8e7361c502d0cc2115d5..ecbec552e5cd1935f57872d2fb502d3e9743e3d8 100644 +--- a/net/minecraft/world/entity/ambient/Bat.java ++++ b/net/minecraft/world/entity/ambient/Bat.java +@@ -94,6 +94,21 @@ public class Bat extends AmbientCreature { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.batMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.batScale); ++ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.batFollowRange); ++ this.getAttribute(Attributes.KNOCKBACK_RESISTANCE).setBaseValue(this.level().purpurConfig.batKnockbackResistance); ++ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.batMovementSpeed); ++ this.getAttribute(Attributes.FLYING_SPEED).setBaseValue(this.level().purpurConfig.batFlyingSpeed); ++ this.getAttribute(Attributes.ARMOR).setBaseValue(this.level().purpurConfig.batArmor); ++ this.getAttribute(Attributes.ARMOR_TOUGHNESS).setBaseValue(this.level().purpurConfig.batArmorToughness); ++ this.getAttribute(Attributes.ATTACK_KNOCKBACK).setBaseValue(this.level().purpurConfig.batAttackKnockback); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public boolean isFlapping() { + return !this.isResting() && this.tickCount % 10.0F == 0.0F; +diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java +index af0cf64b4c74d290dec8032f8a6127867e301130..3cdfded14a2fb74e3f345e893e60364b6b810075 100644 +--- a/net/minecraft/world/entity/animal/Bee.java ++++ b/net/minecraft/world/entity/animal/Bee.java +@@ -472,6 +472,14 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + return beehiveBlockEntity != null && beehiveBlockEntity.isFireNearby(); + } + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.beeMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.beeScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public int getRemainingPersistentAngerTime() { + return this.entityData.get(DATA_REMAINING_ANGER_TIME); +diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java +index f066b0acfa0e954f6d71e62962c76afa1f05a4a5..98ce277c5b27591e22daa3c85241be1b8689bfae 100644 +--- a/net/minecraft/world/entity/animal/Cat.java ++++ b/net/minecraft/world/entity/animal/Cat.java +@@ -118,6 +118,14 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true); +diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java +index aba1bf732bb78a24dba1f063d65894fde92789ef..509163f409a5b8988a484aedb2f3ddf042d5eb13 100644 +--- a/net/minecraft/world/entity/animal/Chicken.java ++++ b/net/minecraft/world/entity/animal/Chicken.java +@@ -68,6 +68,14 @@ public class Chicken extends Animal { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.chickenMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.chickenScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java +index 6a19086e272363701260801f3c6db9b5c91b8ef5..434e1fabf2e360a8f5f4eefed96e3883aa786d10 100644 +--- a/net/minecraft/world/entity/animal/Cod.java ++++ b/net/minecraft/world/entity/animal/Cod.java +@@ -25,6 +25,13 @@ public class Cod extends AbstractSchoolingFish { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.codMaxHealth); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public ItemStack getBucketItemStack() { + return new ItemStack(Items.COD_BUCKET); +diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java +index 656babc0c8810a85eb9f78ced1f3ad9551fdc286..d2a4bfa5334f7361067e4adac36ba5a4a4fa6ad8 100644 +--- a/net/minecraft/world/entity/animal/Cow.java ++++ b/net/minecraft/world/entity/animal/Cow.java +@@ -55,6 +55,14 @@ public class Cow extends Animal { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.cowScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java +index 35bce598bb5857356823594d2a001006ce19f835..5b764c686e8759a7b04a7b50708c69629be02c04 100644 +--- a/net/minecraft/world/entity/animal/Dolphin.java ++++ b/net/minecraft/world/entity/animal/Dolphin.java +@@ -148,6 +148,14 @@ public class Dolphin extends AgeableWaterCreature { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.dolphinMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.dolphinScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Nullable + @Override + public SpawnGroupData finalizeSpawn( +diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java +index 8b0a813f9dd001c6dd108ba7aac04d134a20fbc1..8bf893837586ae2a9b4ef7564d242e16e4863b5d 100644 +--- a/net/minecraft/world/entity/animal/Fox.java ++++ b/net/minecraft/world/entity/animal/Fox.java +@@ -167,6 +167,14 @@ public class Fox extends Animal implements VariantHolder { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.foxMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.foxScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java +index 223c4796f659a24062a719045e484a22d31ab2f0..37a353cbb0e9b16e0fc92bd1bc8194cb4cd3c13a 100644 +--- a/net/minecraft/world/entity/animal/IronGolem.java ++++ b/net/minecraft/world/entity/animal/IronGolem.java +@@ -90,6 +90,14 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ironGolemMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ironGolemScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options +diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java +index 1292146341022483f78a9128ef9d7a88089274a0..990723c31aa1040a4e45b9857a18d86287ef91b4 100644 +--- a/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/net/minecraft/world/entity/animal/MushroomCow.java +@@ -72,6 +72,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.rabbitMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.rabbitScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java +index ebbd6d39c3f5d6c66445c2c743785ed369408389..93eb3cc3605f694337c1604e2db63fed04693617 100644 +--- a/net/minecraft/world/entity/animal/Salmon.java ++++ b/net/minecraft/world/entity/animal/Salmon.java +@@ -47,6 +47,13 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +diff --git a/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/net/minecraft/world/entity/animal/armadillo/Armadillo.java +index 87a190d8646d8bbed8c182f9f0f7d8c398e63d26..c10ebb66dec26b6ccc223e98effa0b9a68363626 100644 +--- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java ++++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java +@@ -97,6 +97,14 @@ public class Armadillo extends Animal { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.armadilloMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.armadilloScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/net/minecraft/world/entity/animal/axolotl/Axolotl.java +index 2054e4624da0c9b04ea69b9bf39443c4574d48be..f2f09a529e9db88784ff4299fdf3966046c736ab 100644 +--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java ++++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java +@@ -132,6 +132,14 @@ public class Axolotl extends Animal implements VariantHolder, B + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.axolotlMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.axolotlScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public float getWalkTargetValue(BlockPos pos, LevelReader level) { + return 0.0F; +diff --git a/net/minecraft/world/entity/animal/camel/Camel.java b/net/minecraft/world/entity/animal/camel/Camel.java +index 11311d2ec37d825e73e2218e60e2606dd3a25a1d..1d7e2358bac193af48dc4b7f5b0295e3bffa152b 100644 +--- a/net/minecraft/world/entity/animal/camel/Camel.java ++++ b/net/minecraft/world/entity/animal/camel/Camel.java +@@ -322,6 +322,23 @@ public class Camel extends AbstractHorse { + return this.dashCooldown; + } + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public float generateMaxHealth(net.minecraft.util.RandomSource random) { ++ return (float) generateMaxHealth(this.level().purpurConfig.camelMaxHealthMin, this.level().purpurConfig.camelMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength(net.minecraft.util.RandomSource random) { ++ return generateJumpStrength(this.level().purpurConfig.camelJumpStrengthMin, this.level().purpurConfig.camelJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateSpeed(net.minecraft.util.RandomSource random) { ++ return generateSpeed(this.level().purpurConfig.camelMovementSpeedMin, this.level().purpurConfig.camelMovementSpeedMax); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected SoundEvent getAmbientSound() { + return SoundEvents.CAMEL_AMBIENT; +diff --git a/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/net/minecraft/world/entity/animal/horse/AbstractHorse.java +index 828406060e50ff62586929371aafb46ef7d81f92..56dc7011ed07f0bd5870fbadde2b5c0c630c5edd 100644 +--- a/net/minecraft/world/entity/animal/horse/AbstractHorse.java ++++ b/net/minecraft/world/entity/animal/horse/AbstractHorse.java +@@ -218,6 +218,46 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.generateMaxHealth(random)); ++ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.generateSpeed(random)); ++ this.getAttribute(Attributes.JUMP_STRENGTH).setBaseValue(this.generateJumpStrength(random)); ++ } ++ ++ protected double generateMaxHealth(double min, double max) { ++ if (min == max) return min; ++ int diff = Mth.floor(max - min); ++ double base = max - diff; ++ int first = Mth.floor((double) diff / 2); ++ int rest = diff - first; ++ return base + random.nextInt(first + 1) + random.nextInt(rest + 1); ++ } ++ ++ protected double generateJumpStrength(double min, double max) { ++ if (min == max) return min; ++ return min + (max - min) * this.random.nextDouble(); ++ } ++ ++ protected double generateSpeed(double min, double max) { ++ if (min == max) return min; ++ return min + (max - min) * this.random.nextDouble(); ++ } ++ ++ protected float generateMaxHealth(RandomSource random) { ++ return 15.0F + (float) random.nextInt(8) + (float) random.nextInt(9); ++ } ++ ++ protected double generateJumpStrength(RandomSource random) { ++ return 0.4F + random.nextDouble() * 0.2 + random.nextDouble() * 0.2 + random.nextDouble() * 0.2; ++ } ++ ++ protected double generateSpeed(RandomSource random) { ++ return (0.45F + random.nextDouble() * 0.3 + random.nextDouble() * 0.3 + random.nextDouble() * 0.3) * 0.25; ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables +@@ -1218,7 +1258,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + spawnGroupData = new AgeableMob.AgeableMobGroupData(0.2F); + } + +- this.randomizeAttributes(level.getRandom()); ++ //this.randomizeAttributes(level.getRandom()); // Purpur - replaced by initAttributes() + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + } + +diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java +index ee3fa710e95f2e84f7f9bdce1159d1136815172d..223f1d109680e3643ab2c8343be22713e89755fd 100644 +--- a/net/minecraft/world/entity/animal/horse/Donkey.java ++++ b/net/minecraft/world/entity/animal/horse/Donkey.java +@@ -23,6 +23,23 @@ public class Donkey extends AbstractChestedHorse { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public float generateMaxHealth(net.minecraft.util.RandomSource random) { ++ return (float) generateMaxHealth(this.level().purpurConfig.donkeyMaxHealthMin, this.level().purpurConfig.donkeyMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength(net.minecraft.util.RandomSource random) { ++ return generateJumpStrength(this.level().purpurConfig.donkeyJumpStrengthMin, this.level().purpurConfig.donkeyJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateSpeed(net.minecraft.util.RandomSource random) { ++ return generateSpeed(this.level().purpurConfig.donkeyMovementSpeedMin, this.level().purpurConfig.donkeyMovementSpeedMax); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected SoundEvent getAmbientSound() { + return SoundEvents.DONKEY_AMBIENT; +diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java +index 361bf346153912bcbfcf962d7f716dfe12ae2a7b..8bd118e82da9e4d4153de0a3efaf6d69e3c4c540 100644 +--- a/net/minecraft/world/entity/animal/horse/Horse.java ++++ b/net/minecraft/world/entity/animal/horse/Horse.java +@@ -50,6 +50,23 @@ public class Horse extends AbstractHorse implements VariantHolder { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public float generateMaxHealth(RandomSource random) { ++ return (float) generateMaxHealth(this.level().purpurConfig.horseMaxHealthMin, this.level().purpurConfig.horseMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength(RandomSource random) { ++ return generateJumpStrength(this.level().purpurConfig.horseJumpStrengthMin, this.level().purpurConfig.horseJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateSpeed(RandomSource random) { ++ return generateSpeed(this.level().purpurConfig.horseMovementSpeedMin, this.level().purpurConfig.horseMovementSpeedMax); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void randomizeAttributes(RandomSource random) { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt)); +diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java +index 164a429d432badcb315e8ece406e29e576a11265..58e726dd33f572a31b4910b9ff666c4252fb03a9 100644 +--- a/net/minecraft/world/entity/animal/horse/Llama.java ++++ b/net/minecraft/world/entity/animal/horse/Llama.java +@@ -124,6 +124,23 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java +index bd0f4d77260f5b123856fc7e72d5f8e74bb45321..1d1cf8748e3fba2e2963ad2fa153fbfe990f5087 100644 +--- a/net/minecraft/world/entity/monster/Illusioner.java ++++ b/net/minecraft/world/entity/monster/Illusioner.java +@@ -74,6 +74,16 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ protected void initAttributes() { ++ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.illusionerMovementSpeed); ++ this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(this.level().purpurConfig.illusionerFollowRange); ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.illusionerMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.illusionerScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java +index f10b204c18b88e9110cebf050b60c23367ea3aa0..2c6b0fd46d9ed6a8d1ca7e90ebf596dd3f310f0e 100644 +--- a/net/minecraft/world/entity/monster/MagmaCube.java ++++ b/net/minecraft/world/entity/monster/MagmaCube.java +@@ -46,6 +46,28 @@ public class MagmaCube extends Slime { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ protected String getMaxHealthEquation() { ++ return level().purpurConfig.magmaCubeMaxHealth; ++ } ++ ++ @Override ++ protected String getAttackDamageEquation() { ++ return level().purpurConfig.magmaCubeAttackDamage; ++ } ++ ++ @Override ++ protected java.util.Map getMaxHealthCache() { ++ return level().purpurConfig.magmaCubeMaxHealthCache; ++ } ++ ++ @Override ++ protected java.util.Map getAttackDamageCache() { ++ return level().purpurConfig.magmaCubeAttackDamageCache; ++ } ++ // Purpur end - Configurable entity base attributes ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); + } +diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java +index 75c6a43a3ab4851a47990402bee49f7e8305cd60..08fc2dc0fecfa370c99e877d502149a8ea147e5f 100644 +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -151,7 +151,10 @@ public class Phantom extends FlyingMob implements Enemy { + private void updatePhantomSizeInfo() { + this.refreshDimensions(); + if (level().purpurConfig.phantomFlamesOnSwoop && attackPhase == AttackPhase.SWOOP) shoot(); // Purpur - Ridables - Phantom flames on swoop +- this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(6 + this.getPhantomSize()); ++ // Purpur start - Configurable entity base attributes ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(getFromCache(() -> this.level().purpurConfig.phantomMaxHealth, () -> this.level().purpurConfig.phantomMaxHealthCache, () -> 20.0D)); ++ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(getFromCache(() -> this.level().purpurConfig.phantomAttackDamage, () -> this.level().purpurConfig.phantomAttackDamageCache, () -> (double) (6 + this.getPhantomSize()))); ++ // Purpur end - Configurable entity base attributes + } + + public int getPhantomSize() { +@@ -176,6 +179,23 @@ public class Phantom extends FlyingMob implements Enemy { + return true; + } + ++ // Purpur start - Configurable entity base attributes ++ private double getFromCache(java.util.function.Supplier equation, java.util.function.Supplier> cache, java.util.function.Supplier defaultValue) { ++ int size = getPhantomSize(); ++ Double value = cache.get().get(size); ++ if (value == null) { ++ try { ++ value = ((Number) scriptEngine.eval("let size = " + size + "; " + equation.get())).doubleValue(); ++ } catch (javax.script.ScriptException e) { ++ e.printStackTrace(); ++ value = defaultValue.get(); ++ } ++ cache.get().put(size, value); ++ } ++ return value; ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public void tick() { + super.tick(); +diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java +index 4e799981f04cd17a34f043dda82869adcf16ea98..9586aa3f3eb61fb0c1224df9d0104da69d7fa6bb 100644 +--- a/net/minecraft/world/entity/monster/Pillager.java ++++ b/net/minecraft/world/entity/monster/Pillager.java +@@ -80,6 +80,14 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.pillagerMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.pillagerScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java +index fb4e91c4f37619ce273ada0909932b32ba3b53f5..36ebfc1102a18e4050eb9a2441d75bafcf3784b8 100644 +--- a/net/minecraft/world/entity/monster/Ravager.java ++++ b/net/minecraft/world/entity/monster/Ravager.java +@@ -89,6 +89,14 @@ public class Ravager extends Raider { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.ravagerMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.ravagerScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java +index e0a496a0c584e1f90967a8528a73536fd991e774..03db684c122a07176aa1365550da935cdb66a1b9 100644 +--- a/net/minecraft/world/entity/monster/Shulker.java ++++ b/net/minecraft/world/entity/monster/Shulker.java +@@ -121,6 +121,14 @@ public class Shulker extends AbstractGolem implements VariantHolder getMaxHealthCache() { ++ return level().purpurConfig.slimeMaxHealthCache; ++ } ++ ++ protected java.util.Map getAttackDamageCache() { ++ return level().purpurConfig.slimeAttackDamageCache; ++ } ++ ++ protected double getFromCache(java.util.function.Supplier equation, java.util.function.Supplier> cache, java.util.function.Supplier defaultValue) { ++ int size = getSize(); ++ Double value = cache.get().get(size); ++ if (value == null) { ++ try { ++ value = ((Number) scriptEngine.eval("let size = " + size + "; " + equation.get())).doubleValue(); ++ } catch (javax.script.ScriptException e) { ++ e.printStackTrace(); ++ value = defaultValue.get(); ++ } ++ cache.get().put(size, value); ++ } ++ return value; ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables +@@ -129,9 +162,9 @@ public class Slime extends Mob implements Enemy { + this.entityData.set(ID_SIZE, i); + this.reapplyPosition(); + this.refreshDimensions(); +- this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(i * i); ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(getFromCache(this::getMaxHealthEquation, this::getMaxHealthCache, () -> (double) (size * size))); // Purpur - Configurable entity base attributes + this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.2F + 0.1F * i); +- this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(i); ++ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(getFromCache(this::getAttackDamageEquation, this::getAttackDamageCache, () -> (double) i)); // Purpur - Configurable entity base attributes + if (resetHealth) { + this.setHealth(this.getMaxHealth()); + } +diff --git a/net/minecraft/world/entity/monster/Spider.java b/net/minecraft/world/entity/monster/Spider.java +index ea83335dd0d128b32d2fe513eab82e642b533b4c..38d75a0a024fa1e7b12bfc5e3ab0ec8bb98cb17a 100644 +--- a/net/minecraft/world/entity/monster/Spider.java ++++ b/net/minecraft/world/entity/monster/Spider.java +@@ -67,6 +67,14 @@ public class Spider extends Monster { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.spiderMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.spiderScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/monster/Stray.java b/net/minecraft/world/entity/monster/Stray.java +index ed7ba19870a09ac78c1f069040a25e47c4b19d3a..0323456fca18450c22bf3999df97ff148a89e4c5 100644 +--- a/net/minecraft/world/entity/monster/Stray.java ++++ b/net/minecraft/world/entity/monster/Stray.java +@@ -39,6 +39,13 @@ public class Stray extends AbstractSkeleton { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.strayMaxHealth); ++ } ++ // Purpur end - Configurable entity base attributes ++ + public static boolean checkStraySpawnRules( + EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java +index 78671f02ef28f4a3b796b357d21fb4c9b64c153e..be0dc92bf5ae3da1368a649e9c4e7ff5dbb1c67c 100644 +--- a/net/minecraft/world/entity/monster/Strider.java ++++ b/net/minecraft/world/entity/monster/Strider.java +@@ -111,6 +111,14 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.striderMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.striderScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + public static boolean checkStriderSpawnRules( + EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java +index 26528bc9a9cffb68f82917a3e70900cfb65304d7..8356906b2c0707e21021bb05f9ca01a95682880a 100644 +--- a/net/minecraft/world/entity/monster/Vex.java ++++ b/net/minecraft/world/entity/monster/Vex.java +@@ -102,6 +102,14 @@ public class Vex extends Monster implements TraceableEntity { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vexMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.vexScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public boolean isFlapping() { + return this.tickCount % TICKS_PER_FLAP == 0; +diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java +index c1a1bb0be8bc77a1c0f771924f3bb8b4936d367b..0fc1b458101ba9d98d25c9637337caf0949bb893 100644 +--- a/net/minecraft/world/entity/monster/Vindicator.java ++++ b/net/minecraft/world/entity/monster/Vindicator.java +@@ -72,6 +72,14 @@ public class Vindicator extends AbstractIllager { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.vindicatorMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.vindicatorScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java +index 0b3c78e646d68ef57a7cf5d7eb77a07c497bd216..ff8380246f6c6c805b222a91ac6a1eb0d130558d 100644 +--- a/net/minecraft/world/entity/monster/Witch.java ++++ b/net/minecraft/world/entity/monster/Witch.java +@@ -73,6 +73,14 @@ public class Witch extends Raider implements RangedAttackMob { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witchMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.witchScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java +index b0f155564b11ff5fd2430694b937b7826df104ea..3342f2d92830049837636ff10b5e52f0d85fbd2c 100644 +--- a/net/minecraft/world/entity/monster/WitherSkeleton.java ++++ b/net/minecraft/world/entity/monster/WitherSkeleton.java +@@ -51,6 +51,14 @@ public class WitherSkeleton extends AbstractSkeleton { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.witherSkeletonMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.witherSkeletonScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); +diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java +index b279e33bb14dfea4813bba770daf950f5343419d..132b38d717ac3c5acc64a5ec519f345ac57021d8 100644 +--- a/net/minecraft/world/entity/monster/Zoglin.java ++++ b/net/minecraft/world/entity/monster/Zoglin.java +@@ -102,6 +102,14 @@ public class Zoglin extends Monster implements HoglinBase { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zoglinMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zoglinScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java +index 6c6806fd7204e3610142f0365d158aee33ef8b2c..8886aa0da372223ecd4d1a17c60971e167ced886 100644 +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -117,6 +117,14 @@ public class Zombie extends Monster { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zombieScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables +@@ -631,7 +639,7 @@ public class Zombie extends Monster { + } + + protected void randomizeReinforcementsChance() { +- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * 0.1F); ++ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieSpawnReinforcements); // Purpur - Configurable entity base attributes + } + + @Override +diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java +index 33bb29bc03bce90750b3b9376a6ed848208a569d..578cfc33a493b5ebc2ed42733577129a8953a461 100644 +--- a/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -95,6 +95,18 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieVillagerMaxHealth); ++ } ++ ++ @Override ++ protected void randomizeReinforcementsChance() { ++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombieVillagerSpawnReinforcements); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +index 369f1224ea787ae034d86d0e92696882304cb271..1424954f5b4cf0fbe821425cd741b4b5c1bfed50 100644 +--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -80,6 +80,14 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombifiedPiglinMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zombifiedPiglinScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public void setPersistentAngerTarget(@Nullable UUID target) { + this.persistentAngerTarget = target; +@@ -262,7 +270,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + + @Override + protected void randomizeReinforcementsChance() { +- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(0.0); ++ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * this.level().purpurConfig.zombifiedPiglinSpawnReinforcements); // Purpur - Configurable entity base attributes + } + + @Nullable +diff --git a/net/minecraft/world/entity/monster/creaking/Creaking.java b/net/minecraft/world/entity/monster/creaking/Creaking.java +index 57ac66c2de97c9b5940c1f0af663a1a26d2c8b73..887a81ea82b86edceaa46eb2032f53fccb84e158 100644 +--- a/net/minecraft/world/entity/monster/creaking/Creaking.java ++++ b/net/minecraft/world/entity/monster/creaking/Creaking.java +@@ -125,6 +125,14 @@ public class Creaking extends Monster { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.creakingMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.creakingScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected BodyRotationControl createBodyControl() { + return new Creaking.CreakingBodyRotationControl(this); +diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +index 028e09e1d8a14d989b2c19ca62e6544a93e1f1c4..54924cd7c84cbcd22ffc0bd37fc24f24e73c18bc 100644 +--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java ++++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +@@ -109,6 +109,14 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.hoglinMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.hoglinScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @VisibleForTesting + public void setTimeInOverworld(int timeInOverworld) { + this.timeInOverworld = timeInOverworld; +diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java +index 02d748ecb10c3e20aafc0c449b99ca5b6cd80e04..897c57263ab7347987b289016a71d11f693bc8b2 100644 +--- a/net/minecraft/world/entity/monster/piglin/Piglin.java ++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java +@@ -168,6 +168,14 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.piglinScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); +diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +index 97241682311797faa93927e0477a7646ce53b2c8..eb82252cd87797927e153974b9280b5eaa251080 100644 +--- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java ++++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +@@ -82,6 +82,14 @@ public class PiglinBrute extends AbstractPiglin { + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.piglinBruteMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.piglinBruteScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes() + .add(Attributes.MAX_HEALTH, 50.0) +diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java +index a7424ad414b72d2adaf0863bf1055f3eff5e2989..c4ce3a2f03bb7665beb131892288d8e4f722a4b5 100644 +--- a/net/minecraft/world/entity/npc/Villager.java ++++ b/net/minecraft/world/entity/npc/Villager.java +@@ -268,6 +268,14 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.villagerMaxHealth); ++ this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.villagerScale); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + public Brain getBrain() { + return (Brain)super.getBrain(); +diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java +index 0f8ec3abead11c46205cd21290c65ec2b859efdc..5d5fa6b4ad18b4213f5098e4d708f3301a6f59c6 100644 +--- a/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -93,6 +93,13 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + } + // Purpur end - Ridables + ++ // Purpur start - Configurable entity base attributes ++ @Override ++ public void initAttributes() { ++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.wanderingTraderMaxHealth); ++ } ++ // Purpur end - Configurable entity base attributes ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); diff --git a/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch b/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch new file mode 100644 index 000000000..af661d0d6 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0003-Barrels-and-enderchests-6-rows.patch @@ -0,0 +1,219 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 23 May 2019 21:50:37 -0500 +Subject: [PATCH] Barrels and enderchests 6 rows + + +diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java +index 2d09f2a2c97f29ac0d941b7a3fb941102a5d545e..94abb9d8f6381aee000dbd0720477db8b7ca279c 100644 +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -1027,6 +1027,27 @@ public abstract class PlayerList { + player.getBukkitEntity().recalculatePermissions(); // CraftBukkit + this.server.getCommands().sendCommands(player); + } // Paper - Add sendOpLevel API ++ ++ // Purpur start - Barrels and enderchests 6 rows ++ if (org.purpurmc.purpur.PurpurConfig.enderChestSixRows && org.purpurmc.purpur.PurpurConfig.enderChestPermissionRows) { ++ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkit = player.getBukkitEntity(); ++ if (bukkit.hasPermission("purpur.enderchest.rows.six")) { ++ player.sixRowEnderchestSlotCount = 54; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.five")) { ++ player.sixRowEnderchestSlotCount = 45; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.four")) { ++ player.sixRowEnderchestSlotCount = 36; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.three")) { ++ player.sixRowEnderchestSlotCount = 27; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.two")) { ++ player.sixRowEnderchestSlotCount = 18; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.one")) { ++ player.sixRowEnderchestSlotCount = 9; ++ } ++ } else { ++ player.sixRowEnderchestSlotCount = -1; ++ } ++ // Purpur end - Barrels and enderchests 6 rows + } + + public boolean isWhiteListed(GameProfile profile) { +diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java +index ca998a8a480af63d4a5f58a1f4490528a7b33c69..43657822f0660613078e9afa512000b5255a1537 100644 +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -202,6 +202,7 @@ public abstract class Player extends LivingEntity { + public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage + public int burpDelay = 0; // Purpur - Burp delay + public boolean canPortalInstant = false; // Purpur - Add portal permission bypass ++ public int sixRowEnderchestSlotCount = -1; // Purpur - Barrels and enderchests 6 rows + + // CraftBukkit start + public boolean fauxSleeping; +diff --git a/net/minecraft/world/inventory/ChestMenu.java b/net/minecraft/world/inventory/ChestMenu.java +index 280169afbd637eeb67ddf7eaeb4eecd464a128d5..ba7730a24831efa33de4c5ffce57bfa7177f89d6 100644 +--- a/net/minecraft/world/inventory/ChestMenu.java ++++ b/net/minecraft/world/inventory/ChestMenu.java +@@ -66,10 +66,30 @@ public class ChestMenu extends AbstractContainerMenu { + return new ChestMenu(MenuType.GENERIC_9x6, containerId, playerInventory, 6); + } + ++ // Purpur start - Barrels and enderchests 6 rows ++ public static ChestMenu oneRow(int syncId, Inventory playerInventory, Container inventory) { ++ return new ChestMenu(MenuType.GENERIC_9x1, syncId, playerInventory, inventory, 1); ++ } ++ ++ public static ChestMenu twoRows(int syncId, Inventory playerInventory, Container inventory) { ++ return new ChestMenu(MenuType.GENERIC_9x2, syncId, playerInventory, inventory, 2); ++ } ++ // Purpur end - Barrels and enderchests 6 rows ++ + public static ChestMenu threeRows(int containerId, Inventory playerInventory, Container container) { + return new ChestMenu(MenuType.GENERIC_9x3, containerId, playerInventory, container, 3); + } + ++ // Purpur start - Barrels and enderchests 6 rows ++ public static ChestMenu fourRows(int syncId, Inventory playerInventory, Container inventory) { ++ return new ChestMenu(MenuType.GENERIC_9x4, syncId, playerInventory, inventory, 4); ++ } ++ ++ public static ChestMenu fiveRows(int syncId, Inventory playerInventory, Container inventory) { ++ return new ChestMenu(MenuType.GENERIC_9x5, syncId, playerInventory, inventory, 5); ++ } ++ // Purpur end - Barrels and enderchests 6 rows ++ + public static ChestMenu sixRows(int containerId, Inventory playerInventory, Container container) { + return new ChestMenu(MenuType.GENERIC_9x6, containerId, playerInventory, container, 6); + } +diff --git a/net/minecraft/world/inventory/PlayerEnderChestContainer.java b/net/minecraft/world/inventory/PlayerEnderChestContainer.java +index a6a359bab2a727f4631b633a8bb370dd40decc75..d2d75e5c34c97300ce5da8c7ea70958aba31fa4a 100644 +--- a/net/minecraft/world/inventory/PlayerEnderChestContainer.java ++++ b/net/minecraft/world/inventory/PlayerEnderChestContainer.java +@@ -25,11 +25,18 @@ public class PlayerEnderChestContainer extends SimpleContainer { + } + + public PlayerEnderChestContainer(Player owner) { +- super(27); ++ super(org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? 54 : 27); // Purpur - Barrels and enderchests 6 rows + this.owner = owner; + // CraftBukkit end + } + ++ // Purpur start - Barrels and enderchests 6 rows ++ @Override ++ public int getContainerSize() { ++ return owner.sixRowEnderchestSlotCount < 0 ? super.getContainerSize() : owner.sixRowEnderchestSlotCount; ++ } ++ // Purpur end - Barrels and enderchests 6 rows ++ + public void setActiveChest(EnderChestBlockEntity enderChestBlockEntity) { + this.activeChest = enderChestBlockEntity; + } +diff --git a/net/minecraft/world/level/block/EnderChestBlock.java b/net/minecraft/world/level/block/EnderChestBlock.java +index f5533960708bdbaf2eacefbc7c7c3123b7d26502..17aa27885b4431bf7b98799e02d080b5a0ecbbf1 100644 +--- a/net/minecraft/world/level/block/EnderChestBlock.java ++++ b/net/minecraft/world/level/block/EnderChestBlock.java +@@ -85,8 +85,8 @@ public class EnderChestBlock extends AbstractChestBlock i + enderChestInventory.setActiveChest(enderChestBlockEntity); // Needs to happen before ChestMenu.threeRows as it is required for opening animations + if (level instanceof ServerLevel serverLevel && player.openMenu( + new SimpleMenuProvider( +- (containerId, playerInventory, player1) -> ChestMenu.threeRows(containerId, playerInventory, enderChestInventory), CONTAINER_TITLE +- ) ++ (containerId, playerInventory, player1) -> org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? getEnderChestSixRows(containerId, playerInventory, player, enderChestInventory) : ChestMenu.threeRows(containerId, playerInventory, enderChestInventory), CONTAINER_TITLE ++ ) // Purpur - Barrels and enderchests 6 rows + ).isPresent()) { + // Paper end - Fix InventoryOpenEvent cancellation - moved up; + player.awardStat(Stats.OPEN_ENDERCHEST); +@@ -100,6 +100,35 @@ public class EnderChestBlock extends AbstractChestBlock i + } + } + ++ // Purpur start - Barrels and enderchests 6 rows ++ private ChestMenu getEnderChestSixRows(int syncId, net.minecraft.world.entity.player.Inventory inventory, Player player, PlayerEnderChestContainer playerEnderChestContainer) { ++ if (org.purpurmc.purpur.PurpurConfig.enderChestPermissionRows) { ++ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkitPlayer = player.getBukkitEntity(); ++ if (bukkitPlayer.hasPermission("purpur.enderchest.rows.six")) { ++ player.sixRowEnderchestSlotCount = 54; ++ return ChestMenu.sixRows(syncId, inventory, playerEnderChestContainer); ++ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.five")) { ++ player.sixRowEnderchestSlotCount = 45; ++ return ChestMenu.fiveRows(syncId, inventory, playerEnderChestContainer); ++ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.four")) { ++ player.sixRowEnderchestSlotCount = 36; ++ return ChestMenu.fourRows(syncId, inventory, playerEnderChestContainer); ++ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.three")) { ++ player.sixRowEnderchestSlotCount = 27; ++ return ChestMenu.threeRows(syncId, inventory, playerEnderChestContainer); ++ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.two")) { ++ player.sixRowEnderchestSlotCount = 18; ++ return ChestMenu.twoRows(syncId, inventory, playerEnderChestContainer); ++ } else if (bukkitPlayer.hasPermission("purpur.enderchest.rows.one")) { ++ player.sixRowEnderchestSlotCount = 9; ++ return ChestMenu.oneRow(syncId, inventory, playerEnderChestContainer); ++ } ++ } ++ player.sixRowEnderchestSlotCount = -1; ++ return ChestMenu.sixRows(syncId, inventory, playerEnderChestContainer); ++ } ++ // Purpur end - Barrels and enderchests 6 rows ++ + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return new EnderChestBlockEntity(pos, state); +diff --git a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java +index 0f808855f58281578c2758513787f0f7330c9291..9f6063089f0aa3a68d26ae7cfe39379123ab2f47 100644 +--- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java +@@ -55,7 +55,17 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { + this.maxStack = i; + } + // CraftBukkit end +- private NonNullList items = NonNullList.withSize(27, ItemStack.EMPTY); ++ // Purpur start - Barrels and enderchests 6 rows ++ private NonNullList items = NonNullList.withSize(switch (org.purpurmc.purpur.PurpurConfig.barrelRows) { ++ case 6 -> 54; ++ case 5 -> 45; ++ case 4 -> 36; ++ case 2 -> 18; ++ case 1 -> 9; ++ default -> 27; ++ }, ItemStack.EMPTY); ++ // Purpur end - Barrels and enderchests 6 rows ++ + public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() { + @Override + protected void onOpen(Level level, BlockPos pos, BlockState state) { +@@ -107,7 +117,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { + + @Override + public int getContainerSize() { +- return 27; ++ // Purpur start - Barrels and enderchests 6 rows ++ return switch (org.purpurmc.purpur.PurpurConfig.barrelRows) { ++ case 6 -> 54; ++ case 5 -> 45; ++ case 4 -> 36; ++ case 2 -> 18; ++ case 1 -> 9; ++ default -> 27; ++ }; ++ // Purpur end - Barrels and enderchests 6 rows + } + + @Override +@@ -127,7 +146,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { + + @Override + protected AbstractContainerMenu createMenu(int id, Inventory player) { +- return ChestMenu.threeRows(id, player, this); ++ // Purpur start - Barrels and enderchests 6 rows ++ return switch (org.purpurmc.purpur.PurpurConfig.barrelRows) { ++ case 6 -> ChestMenu.sixRows(id, player, this); ++ case 5 -> ChestMenu.fiveRows(id, player, this); ++ case 4 -> ChestMenu.fourRows(id, player, this); ++ case 2 -> ChestMenu.twoRows(id, player, this); ++ case 1 -> ChestMenu.oneRow(id, player, this); ++ default -> ChestMenu.threeRows(id, player, this); ++ }; ++ // Purpur end - Barrels and enderchests 6 rows + } + + @Override diff --git a/purpur-server/minecraft-patches/features/0004-Giants-AI-settings.patch b/purpur-server/minecraft-patches/features/0004-Giants-AI-settings.patch new file mode 100644 index 000000000..0418b7349 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0004-Giants-AI-settings.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 12 May 2019 00:43:12 -0500 +Subject: [PATCH] Giants AI settings + + +diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java +index 13021800af7cc9263ef4f393f9cfbda5061a32ae..73da18c4b54e250c434fd75971ef0a8f7c8cf6a3 100644 +--- a/net/minecraft/world/entity/monster/Giant.java ++++ b/net/minecraft/world/entity/monster/Giant.java +@@ -30,8 +30,25 @@ public class Giant extends Monster { + + @Override + protected void registerGoals() { +- this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); +- this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); ++ // Purpur start - Giants AI settings ++ if (level().purpurConfig.giantHaveAI) { ++ this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); ++ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); ++ this.goalSelector.addGoal(7, new net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal(this, 1.0D)); ++ this.goalSelector.addGoal(8, new net.minecraft.world.entity.ai.goal.LookAtPlayerGoal(this, net.minecraft.world.entity.player.Player.class, 16.0F)); ++ this.goalSelector.addGoal(8, new net.minecraft.world.entity.ai.goal.RandomLookAroundGoal(this)); ++ this.goalSelector.addGoal(5, new net.minecraft.world.entity.ai.goal.MoveTowardsRestrictionGoal(this, 1.0D)); ++ if (level().purpurConfig.giantHaveHostileAI) { ++ this.goalSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.0D, false)); ++ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); ++ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class)); ++ this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.player.Player.class, true)); ++ this.targetSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.npc.Villager.class, false)); ++ this.targetSelector.addGoal(4, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.animal.IronGolem.class, true)); ++ this.targetSelector.addGoal(5, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, net.minecraft.world.entity.animal.Turtle.class, true)); ++ } ++ } ++ // Purpur end - Giants AI settings + } + // Purpur end - Ridables + +@@ -49,8 +66,36 @@ public class Giant extends Monster { + return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0); + } + ++ // Purpur - Giants AI settings ++ @Override ++ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason spawnReason, @org.jetbrains.annotations.Nullable net.minecraft.world.entity.SpawnGroupData entityData) { ++ net.minecraft.world.entity.SpawnGroupData groupData = super.finalizeSpawn(world, difficulty, spawnReason, entityData); ++ if (groupData == null) { ++ populateDefaultEquipmentSlots(this.random, difficulty); ++ populateDefaultEquipmentEnchantments(world, this.random, difficulty); ++ } ++ return groupData; ++ } ++ ++ @Override ++ protected void populateDefaultEquipmentSlots(net.minecraft.util.RandomSource random, net.minecraft.world.DifficultyInstance difficulty) { ++ super.populateDefaultEquipmentSlots(this.random, difficulty); ++ // TODO make configurable ++ if (random.nextFloat() < (level().getDifficulty() == net.minecraft.world.Difficulty.HARD ? 0.1F : 0.05F)) { ++ this.setItemSlot(net.minecraft.world.entity.EquipmentSlot.MAINHAND, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.IRON_SWORD)); ++ } ++ } ++ ++ @Override ++ public float getJumpPower() { ++ // make giants jump as high as everything else relative to their size ++ // 1.0 makes bottom of feet about as high as their waist when they jump ++ return level().purpurConfig.giantJumpHeight; ++ } ++ // Purpur end - Giants AI settings ++ + @Override + public float getWalkTargetValue(BlockPos pos, LevelReader level) { +- return level.getPathfindingCostFromLightLevels(pos); ++ return super.getWalkTargetValue(pos, level); // Purpur - Giants AI settings - fix light requirements for natural spawns + } + } diff --git a/purpur-server/minecraft-patches/features/0005-Chickens-can-retaliate.patch b/purpur-server/minecraft-patches/features/0005-Chickens-can-retaliate.patch new file mode 100644 index 000000000..9156be5d5 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0005-Chickens-can-retaliate.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 12 Apr 2020 13:19:34 -0500 +Subject: [PATCH] Chickens can retaliate + + +diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java +index 509163f409a5b8988a484aedb2f3ddf042d5eb13..d718f0ed362c49803260dceed64bd93e2b6744fc 100644 +--- a/net/minecraft/world/entity/animal/Chicken.java ++++ b/net/minecraft/world/entity/animal/Chicken.java +@@ -73,6 +73,11 @@ public class Chicken extends Animal { + public void initAttributes() { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.chickenMaxHealth); + this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.chickenScale); ++ // Purpur start - Chickens can retaliate ++ if (level().purpurConfig.chickenRetaliate) { ++ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(2.0D); ++ } ++ // Purpur end - Chickens can retaliate + } + // Purpur end - Configurable entity base attributes + +@@ -80,13 +85,21 @@ public class Chicken extends Animal { + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables +- this.goalSelector.addGoal(1, new PanicGoal(this, 1.4)); ++ //this.goalSelector.addGoal(1, new PanicGoal(this, 1.4)); // Purpur - Chickens can retaliate - moved down + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); + this.goalSelector.addGoal(3, new TemptGoal(this, 1.0, itemStack -> itemStack.is(ItemTags.CHICKEN_FOOD), false)); + this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.1)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); ++ // Purpur start - Chickens can retaliate ++ if (level().purpurConfig.chickenRetaliate) { ++ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.0D, false)); ++ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this)); ++ } else { ++ this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); ++ } ++ // Purpur end - Chickens can retaliate + } + + @Override +@@ -95,7 +108,7 @@ public class Chicken extends Animal { + } + + public static AttributeSupplier.Builder createAttributes() { +- return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 4.0).add(Attributes.MOVEMENT_SPEED, 0.25); ++ return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 4.0).add(Attributes.MOVEMENT_SPEED, 0.25).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur - Chickens can retaliate + } + + @Override diff --git a/purpur-server/minecraft-patches/features/0006-Minecart-settings-and-WASD-controls.patch b/purpur-server/minecraft-patches/features/0006-Minecart-settings-and-WASD-controls.patch new file mode 100644 index 000000000..bdc45a90d --- /dev/null +++ b/purpur-server/minecraft-patches/features/0006-Minecart-settings-and-WASD-controls.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 29 Jun 2019 02:32:40 -0500 +Subject: [PATCH] Minecart settings and WASD controls + + +diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java +index d77381237f8a7d1b2f280a5032f5e1c8f0ab8f94..9a88ca440fad04b5941cda125c6a39d24adf6d37 100644 +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -1240,6 +1240,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + } else { + // Purpur start - Add boat fall damage config + if (damageSource.is(net.minecraft.tags.DamageTypeTags.IS_FALL)) { ++ // Purpur start - Minecart settings and WASD controls ++ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.AbstractMinecart && level().purpurConfig.minecartControllable && !level().purpurConfig.minecartControllableFallDamage) { ++ return false; ++ } ++ // Purpur end - Minecart settings and WASD controls + if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.Boat && !level().purpurConfig.boatsDoFallDamage) { + return false; + } +diff --git a/net/minecraft/world/entity/vehicle/AbstractMinecart.java b/net/minecraft/world/entity/vehicle/AbstractMinecart.java +index 9e15e7159cf98b3928110df9eae6de93793bf44e..6df4d736d94b9e49a3eb3d59a329e37127aa64cd 100644 +--- a/net/minecraft/world/entity/vehicle/AbstractMinecart.java ++++ b/net/minecraft/world/entity/vehicle/AbstractMinecart.java +@@ -83,6 +83,10 @@ public abstract class AbstractMinecart extends VehicleEntity { + private double flyingY = 0.95; + private double flyingZ = 0.95; + public Double maxSpeed; ++ // Purpur start - Minecart settings and WASD controls ++ public double storedMaxSpeed; ++ public boolean isNewBehavior; ++ // Purpur end - Minecart settings and WASD controls + public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API + // CraftBukkit end + +@@ -91,8 +95,13 @@ public abstract class AbstractMinecart extends VehicleEntity { + this.blocksBuilding = true; + if (useExperimentalMovement(level)) { + this.behavior = new NewMinecartBehavior(this); ++ this.isNewBehavior = true; // Purpur - Minecart settings and WASD controls + } else { + this.behavior = new OldMinecartBehavior(this); ++ // Purpur start - Minecart settings and WASD controls ++ this.isNewBehavior = false; ++ maxSpeed = storedMaxSpeed = level.purpurConfig.minecartMaxSpeed; ++ // Purpur end - Minecart settings and WASD controls + } + } + +@@ -258,6 +267,14 @@ public abstract class AbstractMinecart extends VehicleEntity { + + @Override + public void tick() { ++ // Purpur start - Minecart settings and WASD controls ++ if (!this.isNewBehavior) { ++ if (storedMaxSpeed != level().purpurConfig.minecartMaxSpeed) { ++ maxSpeed = storedMaxSpeed = level().purpurConfig.minecartMaxSpeed; ++ } ++ } ++ // Purpur end - Minecart settings and WASD controls ++ + // CraftBukkit start + double prevX = this.getX(); + double prevY = this.getY(); +@@ -394,15 +411,61 @@ public abstract class AbstractMinecart extends VehicleEntity { + this.behavior.moveAlongTrack(level); + } + ++ // Purpur start - Minecart settings and WASD controls ++ private Double lastSpeed; ++ ++ public double getControllableSpeed() { ++ BlockState blockState = level().getBlockState(this.blockPosition()); ++ if (!blockState.isSolid()) { ++ blockState = level().getBlockState(this.blockPosition().relative(Direction.DOWN)); ++ } ++ Double speed = level().purpurConfig.minecartControllableBlockSpeeds.get(blockState.getBlock()); ++ if (!blockState.isSolid()) { ++ speed = lastSpeed; ++ } ++ if (speed == null) { ++ speed = level().purpurConfig.minecartControllableBaseSpeed; ++ } ++ return lastSpeed = speed; ++ } ++ // Purpur end - Minecart settings and WASD controls ++ + protected void comeOffTrack(ServerLevel level) { + double maxSpeed = this.getMaxSpeed(level); + Vec3 deltaMovement = this.getDeltaMovement(); + this.setDeltaMovement(Mth.clamp(deltaMovement.x, -maxSpeed, maxSpeed), deltaMovement.y, Mth.clamp(deltaMovement.z, -maxSpeed, maxSpeed)); ++ ++ // Purpur start - Minecart settings and WASD controls ++ if (level().purpurConfig.minecartControllable && !isInWater() && !isInLava() && !passengers.isEmpty()) { ++ Entity passenger = passengers.get(0); ++ if (passenger instanceof net.minecraft.server.level.ServerPlayer player) { ++ net.minecraft.world.entity.player.Input lastClientInput = player.getLastClientInput(); ++ float forward = (lastClientInput.forward() == lastClientInput.backward() ? 0.0F : lastClientInput.forward() ? 1.0F : -1.0F); ++ if (lastClientInput.jump() && this.onGround) { ++ setDeltaMovement(new Vec3(getDeltaMovement().x, level().purpurConfig.minecartControllableHopBoost, getDeltaMovement().z)); ++ } ++ if (forward != 0.0F) { ++ org.bukkit.util.Vector velocity = player.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(getControllableSpeed()); ++ if (forward < 0.0) { ++ velocity.multiply(-0.5); ++ } ++ setDeltaMovement(new Vec3(velocity.getX(), getDeltaMovement().y, velocity.getZ())); ++ } ++ this.setYRot(passenger.getYRot() - 90); ++ maxUpStep = level().purpurConfig.minecartControllableStepHeight; ++ } else { ++ maxUpStep = 0.0F; ++ } ++ } else { ++ maxUpStep = 0.0F; ++ } ++ // Purpur end - Minecart settings and WASD controls + if (this.onGround()) { + // CraftBukkit start - replace magic numbers with our variables + this.setDeltaMovement(new Vec3(this.getDeltaMovement().x * this.derailedX, this.getDeltaMovement().y * this.derailedY, this.getDeltaMovement().z * this.derailedZ)); + // CraftBukkit end + } ++ else if (level().purpurConfig.minecartControllable) setDeltaMovement(new Vec3(getDeltaMovement().x * derailedX, getDeltaMovement().y, getDeltaMovement().z * derailedZ)); // Purpur - Minecart settings and WASD controls + + this.move(MoverType.SELF, this.getDeltaMovement()); + if (!this.onGround()) { +diff --git a/net/minecraft/world/item/MinecartItem.java b/net/minecraft/world/item/MinecartItem.java +index 620069daba04d48b57fc933328eda77f6ca9333e..0403b9b01994269d394820e8c8710ba1b9808bf0 100644 +--- a/net/minecraft/world/item/MinecartItem.java ++++ b/net/minecraft/world/item/MinecartItem.java +@@ -30,8 +30,9 @@ public class MinecartItem extends Item { + BlockPos clickedPos = context.getClickedPos(); + BlockState blockState = level.getBlockState(clickedPos); + if (!blockState.is(BlockTags.RAILS)) { +- return InteractionResult.FAIL; +- } else { ++ if (!level.purpurConfig.minecartPlaceAnywhere) return InteractionResult.FAIL; // Purpur - Minecart settings and WASD controls ++ if (blockState.isSolid()) clickedPos = clickedPos.relative(context.getClickedFace()); ++ } // else { // Purpur - Minecart settings and WASD controls + ItemStack itemInHand = context.getItemInHand(); + RailShape railShape = blockState.getBlock() instanceof BaseRailBlock + ? blockState.getValue(((BaseRailBlock)blockState.getBlock()).getShapeProperty()) +@@ -72,6 +73,6 @@ public class MinecartItem extends Item { + itemInHand.shrink(1); + return InteractionResult.SUCCESS; + } +- } ++ // } // Purpur - Minecart settings and WASD controls + } + } diff --git a/purpur-server/minecraft-patches/features/0007-Villagers-follow-emerald-blocks.patch b/purpur-server/minecraft-patches/features/0007-Villagers-follow-emerald-blocks.patch new file mode 100644 index 000000000..50933fa27 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0007-Villagers-follow-emerald-blocks.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 29 Nov 2019 22:10:12 -0600 +Subject: [PATCH] Villagers follow emerald blocks + + +diff --git a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java +index 61ed4d687120fcbb7b91863e400f3657ebcde687..e773c426567964fc8269237d71c3434a5473985c 100644 +--- a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java ++++ b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java +@@ -162,7 +162,7 @@ public class DefaultAttributes { + .put(EntityType.VILLAGER, Villager.createAttributes().build()) + .put(EntityType.VINDICATOR, Vindicator.createAttributes().build()) + .put(EntityType.WARDEN, Warden.createAttributes().build()) +- .put(EntityType.WANDERING_TRADER, Mob.createMobAttributes().build()) ++ .put(EntityType.WANDERING_TRADER, net.minecraft.world.entity.npc.WanderingTrader.createAttributes().build()) // Purpur - Villagers follow emerald blocks + .put(EntityType.WITCH, Witch.createAttributes().build()) + .put(EntityType.WITHER, WitherBoss.createAttributes().build()) + .put(EntityType.WITHER_SKELETON, AbstractSkeleton.createAttributes().build()) +diff --git a/net/minecraft/world/entity/ai/goal/TemptGoal.java b/net/minecraft/world/entity/ai/goal/TemptGoal.java +index 438d6347778a94b4fe430320b268a2d67afa209a..f88f618d34fb343b31de3af1a875d6633703df71 100644 +--- a/net/minecraft/world/entity/ai/goal/TemptGoal.java ++++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java +@@ -58,7 +58,7 @@ public class TemptGoal extends Goal { + } + + private boolean shouldFollow(LivingEntity entity) { +- return this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem()); ++ return (this.items.test(entity.getMainHandItem()) || this.items.test(entity.getOffhandItem())) && (!(this.mob instanceof net.minecraft.world.entity.npc.Villager villager) || !villager.isSleeping()); // Purpur - Villagers follow emerald blocks + } + + @Override +diff --git a/net/minecraft/world/entity/npc/AbstractVillager.java b/net/minecraft/world/entity/npc/AbstractVillager.java +index a71d16d968bb90fd7aca6f01a3dd56df4f9a7ce6..b4e79cac5611942240ce85120f7bbee329ae2fb8 100644 +--- a/net/minecraft/world/entity/npc/AbstractVillager.java ++++ b/net/minecraft/world/entity/npc/AbstractVillager.java +@@ -45,6 +45,8 @@ import org.bukkit.event.entity.VillagerAcquireTradeEvent; + // CraftBukkit end + + public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant { ++ static final net.minecraft.world.item.crafting.Ingredient TEMPT_ITEMS = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.level.block.Blocks.EMERALD_BLOCK.asItem()); // Purpur - Villagers follow emerald blocks ++ + // CraftBukkit start + @Override + public CraftMerchant getCraftMerchant() { +diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java +index c4ce3a2f03bb7665beb131892288d8e4f722a4b5..ff07cfe07200be23f17310522d737fca3251a580 100644 +--- a/net/minecraft/world/entity/npc/Villager.java ++++ b/net/minecraft/world/entity/npc/Villager.java +@@ -265,6 +265,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); ++ if (level().purpurConfig.villagerFollowEmeraldBlock) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, TEMPT_ITEMS, false)); // Purpur - Villagers follow emerald blocks + } + // Purpur end - Ridables + +@@ -273,6 +274,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + public void initAttributes() { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.villagerMaxHealth); + this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.villagerScale); ++ this.getAttribute(Attributes.TEMPT_RANGE).setBaseValue(this.level().purpurConfig.villagerTemptRange); // Purpur - Villagers follow emerald blocks + } + // Purpur end - Configurable entity base attributes + +@@ -341,7 +343,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + } + + public static AttributeSupplier.Builder createAttributes() { +- return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.5); ++ return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.TEMPT_RANGE, 10.0D); // Purpur - Villagers follow emerald blocks + } + + public boolean assignProfessionWhenSpawned() { +diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java +index 5d5fa6b4ad18b4213f5098e4d708f3301a6f59c6..4ba2921dd99f674344fe3371332c9b23365d3aa2 100644 +--- a/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -97,9 +97,16 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + @Override + public void initAttributes() { + this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.wanderingTraderMaxHealth); ++ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.TEMPT_RANGE).setBaseValue(this.level().purpurConfig.wanderingTraderTemptRange); // Purpur - Villagers follow emerald blocks + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Villagers follow emerald blocks ++ public static net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder createAttributes() { ++ return Mob.createMobAttributes().add(net.minecraft.world.entity.ai.attributes.Attributes.TEMPT_RANGE, 10.0D); ++ } ++ // Purpur end - Villagers follow emerald blocks ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +@@ -134,6 +141,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + this.goalSelector.addGoal(1, new PanicGoal(this, 0.5)); + this.goalSelector.addGoal(1, new LookAtTradingPlayerGoal(this)); + this.goalSelector.addGoal(2, new WanderingTrader.WanderToPositionGoal(this, 2.0, 0.35)); ++ if (level().purpurConfig.wanderingTraderFollowEmeraldBlock) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, TEMPT_ITEMS, false)); // Purpur - Villagers follow emerald blocks + this.goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 0.35)); + this.goalSelector.addGoal(8, new WaterAvoidingRandomStrollGoal(this, 0.35)); + this.goalSelector.addGoal(9, new InteractGoal(this, Player.class, 3.0F, 1.0F)); diff --git a/purpur-server/minecraft-patches/features/0008-Configurable-void-damage-height-and-damage.patch b/purpur-server/minecraft-patches/features/0008-Configurable-void-damage-height-and-damage.patch new file mode 100644 index 000000000..e666f3848 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0008-Configurable-void-damage-height-and-damage.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 27 Feb 2020 21:42:19 -0600 +Subject: [PATCH] Configurable void damage height and damage + +temporarily migrate to paper's config +drop patch on the next minecraft release + +diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java +index 9afbfe9bf493e09ca1963e8956ab7573964479b4..d04c06fafd133f773f311e7c2708fa8b049da67c 100644 +--- a/net/minecraft/server/MinecraftServer.java ++++ b/net/minecraft/server/MinecraftServer.java +@@ -1222,6 +1222,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Thu, 25 Jul 2019 18:07:37 -0500 +Subject: [PATCH] Implement elytra settings + + +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index d1f7da0f4adc4609247c349d7ccdb0e6bba9b8f8..6de5f527c018201d874e06a45c9509fa12125766 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -3595,7 +3595,18 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (i1 % 2 == 0) { + List list = EquipmentSlot.VALUES.stream().filter(slot -> canGlideUsing(this.getItemBySlot(slot), slot)).toList(); + EquipmentSlot equipmentSlot = Util.getRandom(list, this.random); +- this.getItemBySlot(equipmentSlot).hurtAndBreak(1, this, equipmentSlot); ++ ++ // Purpur start - Implement elytra settings ++ int damage = level().purpurConfig.elytraDamagePerSecond; ++ if (level().purpurConfig.elytraDamageMultiplyBySpeed > 0) { ++ double speed = getDeltaMovement().lengthSqr(); ++ if (speed > level().purpurConfig.elytraDamageMultiplyBySpeed) { ++ damage *= (int) speed; ++ } ++ } ++ ++ this.getItemBySlot(equipmentSlot).hurtAndBreak(damage, this, equipmentSlot); ++ // Purpur end - Implement elytra settings + } + + this.gameEvent(GameEvent.ELYTRA_GLIDE); +diff --git a/net/minecraft/world/item/FireworkRocketItem.java b/net/minecraft/world/item/FireworkRocketItem.java +index 75a9bd205f32b77c5d242cb9fac0f571ce36045a..b03f182c62c699cc222e67c1ae6eadf99c45d48d 100644 +--- a/net/minecraft/world/item/FireworkRocketItem.java ++++ b/net/minecraft/world/item/FireworkRocketItem.java +@@ -66,6 +66,19 @@ public class FireworkRocketItem extends Item implements ProjectileItem { + com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Firework) delayed.projectile().getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand)); + if (event.callEvent() && delayed.attemptSpawn()) { + player.awardStat(Stats.ITEM_USED.get(this)); // Moved up from below ++ ++ // Purpur start - Implement elytra settings ++ if (level.purpurConfig.elytraDamagePerFireworkBoost > 0) { ++ List list = net.minecraft.world.entity.EquipmentSlot.VALUES.stream().filter((enumitemslot) -> net.minecraft.world.entity.LivingEntity.canGlideUsing(player.getItemBySlot(enumitemslot), enumitemslot)).toList(); ++ net.minecraft.world.entity.EquipmentSlot enumitemslot = net.minecraft.Util.getRandom(list, player.random); ++ ++ ItemStack glideItem = player.getItemBySlot(enumitemslot); ++ if (player.canGlide()) { ++ glideItem.hurtAndBreak(level.purpurConfig.elytraDamagePerFireworkBoost, player, enumitemslot); ++ } ++ } ++ // Purpur end - Implement elytra settings ++ + if (event.shouldConsume() && !player.hasInfiniteMaterials()) { + itemInHand.shrink(1); // Moved up from below + } else { +diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java +index c5426585f53a3139dc9d188a73e3a7ff4cb2e492..264b713e8b7c3d5f7d8e1facc90a60349f2cf414 100644 +--- a/net/minecraft/world/item/ItemStack.java ++++ b/net/minecraft/world/item/ItemStack.java +@@ -733,6 +733,14 @@ public final class ItemStack implements DataComponentHolder { + org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(serverPlayer, this); // Paper - Add EntityDamageItemEvent + } + // CraftBukkit end ++ ++ // Purpur start - Implement elytra settings ++ if (this.has(DataComponents.GLIDER)) { ++ setDamageValue(this.getMaxDamage() - 1); ++ return; ++ } ++ // Purpur end - Implement elytra settings ++ + this.shrink(1); + onBreak.accept(item); + } +diff --git a/net/minecraft/world/item/TridentItem.java b/net/minecraft/world/item/TridentItem.java +index 07f8c7644a112bb1ba283d1eadd8661010e888a4..7ea7db834e7b627a1d7d37ca87cd43eb61408565 100644 +--- a/net/minecraft/world/item/TridentItem.java ++++ b/net/minecraft/world/item/TridentItem.java +@@ -133,6 +133,18 @@ public class TridentItem extends Item implements ProjectileItem { + f1 *= tridentSpinAttackStrength / squareRoot; + f2 *= tridentSpinAttackStrength / squareRoot; + org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(player, stack, f, f1, f2); // CraftBukkit ++ ++ // Purpur start - Implement elytra settings ++ List list = EquipmentSlot.VALUES.stream().filter((enumitemslot) -> LivingEntity.canGlideUsing(entity.getItemBySlot(enumitemslot), enumitemslot)).toList(); ++ if (!list.isEmpty()) { ++ EquipmentSlot enumitemslot = net.minecraft.Util.getRandom(list, entity.random); ++ ItemStack glideItem = entity.getItemBySlot(enumitemslot); ++ if (glideItem.has(net.minecraft.core.component.DataComponents.GLIDER) && level.purpurConfig.elytraDamagePerTridentBoost > 0) { ++ glideItem.hurtAndBreak(level.purpurConfig.elytraDamagePerTridentBoost, entity, enumitemslot); ++ } ++ } ++ // Purpur end - Implement elytra settings ++ + player.push(f, f1, f2); + player.startAutoSpinAttack(20, 8.0F, stack); + if (player.onGround()) { diff --git a/purpur-server/minecraft-patches/features/0010-Configurable-jockey-options.patch b/purpur-server/minecraft-patches/features/0010-Configurable-jockey-options.patch new file mode 100644 index 000000000..4a4f5728f --- /dev/null +++ b/purpur-server/minecraft-patches/features/0010-Configurable-jockey-options.patch @@ -0,0 +1,177 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 26 Mar 2020 21:39:32 -0500 +Subject: [PATCH] Configurable jockey options + + +diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java +index 9c328f67260606d9252547848d5916cab4290e74..83fc978a94be4655e8c47ee634b8cd280d2a6fde 100644 +--- a/net/minecraft/world/entity/monster/Drowned.java ++++ b/net/minecraft/world/entity/monster/Drowned.java +@@ -105,6 +105,23 @@ public class Drowned extends Zombie implements RangedAttackMob { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Configurable jockey options ++ @Override ++ public boolean jockeyOnlyBaby() { ++ return level().purpurConfig.drownedJockeyOnlyBaby; ++ } ++ ++ @Override ++ public double jockeyChance() { ++ return level().purpurConfig.drownedJockeyChance; ++ } ++ ++ @Override ++ public boolean jockeyTryExistingChickens() { ++ return level().purpurConfig.drownedJockeyTryExistingChickens; ++ } ++ // Purpur end - Configurable jockey options ++ + @Override + protected void addBehaviourGoals() { + this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0)); +diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java +index c2365ae1cf6f98e262f302a117c4647c383dfbb5..7a8951f93e65c6df145e30d44b9d928dd0c39189 100644 +--- a/net/minecraft/world/entity/monster/Husk.java ++++ b/net/minecraft/world/entity/monster/Husk.java +@@ -50,6 +50,23 @@ public class Husk extends Zombie { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Configurable jockey options ++ @Override ++ public boolean jockeyOnlyBaby() { ++ return level().purpurConfig.huskJockeyOnlyBaby; ++ } ++ ++ @Override ++ public double jockeyChance() { ++ return level().purpurConfig.huskJockeyChance; ++ } ++ ++ @Override ++ public boolean jockeyTryExistingChickens() { ++ return level().purpurConfig.huskJockeyTryExistingChickens; ++ } ++ // Purpur end - Configurable jockey options ++ + public static boolean checkHuskSpawnRules( + EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java +index 8886aa0da372223ecd4d1a17c60971e167ced886..63446c874e7153dcfb99133145c8b5311d7d86cd 100644 +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -125,6 +125,20 @@ public class Zombie extends Monster { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Configurable jockey options ++ public boolean jockeyOnlyBaby() { ++ return level().purpurConfig.zombieJockeyOnlyBaby; ++ } ++ ++ public double jockeyChance() { ++ return level().purpurConfig.zombieJockeyChance; ++ } ++ ++ public boolean jockeyTryExistingChickens() { ++ return level().purpurConfig.zombieJockeyTryExistingChickens; ++ } ++ // Purpur end - Configurable jockey options ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables +@@ -556,19 +570,18 @@ public class Zombie extends Monster { + } + + if (spawnGroupData instanceof Zombie.ZombieGroupData zombieGroupData) { +- if (zombieGroupData.isBaby) { +- this.setBaby(true); ++ if (!jockeyOnlyBaby() || zombieGroupData.isBaby) { // Purpur - Configurable jockey options ++ this.setBaby(zombieGroupData.isBaby); // Purpur - Configurable jockey options + if (zombieGroupData.canSpawnJockey) { +- if (random.nextFloat() < 0.05) { +- List entitiesOfClass = level.getEntitiesOfClass( ++ if (random.nextFloat() < jockeyChance()) { // Purpur - Configurable jockey options ++ List entitiesOfClass = jockeyTryExistingChickens() ? level.getEntitiesOfClass( // Purpur - Configurable jockey options + Chicken.class, this.getBoundingBox().inflate(5.0, 3.0, 5.0), EntitySelector.ENTITY_NOT_BEING_RIDDEN +- ); ++ ) : java.util.Collections.emptyList(); // Purpur - Configurable jockey options + if (!entitiesOfClass.isEmpty()) { + Chicken chicken = entitiesOfClass.get(0); + chicken.setChickenJockey(true); + this.startRiding(chicken); +- } +- } else if (random.nextFloat() < 0.05) { ++ } else { // Purpur - Configurable jockey options + Chicken chicken1 = EntityType.CHICKEN.create(this.level(), EntitySpawnReason.JOCKEY); + if (chicken1 != null) { + chicken1.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F); +@@ -577,6 +590,7 @@ public class Zombie extends Monster { + this.startRiding(chicken1); + level.addFreshEntity(chicken1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit + } ++ } // Purpur - Configurable jockey options + } + } + } +diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java +index 578cfc33a493b5ebc2ed42733577129a8953a461..f1e9bf75c50f353bd377051be82a391f97d952fd 100644 +--- a/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -107,6 +107,23 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Configurable jockey options ++ @Override ++ public boolean jockeyOnlyBaby() { ++ return level().purpurConfig.zombieVillagerJockeyOnlyBaby; ++ } ++ ++ @Override ++ public double jockeyChance() { ++ return level().purpurConfig.zombieVillagerJockeyChance; ++ } ++ ++ @Override ++ public boolean jockeyTryExistingChickens() { ++ return level().purpurConfig.zombieVillagerJockeyTryExistingChickens; ++ } ++ // Purpur end - Configurable jockey options ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +index 1424954f5b4cf0fbe821425cd741b4b5c1bfed50..9603589e0501feee900cd21b04eb84b02bb45de2 100644 +--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -88,6 +88,23 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Configurable jockey options ++ @Override ++ public boolean jockeyOnlyBaby() { ++ return level().purpurConfig.zombifiedPiglinJockeyOnlyBaby; ++ } ++ ++ @Override ++ public double jockeyChance() { ++ return level().purpurConfig.zombifiedPiglinJockeyChance; ++ } ++ ++ @Override ++ public boolean jockeyTryExistingChickens() { ++ return level().purpurConfig.zombifiedPiglinJockeyTryExistingChickens; ++ } ++ // Purpur end - Configurable jockey options ++ + @Override + public void setPersistentAngerTarget(@Nullable UUID target) { + this.persistentAngerTarget = target; diff --git a/patches/server/0063-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch b/purpur-server/minecraft-patches/features/0011-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch similarity index 63% rename from patches/server/0063-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch rename to purpur-server/minecraft-patches/features/0011-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch index b8b783a89..beeba7f4c 100644 --- a/patches/server/0063-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch +++ b/purpur-server/minecraft-patches/features/0011-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch @@ -4,28 +4,28 @@ Date: Thu, 9 May 2019 18:26:06 -0500 Subject: [PATCH] Phantoms attracted to crystals and crystals shoot phantoms -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -index d8e440e14b72dc48ae97244f1bed2c06abd997ab..2bac39e5ba09e08d23d2a4be37f7fe0da0ce71a6 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -@@ -31,6 +31,12 @@ public class EndCrystal extends Entity { +diff --git a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java +index 67711964552a8e32d3590a64aff78e1db768b026..d58829c88b86358a0c06a982b302fc9a31c15853 100644 +--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java ++++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java +@@ -26,6 +26,12 @@ public class EndCrystal extends Entity { private static final EntityDataAccessor DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN); public int time; public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals -+ // Purpur start ++ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms + private net.minecraft.world.entity.monster.Phantom targetPhantom; + private int phantomBeamTicks = 0; + private int phantomDamageCooldown = 0; + private int idleCooldown = 0; -+ // Purpur end ++ // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms - public EndCrystal(EntityType type, Level world) { - super(type, world); -@@ -80,6 +86,49 @@ public class EndCrystal extends Entity { - // Paper end - Fix invulnerable end crystals - } + public EndCrystal(EntityType entityType, Level level) { + super(entityType, level); +@@ -94,6 +100,49 @@ public class EndCrystal extends Entity { + // Paper end - Fix invulnerable end crystals + if (this.level().purpurConfig.endCrystalCramming > 0 && this.level().getEntitiesOfClass(EndCrystal.class, getBoundingBox()).size() > this.level().purpurConfig.endCrystalCramming) this.hurt(this.damageSources().cramming(), 6.0F); // Purpur - End Crystal Cramming -+ // Purpur start ++ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms + if (level().purpurConfig.phantomAttackedByCrystalRadius <= 0 || --idleCooldown > 0) { + return; // on cooldown + } @@ -67,80 +67,78 @@ index d8e440e14b72dc48ae97244f1bed2c06abd997ab..2bac39e5ba09e08d23d2a4be37f7fe0d + phantomBeamTicks = 0; + phantomDamageCooldown = 0; + idleCooldown = 60; -+ // Purpur end ++ // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms } @Override -diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index 01e8eaecec61e664838b5d7f18a9c3e730f00ddf..e0b1b0106fd3bbb6764d1b0a58ab2810181cac02 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -@@ -48,6 +48,7 @@ public class Phantom extends FlyingMob implements Enemy { - Vec3 moveTargetPoint; - public BlockPos anchorPoint; - Phantom.AttackPhase attackPhase; -+ Vec3 crystalPosition; // Purpur - - public Phantom(EntityType type, Level world) { - super(type, world); -@@ -115,6 +116,23 @@ public class Phantom extends FlyingMob implements Enemy { - level().addFreshEntity(flames); - return true; +diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java +index 08fc2dc0fecfa370c99e877d502149a8ea147e5f..aea7b608d88d243113f67665844841ac879c3f88 100644 +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -47,6 +47,7 @@ public class Phantom extends FlyingMob implements Enemy { + Vec3 moveTargetPoint = Vec3.ZERO; + public BlockPos anchorPoint = BlockPos.ZERO; + Phantom.AttackPhase attackPhase = Phantom.AttackPhase.CIRCLE; ++ Vec3 crystalPosition; // Purpur - Phantoms attracted to crystals and crystals shoot phantoms + // Paper start + @Nullable + public java.util.UUID spawningEntity; +@@ -118,6 +119,25 @@ public class Phantom extends FlyingMob implements Enemy { } -+ + // Purpur end - Ridables + ++ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms + @Override -+ protected void dropFromLootTable(DamageSource damageSource, boolean causedByPlayer) { ++ protected void dropFromLootTable(ServerLevel world, DamageSource damageSource, boolean causedByPlayer) { + boolean dropped = false; + if (lastHurtByPlayer == null && damageSource.getEntity() instanceof net.minecraft.world.entity.boss.enderdragon.EndCrystal) { + if (random.nextInt(5) < 1) { -+ dropped = spawnAtLocation(new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.PHANTOM_MEMBRANE)) != null; ++ dropped = spawnAtLocation(world, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.PHANTOM_MEMBRANE)) != null; + } + } + if (!dropped) { -+ super.dropFromLootTable(damageSource, causedByPlayer); ++ super.dropFromLootTable(world, damageSource, causedByPlayer); + } + } + + public boolean isCirclingCrystal() { + return crystalPosition != null; + } - // Purpur end - ++ // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms ++ @Override -@@ -129,11 +147,17 @@ public class Phantom extends FlyingMob implements Enemy { - + public boolean isFlapping() { + return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0; +@@ -131,9 +151,15 @@ public class Phantom extends FlyingMob implements Enemy { @Override protected void registerGoals() { -- this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables - this.goalSelector.addGoal(1, new Phantom.PhantomAttackStrategyGoal()); - this.goalSelector.addGoal(2, new Phantom.PhantomSweepAttackGoal()); - this.goalSelector.addGoal(3, new Phantom.PhantomCircleAroundAnchorGoal()); -- this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur -+ // Purpur start -+ this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); ++ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms + if (level().purpurConfig.phantomOrbitCrystalRadius > 0) { -+ this.goalSelector.addGoal(1, new FindCrystalGoal(this)); -+ this.goalSelector.addGoal(2, new OrbitCrystalGoal(this)); ++ this.goalSelector.addGoal(1, new PhantomFindCrystalGoal(this)); ++ this.goalSelector.addGoal(2, new PhantomOrbitCrystalGoal(this)); + } + this.goalSelector.addGoal(3, new Phantom.PhantomAttackStrategyGoal()); + this.goalSelector.addGoal(4, new Phantom.PhantomSweepAttackGoal()); + this.goalSelector.addGoal(5, new Phantom.PhantomCircleAroundAnchorGoal()); -+ this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); -+ // Purpur end ++ // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal()); } - -@@ -333,6 +357,124 @@ public class Phantom extends FlyingMob implements Enemy { - private AttackPhase() {} +@@ -509,6 +535,124 @@ public class Phantom extends FlyingMob implements Enemy { + } } -+ // Purpur start -+ class FindCrystalGoal extends Goal { ++ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms ++ class PhantomFindCrystalGoal extends Goal { + private final Phantom phantom; + private net.minecraft.world.entity.boss.enderdragon.EndCrystal crystal; + private Comparator comparator; + -+ FindCrystalGoal(Phantom phantom) { ++ PhantomFindCrystalGoal(Phantom phantom) { + this.phantom = phantom; + this.comparator = Comparator.comparingDouble(phantom::distanceToSqr); + this.setFlags(EnumSet.of(Flag.LOOK)); @@ -188,14 +186,14 @@ index 01e8eaecec61e664838b5d7f18a9c3e730f00ddf..e0b1b0106fd3bbb6764d1b0a58ab2810 + } + } + -+ class OrbitCrystalGoal extends Goal { ++ class PhantomOrbitCrystalGoal extends Goal { + private final Phantom phantom; + private float offset; + private float radius; + private float verticalChange; + private float direction; + -+ OrbitCrystalGoal(Phantom phantom) { ++ PhantomOrbitCrystalGoal(Phantom phantom) { + this.phantom = phantom; + this.setFlags(EnumSet.of(Flag.MOVE)); + } @@ -250,32 +248,8 @@ index 01e8eaecec61e664838b5d7f18a9c3e730f00ddf..e0b1b0106fd3bbb6764d1b0a58ab2810 + this.radius * Mth.sin(this.offset)); + } + } -+ // Purpur end ++ // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms + - private class PhantomMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - + class PhantomMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables private float speed = 0.1F; -diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -index 7fabef36d3f9a5294a62ed956010d7ef853e00ab..e1652079b92a5c951b5191997803e9d486892c61 100644 ---- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -+++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java -@@ -1065,6 +1065,9 @@ public class PurpurWorldConfig { - public String phantomAttackDamage = "6 + size"; - public Map phantomMaxHealthCache = new HashMap<>(); - public Map phantomAttackDamageCache = new HashMap<>(); -+ public double phantomAttackedByCrystalRadius = 0.0D; -+ public float phantomAttackedByCrystalDamage = 1.0F; -+ public double phantomOrbitCrystalRadius = 0.0D; - private void phantomSettings() { - phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); - phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); -@@ -1086,6 +1089,9 @@ public class PurpurWorldConfig { - phantomAttackDamage = getString("mobs.phantom.attributes.attack_damage", phantomAttackDamage); - phantomMaxHealthCache.clear(); - phantomAttackDamageCache.clear(); -+ phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius); -+ phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage); -+ phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius); - } - public boolean pigRidable = false; diff --git a/purpur-server/minecraft-patches/features/0012-Phantoms-burn-in-light.patch b/purpur-server/minecraft-patches/features/0012-Phantoms-burn-in-light.patch new file mode 100644 index 000000000..34631ae4b --- /dev/null +++ b/purpur-server/minecraft-patches/features/0012-Phantoms-burn-in-light.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: draycia +Date: Sun, 12 Apr 2020 20:41:59 -0700 +Subject: [PATCH] Phantoms burn in light + + +diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java +index aea7b608d88d243113f67665844841ac879c3f88..4cc1c8d8967b1e9ee5b0b1c50d887f3de3e8a882 100644 +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -53,6 +53,7 @@ public class Phantom extends FlyingMob implements Enemy { + public java.util.UUID spawningEntity; + public boolean shouldBurnInDay = true; + // Paper end ++ private static final net.minecraft.world.item.crafting.Ingredient TORCH = net.minecraft.world.item.crafting.Ingredient.of(net.minecraft.world.item.Items.TORCH, net.minecraft.world.item.Items.SOUL_TORCH); // Purpur - Phantoms burn in light + + public Phantom(EntityType entityType, Level level) { + super(entityType, level); +@@ -253,7 +254,11 @@ public class Phantom extends FlyingMob implements Enemy { + + @Override + public void aiStep() { +- if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API ++ // Purpur start - Phantoms burn in light ++ boolean burnFromDaylight = this.shouldBurnInDay && this.isSunBurnTick() && this.level().purpurConfig.phantomBurnInDaylight; ++ boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight; ++ if (this.isAlive() && (burnFromDaylight || burnFromLightSource)) { // Paper - shouldBurnInDay API ++ // Purpur end - Phantoms burn in light + if (getRider() == null || !this.isControllable()) // Purpur - Ridables + this.igniteForSeconds(8.0F); + } +@@ -374,6 +379,7 @@ public class Phantom extends FlyingMob implements Enemy { + List nearbyPlayers = serverLevel.getNearbyPlayers( + this.attackTargeting, Phantom.this, Phantom.this.getBoundingBox().inflate(16.0, 64.0, 16.0) + ); ++ if (level().purpurConfig.phantomIgnorePlayersWithTorch) nearbyPlayers.removeIf(human -> TORCH.test(human.getItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND)) || TORCH.test(human.getItemInHand(net.minecraft.world.InteractionHand.OFF_HAND))); // Purpur - Phantoms burn in light + if (!nearbyPlayers.isEmpty()) { + nearbyPlayers.sort(Comparator.comparing(Entity::getY).reversed()); + +@@ -739,6 +745,12 @@ public class Phantom extends FlyingMob implements Enemy { + return false; + } else if (!target.isAlive()) { + return false; ++ // Purpur start - Phantoms burn in light ++ } else if (level().purpurConfig.phantomBurnInLight > 0 && level().getLightEmission(new BlockPos(Phantom.this)) >= level().purpurConfig.phantomBurnInLight) { ++ return false; ++ } else if (level().purpurConfig.phantomIgnorePlayersWithTorch && (TORCH.test(target.getItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND)) || TORCH.test(target.getItemInHand(net.minecraft.world.InteractionHand.OFF_HAND)))) { ++ return false; ++ // Purpur end - Phantoms burn in light + } else if (target instanceof Player player && (target.isSpectator() || player.isCreative())) { + return false; + } else if (!this.canUse()) { diff --git a/purpur-server/minecraft-patches/features/0013-Make-entity-breeding-times-configurable.patch b/purpur-server/minecraft-patches/features/0013-Make-entity-breeding-times-configurable.patch new file mode 100644 index 000000000..87761065c --- /dev/null +++ b/purpur-server/minecraft-patches/features/0013-Make-entity-breeding-times-configurable.patch @@ -0,0 +1,600 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Sun, 15 Nov 2020 02:18:15 -0800 +Subject: [PATCH] Make entity breeding times configurable + + +diff --git a/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java b/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java +index 4fb63e58eac5d67fcd31c3233dca1dae72b98bc4..dd8d315eba203db121e24e3402f2117fc0f3043f 100644 +--- a/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java ++++ b/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java +@@ -118,8 +118,10 @@ public class VillagerMakeLove extends Behavior { + return Optional.empty(); + } + // Move age setting down +- parent.setAge(6000); +- partner.setAge(6000); ++ // Purpur start - Make entity breeding times configurable ++ parent.setAge(level.purpurConfig.villagerBreedingTicks); ++ partner.setAge(level.purpurConfig.villagerBreedingTicks); ++ // Purpur end - Make entity breeding times configurable + level.addFreshEntityWithPassengers(breedOffspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); + // CraftBukkit end + level.broadcastEntityEvent(breedOffspring, (byte)12); +diff --git a/net/minecraft/world/entity/animal/Animal.java b/net/minecraft/world/entity/animal/Animal.java +index 33c3752be451508343cad83766da7c3be1822d02..fa34e7f1c20dfd569b52a9c8e0a8d4d5e659ce20 100644 +--- a/net/minecraft/world/entity/animal/Animal.java ++++ b/net/minecraft/world/entity/animal/Animal.java +@@ -40,6 +40,7 @@ public abstract class Animal extends AgeableMob { + @Nullable + public UUID loveCause; + public ItemStack breedItem; // CraftBukkit - Add breedItem variable ++ public abstract int getPurpurBreedTime(); // Purpur - Make entity breeding times configurable + + protected Animal(EntityType entityType, Level level) { + super(entityType, level); +@@ -279,8 +280,10 @@ public abstract class Animal extends AgeableMob { + player.awardStat(Stats.ANIMALS_BRED); + CriteriaTriggers.BRED_ANIMALS.trigger(player, this, animal, baby); + } // Paper +- this.setAge(6000); +- animal.setAge(6000); ++ // Purpur start - Make entity breeding times configurable ++ this.setAge(this.getPurpurBreedTime()); ++ animal.setAge(animal.getPurpurBreedTime()); ++ // Purpur end - Make entity breeding times configurable + this.resetLove(); + animal.resetLove(); + level.broadcastEntityEvent(this, (byte)18); +diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java +index 3cdfded14a2fb74e3f345e893e60364b6b810075..199bd7e9b053a2eac76987ceb5caebc088d1071d 100644 +--- a/net/minecraft/world/entity/animal/Bee.java ++++ b/net/minecraft/world/entity/animal/Bee.java +@@ -480,6 +480,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.beeBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + public int getRemainingPersistentAngerTime() { + return this.entityData.get(DATA_REMAINING_ANGER_TIME); +diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java +index 98ce277c5b27591e22daa3c85241be1b8689bfae..584568cef949cee24aa7850d2ff99d47cd089a6e 100644 +--- a/net/minecraft/world/entity/animal/Cat.java ++++ b/net/minecraft/world/entity/animal/Cat.java +@@ -126,6 +126,13 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true); +diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java +index d718f0ed362c49803260dceed64bd93e2b6744fc..39ad1729ef03fc35a6365ee215be214eccfd959a 100644 +--- a/net/minecraft/world/entity/animal/Chicken.java ++++ b/net/minecraft/world/entity/animal/Chicken.java +@@ -81,6 +81,13 @@ public class Chicken extends Animal { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.chickenBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java +index d2a4bfa5334f7361067e4adac36ba5a4a4fa6ad8..e4965300eb41512d03a0b111422c98627cf29a54 100644 +--- a/net/minecraft/world/entity/animal/Cow.java ++++ b/net/minecraft/world/entity/animal/Cow.java +@@ -63,6 +63,13 @@ public class Cow extends Animal { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.cowBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java +index 8bf893837586ae2a9b4ef7564d242e16e4863b5d..1acf9b8c9e6a5915b3f095e83d3f209708947093 100644 +--- a/net/minecraft/world/entity/animal/Fox.java ++++ b/net/minecraft/world/entity/animal/Fox.java +@@ -175,6 +175,13 @@ public class Fox extends Animal implements VariantHolder { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.foxBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +@@ -969,8 +976,10 @@ public class Fox extends Animal implements VariantHolder { + CriteriaTriggers.BRED_ANIMALS.trigger(serverPlayer, this.animal, this.partner, fox); + } + +- this.animal.setAge(6000); +- this.partner.setAge(6000); ++ // Purpur start - Make entity breeding times configurable ++ this.animal.setAge(this.animal.getPurpurBreedTime()); ++ this.partner.setAge(this.partner.getPurpurBreedTime()); ++ // Purpur end - Make entity breeding times configurable + this.animal.resetLove(); + this.partner.resetLove(); + serverLevel.addFreshEntityWithPassengers(fox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason +diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java +index 990723c31aa1040a4e45b9857a18d86287ef91b4..a64b609bf5ce38a252bfa1bcff869f88e14389b5 100644 +--- a/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/net/minecraft/world/entity/animal/MushroomCow.java +@@ -79,6 +79,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.rabbitBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + public void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Sheep.java b/net/minecraft/world/entity/animal/Sheep.java +index b66440f5cfbd714c6d2f5b7f66b4e755602b4521..882c799cb66a2acada33ff24f3adb7eb611f89c1 100644 +--- a/net/minecraft/world/entity/animal/Sheep.java ++++ b/net/minecraft/world/entity/animal/Sheep.java +@@ -106,6 +106,13 @@ public class Sheep extends Animal implements Shearable { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.sheepBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + protected void registerGoals() { + this.eatBlockGoal = new EatBlockGoal(this); +diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java +index 4f0fbbb2caeda6d1477d3297fd68f802e4f3a9ca..edbccb7ca27aa8a1917eb8b35b3ba8600c91111a 100644 +--- a/net/minecraft/world/entity/animal/Turtle.java ++++ b/net/minecraft/world/entity/animal/Turtle.java +@@ -109,6 +109,13 @@ public class Turtle extends Animal { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.turtleBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + public void setHomePos(BlockPos homePos) { + this.entityData.set(HOME_POS, homePos); + } +diff --git a/net/minecraft/world/entity/animal/Wolf.java b/net/minecraft/world/entity/animal/Wolf.java +index afc12968313a408e8a71a20c2c0defde52605c4e..9d79946497cfc92ff11160b86d5064d86916af36 100644 +--- a/net/minecraft/world/entity/animal/Wolf.java ++++ b/net/minecraft/world/entity/animal/Wolf.java +@@ -210,6 +210,13 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder, B + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.axolotlBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + public float getWalkTargetValue(BlockPos pos, LevelReader level) { + return 0.0F; +diff --git a/net/minecraft/world/entity/animal/camel/Camel.java b/net/minecraft/world/entity/animal/camel/Camel.java +index 1d7e2358bac193af48dc4b7f5b0295e3bffa152b..1d7ae2a08968860636918e7c66b60139a9d761b4 100644 +--- a/net/minecraft/world/entity/animal/camel/Camel.java ++++ b/net/minecraft/world/entity/animal/camel/Camel.java +@@ -90,6 +90,13 @@ public class Camel extends AbstractHorse { + } + // Purpur end - Ridables + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.camelBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); +diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java +index 9a400c8bf2b54aa5fbcbe65b61670cac5fbebf05..c4ea9485294b7dec2582c638802f003ad70659b6 100644 +--- a/net/minecraft/world/entity/animal/frog/Frog.java ++++ b/net/minecraft/world/entity/animal/frog/Frog.java +@@ -165,6 +165,12 @@ public class Frog extends Animal implements VariantHolder> { + } + // Purpur end - Ridables + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.frogBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java +index 302208b566038a3a352ca867dd70a61887bac104..0a018dbfe3750cf91892d8cfb5c0eac18e83d587 100644 +--- a/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/net/minecraft/world/entity/animal/goat/Goat.java +@@ -128,6 +128,13 @@ public class Goat extends Animal { + } + // Purpur end - Ridables + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.goatBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java +index 223f1d109680e3643ab2c8343be22713e89755fd..b977597785df5665176ab2f330633ec61b7c9feb 100644 +--- a/net/minecraft/world/entity/animal/horse/Donkey.java ++++ b/net/minecraft/world/entity/animal/horse/Donkey.java +@@ -40,6 +40,13 @@ public class Donkey extends AbstractChestedHorse { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.donkeyBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + protected SoundEvent getAmbientSound() { + return SoundEvents.DONKEY_AMBIENT; +diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java +index 8bd118e82da9e4d4153de0a3efaf6d69e3c4c540..0339ab08b3029a9ffc102c5b865e411aca2a863c 100644 +--- a/net/minecraft/world/entity/animal/horse/Horse.java ++++ b/net/minecraft/world/entity/animal/horse/Horse.java +@@ -67,6 +67,13 @@ public class Horse extends AbstractHorse implements VariantHolder { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.horseBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + protected void randomizeAttributes(RandomSource random) { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt)); +diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java +index 58e726dd33f572a31b4910b9ff666c4252fb03a9..6efe52edb6909ed2b38210ce6a0334eddc55f261 100644 +--- a/net/minecraft/world/entity/animal/horse/Llama.java ++++ b/net/minecraft/world/entity/animal/horse/Llama.java +@@ -141,6 +141,13 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +index 54924cd7c84cbcd22ffc0bd37fc24f24e73c18bc..266d1838e6602ef6322c15732f2693a865911f2e 100644 +--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java ++++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +@@ -122,6 +122,13 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + this.timeInOverworld = timeInOverworld; + } + ++ // Purpur start - Make entity breeding times configurable ++ @Override ++ public int getPurpurBreedTime() { ++ return this.level().purpurConfig.hoglinBreedingTicks; ++ } ++ // Purpur end - Make entity breeding times configurable ++ + @Override + public boolean canBeLeashed() { + return true; diff --git a/purpur-server/minecraft-patches/features/0014-Apply-display-names-from-item-forms-of-entities-to-e.patch b/purpur-server/minecraft-patches/features/0014-Apply-display-names-from-item-forms-of-entities-to-e.patch new file mode 100644 index 000000000..15d244724 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0014-Apply-display-names-from-item-forms-of-entities-to-e.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Tue, 17 Nov 2020 03:23:48 -0800 +Subject: [PATCH] Apply display names from item forms of entities to entities + and vice versa + + +diff --git a/net/minecraft/world/entity/decoration/ArmorStand.java b/net/minecraft/world/entity/decoration/ArmorStand.java +index d368b1971b270c44efc849464a100832bc29a679..8c0ab32487c56e2caf42404184f86c9bcf5f8b41 100644 +--- a/net/minecraft/world/entity/decoration/ArmorStand.java ++++ b/net/minecraft/world/entity/decoration/ArmorStand.java +@@ -564,6 +564,7 @@ public class ArmorStand extends LivingEntity { + + private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(ServerLevel level, DamageSource damageSource) { // Paper + ItemStack itemStack = new ItemStack(Items.ARMOR_STAND); ++ if (level.purpurConfig.persistentDroppableEntityDisplayNames) // Purpur - Apply display names from item forms of entities to entities and vice versa + itemStack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); + this.drops.add(new DefaultDrop(itemStack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior + return this.brokenByAnything(level, damageSource); // Paper +diff --git a/net/minecraft/world/entity/decoration/ItemFrame.java b/net/minecraft/world/entity/decoration/ItemFrame.java +index 65e1d7c5ac94b1cfb921fa009be59d3e5872f0b5..3ee1d8798db666ee8d83556047e40ff217cda732 100644 +--- a/net/minecraft/world/entity/decoration/ItemFrame.java ++++ b/net/minecraft/world/entity/decoration/ItemFrame.java +@@ -223,7 +223,11 @@ public class ItemFrame extends HangingEntity { + this.removeFramedMap(item); + } else { + if (dropItem) { +- this.spawnAtLocation(level, this.getFrameItemStack()); ++ // Purpur start - Apply display names from item forms of entities to entities and vice versa ++ final ItemStack itemFrame = this.getFrameItemStack(); ++ if (!level.purpurConfig.persistentDroppableEntityDisplayNames) itemFrame.set(DataComponents.CUSTOM_NAME, null); ++ this.spawnAtLocation(level, itemFrame); ++ // Purpur end - Apply display names from item forms of entities to entities and vice versa + } + + if (!item.isEmpty()) { +diff --git a/net/minecraft/world/entity/decoration/Painting.java b/net/minecraft/world/entity/decoration/Painting.java +index 5b905a4d49c44b04d5795c2bf297f3c69d183d7c..b6429a2bbb6fc1e08610ab20e50f8f0414f0ad26 100644 +--- a/net/minecraft/world/entity/decoration/Painting.java ++++ b/net/minecraft/world/entity/decoration/Painting.java +@@ -162,7 +162,11 @@ public class Painting extends HangingEntity implements VariantHolder +Date: Sat, 5 Dec 2020 01:20:16 -0800 +Subject: [PATCH] Option for Villager Clerics to farm Nether Wart + +Adds an option so that Villagers with the Cleric profession are able to +farm Nether Wart. Reimplemented based on a feature of the carpet-extra +mod. + +diff --git a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java +index 4106549bd4dec1cc47d8765be8f5d119fe33bf56..e98fac58b29f78cb63bd868811cca41e1644e9ac 100644 +--- a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java ++++ b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java +@@ -32,6 +32,7 @@ public class HarvestFarmland extends Behavior { + private long nextOkStartTime; + private int timeWorkedSoFar; + private final List validFarmlandAroundVillager = Lists.newArrayList(); ++ private boolean clericWartFarmer = false; // Purpur - Option for Villager Clerics to farm Nether Wart + + public HarvestFarmland() { + super( +@@ -50,9 +51,10 @@ public class HarvestFarmland extends Behavior { + protected boolean checkExtraStartConditions(ServerLevel level, Villager owner) { + if (!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { + return false; +- } else if (owner.getVillagerData().getProfession() != VillagerProfession.FARMER) { ++ } else if (owner.getVillagerData().getProfession() != VillagerProfession.FARMER && !(level.purpurConfig.villagerClericsFarmWarts && owner.getVillagerData().getProfession() == VillagerProfession.CLERIC)) { // Purpur - Option for Villager Clerics to farm Nether Wart + return false; + } else { ++ if (!this.clericWartFarmer && owner.getVillagerData().getProfession() == VillagerProfession.CLERIC) this.clericWartFarmer = true; // Purpur - Option for Villager Clerics to farm Nether Wart + BlockPos.MutableBlockPos mutableBlockPos = owner.blockPosition().mutable(); + this.validFarmlandAroundVillager.clear(); + +@@ -83,6 +85,7 @@ public class HarvestFarmland extends Behavior { + BlockState blockState = serverLevel.getBlockState(pos); + Block block = blockState.getBlock(); + Block block1 = serverLevel.getBlockState(pos.below()).getBlock(); ++ if (this.clericWartFarmer) return block == net.minecraft.world.level.block.Blocks.NETHER_WART && blockState.getValue(net.minecraft.world.level.block.NetherWartBlock.AGE) == 3 || blockState.isAir() && block1 == net.minecraft.world.level.block.Blocks.SOUL_SAND; // Purpur - Option for Villager Clerics to farm Nether Wart + return block instanceof CropBlock && ((CropBlock)block).isMaxAge(blockState) || blockState.isAir() && block1 instanceof FarmBlock; + } + +@@ -109,19 +112,19 @@ public class HarvestFarmland extends Behavior { + BlockState blockState = level.getBlockState(this.aboveFarmlandPos); + Block block = blockState.getBlock(); + Block block1 = level.getBlockState(this.aboveFarmlandPos.below()).getBlock(); +- if (block instanceof CropBlock && ((CropBlock)block).isMaxAge(blockState)) { ++ if (block instanceof CropBlock && ((CropBlock)block).isMaxAge(blockState) && !this.clericWartFarmer || this.clericWartFarmer && block == net.minecraft.world.level.block.Blocks.NETHER_WART && blockState.getValue(net.minecraft.world.level.block.NetherWartBlock.AGE) == 3) { // Purpur - Option for Villager Clerics to farm Nether Wart + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(owner, this.aboveFarmlandPos, blockState.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state + level.destroyBlock(this.aboveFarmlandPos, true, owner); + } // CraftBukkit + } + +- if (blockState.isAir() && block1 instanceof FarmBlock && owner.hasFarmSeeds()) { ++ if (blockState.isAir() && block1 instanceof FarmBlock && !this.clericWartFarmer || this.clericWartFarmer && block1 == net.minecraft.world.level.block.Blocks.SOUL_SAND && owner.hasFarmSeeds()) { // Purpur - Option for Villager Clerics to farm Nether Wart + SimpleContainer inventory = owner.getInventory(); + + for (int i = 0; i < inventory.getContainerSize(); i++) { + ItemStack item = inventory.getItem(i); + boolean flag = false; +- if (!item.isEmpty() && item.is(ItemTags.VILLAGER_PLANTABLE_SEEDS) && item.getItem() instanceof BlockItem blockItem) { ++ if (!item.isEmpty() && (item.is(ItemTags.VILLAGER_PLANTABLE_SEEDS) || this.clericWartFarmer && item.getItem() == net.minecraft.world.item.Items.NETHER_WART) && item.getItem() instanceof BlockItem blockItem) { // Purpur - Option for Villager Clerics to farm Nether Wart + BlockState blockState1 = blockItem.getBlock().defaultBlockState(); + if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(owner, this.aboveFarmlandPos, blockState1)) { // CraftBukkit + level.setBlockAndUpdate(this.aboveFarmlandPos, blockState1); +@@ -136,7 +139,7 @@ public class HarvestFarmland extends Behavior { + this.aboveFarmlandPos.getX(), + this.aboveFarmlandPos.getY(), + this.aboveFarmlandPos.getZ(), +- SoundEvents.CROP_PLANTED, ++ this.clericWartFarmer ? SoundEvents.NETHER_WART_PLANTED : SoundEvents.CROP_PLANTED, // Purpur - Option for Villager Clerics to farm Nether Wart + SoundSource.BLOCKS, + 1.0F, + 1.0F +diff --git a/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java b/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java +index 243ac036f95794e7766aefb4630b635681ae5a5f..4d8523a43d60cd6b4fd5546ffb3a61417b2c475b 100644 +--- a/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java ++++ b/net/minecraft/world/entity/ai/behavior/TradeWithVillager.java +@@ -59,6 +59,12 @@ public class TradeWithVillager extends Behavior { + throwHalfStack(owner, ImmutableSet.of(Items.WHEAT), villager); + } + ++ // Purpur start - Option for Villager Clerics to farm Nether Wart ++ if (level.purpurConfig.villagerClericsFarmWarts && level.purpurConfig.villagerClericFarmersThrowWarts && owner.getVillagerData().getProfession() == VillagerProfession.CLERIC && owner.getInventory().countItem(Items.NETHER_WART) > Items.NETHER_WART.getDefaultMaxStackSize() / 2) { ++ throwHalfStack(owner, ImmutableSet.of(Items.NETHER_WART), villager); ++ } ++ // Purpur end - Option for Villager Clerics to farm Nether Wart ++ + if (!this.trades.isEmpty() && owner.getInventory().hasAnyOf(this.trades)) { + throwHalfStack(owner, this.trades, villager); + } +diff --git a/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java b/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java +index 84afd8646b05409c582f29d73f9fea4b09feb603..32779b121322688a4b14e460b1f902ef67770b32 100644 +--- a/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java ++++ b/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java +@@ -74,8 +74,13 @@ public class VillagerGoalPackages { + } + + public static ImmutableList>> getWorkPackage(VillagerProfession profession, float speedModifier) { ++ // Purpur start - Option for Villager Clerics to farm Nether Wart ++ return getWorkPackage(profession, speedModifier, false); ++ } ++ public static ImmutableList>> getWorkPackage(VillagerProfession profession, float speedModifier, boolean clericsFarmWarts) { ++ // Purpur end - Option for Villager Clerics to farm Nether Wart + WorkAtPoi workAtPoi; +- if (profession == VillagerProfession.FARMER) { ++ if (profession == VillagerProfession.FARMER || (clericsFarmWarts && profession == VillagerProfession.CLERIC)) { // Purpur - Option for Villager Clerics to farm Nether Wart + workAtPoi = new WorkAtComposter(); + } else { + workAtPoi = new WorkAtPoi(); +diff --git a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java +index 6b99afb4f237b5d6def98f3e03492975b795bc95..234e9d4aca14bc2a2e138918be1430516d710060 100644 +--- a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java ++++ b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java +@@ -22,6 +22,13 @@ public class SecondaryPoiSensor extends Sensor { + + @Override + protected void doTick(ServerLevel level, Villager entity) { ++ // Purpur start - Option for Villager Clerics to farm Nether Wart - make sure clerics don't wander to soul sand when the option is off ++ Brain brain = entity.getBrain(); ++ if (!level.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().getProfession() == net.minecraft.world.entity.npc.VillagerProfession.CLERIC) { ++ brain.eraseMemory(MemoryModuleType.SECONDARY_JOB_SITE); ++ return; ++ } ++ // Purpur end - Option for Villager Clerics to farm Nether Wart + ResourceKey resourceKey = level.dimension(); + BlockPos blockPos = entity.blockPosition(); + List list = Lists.newArrayList(); +@@ -38,7 +45,7 @@ public class SecondaryPoiSensor extends Sensor { + } + } + +- Brain brain = entity.getBrain(); ++ //Brain brain = entity.getBrain(); // Purpur - Option for Villager Clerics to farm Nether Wart - moved up + if (!list.isEmpty()) { + brain.setMemory(MemoryModuleType.SECONDARY_JOB_SITE, list); + } else { +diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java +index ff07cfe07200be23f17310522d737fca3251a580..017b54e0b8dec8996c90a3c6651867277dd516df 100644 +--- a/net/minecraft/world/entity/npc/Villager.java ++++ b/net/minecraft/world/entity/npc/Villager.java +@@ -311,7 +311,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + villagerBrain.setSchedule(Schedule.VILLAGER_DEFAULT); + villagerBrain.addActivityWithConditions( + Activity.WORK, +- VillagerGoalPackages.getWorkPackage(profession, 0.5F), ++ VillagerGoalPackages.getWorkPackage(profession, 0.5F, this.level().purpurConfig.villagerClericsFarmWarts), // Purpur - Option for Villager Clerics to farm Nether Wart + ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT)) + ); + } +@@ -977,7 +977,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + } + + public boolean hasFarmSeeds() { +- return this.getInventory().hasAnyMatching(itemStack -> itemStack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS)); ++ return this.getInventory().hasAnyMatching(itemStack -> this.level().purpurConfig.villagerClericsFarmWarts && this.getVillagerData().getProfession() == VillagerProfession.CLERIC ? itemStack.is(Items.NETHER_WART) : itemStack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS)); // Purpur - Option for Villager Clerics to farm Nether Wart + } + + @Override +diff --git a/net/minecraft/world/entity/npc/VillagerProfession.java b/net/minecraft/world/entity/npc/VillagerProfession.java +index 1ec8ad124c76483d11057eb97fcfb9aebee0c301..f783d058a080408d572938d36ba031f33a08e9af 100644 +--- a/net/minecraft/world/entity/npc/VillagerProfession.java ++++ b/net/minecraft/world/entity/npc/VillagerProfession.java +@@ -31,7 +31,7 @@ public record VillagerProfession( + public static final VillagerProfession ARMORER = register("armorer", PoiTypes.ARMORER, SoundEvents.VILLAGER_WORK_ARMORER); + public static final VillagerProfession BUTCHER = register("butcher", PoiTypes.BUTCHER, SoundEvents.VILLAGER_WORK_BUTCHER); + public static final VillagerProfession CARTOGRAPHER = register("cartographer", PoiTypes.CARTOGRAPHER, SoundEvents.VILLAGER_WORK_CARTOGRAPHER); +- public static final VillagerProfession CLERIC = register("cleric", PoiTypes.CLERIC, SoundEvents.VILLAGER_WORK_CLERIC); ++ public static final VillagerProfession CLERIC = register("cleric", PoiTypes.CLERIC, ImmutableSet.of(Items.NETHER_WART), ImmutableSet.of(Blocks.SOUL_SAND), SoundEvents.VILLAGER_WORK_CLERIC); // Purpur - Option for Villager Clerics to farm Nether Wart + public static final VillagerProfession FARMER = register( + "farmer", + PoiTypes.FARMER, diff --git a/purpur-server/minecraft-patches/features/0016-Add-mobGriefing-bypass-to-everything-affected.patch b/purpur-server/minecraft-patches/features/0016-Add-mobGriefing-bypass-to-everything-affected.patch new file mode 100644 index 000000000..4e21dcf5d --- /dev/null +++ b/purpur-server/minecraft-patches/features/0016-Add-mobGriefing-bypass-to-everything-affected.patch @@ -0,0 +1,360 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 5 Jan 2021 22:21:56 -0500 +Subject: [PATCH] Add mobGriefing bypass to everything affected + + +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index 6de5f527c018201d874e06a45c9509fa12125766..2dc588e2d503c16ccd2589ce18abd2ecebbc8e74 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -1818,7 +1818,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (this.level() instanceof ServerLevel serverLevel) { + boolean var6 = false; + if (this.dead && entitySource instanceof WitherBoss) { // Paper +- if (serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (serverLevel.purpurConfig.witherBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + BlockPos blockPos = this.blockPosition(); + BlockState blockState = Blocks.WITHER_ROSE.defaultBlockState(); + if (this.level().getBlockState(blockPos).isAir() && blockState.canSurvive(this.level(), blockPos)) { +diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java +index c431f28c3f4f6cec946048f5752c364429af5ba1..d93584c6793818463e8883ffe399bf16b03263a9 100644 +--- a/net/minecraft/world/entity/Mob.java ++++ b/net/minecraft/world/entity/Mob.java +@@ -648,7 +648,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + && this.canPickUpLoot() + && this.isAlive() + && !this.dead +- && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ && serverLevel.purpurConfig.entitiesPickUpLootBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + Vec3i pickupReach = this.getPickupReach(); + + for (ItemEntity itemEntity : this.level() +diff --git a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java +index e98fac58b29f78cb63bd868811cca41e1644e9ac..56d49bc71cb0cb0a08ff771991fd77ab774b4b59 100644 +--- a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java ++++ b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java +@@ -49,7 +49,7 @@ public class HarvestFarmland extends Behavior { + + @Override + protected boolean checkExtraStartConditions(ServerLevel level, Villager owner) { +- if (!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (!level.purpurConfig.villagerBypassMobGriefing == !level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + return false; + } else if (owner.getVillagerData().getProfession() != VillagerProfession.FARMER && !(level.purpurConfig.villagerClericsFarmWarts && owner.getVillagerData().getProfession() == VillagerProfession.CLERIC)) { // Purpur - Option for Villager Clerics to farm Nether Wart + return false; +diff --git a/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java +index e026e07ca86700c864a3dceda6817fb7b6cb11e9..f1dfe0bf047e7d331b2379a672ff7b8eae4c9c90 100644 +--- a/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java ++++ b/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java +@@ -30,7 +30,7 @@ public class BreakDoorGoal extends DoorInteractGoal { + @Override + public boolean canUse() { + return super.canUse() +- && getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ++ && this.mob.level().purpurConfig.zombieBypassMobGriefing == !getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) // Purpur - Add mobGriefing bypass to everything affected + && this.isValidDifficulty(this.mob.level().getDifficulty()) + && !this.isOpen(); + } +diff --git a/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/net/minecraft/world/entity/ai/goal/EatBlockGoal.java +index e84893780b533b1ecb3675606b5c2daf7339b861..65eb4d8001b07cb3f7cda17565eea10a88a9c47c 100644 +--- a/net/minecraft/world/entity/ai/goal/EatBlockGoal.java ++++ b/net/minecraft/world/entity/ai/goal/EatBlockGoal.java +@@ -67,7 +67,7 @@ public class EatBlockGoal extends Goal { + BlockPos blockPos = this.mob.blockPosition(); + final BlockState blockState = this.level.getBlockState(blockPos); // Paper - fix wrong block state + if (IS_TALL_GRASS.test(blockState)) { // Paper - fix wrong block state +- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).purpurConfig.sheepBypassMobGriefing == !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state // Purpur - Add mobGriefing bypass to everything affected + this.level.destroyBlock(blockPos, false); + } + +@@ -75,7 +75,7 @@ public class EatBlockGoal extends Goal { + } else { + BlockPos blockPos1 = blockPos.below(); + if (this.level.getBlockState(blockPos1).is(Blocks.GRASS_BLOCK)) { +- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).purpurConfig.sheepBypassMobGriefing == !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state // Purpur - Add mobGriefing bypass to everything affected + this.level.levelEvent(2001, blockPos1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState())); + this.level.setBlock(blockPos1, Blocks.DIRT.defaultBlockState(), 2); + } +diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +index 579ca031d461ed4327fe4fb45c5289565322e64e..95fa516910a3834bbd4db6d11279e13a1f0dac41 100644 +--- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java ++++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +@@ -35,7 +35,7 @@ public class RemoveBlockGoal extends MoveToBlockGoal { + + @Override + public boolean canUse() { +- if (!getServerLevel(this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (!getServerLevel(this.removerMob).purpurConfig.zombieBypassMobGriefing == !getServerLevel(this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + return false; + } else if (this.nextStartTick > 0) { + this.nextStartTick--; +diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java +index 1acf9b8c9e6a5915b3f095e83d3f209708947093..3d94d5c9ecab0fe7332daf4cdac879385159eaa1 100644 +--- a/net/minecraft/world/entity/animal/Fox.java ++++ b/net/minecraft/world/entity/animal/Fox.java +@@ -1038,7 +1038,7 @@ public class Fox extends Animal implements VariantHolder { + } + + protected void onReachedTarget() { +- if (getServerLevel(Fox.this.level()).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (getServerLevel(Fox.this.level()).purpurConfig.foxBypassMobGriefing ^ getServerLevel(Fox.this.level()).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + BlockState blockState = Fox.this.level().getBlockState(this.blockPos); + if (blockState.is(Blocks.SWEET_BERRY_BUSH)) { + this.pickSweetBerries(blockState); +diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java +index bbdd06002b07699fffebdf6ed8148abdb69c24cc..7379def14f3f700fb8a746dc89d89e249e93b7b9 100644 +--- a/net/minecraft/world/entity/animal/Rabbit.java ++++ b/net/minecraft/world/entity/animal/Rabbit.java +@@ -620,7 +620,7 @@ public class Rabbit extends Animal implements VariantHolder { + @Override + public boolean canUse() { + if (this.nextStartTick <= 0) { +- if (!getServerLevel(this.rabbit).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (!getServerLevel(this.rabbit).purpurConfig.rabbitBypassMobGriefing == !getServerLevel(this.rabbit).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + return false; + } + +diff --git a/net/minecraft/world/entity/animal/SnowGolem.java b/net/minecraft/world/entity/animal/SnowGolem.java +index d97a297db3bec0c86c6a82ef1c353015df2115f7..6ee73b798ab306f7c828c9f06ca5b1a96bd96139 100644 +--- a/net/minecraft/world/entity/animal/SnowGolem.java ++++ b/net/minecraft/world/entity/animal/SnowGolem.java +@@ -136,7 +136,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + this.hurtServer(serverLevel, this.damageSources().melting(), 1.0F); // CraftBukkit - DamageSources.ON_FIRE -> CraftEventFactory.MELTING + } + +- if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (!serverLevel.purpurConfig.snowGolemBypassMobGriefing == !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + return; + } + +diff --git a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +index ca900bb646e16c7b4342f23c3ffae786eab28145..724d259d4b793f2043e63dda9022bdfddc4dca38 100644 +--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java ++++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +@@ -547,7 +547,7 @@ public class EnderDragon extends Mob implements Enemy { + BlockPos blockPos = new BlockPos(i, i1, i2); + BlockState blockState = level.getBlockState(blockPos); + if (!blockState.isAir() && !blockState.is(BlockTags.DRAGON_TRANSPARENT)) { +- if (level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !blockState.is(BlockTags.DRAGON_IMMUNE)) { ++ if (level.purpurConfig.enderDragonBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !blockState.is(BlockTags.DRAGON_IMMUNE)) { // Purpur - Add mobGriefing bypass to everything affected + // CraftBukkit start - Add blocks to list rather than destroying them + //flag1 = level.removeBlock(blockPos, false) || flag1; + flag1 = true; +diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java +index 60e666aa8afe14b519010b6d137a89e3d22f6c81..a325fa87e149e7f354ed4cf3dbb30a002c4ce32a 100644 +--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java ++++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -493,7 +493,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { + + if (this.destroyBlocksTick > 0) { + this.destroyBlocksTick--; +- if (this.destroyBlocksTick == 0 && level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (this.destroyBlocksTick == 0 && level.purpurConfig.witherBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + boolean flag = false; + int alternativeTarget = Mth.floor(this.getBbWidth() / 2.0F + 1.0F); + int floor = Mth.floor(this.getBbHeight()); +diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java +index f8d6935439b4e672ed655b2a458451d4b1fa8ffd..7b74322aef3d7d45a322abccc71d9168b3c0911b 100644 +--- a/net/minecraft/world/entity/monster/EnderMan.java ++++ b/net/minecraft/world/entity/monster/EnderMan.java +@@ -516,7 +516,7 @@ public class EnderMan extends Monster implements NeutralMob { + public boolean canUse() { + if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls + return this.enderman.getCarriedBlock() != null +- && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ++ && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) == !this.enderman.level().purpurConfig.endermanBypassMobGriefing // Purpur - Add mobGriefing bypass to everything affected + && this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0; + } + +@@ -666,7 +666,7 @@ public class EnderMan extends Monster implements NeutralMob { + public boolean canUse() { + if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls + return this.enderman.getCarriedBlock() == null +- && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ++ && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) == !this.enderman.level().purpurConfig.endermanBypassMobGriefing // Purpur - Add mobGriefing bypass to everything affected + && this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0; + } + +diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java +index d3d7e11a12af404d83e81888a9a633dfb93412ec..91574baf7ca095eae909e8e7225ad500bde15af2 100644 +--- a/net/minecraft/world/entity/monster/Evoker.java ++++ b/net/minecraft/world/entity/monster/Evoker.java +@@ -323,7 +323,7 @@ public class Evoker extends SpellcasterIllager { + return false; + } else { + ServerLevel serverLevel = getServerLevel(Evoker.this.level()); +- if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ if (!serverLevel.purpurConfig.evokerBypassMobGriefing == !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + return false; + } else { + List nearbyEntities = serverLevel.getNearbyEntities( +diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java +index 36ebfc1102a18e4050eb9a2441d75bafcf3784b8..3449628fb87fd760abd730d84699c3a09c6ec761 100644 +--- a/net/minecraft/world/entity/monster/Ravager.java ++++ b/net/minecraft/world/entity/monster/Ravager.java +@@ -175,7 +175,7 @@ public class Ravager extends Raider { + + if (this.level() instanceof ServerLevel serverLevel + && this.horizontalCollision +- && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ && serverLevel.purpurConfig.ravagerBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected + boolean flag = false; + AABB aabb = this.getBoundingBox().inflate(0.2); + +diff --git a/net/minecraft/world/entity/monster/Silverfish.java b/net/minecraft/world/entity/monster/Silverfish.java +index d3befe91bc65bbc2bc0d8651b78e8c9576cd0f75..0d3b8b64a23a19d67a1a4a01faaf6649a59f54ad 100644 +--- a/net/minecraft/world/entity/monster/Silverfish.java ++++ b/net/minecraft/world/entity/monster/Silverfish.java +@@ -170,7 +170,7 @@ public class Silverfish extends Monster { + return false; + } else { + RandomSource random = this.mob.getRandom(); +- if (getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && random.nextInt(reducedTickDelay(10)) == 0) { ++ if (getServerLevel(this.mob).purpurConfig.silverfishBypassMobGriefing ^ getServerLevel(this.mob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && random.nextInt(reducedTickDelay(10)) == 0) { // Purpur - Add mobGriefing bypass to everything affected + this.selectedDirection = Direction.getRandom(random); + BlockPos blockPos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5, this.mob.getZ()).relative(this.selectedDirection); + BlockState blockState = this.mob.level().getBlockState(blockPos); +@@ -247,7 +247,7 @@ public class Silverfish extends Monster { + Block block = blockState.getBlock(); + if (block instanceof InfestedBlock) { + // CraftBukkit start +- BlockState afterState = getServerLevel(level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(blockPos1)); // Paper - fix wrong block state ++ BlockState afterState = getServerLevel(level).purpurConfig.silverfishBypassMobGriefing ^ getServerLevel(level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(blockPos1)); // Paper - fix wrong block state // Purpur - Add mobGriefing bypass to everything affected + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockPos1, afterState)) { // Paper - fix wrong block state + continue; + } +diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java +index 897c57263ab7347987b289016a71d11f693bc8b2..d923a424e2b33b7d4e9e4ecdce8e0a8c825038de 100644 +--- a/net/minecraft/world/entity/monster/piglin/Piglin.java ++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java +@@ -473,7 +473,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + + @Override + public boolean wantsToPickUp(ServerLevel level, ItemStack stack) { +- return level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack); ++ return level.purpurConfig.piglinBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && this.canPickUpLoot() && PiglinAi.wantsToPickup(this, stack); // Purpur - Add mobGriefing bypass to everything affected + } + + protected boolean canReplaceCurrentItem(ItemStack candidate) { +diff --git a/net/minecraft/world/entity/projectile/LargeFireball.java b/net/minecraft/world/entity/projectile/LargeFireball.java +index 4a752ace041228f095af7b1b4878a03c5ed2381f..3e8b5d042eddb817dee2504ff9aa263f6195b1c7 100644 +--- a/net/minecraft/world/entity/projectile/LargeFireball.java ++++ b/net/minecraft/world/entity/projectile/LargeFireball.java +@@ -18,20 +18,20 @@ public class LargeFireball extends Fireball { + + public LargeFireball(EntityType entityType, Level level) { + super(entityType, level); +- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit ++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.purpurConfig.fireballsBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit // Purpur - Add mobGriefing bypass to everything affected + } + + public LargeFireball(Level level, LivingEntity owner, Vec3 movement, int explosionPower) { + super(EntityType.FIREBALL, owner, movement, level); + this.explosionPower = explosionPower; +- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit ++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.purpurConfig.fireballsBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // CraftBukkit // Purpur - Add mobGriefing bypass to everything affected + } + + @Override + protected void onHit(HitResult result) { + super.onHit(result); + if (this.level() instanceof ServerLevel serverLevel) { +- boolean _boolean = serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); ++ boolean _boolean = serverLevel.purpurConfig.fireballsBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - Add mobGriefing bypass to everything affected + // CraftBukkit start - fire ExplosionPrimeEvent + org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); + this.level().getCraftServer().getPluginManager().callEvent(event); +diff --git a/net/minecraft/world/entity/projectile/Projectile.java b/net/minecraft/world/entity/projectile/Projectile.java +index ad0bb896d6ea669ce88bfe6490319e8ba7a29001..843f1396a6567672e5e8002d7e48fb18cf39d5de 100644 +--- a/net/minecraft/world/entity/projectile/Projectile.java ++++ b/net/minecraft/world/entity/projectile/Projectile.java +@@ -454,7 +454,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { + @Override + public boolean mayInteract(ServerLevel level, BlockPos pos) { + Entity owner = this.getOwner(); +- return owner instanceof Player ? owner.mayInteract(level, pos) : owner == null || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); ++ return owner instanceof Player ? owner.mayInteract(level, pos) : owner == null || level.purpurConfig.projectilesBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - Add mobGriefing bypass to everything affected + } + + public boolean mayBreak(ServerLevel level) { +diff --git a/net/minecraft/world/entity/projectile/SmallFireball.java b/net/minecraft/world/entity/projectile/SmallFireball.java +index 8c84cea43fc0e42a576004663670977eac99f1a6..808aa5dcb27c87b6ba5c1eee639486067447e370 100644 +--- a/net/minecraft/world/entity/projectile/SmallFireball.java ++++ b/net/minecraft/world/entity/projectile/SmallFireball.java +@@ -25,7 +25,7 @@ public class SmallFireball extends Fireball { + super(EntityType.SMALL_FIREBALL, owner, movement, level); + // CraftBukkit start + if (this.getOwner() != null && this.getOwner() instanceof Mob) { +- this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); ++ this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.purpurConfig.fireballsBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - Add mobGriefing bypass to everything affected + } + // CraftBukkit end + } +diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java +index 8270d76a753bfd26a4c8ef6610bee5c24ee59cfe..c06b589e669b055a26f662df60070d5908256220 100644 +--- a/net/minecraft/world/entity/raid/Raider.java ++++ b/net/minecraft/world/entity/raid/Raider.java +@@ -399,7 +399,7 @@ public abstract class Raider extends PatrollingMonster { + } + + private boolean cannotPickUpBanner() { +- if (!getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items ++ if (!this.mob.level().purpurConfig.pillagerBypassMobGriefing == !getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items // Purpur - Add mobGriefing bypass to everything affected + if (!this.mob.hasActiveRaid()) { + return true; + } else if (this.mob.getCurrentRaid().isOver()) { +diff --git a/net/minecraft/world/level/block/CropBlock.java b/net/minecraft/world/level/block/CropBlock.java +index b43f16297ac4441d78d0dc1fadb555698b0c3f6d..27f0c5c886a3f8b14ef9a00e2aaaabf4bf09c7db 100644 +--- a/net/minecraft/world/level/block/CropBlock.java ++++ b/net/minecraft/world/level/block/CropBlock.java +@@ -182,7 +182,7 @@ public class CropBlock extends BushBlock implements BonemealableBlock { + @Override + protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent +- if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.purpurConfig.ravagerGriefableBlocks.contains(serverLevel.getBlockState(pos).getBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Purpur - Configurable ravager griefable blocks list ++ if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.purpurConfig.ravagerGriefableBlocks.contains(serverLevel.getBlockState(pos).getBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.purpurConfig.ravagerBypassMobGriefing == !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Purpur - Configurable ravager griefable blocks list // Purpur - Add mobGriefing bypass to everything affected + serverLevel.destroyBlock(pos, true, entity); + } + +diff --git a/net/minecraft/world/level/block/FarmBlock.java b/net/minecraft/world/level/block/FarmBlock.java +index 6ab9a1188ce60e114ef35e393d9f2f46d490af83..9a7ca836e54cc3f58001c85f0079747f4d4941ad 100644 +--- a/net/minecraft/world/level/block/FarmBlock.java ++++ b/net/minecraft/world/level/block/FarmBlock.java +@@ -114,7 +114,7 @@ public class FarmBlock extends Block { + if (level instanceof ServerLevel serverLevel + && (serverLevel.purpurConfig.farmlandTrampleHeight >= 0D ? fallDistance >= serverLevel.purpurConfig.farmlandTrampleHeight : level.random.nextFloat() < fallDistance - 0.5F) // // Purpur - Configurable farmland trample height + && entity instanceof LivingEntity +- && (entity instanceof Player || serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) ++ && (entity instanceof Player || serverLevel.purpurConfig.farmlandBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) + && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { + // CraftBukkit start - Interact soil + org.bukkit.event.Cancellable cancellable; +diff --git a/net/minecraft/world/level/block/PowderSnowBlock.java b/net/minecraft/world/level/block/PowderSnowBlock.java +index 9c0ded7ae7e3a520704033a866f80743ae85d772..4f3646961beb877520e257e11224c3045467d351 100644 +--- a/net/minecraft/world/level/block/PowderSnowBlock.java ++++ b/net/minecraft/world/level/block/PowderSnowBlock.java +@@ -84,7 +84,7 @@ public class PowderSnowBlock extends Block implements BucketPickup { + // CraftBukkit - move down + && entity.mayInteract(serverLevel, pos)) { + // CraftBukkit start +- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !(serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || entity instanceof Player))) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !(serverLevel.purpurConfig.powderSnowBypassMobGriefing ^ serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || entity instanceof Player))) { + return; + } + // CraftBukkit end +diff --git a/net/minecraft/world/level/block/TurtleEggBlock.java b/net/minecraft/world/level/block/TurtleEggBlock.java +index c97d5bd7b4c1b6f8eccbe2d123292e913a285ef2..a3a093d95306baac22e5cf720f5b14f733b548d4 100644 +--- a/net/minecraft/world/level/block/TurtleEggBlock.java ++++ b/net/minecraft/world/level/block/TurtleEggBlock.java +@@ -216,7 +216,7 @@ public class TurtleEggBlock extends Block { + // Purpur end - Option to disable turtle egg trampling with feather falling + if (entity instanceof Player) return true; + +- return level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); ++ return level.purpurConfig.turtleEggsBypassMobGriefing ^ level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Purpur - Add mobGriefing bypass to everything affected + // Purpur end - Add turtle egg block options + } + } diff --git a/purpur-server/minecraft-patches/features/0017-Add-EntityTeleportHinderedEvent.patch b/purpur-server/minecraft-patches/features/0017-Add-EntityTeleportHinderedEvent.patch new file mode 100644 index 000000000..3947801b1 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0017-Add-EntityTeleportHinderedEvent.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 9 Jan 2021 15:26:04 +0100 +Subject: [PATCH] Add EntityTeleportHinderedEvent + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/net/minecraft/world/level/block/EndGatewayBlock.java b/net/minecraft/world/level/block/EndGatewayBlock.java +index 84a1bd5e40e635962d795506861447851e443eee..54abeb142e119edd1c1d1c263821b95b1f05c388 100644 +--- a/net/minecraft/world/level/block/EndGatewayBlock.java ++++ b/net/minecraft/world/level/block/EndGatewayBlock.java +@@ -98,6 +98,13 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal { + org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(level.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.END_GATEWAY); // Paper - add portal type + if (!event.callEvent()) return; + // Paper end - call EntityPortalEnterEvent ++ // Purpur start - Add EntityTeleportHinderedEvent ++ if (level.purpurConfig.imposeTeleportRestrictionsOnGateways && (entity.isVehicle() || entity.isPassenger())) { ++ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY).callEvent()) { ++ return; ++ } ++ } ++ // Purpur end - Add EntityTeleportHinderedEvent + entity.setAsInsidePortal(this, pos); + TheEndGatewayBlockEntity.triggerCooldown(level, pos, state, theEndGatewayBlockEntity); + } +diff --git a/net/minecraft/world/level/block/EndPortalBlock.java b/net/minecraft/world/level/block/EndPortalBlock.java +index 01cddd7001b4a7f99c1b1d147fac904d3064d733..7e60bcadd2d343e00fc554dba0b85c9191f7efb6 100644 +--- a/net/minecraft/world/level/block/EndPortalBlock.java ++++ b/net/minecraft/world/level/block/EndPortalBlock.java +@@ -58,6 +58,13 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { + protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + if (entity.canUsePortal(false)) { ++ // Purpur start - Add EntityTeleportHinderedEvent ++ if (level.purpurConfig.imposeTeleportRestrictionsOnEndPortals && (entity.isVehicle() || entity.isPassenger())) { ++ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL).callEvent()) { ++ return; ++ } ++ } ++ // Purpur end - Add EntityTeleportHinderedEvent + // CraftBukkit start - Entity in portal + org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(level.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.ENDER); // Paper - add portal type + level.getCraftServer().getPluginManager().callEvent(event); +diff --git a/net/minecraft/world/level/block/NetherPortalBlock.java b/net/minecraft/world/level/block/NetherPortalBlock.java +index 006444811c00a8820bddaf75950e794271efdd82..eb659209008209c0930770e5f9671a3d7a4abae6 100644 +--- a/net/minecraft/world/level/block/NetherPortalBlock.java ++++ b/net/minecraft/world/level/block/NetherPortalBlock.java +@@ -117,6 +117,13 @@ public class NetherPortalBlock extends Block implements Portal { + protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent + if (entity.canUsePortal(false)) { ++ // Purpur start - Add EntityTeleportHinderedEvent ++ if (level.purpurConfig.imposeTeleportRestrictionsOnNetherPortals && (entity.isVehicle() || entity.isPassenger())) { ++ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL).callEvent()) { ++ return; ++ } ++ } ++ // Purpur end - Add EntityTeleportHinderedEvent + // CraftBukkit start - Entity in portal + org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(level.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.NETHER); // Paper - add portal type + level.getCraftServer().getPluginManager().callEvent(event); diff --git a/purpur-server/minecraft-patches/features/0018-Toggle-for-water-sensitive-mob-damage.patch b/purpur-server/minecraft-patches/features/0018-Toggle-for-water-sensitive-mob-damage.patch new file mode 100644 index 000000000..bdc613a79 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0018-Toggle-for-water-sensitive-mob-damage.patch @@ -0,0 +1,1334 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: YouHaveTrouble +Date: Fri, 5 Feb 2021 01:11:22 +0100 +Subject: [PATCH] Toggle for water sensitive mob damage + + +diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java +index 898b1e01026ec1f44cfe60e9f18a997c86e30594..e717c063c8f9623b8c4b4ea3843d05fd79af3653 100644 +--- a/net/minecraft/world/entity/GlowSquid.java ++++ b/net/minecraft/world/entity/GlowSquid.java +@@ -52,6 +52,13 @@ public class GlowSquid extends Squid { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.glowSquidTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected ParticleOptions getInkParticle() { + return ParticleTypes.GLOW_SQUID_INK; +diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java +index ecbec552e5cd1935f57872d2fb502d3e9743e3d8..4fa526496265a85b637136f0fd0692ef4f570ad6 100644 +--- a/net/minecraft/world/entity/ambient/Bat.java ++++ b/net/minecraft/world/entity/ambient/Bat.java +@@ -109,6 +109,13 @@ public class Bat extends AmbientCreature { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.batTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public boolean isFlapping() { + return !this.isResting() && this.tickCount % 10.0F == 0.0F; +diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java +index 199bd7e9b053a2eac76987ceb5caebc088d1071d..636ff0f4f8415b6ce23d2676781503443c854cfe 100644 +--- a/net/minecraft/world/entity/animal/Bee.java ++++ b/net/minecraft/world/entity/animal/Bee.java +@@ -177,7 +177,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + // Paper end - Fix MC-167279 + this.lookControl = new Bee.BeeLookControl(this); + this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F); +- this.setPathfindingMalus(PathType.WATER, -1.0F); ++ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - Toggle for water sensitive mob damage + this.setPathfindingMalus(PathType.WATER_BORDER, 16.0F); + this.setPathfindingMalus(PathType.COCOA, -1.0F); + this.setPathfindingMalus(PathType.FENCE, -1.0F); +@@ -487,6 +487,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + } + // Purpur end - Make entity breeding times configurable + ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.beeTakeDamageFromWater; ++ } ++ + @Override + public int getRemainingPersistentAngerTime() { + return this.entityData.get(DATA_REMAINING_ANGER_TIME); +diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java +index 584568cef949cee24aa7850d2ff99d47cd089a6e..b41ca04043e65f107edaebc49d398650898e35fb 100644 +--- a/net/minecraft/world/entity/animal/Cat.java ++++ b/net/minecraft/world/entity/animal/Cat.java +@@ -133,6 +133,13 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true); +diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java +index 39ad1729ef03fc35a6365ee215be214eccfd959a..2364596156c21e82879f5bf4fd873b9d90b1c308 100644 +--- a/net/minecraft/world/entity/animal/Chicken.java ++++ b/net/minecraft/world/entity/animal/Chicken.java +@@ -88,6 +88,13 @@ public class Chicken extends Animal { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.chickenTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java +index 434e1fabf2e360a8f5f4eefed96e3883aa786d10..ac7259cfc8428131f90956d7f76f2227049ffae3 100644 +--- a/net/minecraft/world/entity/animal/Cod.java ++++ b/net/minecraft/world/entity/animal/Cod.java +@@ -32,6 +32,13 @@ public class Cod extends AbstractSchoolingFish { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.codTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public ItemStack getBucketItemStack() { + return new ItemStack(Items.COD_BUCKET); +diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java +index e4965300eb41512d03a0b111422c98627cf29a54..a8c76fcbbaa4afd2d0bd568874995b91d8d67c03 100644 +--- a/net/minecraft/world/entity/animal/Cow.java ++++ b/net/minecraft/world/entity/animal/Cow.java +@@ -70,6 +70,13 @@ public class Cow extends Animal { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.cowTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java +index 5b764c686e8759a7b04a7b50708c69629be02c04..e104058b3c01bea4cc8a77de2ad4378465903b34 100644 +--- a/net/minecraft/world/entity/animal/Dolphin.java ++++ b/net/minecraft/world/entity/animal/Dolphin.java +@@ -156,6 +156,13 @@ public class Dolphin extends AgeableWaterCreature { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.dolphinTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Nullable + @Override + public SpawnGroupData finalizeSpawn( +diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java +index 3d94d5c9ecab0fe7332daf4cdac879385159eaa1..22a70c6af965114e272bb56cb217f975a3cd1bd4 100644 +--- a/net/minecraft/world/entity/animal/Fox.java ++++ b/net/minecraft/world/entity/animal/Fox.java +@@ -182,6 +182,13 @@ public class Fox extends Animal implements VariantHolder { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.foxTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java +index 37a353cbb0e9b16e0fc92bd1bc8194cb4cd3c13a..23108729ce65ef8b7b215b82f29347513cfd4ebf 100644 +--- a/net/minecraft/world/entity/animal/IronGolem.java ++++ b/net/minecraft/world/entity/animal/IronGolem.java +@@ -98,6 +98,13 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.ironGolemTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options +diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java +index a64b609bf5ce38a252bfa1bcff869f88e14389b5..5e9795f447e88a42909730d383eaa36acfaf18f5 100644 +--- a/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/net/minecraft/world/entity/animal/MushroomCow.java +@@ -86,6 +86,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.rabbitTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java +index 93eb3cc3605f694337c1604e2db63fed04693617..8bd4b2b29438bff65ed00a42bbc9639111af181f 100644 +--- a/net/minecraft/world/entity/animal/Salmon.java ++++ b/net/minecraft/world/entity/animal/Salmon.java +@@ -54,6 +54,13 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder, B + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.axolotlTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public float getWalkTargetValue(BlockPos pos, LevelReader level) { + return 0.0F; +diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java +index 0a018dbfe3750cf91892d8cfb5c0eac18e83d587..0c357ffacfe4dd982a58e6cf2338c7e6b24610f5 100644 +--- a/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/net/minecraft/world/entity/animal/goat/Goat.java +@@ -135,6 +135,13 @@ public class Goat extends Animal { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.goatTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java +index b977597785df5665176ab2f330633ec61b7c9feb..1db6ccdc6c83c704aa84a46ee2751a17125bf457 100644 +--- a/net/minecraft/world/entity/animal/horse/Donkey.java ++++ b/net/minecraft/world/entity/animal/horse/Donkey.java +@@ -47,6 +47,13 @@ public class Donkey extends AbstractChestedHorse { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.donkeyTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected SoundEvent getAmbientSound() { + return SoundEvents.DONKEY_AMBIENT; +diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java +index 0339ab08b3029a9ffc102c5b865e411aca2a863c..f257d549570918381925cef98734fc0aa605f8f2 100644 +--- a/net/minecraft/world/entity/animal/horse/Horse.java ++++ b/net/minecraft/world/entity/animal/horse/Horse.java +@@ -74,6 +74,13 @@ public class Horse extends AbstractHorse implements VariantHolder { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.horseTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void randomizeAttributes(RandomSource random) { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt)); +diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java +index 6efe52edb6909ed2b38210ce6a0334eddc55f261..872a54186a20fd855fe7981f3ff1c867f4c64d19 100644 +--- a/net/minecraft/world/entity/animal/horse/Llama.java ++++ b/net/minecraft/world/entity/animal/horse/Llama.java +@@ -148,6 +148,13 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entityType, Level level) { + super(entityType, level); + this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur - Ridables +- this.setPathfindingMalus(PathType.WATER, -1.0F); ++ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - Toggle for water sensitive mob damage + this.setPathfindingMalus(PathType.LAVA, 8.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); + this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); +@@ -157,7 +157,7 @@ public class Blaze extends Monster { + + @Override + public boolean isSensitiveToWater() { +- return true; ++ return this.level().purpurConfig.blazeTakeDamageFromWater; // Purpur - Toggle for water sensitive mob damage + } + + @Override +diff --git a/net/minecraft/world/entity/monster/CaveSpider.java b/net/minecraft/world/entity/monster/CaveSpider.java +index 64eecd8d1acd318743800c1daa77cd97097a0f7c..420fe0d01d0b173a6a541f77e1aaca3f3bb565e7 100644 +--- a/net/minecraft/world/entity/monster/CaveSpider.java ++++ b/net/minecraft/world/entity/monster/CaveSpider.java +@@ -51,6 +51,13 @@ public class CaveSpider extends Spider { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.caveSpiderTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public boolean doHurtTarget(ServerLevel level, Entity source) { + if (super.doHurtTarget(level, source)) { +diff --git a/net/minecraft/world/entity/monster/Creeper.java b/net/minecraft/world/entity/monster/Creeper.java +index 31ede62a19321970d26f302399a60947b8d88b37..6d9995d5f38b2f94a2d3362da7861b3e90e4fb6f 100644 +--- a/net/minecraft/world/entity/monster/Creeper.java ++++ b/net/minecraft/world/entity/monster/Creeper.java +@@ -267,6 +267,13 @@ public class Creeper extends Monster { + } + // Purpur end - Config to make Creepers explode on death + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.creeperTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected SoundEvent getHurtSound(DamageSource damageSource) { + return SoundEvents.CREEPER_HURT; +diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java +index 83fc978a94be4655e8c47ee634b8cd280d2a6fde..0a1a78e65b6472b713835262b5937bc7ea67b95c 100644 +--- a/net/minecraft/world/entity/monster/Drowned.java ++++ b/net/minecraft/world/entity/monster/Drowned.java +@@ -122,6 +122,13 @@ public class Drowned extends Zombie implements RangedAttackMob { + } + // Purpur end - Configurable jockey options + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.drownedTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void addBehaviourGoals() { + this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0)); +diff --git a/net/minecraft/world/entity/monster/ElderGuardian.java b/net/minecraft/world/entity/monster/ElderGuardian.java +index 148ae4bca77874545a2a05fb7f29f9ac284feff6..2b1d33f4938b978c5b04ede7562bdecb5fbd2245 100644 +--- a/net/minecraft/world/entity/monster/ElderGuardian.java ++++ b/net/minecraft/world/entity/monster/ElderGuardian.java +@@ -51,6 +51,13 @@ public class ElderGuardian extends Guardian { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.elderGuardianTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + public static AttributeSupplier.Builder createAttributes() { + return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.ATTACK_DAMAGE, 8.0).add(Attributes.MAX_HEALTH, 80.0); + } +diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java +index 7b74322aef3d7d45a322abccc71d9168b3c0911b..6fccfb243c26c27b665df57e5e19eb3350c52ddf 100644 +--- a/net/minecraft/world/entity/monster/EnderMan.java ++++ b/net/minecraft/world/entity/monster/EnderMan.java +@@ -87,7 +87,7 @@ public class EnderMan extends Monster implements NeutralMob { + + public EnderMan(EntityType entityType, Level level) { + super(entityType, level); +- this.setPathfindingMalus(PathType.WATER, -1.0F); ++ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - Toggle for water sensitive mob damage + } + + // Purpur start - Ridables +@@ -294,7 +294,7 @@ public class EnderMan extends Monster implements NeutralMob { + + @Override + public boolean isSensitiveToWater() { +- return true; ++ return this.level().purpurConfig.endermanTakeDamageFromWater; // Purpur - Toggle for water sensitive mob damage + } + + @Override +diff --git a/net/minecraft/world/entity/monster/Endermite.java b/net/minecraft/world/entity/monster/Endermite.java +index 2ea45eba13d0b0ea2d3c1d1a3666d6e2e027a3ef..38e3b3ed2c003fe7bbb476f7bf9a882ea2de792a 100644 +--- a/net/minecraft/world/entity/monster/Endermite.java ++++ b/net/minecraft/world/entity/monster/Endermite.java +@@ -70,6 +70,13 @@ public class Endermite extends Monster { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.endermiteTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java +index 91574baf7ca095eae909e8e7225ad500bde15af2..61ed6606948cc5f8af543eb9ae05f9aeb4e73b89 100644 +--- a/net/minecraft/world/entity/monster/Evoker.java ++++ b/net/minecraft/world/entity/monster/Evoker.java +@@ -75,6 +75,13 @@ public class Evoker extends SpellcasterIllager { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.evokerTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Ghast.java b/net/minecraft/world/entity/monster/Ghast.java +index c5987f50b343ded580b3d3f264498d3893433f92..68debfa8c6d0fc3ff536d2b4d89c131fd6aca935 100644 +--- a/net/minecraft/world/entity/monster/Ghast.java ++++ b/net/minecraft/world/entity/monster/Ghast.java +@@ -84,6 +84,13 @@ public class Ghast extends FlyingMob implements Enemy { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.ghastTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables +diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java +index 73da18c4b54e250c434fd75971ef0a8f7c8cf6a3..009b8a8b1b9aabc0aef1c12a0c0f65f9ccfcd306 100644 +--- a/net/minecraft/world/entity/monster/Giant.java ++++ b/net/minecraft/world/entity/monster/Giant.java +@@ -62,6 +62,13 @@ public class Giant extends Monster { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.giantTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0); + } +diff --git a/net/minecraft/world/entity/monster/Guardian.java b/net/minecraft/world/entity/monster/Guardian.java +index 546a4fe6d038d04c0be500e76ff4aebb02c3681a..819679a224ffe33e03d8e6b429c8e31b67c769fa 100644 +--- a/net/minecraft/world/entity/monster/Guardian.java ++++ b/net/minecraft/world/entity/monster/Guardian.java +@@ -98,6 +98,13 @@ public class Guardian extends Monster { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.guardianTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + MoveTowardsRestrictionGoal moveTowardsRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0); +diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java +index 7a8951f93e65c6df145e30d44b9d928dd0c39189..31eef2869945d9de565d627cac3fc1a5db380a2a 100644 +--- a/net/minecraft/world/entity/monster/Husk.java ++++ b/net/minecraft/world/entity/monster/Husk.java +@@ -67,6 +67,13 @@ public class Husk extends Zombie { + } + // Purpur end - Configurable jockey options + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.huskTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + public static boolean checkHuskSpawnRules( + EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java +index 1d1cf8748e3fba2e2963ad2fa153fbfe990f5087..ad661f2bf8957644605b52a469d6a7cf8e064398 100644 +--- a/net/minecraft/world/entity/monster/Illusioner.java ++++ b/net/minecraft/world/entity/monster/Illusioner.java +@@ -84,6 +84,13 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.illusionerTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java +index 2c6b0fd46d9ed6a8d1ca7e90ebf596dd3f310f0e..bf26f5f6017c60d5991d5f6c87da2acbd95ef5bb 100644 +--- a/net/minecraft/world/entity/monster/MagmaCube.java ++++ b/net/minecraft/world/entity/monster/MagmaCube.java +@@ -68,6 +68,13 @@ public class MagmaCube extends Slime { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.magmaCubeTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); + } +diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java +index 4cc1c8d8967b1e9ee5b0b1c50d887f3de3e8a882..32b7c34d3c68dcfa936b628b2d038524204129a3 100644 +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -139,6 +139,13 @@ public class Phantom extends FlyingMob implements Enemy { + } + // Purpur end - Phantoms attracted to crystals and crystals shoot phantoms + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.phantomTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public boolean isFlapping() { + return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0; +diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java +index 9586aa3f3eb61fb0c1224df9d0104da69d7fa6bb..869a1007de13f3f5d757968d0f84cbf43786c870 100644 +--- a/net/minecraft/world/entity/monster/Pillager.java ++++ b/net/minecraft/world/entity/monster/Pillager.java +@@ -88,6 +88,13 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.pillagerTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java +index 3449628fb87fd760abd730d84699c3a09c6ec761..3d9eae0403875a99c25ccb47888dc591f051e744 100644 +--- a/net/minecraft/world/entity/monster/Ravager.java ++++ b/net/minecraft/world/entity/monster/Ravager.java +@@ -97,6 +97,13 @@ public class Ravager extends Raider { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.ravagerTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java +index 03db684c122a07176aa1365550da935cdb66a1b9..c26e4858a14571d58e439cabd5f2593da4ee2634 100644 +--- a/net/minecraft/world/entity/monster/Shulker.java ++++ b/net/minecraft/world/entity/monster/Shulker.java +@@ -129,6 +129,13 @@ public class Shulker extends AbstractGolem implements VariantHolder entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java +index f36e94437b4e21961532ac9ab91767617f9c3c32..d01bc46d77340b10b23d0c0d50bddc37657028c8 100644 +--- a/net/minecraft/world/entity/monster/Strider.java ++++ b/net/minecraft/world/entity/monster/Strider.java +@@ -88,7 +88,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { + public Strider(EntityType entityType, Level level) { + super(entityType, level); + this.blocksBuilding = true; +- this.setPathfindingMalus(PathType.WATER, -1.0F); ++ if (isSensitiveToWater()) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - Toggle for water sensitive mob damage + this.setPathfindingMalus(PathType.LAVA, 0.0F); + this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); + this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); +@@ -403,7 +403,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { + + @Override + public boolean isSensitiveToWater() { +- return true; ++ return this.level().purpurConfig.striderTakeDamageFromWater; // Purpur - Toggle for water sensitive mob damage + } + + @Override +diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java +index 8356906b2c0707e21021bb05f9ca01a95682880a..ffdb200d9716104f8df91dbeef590b2264e587b8 100644 +--- a/net/minecraft/world/entity/monster/Vex.java ++++ b/net/minecraft/world/entity/monster/Vex.java +@@ -110,6 +110,13 @@ public class Vex extends Monster implements TraceableEntity { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.vexTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public boolean isFlapping() { + return this.tickCount % TICKS_PER_FLAP == 0; +diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java +index 0fc1b458101ba9d98d25c9637337caf0949bb893..5f68d73460adfac2ead57d168156a2784af979ae 100644 +--- a/net/minecraft/world/entity/monster/Vindicator.java ++++ b/net/minecraft/world/entity/monster/Vindicator.java +@@ -80,6 +80,13 @@ public class Vindicator extends AbstractIllager { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.vindicatorTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java +index ff8380246f6c6c805b222a91ac6a1eb0d130558d..96ba35f3530ab405a960c79955699666deb6b845 100644 +--- a/net/minecraft/world/entity/monster/Witch.java ++++ b/net/minecraft/world/entity/monster/Witch.java +@@ -81,6 +81,13 @@ public class Witch extends Raider implements RangedAttackMob { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.witchTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java +index 3342f2d92830049837636ff10b5e52f0d85fbd2c..a4dc9b7fbde19b08eb389dc42df21aa5df94e703 100644 +--- a/net/minecraft/world/entity/monster/WitherSkeleton.java ++++ b/net/minecraft/world/entity/monster/WitherSkeleton.java +@@ -59,6 +59,13 @@ public class WitherSkeleton extends AbstractSkeleton { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.witherSkeletonTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); +diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java +index 132b38d717ac3c5acc64a5ec519f345ac57021d8..79a4a3f4e10e1f9c1a6100060a95636075fc8236 100644 +--- a/net/minecraft/world/entity/monster/Zoglin.java ++++ b/net/minecraft/world/entity/monster/Zoglin.java +@@ -110,6 +110,13 @@ public class Zoglin extends Monster implements HoglinBase { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.zoglinTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java +index 63446c874e7153dcfb99133145c8b5311d7d86cd..bb8c37c8348172947efe14d48ed9ae203409affa 100644 +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -139,6 +139,13 @@ public class Zombie extends Monster { + } + // Purpur end - Configurable jockey options + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.zombieTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables +diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java +index f1e9bf75c50f353bd377051be82a391f97d952fd..94b9abc765b78a40a7ecbf4cbd775b778d49c815 100644 +--- a/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -124,6 +124,13 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + } + // Purpur end - Configurable jockey options + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.zombieVillagerTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +index 9603589e0501feee900cd21b04eb84b02bb45de2..09c991d8e344f11bc84dea453042ee35c39e580e 100644 +--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -105,6 +105,13 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + } + // Purpur end - Configurable jockey options + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.zombifiedPiglinTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public void setPersistentAngerTarget(@Nullable UUID target) { + this.persistentAngerTarget = target; +diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +index 266d1838e6602ef6322c15732f2693a865911f2e..896bd531a5333d6dc8996bbdfc5c878b1a7d2da0 100644 +--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java ++++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +@@ -129,6 +129,13 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.hoglinTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public boolean canBeLeashed() { + return true; +diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java +index d923a424e2b33b7d4e9e4ecdce8e0a8c825038de..55ebfa5df06a59203248514d10dced9660ebf215 100644 +--- a/net/minecraft/world/entity/monster/piglin/Piglin.java ++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java +@@ -176,6 +176,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.piglinTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); +diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +index eb82252cd87797927e153974b9280b5eaa251080..2237681f298113bda0556699e19e880f4b04a853 100644 +--- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java ++++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +@@ -90,6 +90,13 @@ public class PiglinBrute extends AbstractPiglin { + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.piglinBruteTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes() + .add(Attributes.MAX_HEALTH, 50.0) +diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java +index 017b54e0b8dec8996c90a3c6651867277dd516df..97e5bb0cc335b23211e78044919282bfabad26a5 100644 +--- a/net/minecraft/world/entity/npc/Villager.java ++++ b/net/minecraft/world/entity/npc/Villager.java +@@ -278,6 +278,13 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + } + // Purpur end - Configurable entity base attributes + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.villagerTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + public Brain getBrain() { + return (Brain)super.getBrain(); +diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java +index 4ba2921dd99f674344fe3371332c9b23365d3aa2..8046a2d640e7c4d59cb5b9c6dff3bf5f026c7153 100644 +--- a/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -107,6 +107,13 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + } + // Purpur end - Villagers follow emerald blocks + ++ // Purpur start - Toggle for water sensitive mob damage ++ @Override ++ public boolean isSensitiveToWater() { ++ return this.level().purpurConfig.wanderingTraderTakeDamageFromWater; ++ } ++ // Purpur end - Toggle for water sensitive mob damage ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); diff --git a/purpur-server/minecraft-patches/features/0019-API-for-any-mob-to-burn-daylight.patch b/purpur-server/minecraft-patches/features/0019-API-for-any-mob-to-burn-daylight.patch new file mode 100644 index 000000000..82e4c0a82 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0019-API-for-any-mob-to-burn-daylight.patch @@ -0,0 +1,344 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Tue, 25 May 2021 16:31:09 -0400 +Subject: [PATCH] API for any mob to burn daylight + +Co-authored by: Encode42 + +diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java +index 62a38ecedbd579b32a8fd9cff5a433bfe635fc62..8473a7d9af9d83e97387ddf4cc50f6ad22730def 100644 +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -530,6 +530,24 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + // Purpur end - Add canSaveToDisk to Entity + ++ // Purpur start - copied from Mob - API for any mob to burn daylight ++ public boolean isSunBurnTick() { ++ if (this.level().isDay() && !this.level().isClientSide) { ++ float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue(); ++ BlockPos blockPos = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ()); ++ boolean flag = this.isInWaterRainOrBubble() || this.isInPowderSnow || this.wasInPowderSnow; ++ if (lightLevelDependentMagicValue > 0.5F ++ && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F ++ && !flag ++ && this.level().canSeeSky(blockPos)) { ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ // Purpur end - copied from Mob - API for any mob to burn daylight ++ + public Entity(EntityType entityType, Level level) { + this.type = entityType; + this.level = level; +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index 2dc588e2d503c16ccd2589ce18abd2ecebbc8e74..db5a2227009bc4d655fc781d5850221f36f2d112 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -301,6 +301,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper + public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event + public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API ++ protected boolean shouldBurnInDay = false; public boolean shouldBurnInDay() { return this.shouldBurnInDay; } public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } // Purpur - API for any mob to burn daylight + + @Override + public float getBukkitYaw() { +@@ -809,6 +810,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + }); + DataResult dataResult = this.brain.serializeStart(NbtOps.INSTANCE); + dataResult.resultOrPartial(LOGGER::error).ifPresent(brain -> compound.put("Brain", brain)); ++ compound.putBoolean("Purpur.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - API for any mob to burn daylight + } + + @Override +@@ -892,6 +894,12 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (compound.contains("Brain", 10)) { + this.brain = this.makeBrain(new Dynamic<>(NbtOps.INSTANCE, compound.get("Brain"))); + } ++ ++ // Purpur start - API for any mob to burn daylight ++ if (compound.contains("Purpur.ShouldBurnInDay")) { ++ this.shouldBurnInDay = compound.getBoolean("Purpur.ShouldBurnInDay"); ++ } ++ // Purpur end - API for any mob to burn daylight + } + + // CraftBukkit start +@@ -3574,6 +3582,32 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { + this.hurtServer(serverLevel, this.damageSources().drown(), 1.0F); + } ++ ++ // Purpur start - copied from Zombie - API for any mob to burn daylight ++ if (this.isAlive()) { ++ boolean flag = this.shouldBurnInDay() && this.isSunBurnTick(); // Paper - shouldBurnInDay API // Purpur - use shouldBurnInDay() method to handle Phantoms properly - API for any mob to burn daylight ++ if (flag) { ++ ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD); ++ if (!itemBySlot.isEmpty()) { ++ if (itemBySlot.isDamageableItem()) { ++ Item item = itemBySlot.getItem(); ++ itemBySlot.setDamageValue(itemBySlot.getDamageValue() + this.random.nextInt(2)); ++ if (itemBySlot.getDamageValue() >= itemBySlot.getMaxDamage()) { ++ this.onEquippedItemBroken(item, EquipmentSlot.HEAD); ++ this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY); ++ } ++ } ++ ++ flag = false; ++ } ++ ++ if (flag) { ++ if (getRider() == null || !this.isControllable()) // Purpur - ignore mobs which are uncontrollable or without rider - API for any mob to burn daylight ++ this.igniteForSeconds(8.0F); ++ } ++ } ++ } ++ // Purpur end - copied from Zombie - API for any mob to burn daylight + } + + public boolean isSensitiveToWater() { +diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java +index d93584c6793818463e8883ffe399bf16b03263a9..70ee86993d381445855ac7e7290da384d6675987 100644 +--- a/net/minecraft/world/entity/Mob.java ++++ b/net/minecraft/world/entity/Mob.java +@@ -1655,19 +1655,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + } + + public boolean isSunBurnTick() { +- if (this.level().isDay() && !this.level().isClientSide) { +- float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue(); +- BlockPos blockPos = BlockPos.containing(this.getX(), this.getEyeY(), this.getZ()); +- boolean flag = this.isInWaterRainOrBubble() || this.isInPowderSnow || this.wasInPowderSnow; +- if (lightLevelDependentMagicValue > 0.5F +- && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F +- && !flag +- && this.level().canSeeSky(blockPos)) { +- return true; +- } +- } +- +- return false; ++ // Purpur - implemented in Entity - API for any mob to burn daylight ++ return super.isSunBurnTick(); + } + + @Override +diff --git a/net/minecraft/world/entity/monster/AbstractSkeleton.java b/net/minecraft/world/entity/monster/AbstractSkeleton.java +index e186aee80b052b7fc4bfe02763010bfb2d55ea35..223739818e9ac6c9fe396b82bce53a3ab029610a 100644 +--- a/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -64,11 +64,12 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + AbstractSkeleton.this.setAggressive(true); + } + }; +- private boolean shouldBurnInDay = true; // Paper - shouldBurnInDay API ++ //private boolean shouldBurnInDay = true; // Paper - shouldBurnInDay API // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight + + protected AbstractSkeleton(EntityType entityType, Level level) { + super(entityType, level); + this.reassessWeaponGoal(); ++ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight + } + + @Override +@@ -110,27 +111,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + + @Override + public void aiStep() { +- boolean isSunBurnTick = this.shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API +- if (isSunBurnTick) { +- ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD); +- if (!itemBySlot.isEmpty()) { +- if (itemBySlot.isDamageableItem()) { +- Item item = itemBySlot.getItem(); +- itemBySlot.setDamageValue(itemBySlot.getDamageValue() + this.random.nextInt(2)); +- if (itemBySlot.getDamageValue() >= itemBySlot.getMaxDamage()) { +- this.onEquippedItemBroken(item, EquipmentSlot.HEAD); +- this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY); +- } +- } +- +- isSunBurnTick = false; +- } +- +- if (isSunBurnTick) { +- this.igniteForSeconds(8.0F); +- } +- } +- ++ // Purpur - implemented in LivingEntity - API for any mob to burn daylight + super.aiStep(); + } + +@@ -243,7 +224,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + super.readAdditionalSaveData(compound); + this.reassessWeaponGoal(); + // Paper start - shouldBurnInDay API +- if (compound.contains("Paper.ShouldBurnInDay")) { ++ if (false && compound.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight + this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay"); + } + // Paper end - shouldBurnInDay API +@@ -252,7 +233,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo + @Override + public void addAdditionalSaveData(final net.minecraft.nbt.CompoundTag nbt) { + super.addAdditionalSaveData(nbt); +- nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); ++ //nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - implemented in LivingEntity - API for any mob to burn daylight + } + // Paper end - shouldBurnInDay API + +diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java +index 31eef2869945d9de565d627cac3fc1a5db380a2a..e618e716cb5ff3a3c5d284e985455694cc0edde0 100644 +--- a/net/minecraft/world/entity/monster/Husk.java ++++ b/net/minecraft/world/entity/monster/Husk.java +@@ -19,6 +19,7 @@ import net.minecraft.world.level.ServerLevelAccessor; + public class Husk extends Zombie { + public Husk(EntityType entityType, Level level) { + super(entityType, level); ++ this.setShouldBurnInDay(false); // Purpur - API for any mob to burn daylight + } + + // Purpur start - Ridables +@@ -82,7 +83,7 @@ public class Husk extends Zombie { + + @Override + public boolean isSunSensitive() { +- return false; ++ return this.shouldBurnInDay; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight + } + + @Override +diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java +index 32b7c34d3c68dcfa936b628b2d038524204129a3..0ee817699fffbb929011465029182cc56befc30c 100644 +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -60,6 +60,7 @@ public class Phantom extends FlyingMob implements Enemy { + this.xpReward = 5; + this.moveControl = new Phantom.PhantomMoveControl(this); + this.lookControl = new Phantom.PhantomLookControl(this); ++ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight + } + + // Purpur start - Ridables +@@ -146,6 +147,16 @@ public class Phantom extends FlyingMob implements Enemy { + } + // Purpur end - Toggle for water sensitive mob damage + ++ //private boolean shouldBurnInDay = true; // Purpur - moved to LivingEntity; keep methods for ABI compatibility - API for any mob to burn daylight ++ // Purpur start - API for any mob to burn daylight ++ public boolean shouldBurnInDay() { ++ boolean burnFromDaylight = this.shouldBurnInDay && this.level().purpurConfig.phantomBurnInDaylight; ++ boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight; ++ return burnFromDaylight || burnFromLightSource; ++ } ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } ++ // Purpur end - API for any mob to burn daylight ++ + @Override + public boolean isFlapping() { + return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0; +@@ -261,6 +272,7 @@ public class Phantom extends FlyingMob implements Enemy { + + @Override + public void aiStep() { ++ // Purpur - implemented in LivingEntity; moved down to shouldBurnInDay() - API for any mob to burn daylight + // Purpur start - Phantoms burn in light + boolean burnFromDaylight = this.shouldBurnInDay && this.isSunBurnTick() && this.level().purpurConfig.phantomBurnInDaylight; + boolean burnFromLightSource = this.level().purpurConfig.phantomBurnInLight > 0 && this.level().getMaxLocalRawBrightness(blockPosition()) >= this.level().purpurConfig.phantomBurnInLight; +@@ -299,7 +311,7 @@ public class Phantom extends FlyingMob implements Enemy { + if (compound.hasUUID("Paper.SpawningEntity")) { + this.spawningEntity = compound.getUUID("Paper.SpawningEntity"); + } +- if (compound.contains("Paper.ShouldBurnInDay")) { ++ if (false && compound.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight + this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay"); + } + // Paper end +@@ -316,7 +328,7 @@ public class Phantom extends FlyingMob implements Enemy { + if (this.spawningEntity != null) { + compound.putUUID("Paper.SpawningEntity", this.spawningEntity); + } +- compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); ++ //compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Purpur - implemented in LivingEntity - API for any mob to burn daylight + // Paper end + } + +diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java +index bb8c37c8348172947efe14d48ed9ae203409affa..b1da45df27f02395d793e7eafe576f5f92aa3a7b 100644 +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -89,11 +89,12 @@ public class Zombie extends Monster { + private boolean canBreakDoors; + private int inWaterTime; + public int conversionTime; +- private boolean shouldBurnInDay = true; // Paper - Add more Zombie API ++ //private boolean shouldBurnInDay = true; // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight + + public Zombie(EntityType entityType, Level level) { + super(entityType, level); + this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(level.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(entityType, level.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty ++ this.setShouldBurnInDay(true); // Purpur - API for any mob to burn daylight + } + + public Zombie(Level level) { +@@ -290,29 +291,7 @@ public class Zombie extends Monster { + + @Override + public void aiStep() { +- if (this.isAlive()) { +- boolean flag = this.isSunSensitive() && this.isSunBurnTick(); +- if (flag) { +- ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD); +- if (!itemBySlot.isEmpty()) { +- if (itemBySlot.isDamageableItem()) { +- Item item = itemBySlot.getItem(); +- itemBySlot.setDamageValue(itemBySlot.getDamageValue() + this.random.nextInt(2)); +- if (itemBySlot.getDamageValue() >= itemBySlot.getMaxDamage()) { +- this.onEquippedItemBroken(item, EquipmentSlot.HEAD); +- this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY); +- } +- } +- +- flag = false; +- } +- +- if (flag) { +- this.igniteForSeconds(8.0F); +- } +- } +- } +- ++ // Purpur - implemented in LivingEntity - API for any mob to burn daylight + super.aiStep(); + } + +@@ -371,6 +350,7 @@ public class Zombie extends Monster { + // CraftBukkit end + } + ++ public boolean shouldBurnInDay() { return this.isSunSensitive(); } // Purpur - for ABI compatibility - API for any mob to burn daylight + public boolean isSunSensitive() { + return this.shouldBurnInDay; // Paper - Add more Zombie API + } +@@ -509,7 +489,7 @@ public class Zombie extends Monster { + compound.putBoolean("CanBreakDoors", this.canBreakDoors()); + compound.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1); + compound.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1); +- compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API ++ //compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight + } + + @Override +@@ -522,7 +502,7 @@ public class Zombie extends Monster { + this.startUnderWaterConversion(compound.getInt("DrownedConversionTime")); + } + // Paper start - Add more Zombie API +- if (compound.contains("Paper.ShouldBurnInDay")) { ++ if (false && compound.contains("Paper.ShouldBurnInDay")) { // Purpur - implemented in LivingEntity - API for any mob to burn daylight + this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay"); + } + // Paper end - Add more Zombie API diff --git a/purpur-server/minecraft-patches/features/0020-Cows-naturally-aggressive-to-players-chance.patch b/purpur-server/minecraft-patches/features/0020-Cows-naturally-aggressive-to-players-chance.patch new file mode 100644 index 000000000..9df4054e7 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0020-Cows-naturally-aggressive-to-players-chance.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 30 Aug 2021 22:49:53 -0500 +Subject: [PATCH] Cows naturally aggressive to players chance + + +diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java +index a8c76fcbbaa4afd2d0bd568874995b91d8d67c03..b62c4449047da36d8b4d4b87d03c77906d12dc31 100644 +--- a/net/minecraft/world/entity/animal/Cow.java ++++ b/net/minecraft/world/entity/animal/Cow.java +@@ -32,6 +32,8 @@ import net.minecraft.world.level.Level; + import net.minecraft.world.level.block.state.BlockState; + + public class Cow extends Animal { ++ private boolean isNaturallyAggressiveToPlayers; // Purpur - Cows naturally aggressive to players chance ++ + private static final EntityDimensions BABY_DIMENSIONS = EntityType.COW.getDimensions().scale(0.5F).withEyeHeight(0.665F); + + public Cow(EntityType entityType, Level level) { +@@ -60,6 +62,7 @@ public class Cow extends Animal { + public void initAttributes() { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.cowMaxHealth); + this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.cowScale); ++ this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(this.level().purpurConfig.cowNaturallyAggressiveToPlayersDamage); // Purpur - Cows naturally aggressive to players chance + } + // Purpur end - Configurable entity base attributes + +@@ -77,17 +80,27 @@ public class Cow extends Animal { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Cows naturally aggressive to players chance ++ @Override ++ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason spawnReason, net.minecraft.world.entity.SpawnGroupData entityData) { ++ this.isNaturallyAggressiveToPlayers = world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= world.getLevel().purpurConfig.cowNaturallyAggressiveToPlayersChance; ++ return super.finalizeSpawn(world, difficulty, spawnReason, entityData); ++ } ++ // Purpur end - Cows naturally aggressive to players chance ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.goalSelector.addGoal(1, new PanicGoal(this, 2.0)); ++ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - Cows naturally aggressive to players chance + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); + this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, itemStack -> level().purpurConfig.cowFeedMushrooms > 0 && (itemStack.is(net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem()) || itemStack.is(net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem())) || itemStack.is(ItemTags.COW_FOOD), false)); // Purpur - Cows eat mushrooms + this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur - Cows naturally aggressive to players chance + } + + @Override +@@ -96,7 +109,7 @@ public class Cow extends Animal { + } + + public static AttributeSupplier.Builder createAttributes() { +- return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.MOVEMENT_SPEED, 0.2F); ++ return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.MOVEMENT_SPEED, 0.2F).add(Attributes.ATTACK_DAMAGE, 0.0D); // Purpur - Cows naturally aggressive to players chance + } + + @Override diff --git a/purpur-server/minecraft-patches/features/0021-Mobs-always-drop-experience.patch b/purpur-server/minecraft-patches/features/0021-Mobs-always-drop-experience.patch new file mode 100644 index 000000000..48e8a9675 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0021-Mobs-always-drop-experience.patch @@ -0,0 +1,1302 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 21 Dec 2021 20:40:42 -0600 +Subject: [PATCH] Mobs always drop experience + + +diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java +index e717c063c8f9623b8c4b4ea3843d05fd79af3653..b982d4b7bdf39fcaf5f22cc889467d7b953e3a8e 100644 +--- a/net/minecraft/world/entity/GlowSquid.java ++++ b/net/minecraft/world/entity/GlowSquid.java +@@ -59,6 +59,13 @@ public class GlowSquid extends Squid { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.glowSquidAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected ParticleOptions getInkParticle() { + return ParticleTypes.GLOW_SQUID_INK; +diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java +index 4fa526496265a85b637136f0fd0692ef4f570ad6..4ac052a78841939a53dac2afb575cb115581e249 100644 +--- a/net/minecraft/world/entity/ambient/Bat.java ++++ b/net/minecraft/world/entity/ambient/Bat.java +@@ -116,6 +116,13 @@ public class Bat extends AmbientCreature { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.batAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public boolean isFlapping() { + return !this.isResting() && this.tickCount % 10.0F == 0.0F; +diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java +index 636ff0f4f8415b6ce23d2676781503443c854cfe..57c50ce5724b073b1aedf4df3129285143097303 100644 +--- a/net/minecraft/world/entity/animal/Bee.java ++++ b/net/minecraft/world/entity/animal/Bee.java +@@ -487,6 +487,13 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.beeAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public boolean isSensitiveToWater() { + return this.level().purpurConfig.beeTakeDamageFromWater; +diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java +index b41ca04043e65f107edaebc49d398650898e35fb..edd796fd34e43d66a48104201d885756fdd968c3 100644 +--- a/net/minecraft/world/entity/animal/Cat.java ++++ b/net/minecraft/world/entity/animal/Cat.java +@@ -140,6 +140,13 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true); +diff --git a/net/minecraft/world/entity/animal/Chicken.java b/net/minecraft/world/entity/animal/Chicken.java +index 2364596156c21e82879f5bf4fd873b9d90b1c308..4d0b172a9d54b1524c8052051859c7178774bef7 100644 +--- a/net/minecraft/world/entity/animal/Chicken.java ++++ b/net/minecraft/world/entity/animal/Chicken.java +@@ -95,6 +95,13 @@ public class Chicken extends Animal { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.chickenAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java +index ac7259cfc8428131f90956d7f76f2227049ffae3..b259de78198e0e3df9e5901019283ad246c8e044 100644 +--- a/net/minecraft/world/entity/animal/Cod.java ++++ b/net/minecraft/world/entity/animal/Cod.java +@@ -39,6 +39,13 @@ public class Cod extends AbstractSchoolingFish { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.codAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public ItemStack getBucketItemStack() { + return new ItemStack(Items.COD_BUCKET); +diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java +index b62c4449047da36d8b4d4b87d03c77906d12dc31..a0297ac3ba520122ed2095d6008c057d749b731e 100644 +--- a/net/minecraft/world/entity/animal/Cow.java ++++ b/net/minecraft/world/entity/animal/Cow.java +@@ -88,6 +88,13 @@ public class Cow extends Animal { + } + // Purpur end - Cows naturally aggressive to players chance + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.cowAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java +index e104058b3c01bea4cc8a77de2ad4378465903b34..7003b532182737a745491e397a967b72e6b308aa 100644 +--- a/net/minecraft/world/entity/animal/Dolphin.java ++++ b/net/minecraft/world/entity/animal/Dolphin.java +@@ -163,6 +163,13 @@ public class Dolphin extends AgeableWaterCreature { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.dolphinAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Nullable + @Override + public SpawnGroupData finalizeSpawn( +diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java +index 22a70c6af965114e272bb56cb217f975a3cd1bd4..aa610af9db105081fcabc1f299e5f2dd1f4d907e 100644 +--- a/net/minecraft/world/entity/animal/Fox.java ++++ b/net/minecraft/world/entity/animal/Fox.java +@@ -189,6 +189,13 @@ public class Fox extends Animal implements VariantHolder { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.foxAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java +index 23108729ce65ef8b7b215b82f29347513cfd4ebf..ccadc9a151e258ff2c74c65c374b1f09d56d10ec 100644 +--- a/net/minecraft/world/entity/animal/IronGolem.java ++++ b/net/minecraft/world/entity/animal/IronGolem.java +@@ -105,6 +105,13 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.ironGolemAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options +diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java +index 5e9795f447e88a42909730d383eaa36acfaf18f5..3bcd119757dfc579df790fcc8919a3636bafa7fe 100644 +--- a/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/net/minecraft/world/entity/animal/MushroomCow.java +@@ -93,6 +93,13 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.rabbitAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); +diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java +index 8bd4b2b29438bff65ed00a42bbc9639111af181f..5da2f14770aebb2286c3e8cbd9622a89a33e0e20 100644 +--- a/net/minecraft/world/entity/animal/Salmon.java ++++ b/net/minecraft/world/entity/animal/Salmon.java +@@ -61,6 +61,13 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder, B + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.axolotlAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public float getWalkTargetValue(BlockPos pos, LevelReader level) { + return 0.0F; +diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java +index 0c357ffacfe4dd982a58e6cf2338c7e6b24610f5..6f106f10466440f8e65e04511f67d48f082d703f 100644 +--- a/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/net/minecraft/world/entity/animal/goat/Goat.java +@@ -142,6 +142,13 @@ public class Goat extends Animal { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.goatAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java +index 1db6ccdc6c83c704aa84a46ee2751a17125bf457..3e0181578a6f2d22d1da3776abf30bf97d124620 100644 +--- a/net/minecraft/world/entity/animal/horse/Donkey.java ++++ b/net/minecraft/world/entity/animal/horse/Donkey.java +@@ -54,6 +54,13 @@ public class Donkey extends AbstractChestedHorse { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.donkeyAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected SoundEvent getAmbientSound() { + return SoundEvents.DONKEY_AMBIENT; +diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java +index f257d549570918381925cef98734fc0aa605f8f2..be0d636ca894c5995f28f59c196cd8e56dd228c4 100644 +--- a/net/minecraft/world/entity/animal/horse/Horse.java ++++ b/net/minecraft/world/entity/animal/horse/Horse.java +@@ -81,6 +81,13 @@ public class Horse extends AbstractHorse implements VariantHolder { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.horseAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void randomizeAttributes(RandomSource random) { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt)); +diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java +index 872a54186a20fd855fe7981f3ff1c867f4c64d19..c21d558a6a3a61d6c54b8163f8cb4963846b2c26 100644 +--- a/net/minecraft/world/entity/animal/horse/Llama.java ++++ b/net/minecraft/world/entity/animal/horse/Llama.java +@@ -155,6 +155,13 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java +index ad661f2bf8957644605b52a469d6a7cf8e064398..9686658b90e886d6236f553d7406771814d18672 100644 +--- a/net/minecraft/world/entity/monster/Illusioner.java ++++ b/net/minecraft/world/entity/monster/Illusioner.java +@@ -91,6 +91,13 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.illusionerAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java +index bf26f5f6017c60d5991d5f6c87da2acbd95ef5bb..312d4a3d312b5c326d6ca13ccfc48171e18f4370 100644 +--- a/net/minecraft/world/entity/monster/MagmaCube.java ++++ b/net/minecraft/world/entity/monster/MagmaCube.java +@@ -75,6 +75,13 @@ public class MagmaCube extends Slime { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.magmaCubeAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); + } +diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java +index 0ee817699fffbb929011465029182cc56befc30c..39f94cee78e8fc14d892cb64fb5234bf88d964ad 100644 +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -157,6 +157,13 @@ public class Phantom extends FlyingMob implements Enemy { + public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } + // Purpur end - API for any mob to burn daylight + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.phantomAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public boolean isFlapping() { + return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0; +diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java +index 869a1007de13f3f5d757968d0f84cbf43786c870..a57d869cdc6a05124237933437aa2d26ff72cab3 100644 +--- a/net/minecraft/world/entity/monster/Pillager.java ++++ b/net/minecraft/world/entity/monster/Pillager.java +@@ -95,6 +95,13 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.pillagerAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java +index 3d9eae0403875a99c25ccb47888dc591f051e744..ce5cd032203839887a29008c2a1420c6bb6f4fee 100644 +--- a/net/minecraft/world/entity/monster/Ravager.java ++++ b/net/minecraft/world/entity/monster/Ravager.java +@@ -104,6 +104,13 @@ public class Ravager extends Raider { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.ravagerAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java +index c26e4858a14571d58e439cabd5f2593da4ee2634..a006300aea2cbb05400550f1c79e872d095384f8 100644 +--- a/net/minecraft/world/entity/monster/Shulker.java ++++ b/net/minecraft/world/entity/monster/Shulker.java +@@ -136,6 +136,13 @@ public class Shulker extends AbstractGolem implements VariantHolder entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java +index d01bc46d77340b10b23d0c0d50bddc37657028c8..241526239bdbd5d9276f85e7fca46a7051f46a25 100644 +--- a/net/minecraft/world/entity/monster/Strider.java ++++ b/net/minecraft/world/entity/monster/Strider.java +@@ -126,6 +126,13 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { + } + // Purpur end - Make entity breeding times configurable + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.striderAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + public static boolean checkStriderSpawnRules( + EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random + ) { +diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java +index ffdb200d9716104f8df91dbeef590b2264e587b8..0ce9eb1f4108b6afab6df84d5e709be0882e515a 100644 +--- a/net/minecraft/world/entity/monster/Vex.java ++++ b/net/minecraft/world/entity/monster/Vex.java +@@ -117,6 +117,13 @@ public class Vex extends Monster implements TraceableEntity { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.vexAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public boolean isFlapping() { + return this.tickCount % TICKS_PER_FLAP == 0; +diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java +index 5f68d73460adfac2ead57d168156a2784af979ae..b584f71440a81ac09d24e59763a21e857f290e5a 100644 +--- a/net/minecraft/world/entity/monster/Vindicator.java ++++ b/net/minecraft/world/entity/monster/Vindicator.java +@@ -87,6 +87,13 @@ public class Vindicator extends AbstractIllager { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.vindicatorAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java +index 96ba35f3530ab405a960c79955699666deb6b845..e4353c64732067198f082cdd266c1f1ee1fe4f4e 100644 +--- a/net/minecraft/world/entity/monster/Witch.java ++++ b/net/minecraft/world/entity/monster/Witch.java +@@ -88,6 +88,13 @@ public class Witch extends Raider implements RangedAttackMob { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.witchAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + super.registerGoals(); +diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java +index a4dc9b7fbde19b08eb389dc42df21aa5df94e703..ff2596f69d00b36c65872ab2e27e5d44a6ffa3e1 100644 +--- a/net/minecraft/world/entity/monster/WitherSkeleton.java ++++ b/net/minecraft/world/entity/monster/WitherSkeleton.java +@@ -66,6 +66,13 @@ public class WitherSkeleton extends AbstractSkeleton { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.witherSkeletonAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); +diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java +index 79a4a3f4e10e1f9c1a6100060a95636075fc8236..d2a67f3e1c971f737e58567dae23fa70e9d942ea 100644 +--- a/net/minecraft/world/entity/monster/Zoglin.java ++++ b/net/minecraft/world/entity/monster/Zoglin.java +@@ -117,6 +117,13 @@ public class Zoglin extends Monster implements HoglinBase { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.zoglinAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); +diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java +index b1da45df27f02395d793e7eafe576f5f92aa3a7b..7af71c777dca26cd94b1807a2a77ea0d30e92976 100644 +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -147,6 +147,13 @@ public class Zombie extends Monster { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.zombieAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables +diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java +index 94b9abc765b78a40a7ecbf4cbd775b778d49c815..1ca0514732916d325c4a76d73120aaf613c3f780 100644 +--- a/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -131,6 +131,13 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.zombieVillagerAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); +diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +index 09c991d8e344f11bc84dea453042ee35c39e580e..fddbbffafea275dad187b7908386cf4c05c86743 100644 +--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -112,6 +112,13 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.zombifiedPiglinAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public void setPersistentAngerTarget(@Nullable UUID target) { + this.persistentAngerTarget = target; +diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +index 896bd531a5333d6dc8996bbdfc5c878b1a7d2da0..cf0a15ff4a49bcc17dc6dd58e91eadec0c519455 100644 +--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java ++++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java +@@ -136,6 +136,13 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.hoglinAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public boolean canBeLeashed() { + return true; +diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java +index 55ebfa5df06a59203248514d10dced9660ebf215..f0d78cf5fe2c39add9a673471103c352cce72a45 100644 +--- a/net/minecraft/world/entity/monster/piglin/Piglin.java ++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java +@@ -183,6 +183,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.piglinAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); +diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +index 2237681f298113bda0556699e19e880f4b04a853..4984b9864b63f92bc939b530253e871ca94a3277 100644 +--- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java ++++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +@@ -97,6 +97,13 @@ public class PiglinBrute extends AbstractPiglin { + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.piglinBruteAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + public static AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes() + .add(Attributes.MAX_HEALTH, 50.0) +diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java +index 97e5bb0cc335b23211e78044919282bfabad26a5..16fbe4e6521cd4f6baa8f5dd590da0fc749f6585 100644 +--- a/net/minecraft/world/entity/npc/Villager.java ++++ b/net/minecraft/world/entity/npc/Villager.java +@@ -285,6 +285,13 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.villagerAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + public Brain getBrain() { + return (Brain)super.getBrain(); +diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java +index 8046a2d640e7c4d59cb5b9c6dff3bf5f026c7153..c3fbcc7956a64d49466874776f257ba27f55f2a4 100644 +--- a/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -114,6 +114,13 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill + } + // Purpur end - Toggle for water sensitive mob damage + ++ // Purpur start - Mobs always drop experience ++ @Override ++ protected boolean isAlwaysExperienceDropper() { ++ return this.level().purpurConfig.wanderingTraderAlwaysDropExp; ++ } ++ // Purpur end - Mobs always drop experience ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); diff --git a/purpur-server/minecraft-patches/features/0022-config-for-turning-bundles-into-functional-quivers.patch b/purpur-server/minecraft-patches/features/0022-config-for-turning-bundles-into-functional-quivers.patch new file mode 100644 index 000000000..0169bc237 --- /dev/null +++ b/purpur-server/minecraft-patches/features/0022-config-for-turning-bundles-into-functional-quivers.patch @@ -0,0 +1,184 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: granny +Date: Mon, 16 Oct 2023 21:54:47 -0700 +Subject: [PATCH] config for turning bundles into functional quivers + + +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index db5a2227009bc4d655fc781d5850221f36f2d112..c26846d3b92be4ed8ec40ce21128dfe912f19298 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -4456,6 +4456,11 @@ public abstract class LivingEntity extends Entity implements Attackable { + } + + public ItemStack getProjectile(ItemStack weaponStack) { ++ // Purpur start - config for turning bundles into functional quivers ++ return getProjectile(weaponStack, false); ++ } ++ public ItemStack getProjectile(ItemStack weaponStack, boolean useBundleItemStack) { ++ // Purpur end - config for turning bundles into functional quivers + return ItemStack.EMPTY; + } + +diff --git a/net/minecraft/world/entity/monster/Monster.java b/net/minecraft/world/entity/monster/Monster.java +index c1ebb74b0d4a8e2eb8880ccaf20f0f9bc1940094..4d0916c0ec6c199f9ef359a17cda0891448d07f6 100644 +--- a/net/minecraft/world/entity/monster/Monster.java ++++ b/net/minecraft/world/entity/monster/Monster.java +@@ -144,6 +144,12 @@ public abstract class Monster extends PathfinderMob implements Enemy { + + @Override + public ItemStack getProjectile(ItemStack shootable) { ++ // Purpur start - config for turning bundles into functional quivers ++ return getProjectile(shootable, false); ++ } ++ @Override ++ public ItemStack getProjectile(ItemStack shootable, boolean useBundleItemStack) { ++ // Purpur end - config for turning bundles into functional quivers + if (shootable.getItem() instanceof ProjectileWeaponItem) { + Predicate supportedHeldProjectiles = ((ProjectileWeaponItem)shootable.getItem()).getSupportedHeldProjectiles(); + ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedHeldProjectiles); +diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java +index 43657822f0660613078e9afa512000b5255a1537..2363ec5b718b50cb178f231e544b89c00af79796 100644 +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -2294,6 +2294,12 @@ public abstract class Player extends LivingEntity { + + @Override + public ItemStack getProjectile(ItemStack shootable) { ++ // Purpur start - config for turning bundles into functional quivers ++ return getProjectile(shootable, false); ++ } ++ @Override ++ public ItemStack getProjectile(ItemStack shootable, boolean useBundleItemStack) { ++ // Purpur end - config for turning bundles into functional quivers + if (!(shootable.getItem() instanceof ProjectileWeaponItem)) { + return ItemStack.EMPTY; + } else { +@@ -2306,6 +2312,39 @@ public abstract class Player extends LivingEntity { + + for (int i = 0; i < this.inventory.getContainerSize(); i++) { + ItemStack item = this.inventory.getItem(i); ++ ++ // Purpur start - config for turning bundles into functional quivers ++ if ((this.level().purpurConfig.bowUseBundleAsQuiver || this.level().purpurConfig.crossbowUseBundleAsQuiver) && item.getItem() instanceof net.minecraft.world.item.BundleItem) { ++ net.minecraft.world.item.component.BundleContents bundleContents = item.get(net.minecraft.core.component.DataComponents.BUNDLE_CONTENTS); ++ if (bundleContents == null || bundleContents.isEmpty()) { ++ continue; ++ } ++ ++ Optional first = bundleContents.itemCopyStream().filter(supportedHeldProjectiles).findFirst(); ++ ++ if (first.isEmpty()) { ++ continue; ++ } ++ ++ ItemStack itemStack = first.get(); ++ if (useBundleItemStack) { ++ net.minecraft.world.item.component.BundleContents.Mutable mutable = new net.minecraft.world.item.component.BundleContents.Mutable(bundleContents); ++ ItemStack itemStack2 = mutable.removeOne(itemStack); ++ if (itemStack2 == null) { ++ continue; ++ } ++ ++ itemStack2.shrink(1); ++ if (itemStack2.getCount() != 0) { ++ mutable.tryInsert(itemStack2); ++ } ++ item.set(net.minecraft.core.component.DataComponents.BUNDLE_CONTENTS, mutable.toImmutable()); ++ } ++ itemStack.setCount(1); ++ return itemStack; ++ } ++ // Purpur end - config for turning bundles into functional quivers ++ + if (supportedHeldProjectiles.test(item)) { + return item; + } +diff --git a/net/minecraft/world/item/BowItem.java b/net/minecraft/world/item/BowItem.java +index b3e003694ce0da357e91ab3ce2b1380f9ab0a32a..186bd391ed3738734ca2d8e82339af0158ae4875 100644 +--- a/net/minecraft/world/item/BowItem.java ++++ b/net/minecraft/world/item/BowItem.java +@@ -27,7 +27,7 @@ public class BowItem extends ProjectileWeaponItem { + if (!(entity instanceof Player player)) { + return false; + } else { +- ItemStack projectile = player.getProjectile(stack); ++ ItemStack projectile = player.getProjectile(stack, true); // Purpur - config for turning bundles into functional quivers + // Purpur start - Infinity bow settings + if (level.purpurConfig.infinityWorksWithoutArrows && projectile.isEmpty() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, stack) > 0) { + projectile = new ItemStack(Items.ARROW); +diff --git a/net/minecraft/world/item/BundleItem.java b/net/minecraft/world/item/BundleItem.java +index 966029b761bcb31113b167831fe7f4f2dea4b17d..eda25cc71b4804d805b1a7f875f823b20efc754b 100644 +--- a/net/minecraft/world/item/BundleItem.java ++++ b/net/minecraft/world/item/BundleItem.java +@@ -131,7 +131,7 @@ public class BundleItem extends Item { + } + + private void dropContent(Level level, Player player, ItemStack stack) { +- if (this.dropContent(stack, player)) { ++ if (!(level.purpurConfig.bowUseBundleAsQuiver || level.purpurConfig.bowUseBundleAsQuiver) && this.dropContent(stack, player)) { // Purpur - config for turning bundles into functional quivers + playDropContentsSound(level, player); + player.awardStat(Stats.ITEM_USED.get(this)); + } +diff --git a/net/minecraft/world/item/CrossbowItem.java b/net/minecraft/world/item/CrossbowItem.java +index 1131e984fd30e40c1b99054b5db9462ffe55b5f1..c9dbe63316cad0437f50fa3f7ffe345ec1906752 100644 +--- a/net/minecraft/world/item/CrossbowItem.java ++++ b/net/minecraft/world/item/CrossbowItem.java +@@ -72,7 +72,7 @@ public class CrossbowItem extends ProjectileWeaponItem { + if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { + this.performShooting(level, player, hand, itemInHand, getShootingPower(chargedProjectiles), (float) level.purpurConfig.crossbowProjectileOffset, null); // Purpur - Projectile offset config + return InteractionResult.CONSUME; +- } else if (!player.getProjectile(itemInHand).isEmpty()) { ++ } else if (!player.getProjectile(itemInHand).isEmpty()) { // Purpur - config for turning bundles into functional quivers + this.startSoundPlayed = false; + this.midLoadSoundPlayed = false; + player.startUsingItem(hand); +@@ -124,7 +124,7 @@ public class CrossbowItem extends ProjectileWeaponItem { + return CrossbowItem.tryLoadProjectiles(shooter, crossbowStack, true); + } + private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbowStack, boolean consume) { +- List list = draw(crossbowStack, shooter.getProjectile(crossbowStack), shooter, consume); ++ List list = draw(crossbowStack, shooter.getProjectile(crossbowStack, true), shooter, consume); // Purpur - config for turning bundles into functional quivers + // Paper end - Add EntityLoadCrossbowEvent + if (!list.isEmpty()) { + crossbowStack.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(list)); +diff --git a/net/minecraft/world/item/component/BundleContents.java b/net/minecraft/world/item/component/BundleContents.java +index fca2dd0fb9ff4ff795a01de722fbb31dc02682fa..6fb9becef49bd4161c7829d240dd9e786f2226b5 100644 +--- a/net/minecraft/world/item/component/BundleContents.java ++++ b/net/minecraft/world/item/component/BundleContents.java +@@ -163,7 +163,12 @@ public final class BundleContents implements TooltipComponent { + } + + private int findStackIndex(ItemStack stack) { +- if (!stack.isStackable()) { ++ // Purpur start - config for turning bundles into functional quivers ++ return this.findStackIndex(stack, false); ++ } ++ private int findStackIndex(ItemStack stack, boolean skipStackableCheck) { ++ if (!skipStackableCheck && !stack.isStackable()) { ++ // Purpur end - config for turning bundles into functional quivers + return -1; + } else { + for (int i = 0; i < this.items.size(); i++) { +@@ -223,11 +228,20 @@ public final class BundleContents implements TooltipComponent { + + @Nullable + public ItemStack removeOne() { ++ // Purpur start - config for turning bundles into functional quivers ++ return this.removeOne(null); ++ } ++ @Nullable ++ public ItemStack removeOne(ItemStack itemStack2) { ++ // Purpur end - config for turning bundles into functional quivers + if (this.items.isEmpty()) { + return null; + } else { + int i = this.selectedItem != -1 && this.selectedItem < this.items.size() ? this.selectedItem : 0; +- ItemStack itemStack = this.items.remove(i).copy(); ++ // Purpur start - config for turning bundles into functional quivers ++ int stackIndex = itemStack2 != null ? this.findStackIndex(itemStack2, true) : -1; ++ ItemStack itemStack = this.items.remove(stackIndex == -1 ? i : stackIndex).copy(); ++ // Purpur end - config for turning bundles into functional quivers + this.weight = this.weight.subtract(BundleContents.getWeight(itemStack).multiplyBy(Fraction.getFraction(itemStack.getCount(), 1))); + this.toggleSelectedItem(-1); + return itemStack; diff --git a/purpur-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch b/purpur-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch new file mode 100644 index 000000000..cca45cce0 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch @@ -0,0 +1,19 @@ +--- a/io/papermc/paper/entity/activation/ActivationRange.java ++++ b/io/papermc/paper/entity/activation/ActivationRange.java +@@ -141,6 +_,8 @@ + continue; + } + ++ if (!player.level().purpurConfig.idleTimeoutTickNearbyEntities && player.isAfk()) continue; // Purpur - AFK API ++ + final int worldHeight = world.getHeight(); + ActivationRange.maxBB = player.getBoundingBox().inflate(maxRange, worldHeight, maxRange); + ActivationType.MISC.boundingBox = player.getBoundingBox().inflate(miscActivationRange, worldHeight, miscActivationRange); +@@ -282,6 +_,7 @@ + * @return + */ + public static boolean checkIfActive(final Entity entity) { ++ if (entity.level().purpurConfig.squidImmuneToEAR && entity instanceof net.minecraft.world.entity.animal.Squid) return true; // Purpur - Squid EAR immunity + // Never safe to skip fireworks or item gravity + if (entity instanceof FireworkRocketEntity || (entity instanceof ItemEntity && (entity.tickCount + entity.getId()) % 4 == 0)) { // Needed for item gravity, see ItemEntity tick + return true; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/CrashReport.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/CrashReport.java.patch new file mode 100644 index 000000000..52cafd0d1 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/CrashReport.java.patch @@ -0,0 +1,28 @@ +--- a/net/minecraft/CrashReport.java ++++ b/net/minecraft/CrashReport.java +@@ -30,6 +_,7 @@ + private boolean trackingStackTrace = true; + private StackTraceElement[] uncategorizedStackTrace = new StackTraceElement[0]; + private final SystemReport systemReport = new SystemReport(); ++ private List extraInfo = List.of("", "DO NOT REPORT THIS TO PAPER! REPORT TO PURPUR INSTEAD!", ""); // Purpur - Rebrand + + public CrashReport(String title, Throwable exception) { + io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper +@@ -130,7 +_,7 @@ + } + + public String getFriendlyReport(ReportType type) { +- return this.getFriendlyReport(type, List.of()); ++ return this.getFriendlyReport(type, extraInfo); // Purpur - Rebrand + } + + @Nullable +@@ -161,7 +_,7 @@ + } + + public boolean saveToFile(Path path, ReportType type) { +- return this.saveToFile(path, type, List.of()); ++ return this.saveToFile(path, type, extraInfo); // Purpur - Rebrand + } + + public SystemReport getSystemReport() { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/commands/CommandSourceStack.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/commands/CommandSourceStack.java.patch new file mode 100644 index 000000000..1a48edcf9 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/commands/CommandSourceStack.java.patch @@ -0,0 +1,53 @@ +--- a/net/minecraft/commands/CommandSourceStack.java ++++ b/net/minecraft/commands/CommandSourceStack.java +@@ -455,6 +_,19 @@ + } + // CraftBukkit end + ++ // Purpur start - Gamemode extra permissions ++ public boolean testPermission(int i, String bukkitPermission) { ++ if (hasPermission(i, bukkitPermission)) { ++ return true; ++ } ++ net.kyori.adventure.text.Component permissionMessage = getLevel().getServer().server.permissionMessage(); ++ if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) { ++ sendFailure(io.papermc.paper.adventure.PaperAdventure.asVanilla(permissionMessage.replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("").replacement(bukkitPermission).build()))); ++ } ++ return false; ++ } ++ // Purpur end - Gamemode extra permissions ++ + public Vec3 getPosition() { + return this.worldPosition; + } +@@ -540,6 +_,30 @@ + } + } + } ++ ++ // Purpur start - Purpur config files ++ public void sendSuccess(@Nullable String message) { ++ sendSuccess(message, false); ++ } ++ ++ public void sendSuccess(@Nullable String message, boolean broadcastToOps) { ++ if (message == null) { ++ return; ++ } ++ sendSuccess(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message), broadcastToOps); ++ } ++ ++ public void sendSuccess(@Nullable net.kyori.adventure.text.Component message) { ++ sendSuccess(message, false); ++ } ++ ++ public void sendSuccess(@Nullable net.kyori.adventure.text.Component message, boolean broadcastToOps) { ++ if (message == null) { ++ return; ++ } ++ sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(message), broadcastToOps); ++ } ++ // Purpur end - Purpur config files + + public void sendSuccess(Supplier messageSupplier, boolean allowLogging) { + boolean flag = this.source.acceptsSuccess() && !this.silent; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/commands/Commands.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/commands/Commands.java.patch new file mode 100644 index 000000000..f6226f550 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/commands/Commands.java.patch @@ -0,0 +1,44 @@ +--- a/net/minecraft/commands/Commands.java ++++ b/net/minecraft/commands/Commands.java +@@ -216,8 +_,8 @@ + JfrCommand.register(this.dispatcher); + } + +- if (SharedConstants.IS_RUNNING_IN_IDE) { +- TestCommand.register(this.dispatcher); ++ if (org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands || SharedConstants.IS_RUNNING_IN_IDE) { // Purpur - register minecraft debug commands ++ if (!org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands) TestCommand.register(this.dispatcher); // Purpur - register minecraft debug commands + RaidCommand.register(this.dispatcher, context); + DebugPathCommand.register(this.dispatcher); + DebugMobSpawningCommand.register(this.dispatcher); +@@ -245,6 +_,14 @@ + StopCommand.register(this.dispatcher); + TransferCommand.register(this.dispatcher); + WhitelistCommand.register(this.dispatcher); ++ org.purpurmc.purpur.command.CreditsCommand.register(this.dispatcher); // Purpur - Add credits command ++ org.purpurmc.purpur.command.DemoCommand.register(this.dispatcher); // Purpur - Add demo command ++ org.purpurmc.purpur.command.PingCommand.register(this.dispatcher); // Purpur - Add ping command ++ org.purpurmc.purpur.command.UptimeCommand.register(this.dispatcher); // Purpur - Add uptime command ++ org.purpurmc.purpur.command.TPSBarCommand.register(this.dispatcher); // Purpur - Implement TPSBar ++ org.purpurmc.purpur.command.CompassCommand.register(this.dispatcher); // Purpur - Add compass command ++ org.purpurmc.purpur.command.RamBarCommand.register(this.dispatcher); // Purpur - Add rambar command ++ org.purpurmc.purpur.command.RamCommand.register(this.dispatcher); // Purpur - Add ram command + } + + if (selection.includeIntegrated) { +@@ -488,6 +_,7 @@ + private void runSync(ServerPlayer player, java.util.Collection bukkit, RootCommandNode rootCommandNode) { + // Paper end - Perf: Async command map building + new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootCommandNode, true).callEvent(); // Paper - Brigadier API ++ if (org.bukkit.event.player.PlayerCommandSendEvent.getHandlerList().getRegisteredListeners().length > 0) { // Purpur - Skip events if there's no listeners + org.bukkit.event.player.PlayerCommandSendEvent event = new org.bukkit.event.player.PlayerCommandSendEvent(player.getBukkitEntity(), new java.util.LinkedHashSet<>(bukkit)); + event.getPlayer().getServer().getPluginManager().callEvent(event); + +@@ -498,6 +_,7 @@ + } + } + // CraftBukkit end ++ } // Purpur - Skip events if there's no listeners + + player.connection.send(new ClientboundCommandsPacket(rootCommandNode)); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch new file mode 100644 index 000000000..c89e997d6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch @@ -0,0 +1,45 @@ +--- a/net/minecraft/commands/arguments/selector/EntitySelector.java ++++ b/net/minecraft/commands/arguments/selector/EntitySelector.java +@@ -192,26 +_,27 @@ + this.checkPermissions(source); + if (this.playerName != null) { + ServerPlayer playerByName = source.getServer().getPlayerList().getPlayerByName(this.playerName); +- return playerByName == null ? List.of() : List.of(playerByName); ++ return playerByName == null || !canSee(source, playerByName) ? List.of() : List.of(playerByName); // Purpur - Hide hidden players from entity selector + } else if (this.entityUUID != null) { + ServerPlayer playerByName = source.getServer().getPlayerList().getPlayer(this.entityUUID); +- return playerByName == null ? List.of() : List.of(playerByName); ++ return playerByName == null || !canSee(source, playerByName) ? List.of() : List.of(playerByName); // Purpur - Hide hidden players from entity selector + } else { + Vec3 vec3 = this.position.apply(source.getPosition()); + AABB absoluteAabb = this.getAbsoluteAabb(vec3); + Predicate predicate = this.getPredicate(vec3, absoluteAabb, null); + if (this.currentEntity) { +- return source.getEntity() instanceof ServerPlayer serverPlayer && predicate.test(serverPlayer) ? List.of(serverPlayer) : List.of(); ++ return source.getEntity() instanceof ServerPlayer serverPlayer && predicate.test(serverPlayer) && canSee(source, serverPlayer) ? List.of(serverPlayer) : List.of(); // Purpur - Hide hidden players from entity selector + } else { + int resultLimit = this.getResultLimit(); + List players; + if (this.isWorldLimited()) { + players = source.getLevel().getPlayers(predicate, resultLimit); ++ players.removeIf(entityplayer3 -> !canSee(source, entityplayer3)); // Purpur - Hide hidden players from entity selector + } else { + players = new ObjectArrayList<>(); + + for (ServerPlayer serverPlayer1 : source.getServer().getPlayerList().getPlayers()) { +- if (predicate.test(serverPlayer1)) { ++ if (predicate.test(serverPlayer1) && canSee(source, serverPlayer1)) { // Purpur - Hide hidden players from entity selector + players.add(serverPlayer1); + if (players.size() >= resultLimit) { + return players; +@@ -270,4 +_,10 @@ + public static Component joinNames(List names) { + return ComponentUtils.formatList(names, Entity::getDisplayName); + } ++ ++ // Purpur start - Hide hidden players from entity selector ++ private boolean canSee(CommandSourceStack sender, ServerPlayer target) { ++ return !org.purpurmc.purpur.PurpurConfig.hideHiddenPlayersFromEntitySelector || !(sender.getEntity() instanceof ServerPlayer player) || player.getBukkitEntity().canSee(target.getBukkitEntity()); ++ } ++ // Purpur end - Hide hidden players from entity selector + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch new file mode 100644 index 000000000..8b669b1d6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/core/BlockPos.java ++++ b/net/minecraft/core/BlockPos.java +@@ -63,6 +_,12 @@ + public static final int MAX_HORIZONTAL_COORDINATE = 33554431; + // Paper end - Optimize Bit Operations by inlining + ++ // Purpur start - Ridables ++ public BlockPos(net.minecraft.world.entity.Entity entity) { ++ super(entity.getBlockX(), entity.getBlockY(), entity.getBlockZ()); ++ } ++ // Purpur end - Ridables ++ + public BlockPos(int x, int y, int z) { + super(x, y, z); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch new file mode 100644 index 000000000..067298651 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch @@ -0,0 +1,25 @@ +--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -892,5 +_,22 @@ + DispenserBlock.registerBehavior(Items.TNT_MINECART, new MinecartDispenseItemBehavior(EntityType.TNT_MINECART)); + DispenserBlock.registerBehavior(Items.HOPPER_MINECART, new MinecartDispenseItemBehavior(EntityType.HOPPER_MINECART)); + DispenserBlock.registerBehavior(Items.COMMAND_BLOCK_MINECART, new MinecartDispenseItemBehavior(EntityType.COMMAND_BLOCK_MINECART)); ++ // Purpur start - Dispensers place anvils option ++ DispenserBlock.registerBehavior(Items.ANVIL, (new OptionalDispenseItemBehavior() { ++ @Override ++ public ItemStack execute(BlockSource dispenser, ItemStack stack) { ++ net.minecraft.world.level.Level level = dispenser.level(); ++ if (!level.purpurConfig.dispenserPlaceAnvils) return super.execute(dispenser, stack); ++ Direction facing = dispenser.blockEntity().getBlockState().getValue(DispenserBlock.FACING); ++ BlockPos pos = dispenser.pos().relative(facing); ++ BlockState state = level.getBlockState(pos); ++ if (state.isAir()) { ++ level.setBlockAndUpdate(pos, Blocks.ANVIL.defaultBlockState().setValue(net.minecraft.world.level.block.AnvilBlock.FACING, facing.getAxis() == Direction.Axis.Y ? Direction.NORTH : facing.getClockWise())); ++ stack.shrink(1); ++ } ++ return stack; ++ } ++ })); ++ // Purpur end - Dispensers place anvils option + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch new file mode 100644 index 000000000..c0e69aa51 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java ++++ b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java +@@ -31,7 +_,7 @@ + return false; + } else { + LivingEntity livingEntity = entitiesOfClass.getFirst(); +- EquipmentSlot equipmentSlotForItem = livingEntity.getEquipmentSlotForItem(item); ++ EquipmentSlot equipmentSlotForItem = blockSource.level().purpurConfig.dispenserApplyCursedArmor ? livingEntity.getEquipmentSlotForItem(item) : livingEntity.getEquipmentSlotForDispenserItem(item); if (equipmentSlotForItem == null) return false; // Purpur - Dispenser curse of binding protection + ItemStack itemStack = item.copyWithCount(1); // Paper - shrink below and single item in event + // CraftBukkit start + net.minecraft.world.level.Level world = blockSource.level(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/GameTestHelper.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/GameTestHelper.java.patch new file mode 100644 index 000000000..2076037b3 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/gametest/framework/GameTestHelper.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/gametest/framework/GameTestHelper.java ++++ b/net/minecraft/gametest/framework/GameTestHelper.java +@@ -279,6 +_,8 @@ + return gameType.isCreative(); + } + ++ public void setAfk(final boolean afk) {} // Purpur - AFK API ++ + @Override + public boolean isLocalPlayer() { + return true; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch new file mode 100644 index 000000000..ac6b9a64d --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/network/Connection.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/network/Connection.java ++++ b/net/minecraft/network/Connection.java +@@ -588,11 +_,20 @@ + private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world + private static int joinAttemptsThisTick; // Paper - Buffer joins to world + private static int currTick; // Paper - Buffer joins to world ++ private static int tickSecond; // Purpur - Max joins per second + public void tick() { + this.flushQueue(); + // Paper start - Buffer joins to world + if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) { + Connection.currTick = net.minecraft.server.MinecraftServer.currentTick; ++ // Purpur start - Max joins per second ++ if (org.purpurmc.purpur.PurpurConfig.maxJoinsPerSecond) { ++ if (++Connection.tickSecond > 20) { ++ Connection.tickSecond = 0; ++ Connection.joinAttemptsThisTick = 0; ++ } ++ } else ++ // Purpur end - Max joins per second + Connection.joinAttemptsThisTick = 0; + } + // Paper end - Buffer joins to world diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch new file mode 100644 index 000000000..60c29bda0 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/network/chat/SignedMessageChain.java ++++ b/net/minecraft/network/chat/SignedMessageChain.java +@@ -45,7 +_,7 @@ + SignedMessageLink signedMessageLink = SignedMessageChain.this.nextLink; + if (signedMessageLink == null) { + throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.CHAIN_BROKEN); +- } else if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) { ++ } else if (org.purpurmc.purpur.PurpurConfig.kickForOutOfOrderChat && body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) { // Purpur - Option to disable kick for out of order chat + this.setChainBroken(); + throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes + } else { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/Main.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/Main.java.patch new file mode 100644 index 000000000..16550b7e6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/Main.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/server/Main.java ++++ b/net/minecraft/server/Main.java +@@ -108,6 +_,12 @@ + JvmProfiler.INSTANCE.start(Environment.SERVER); + } + ++ // Purpur start - Add toggle for enchant level clamping - load config files early ++ org.bukkit.configuration.file.YamlConfiguration purpurConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("purpur-settings")); ++ org.purpurmc.purpur.PurpurConfig.clampEnchantLevels = purpurConfiguration.getBoolean("settings.enchantment.clamp-levels", true); ++ org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands = purpurConfiguration.getBoolean("settings.register-minecraft-debug-commands"); // Purpur - register minecraft debug commands ++ // Purpur end - Add toggle for enchant level clamping - load config files early ++ + io.papermc.paper.plugin.PluginInitializerManager.load(optionSet); // Paper + Bootstrap.bootStrap(); + Bootstrap.validate(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch new file mode 100644 index 000000000..a3769afc7 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -0,0 +1,133 @@ +--- a/net/minecraft/server/MinecraftServer.java ++++ b/net/minecraft/server/MinecraftServer.java +@@ -284,6 +_,7 @@ + public joptsimple.OptionSet options; + public org.bukkit.command.ConsoleCommandSender console; + public static int currentTick; // Paper - improve tick loop ++ public static final long startTimeMillis = System.currentTimeMillis(); // Purpur - Add uptime command + public java.util.Queue processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); + public int autosavePeriod; + // Paper - don't store the vanilla dispatcher +@@ -294,7 +_,7 @@ + public static final int TICK_TIME = 1000000000 / MinecraftServer.TPS; + private static final int SAMPLE_INTERVAL = 20; // Paper - improve server tick loop + @Deprecated(forRemoval = true) // Paper +- public final double[] recentTps = new double[3]; ++ public final double[] recentTps = new double[4]; // Purpur - Add 5 second tps average in /tps + // Spigot end + public volatile boolean hasFullyShutdown; // Paper - Improved watchdog support + public volatile boolean abnormalExit; // Paper - Improved watchdog support +@@ -302,7 +_,9 @@ + public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files + public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked + private final Set pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping ++ public boolean lagging = false; // Purpur - Lagging threshold + public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation ++ protected boolean upnp = false; // Purpur - UPnP Port Forwarding + + public static S spin(Function threadFunction) { + ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system +@@ -1001,6 +_,15 @@ + + LOGGER.info("Stopping server"); + Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing ++ // Purpur start - UPnP Port Forwarding ++ if (upnp) { ++ if (dev.omega24.upnp4j.UPnP4J.close(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) { ++ LOGGER.info("[UPnP] Port {} closed", this.getPort()); ++ } else { ++ LOGGER.error("[UPnP] Failed to close port {}", this.getPort()); ++ } ++ } ++ // Purpur end - UPnP Port Forwarding + // CraftBukkit start + if (this.server != null) { + this.server.spark.disable(); // Paper - spark +@@ -1093,6 +_,8 @@ + this.safeShutdown(waitForServer, false); + } + public void safeShutdown(boolean waitForServer, boolean isRestarting) { ++ org.purpurmc.purpur.task.BossBarTask.stopAll(); // Purpur - Implement TPSBar ++ org.purpurmc.purpur.task.BeehiveTask.instance().unregister(); // Purpur - Give bee counts in beehives to Purpur clients + this.isRestarting = isRestarting; + this.hasLoggedStop = true; // Paper - Debugging + if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging +@@ -1112,6 +_,7 @@ + private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L; + private long lastTick = 0; + private long catchupTime = 0; ++ public final RollingAverage tps5s = new RollingAverage(5); // Purpur - Add 5 second tps average in /tps + public final RollingAverage tps1 = new RollingAverage(60); + public final RollingAverage tps5 = new RollingAverage(60 * 5); + public final RollingAverage tps15 = new RollingAverage(60 * 15); +@@ -1197,6 +_,16 @@ + } + // Paper end - Add onboarding message for initial server start + ++ // Purpur start - config for startup commands ++ if (!Boolean.getBoolean("Purpur.IReallyDontWantStartupCommands") && !org.purpurmc.purpur.PurpurConfig.startupCommands.isEmpty()) { ++ LOGGER.info("Purpur: Running startup commands specified in purpur.yml."); ++ for (final String startupCommand : org.purpurmc.purpur.PurpurConfig.startupCommands) { ++ LOGGER.info("Purpur: Running the following command: \"{}\"", startupCommand); ++ ((net.minecraft.server.dedicated.DedicatedServer) this).handleConsoleInput(startupCommand, this.createCommandSourceStack()); ++ } ++ } ++ // Purpur end - config for startup commands ++ + while (this.running) { + long l; + if (!this.isPaused() && this.tickRateManager.isSprinting() && this.tickRateManager.checkShouldSprintThisTick()) { +@@ -1221,14 +_,19 @@ + if (++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0) { + final long diff = currentTime - tickSection; + final java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP); ++ tps5s.add(currentTps, diff); // Purpur - Add 5 second tps average in /tps + tps1.add(currentTps, diff); + tps5.add(currentTps, diff); + tps15.add(currentTps, diff); + + // Backwards compat with bad plugins +- this.recentTps[0] = tps1.getAverage(); +- this.recentTps[1] = tps5.getAverage(); +- this.recentTps[2] = tps15.getAverage(); ++ // Purpur start - Add 5 second tps average in /tps ++ this.recentTps[0] = tps5s.getAverage(); ++ this.recentTps[1] = tps1.getAverage(); ++ this.recentTps[2] = tps5.getAverage(); ++ this.recentTps[3] = tps15.getAverage(); ++ // Purpur end - Add 5 second tps average in /tps ++ lagging = recentTps[0] < org.purpurmc.purpur.PurpurConfig.laggingThreshold; // Purpur - Lagging threshold + tickSection = currentTime; + } + // Paper end - further improve server tick loop +@@ -1260,6 +_,12 @@ + profilerFiller.popPush("nextTickWait"); + this.mayHaveDelayedTasks = true; + this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + l, this.nextTickTimeNanos); ++ // Purpur start - Configurable TPS Catchup ++ if (!org.purpurmc.purpur.PurpurConfig.tpsCatchup /*|| !gg.pufferfish.pufferfish.PufferfishConfig.tpsCatchup*/) { // Purpur - Configurable TPS Catchup ++ this.nextTickTimeNanos = currentTime + l; ++ this.delayedTasksMaxNextTickTimeNanos = nextTickTimeNanos; ++ } ++ // Purpur end - Configurable TPS Catchup + this.startMeasuringTaskExecutionTime(); + this.waitUntilNextTick(); + this.finishMeasuringTaskExecutionTime(); +@@ -1690,7 +_,7 @@ + long worldTime = level.getGameTime(); + final ClientboundSetTimePacket worldPacket = new ClientboundSetTimePacket(worldTime, dayTime, doDaylight); + for (Player entityhuman : level.players()) { +- if (!(entityhuman instanceof ServerPlayer) || (tickCount + entityhuman.getId()) % 20 != 0) { ++ if (!(entityhuman instanceof ServerPlayer) || (!level.isForceTime() && (tickCount + entityhuman.getId()) % 20 != 0)) { // Purpur - Configurable daylight cycle + continue; + } + ServerPlayer entityplayer = (ServerPlayer) entityhuman; +@@ -1855,7 +_,7 @@ + + @DontObfuscate + public String getServerModName() { +- return io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper ++ return org.purpurmc.purpur.PurpurConfig.serverModName; // Paper // Purpur - Configurable server mod name + } + + public SystemReport fillSystemReport(SystemReport systemReport) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/PlayerAdvancements.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/PlayerAdvancements.java.patch new file mode 100644 index 000000000..423015dc4 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/PlayerAdvancements.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/server/PlayerAdvancements.java ++++ b/net/minecraft/server/PlayerAdvancements.java +@@ -148,6 +_,7 @@ + AdvancementHolder advancementHolder = advancementManager.get(path); + if (advancementHolder == null) { + if (!path.getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) return; // CraftBukkit ++ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressIgnoredAdvancementWarnings) // Purpur - Logger settings (suppressing pointless logs) + LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", path, this.playerSavePath); + } else { + this.startProgress(advancementHolder, progress); +@@ -195,6 +_,7 @@ + advancement.value().display().ifPresent(displayInfo -> { + // Paper start - Add Adventure message to PlayerAdvancementDoneEvent + if (event.message() != null && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) { ++ if (org.purpurmc.purpur.PurpurConfig.advancementOnlyBroadcastToAffectedPlayer) this.player.sendMessage(message); else // Purpur - Configurable broadcast settings + this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false); + // Paper end + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/EnchantCommand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/EnchantCommand.java.patch new file mode 100644 index 000000000..74bd1f710 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/EnchantCommand.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/server/commands/EnchantCommand.java ++++ b/net/minecraft/server/commands/EnchantCommand.java +@@ -70,7 +_,7 @@ + + private static int enchant(CommandSourceStack source, Collection targets, Holder enchantment, int level) throws CommandSyntaxException { + Enchantment enchantment1 = enchantment.value(); +- if (level > enchantment1.getMaxLevel()) { ++ if (!org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchantCommand && level > enchantment1.getMaxLevel()) { // Purpur - Config to allow unsafe enchants + throw ERROR_LEVEL_TOO_HIGH.create(level, enchantment1.getMaxLevel()); + } else { + int i = 0; +@@ -81,7 +_,7 @@ + ItemStack mainHandItem = livingEntity.getMainHandItem(); + if (!mainHandItem.isEmpty()) { + if (enchantment1.canEnchant(mainHandItem) +- && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(mainHandItem).keySet(), enchantment)) { ++ && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(mainHandItem).keySet(), enchantment) || (org.purpurmc.purpur.PurpurConfig.allowUnsafeEnchantCommand && !mainHandItem.hasEnchantment(enchantment))) { // Purpur - Config to allow unsafe enchants + mainHandItem.enchant(enchantment, level); + i++; + } else if (targets.size() == 1) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch new file mode 100644 index 000000000..b1ef32c8b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GameModeCommand.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/server/commands/GameModeCommand.java ++++ b/net/minecraft/server/commands/GameModeCommand.java +@@ -51,6 +_,18 @@ + } + + private static int setMode(CommandContext source, Collection players, GameType gameType) { ++ // Purpur start - Gamemode extra permissions ++ if (org.purpurmc.purpur.PurpurConfig.commandGamemodeRequiresPermission) { ++ String gamemode = gameType.getName(); ++ CommandSourceStack sender = source.getSource(); ++ if (!sender.testPermission(2, "minecraft.command.gamemode." + gamemode)) { ++ return 0; ++ } ++ if (sender.getEntity() instanceof ServerPlayer player && (players.size() > 1 || !players.contains(player)) && !sender.testPermission(2, "minecraft.command.gamemode." + gamemode + ".other")) { ++ return 0; ++ } ++ } ++ // Purpur end - Gamemode extra permissions + int i = 0; + + for (ServerPlayer serverPlayer : players) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GiveCommand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GiveCommand.java.patch new file mode 100644 index 000000000..5cedf347f --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/commands/GiveCommand.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/server/commands/GiveCommand.java ++++ b/net/minecraft/server/commands/GiveCommand.java +@@ -66,6 +_,7 @@ + i1 -= min; + ItemStack itemStack1 = item.createItemStack(min, false); + boolean flag = serverPlayer.getInventory().add(itemStack1); ++ if (org.purpurmc.purpur.PurpurConfig.disableGiveCommandDrops) continue; // Purpur - add config option for toggling give command dropping + if (flag && itemStack1.isEmpty()) { + ItemEntity itemEntity = serverPlayer.drop(itemStack, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event + if (itemEntity != null) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch new file mode 100644 index 000000000..af8b6989d --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -0,0 +1,66 @@ +--- a/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/net/minecraft/server/dedicated/DedicatedServer.java +@@ -106,6 +_,7 @@ + // CraftBukkit start + if (!org.bukkit.craftbukkit.Main.useConsole) return; + // Paper start - Use TerminalConsoleAppender ++ if (DedicatedServer.this.gui == null || System.console() != null) // Purpur - GUI Improvements - has no GUI or has console (did not double-click) + new com.destroystokyo.paper.console.PaperConsole(DedicatedServer.this).start(); + /* + jline.console.ConsoleReader bufferedreader = DedicatedServer.this.reader; +@@ -224,6 +_,15 @@ + io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command + this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark + com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics ++ /*// Purpur start - Purpur config files // Purpur - Configurable void damage height and damage ++ try { ++ org.purpurmc.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings")); ++ } catch (Exception e) { ++ DedicatedServer.LOGGER.error("Unable to load server configuration", e); ++ return false; ++ } ++ org.purpurmc.purpur.PurpurConfig.registerCommands(); ++ */// Purpur end - Purpur config files // Purpur - Configurable void damage height and damage + com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now + + this.setPvpAllowed(properties.pvp); +@@ -271,6 +_,30 @@ + if (true) throw new IllegalStateException("Failed to bind to port", var10); // Paper - Propagate failed to bind to port error + return false; + } ++ // Purpur start - UPnP Port Forwarding ++ if (org.purpurmc.purpur.PurpurConfig.useUPnP) { ++ LOGGER.info("[UPnP] Attempting to start UPnP port forwarding service..."); ++ if (dev.omega24.upnp4j.UPnP4J.isUPnPAvailable()) { ++ if (dev.omega24.upnp4j.UPnP4J.isOpen(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) { ++ this.upnp = false; ++ LOGGER.info("[UPnP] Port {} is already open", this.getPort()); ++ } else if (dev.omega24.upnp4j.UPnP4J.open(this.getPort(), dev.omega24.upnp4j.util.Protocol.TCP)) { ++ this.upnp = true; ++ LOGGER.info("[UPnP] Successfully opened port {}", this.getPort()); ++ } else { ++ this.upnp = false; ++ LOGGER.info("[UPnP] Failed to open port {}", this.getPort()); ++ } ++ ++ if (upnp) { ++ LOGGER.info("[UPnP] {}:{}", dev.omega24.upnp4j.UPnP4J.getExternalIP(), this.getPort()); ++ } ++ } else { ++ this.upnp = false; ++ LOGGER.error("[UPnP] Service is unavailable"); ++ } ++ } ++ // Purpur end - UPnP Port Forwarding + + // CraftBukkit start + // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // Spigot - moved up +@@ -350,6 +_,8 @@ + LOGGER.info("JMX monitoring enabled"); + } + ++ org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur - Implement TPSBar ++ if (org.purpurmc.purpur.PurpurConfig.beeCountPayload) org.purpurmc.purpur.task.BeehiveTask.instance().register(); // Purpur - Give bee counts in beehives to Purpur clients + return true; + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch new file mode 100644 index 000000000..14576e237 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/server/dedicated/DedicatedServerProperties.java ++++ b/net/minecraft/server/dedicated/DedicatedServerProperties.java +@@ -49,6 +_,7 @@ + public final boolean onlineMode = this.get("online-mode", true); + public final boolean preventProxyConnections = this.get("prevent-proxy-connections", false); + public final String serverIp = this.get("server-ip", ""); ++ public final String serverName = this.get("server-name", "Unknown Server"); // Purpur - Bring back server name + public final boolean pvp = this.get("pvp", true); + public final boolean allowFlight = this.get("allow-flight", false); + public final String motd = this.get("motd", "A Minecraft Server"); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch new file mode 100644 index 000000000..910e0b882 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch @@ -0,0 +1,135 @@ +--- a/net/minecraft/server/gui/MinecraftServerGui.java ++++ b/net/minecraft/server/gui/MinecraftServerGui.java +@@ -39,6 +_,11 @@ + private Thread logAppenderThread; + private final Collection finalizers = Lists.newArrayList(); + final AtomicBoolean isClosing = new AtomicBoolean(); ++ // Purpur start - GUI Improvements ++ private final CommandHistory history = new CommandHistory(); ++ private String currentCommand = ""; ++ private int historyIndex = 0; ++ // Purpur end - GUI Improvements + + public static MinecraftServerGui showFrameFor(final DedicatedServer server) { + try { +@@ -46,7 +_,7 @@ + } catch (Exception var3) { + } + +- final JFrame jFrame = new JFrame("Minecraft server"); ++ final JFrame jFrame = new JFrame("Purpur Minecraft server"); // Purpur - Improve GUI + final MinecraftServerGui minecraftServerGui = new MinecraftServerGui(server); + jFrame.setDefaultCloseOperation(2); + jFrame.add(minecraftServerGui); +@@ -54,7 +_,7 @@ + jFrame.setLocationRelativeTo(null); + jFrame.setVisible(true); + // Paper start - Improve ServerGUI +- jFrame.setName("Minecraft server"); ++ jFrame.setName("Purpur Minecraft server"); // Purpur - Improve GUI + try { + jFrame.setIconImage(javax.imageio.ImageIO.read(java.util.Objects.requireNonNull(MinecraftServerGui.class.getClassLoader().getResourceAsStream("logo.png")))); + } catch (java.io.IOException ignore) { +@@ -64,7 +_,7 @@ + @Override + public void windowClosing(WindowEvent event) { + if (!minecraftServerGui.isClosing.getAndSet(true)) { +- jFrame.setTitle("Minecraft server - shutting down!"); ++ jFrame.setTitle("Purpur Minecraft server - shutting down!"); // Purpur - Improve GUI + server.halt(true); + minecraftServerGui.runFinalizers(); + } +@@ -112,7 +_,7 @@ + + private JComponent buildChatPanel() { + JPanel jPanel = new JPanel(new BorderLayout()); +- JTextArea jTextArea = new JTextArea(); ++ org.purpurmc.purpur.gui.JColorTextPane jTextArea = new org.purpurmc.purpur.gui.JColorTextPane(); // Purpur - GUI Improvements + JScrollPane jScrollPane = new JScrollPane(jTextArea, 22, 30); + jTextArea.setEditable(false); + jTextArea.setFont(MONOSPACED); +@@ -121,10 +_,43 @@ + String trimmed = jTextField.getText().trim(); + if (!trimmed.isEmpty()) { + this.server.handleConsoleInput(trimmed, this.server.createCommandSourceStack()); ++ // Purpur start - GUI Improvements ++ history.add(trimmed); ++ historyIndex = -1; ++ // Purpur end - GUI Improvements + } + + jTextField.setText(""); + }); ++ // Purpur start - GUI Improvements ++ jTextField.getInputMap().put(javax.swing.KeyStroke.getKeyStroke("UP"), "up"); ++ jTextField.getInputMap().put(javax.swing.KeyStroke.getKeyStroke("DOWN"), "down"); ++ jTextField.getActionMap().put("up", new javax.swing.AbstractAction() { ++ @Override ++ public void actionPerformed(java.awt.event.ActionEvent actionEvent) { ++ if (historyIndex < 0) { ++ currentCommand = jTextField.getText(); ++ } ++ if (historyIndex < history.size() - 1) { ++ jTextField.setText(history.get(++historyIndex)); ++ } ++ } ++ }); ++ jTextField.getActionMap().put("down", new javax.swing.AbstractAction() { ++ @Override ++ public void actionPerformed(java.awt.event.ActionEvent actionEvent) { ++ if (historyIndex >= 0) { ++ if (historyIndex == 0) { ++ --historyIndex; ++ jTextField.setText(currentCommand); ++ } else { ++ --historyIndex; ++ jTextField.setText(history.get(historyIndex)); ++ } ++ } ++ } ++ }); ++ // Purpur end - GUI Improvements + jTextArea.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent event) { +@@ -159,7 +_,7 @@ + } + + private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\e\\[[\\d;]*[^\\d;]"); // CraftBukkit // Paper +- public void print(JTextArea textArea, JScrollPane scrollPane, String line) { ++ public void print(org.purpurmc.purpur.gui.JColorTextPane textArea, JScrollPane scrollPane, String line) { // Purpur - GUI Improvements + if (!SwingUtilities.isEventDispatchThread()) { + SwingUtilities.invokeLater(() -> this.print(textArea, scrollPane, line)); + } else { +@@ -170,16 +_,29 @@ + flag = verticalScrollBar.getValue() + verticalScrollBar.getSize().getHeight() + MONOSPACED.getSize() * 4 > verticalScrollBar.getMaximum(); + } + +- try { ++ /*try { // Purpur - GUI Improvements + document.insertString(document.getLength(), MinecraftServerGui.ANSI.matcher(line).replaceAll(""), null); // CraftBukkit + } catch (BadLocationException var8) { +- } ++ }*/ // Purpur - GUI Improvements ++ textArea.append(line); // Purpur - GUI Improvements + + if (flag) { + verticalScrollBar.setValue(Integer.MAX_VALUE); + } + } + } ++ ++ // Purpur start - GUI Improvements ++ public static class CommandHistory extends java.util.LinkedList { ++ @Override ++ public boolean add(String command) { ++ if (size() > 1000) { ++ remove(); ++ } ++ return super.offerFirst(command); ++ } ++ } ++ // Purpur end - GUI Improvements + + // Paper start - Add onboarding message for initial server start + private JComponent buildOnboardingPanel() { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/StatsComponent.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/StatsComponent.java.patch new file mode 100644 index 000000000..a082bca56 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/gui/StatsComponent.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/server/gui/StatsComponent.java ++++ b/net/minecraft/server/gui/StatsComponent.java +@@ -43,7 +_,7 @@ + } + this.msgs[0] = "Memory use: " + l / 1024L / 1024L + " mb (" + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + "% free)"; + this.msgs[1] = "Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms"; +- this.msgs[2] = "TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg); ++ this.msgs[2] = "TPS from last 5s, 1m, 5m, 15m: " + String.join(", ", tpsAvg); // Purpur - Add 5 second tps average in /tps + // Paper end - Improve ServerGUI + this.values[this.vp++ & 0xFF] = (int)(l * 100L / Runtime.getRuntime().maxMemory()); + this.repaint(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch new file mode 100644 index 000000000..a4cf79160 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -0,0 +1,172 @@ +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -207,6 +_,8 @@ + private final StructureManager structureManager; + private final StructureCheck structureCheck; + private final boolean tickTime; ++ private double preciseTime; // Purpur - Configurable daylight cycle ++ private boolean forceTime; // Purpur - Configurable daylight cycle + private final RandomSequences randomSequences; + + // CraftBukkit start +@@ -595,7 +_,24 @@ + // CraftBukkit end + this.tickTime = tickTime; + this.server = server; +- this.customSpawners = customSpawners; ++ // Purpur start - Allow toggling special MobSpawners per world ++ this.customSpawners = new ArrayList<>(); ++ if (purpurConfig.phantomSpawning) { ++ this.customSpawners.add(new net.minecraft.world.level.levelgen.PhantomSpawner()); ++ } ++ if (purpurConfig.patrolSpawning) { ++ this.customSpawners.add(new net.minecraft.world.level.levelgen.PatrolSpawner()); ++ } ++ if (purpurConfig.catSpawning) { ++ this.customSpawners.add(new net.minecraft.world.entity.npc.CatSpawner()); ++ } ++ if (purpurConfig.villageSiegeSpawning) { ++ this.customSpawners.add(new net.minecraft.world.entity.ai.village.VillageSiege()); ++ } ++ if (purpurConfig.villagerTraderSpawning) { ++ this.customSpawners.add(new net.minecraft.world.entity.npc.WanderingTraderSpawner(serverLevelData)); ++ } ++ // Purpur end - Allow toggling special MobSpawners per world + this.serverLevelData = serverLevelData; + ChunkGenerator chunkGenerator = levelStem.generator(); + // CraftBukkit start +@@ -681,6 +_,7 @@ + this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler); + // Paper end - rewrite chunk system + this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit ++ this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle + } + + // Paper start +@@ -727,7 +_,7 @@ + } + + int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); +- if (this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { ++ if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { // Purpur - Config for skipping night + // Paper start - create time skip event - move up calculations + final long newDayTime = this.levelData.getDayTime() + 24000L; + org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent( +@@ -846,6 +_,13 @@ + this.serverLevelData.getScheduledEvents().tick(this.server, l); + Profiler.get().pop(); + if (this.serverLevelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { ++ // Purpur start - Configurable daylight cycle ++ int incrementTicks = isDay() ? this.purpurConfig.daytimeTicks : this.purpurConfig.nighttimeTicks; ++ if (incrementTicks != 12000) { ++ this.preciseTime += 12000 / (double) incrementTicks; ++ this.setDayTime(this.preciseTime); ++ } else ++ // Purpur end - Configurable daylight cycle + this.setDayTime(this.levelData.getDayTime() + 1L); + } + } +@@ -853,7 +_,21 @@ + + public void setDayTime(long time) { + this.serverLevelData.setDayTime(time); +- } ++ // Purpur start - Configurable daylight cycle ++ this.preciseTime = time; ++ this.forceTime = false; ++ } ++ public void setDayTime(double i) { ++ this.serverLevelData.setDayTime((long) i); ++ this.forceTime = true; ++ // Purpur end - Configurable daylight cycle ++ } ++ ++ // Purpur start - Configurable daylight cycle ++ public boolean isForceTime() { ++ return this.forceTime; ++ } ++ // Purpur end - Configurable daylight cycle + + public void tickCustomSpawners(boolean spawnEnemies, boolean spawnFriendlies) { + for (CustomSpawner customSpawner : this.customSpawners) { +@@ -934,9 +_,18 @@ + && this.random.nextDouble() < currentDifficultyAt.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01) // Paper - Configurable spawn chances for skeleton horses + && !this.getBlockState(blockPos.below()).is(Blocks.LIGHTNING_ROD); + if (flag) { ++ // Purpur start - Special mobs naturally spawn ++ net.minecraft.world.entity.animal.horse.AbstractHorse entityhorseskeleton; ++ if (purpurConfig.zombieHorseSpawnChance > 0D && random.nextDouble() <= purpurConfig.zombieHorseSpawnChance) { ++ entityhorseskeleton = EntityType.ZOMBIE_HORSE.create(this, EntitySpawnReason.EVENT); ++ } else { ++ entityhorseskeleton = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT); ++ if (entityhorseskeleton != null) ((SkeletonHorse) entityhorseskeleton).setTrap(true); ++ } ++ // Purpur end - Special mobs naturally spawn + SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT); + if (skeletonHorse != null) { +- skeletonHorse.setTrap(true); ++ //skeletonHorse.setTrap(true); // Purpur - Special mobs naturally spawn - moved up + skeletonHorse.setAge(0); + skeletonHorse.setPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + this.addFreshEntity(skeletonHorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit +@@ -1009,7 +_,7 @@ + pointOfInterestType -> pointOfInterestType.is(PoiTypes.LIGHTNING_ROD), + blockPos -> blockPos.getY() == this.getHeight(Heightmap.Types.WORLD_SURFACE, blockPos.getX(), blockPos.getZ()) - 1, + pos, +- 128, ++ org.purpurmc.purpur.PurpurConfig.lightningRodRange, // Purpur - Make lightning rod range configurable + PoiManager.Occupancy.ANY + ); + return optional.map(blockPos -> blockPos.above(1)); +@@ -1057,8 +_,26 @@ + int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); + Component component; + if (this.sleepStatus.areEnoughSleeping(_int)) { ++ // Purpur start - Customizable sleeping actionbar messages ++ if (org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.isBlank()) { ++ return; ++ } ++ if (!org.purpurmc.purpur.PurpurConfig.sleepSkippingNight.equalsIgnoreCase("default")) { ++ component = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepSkippingNight)); ++ } else ++ // Purpur end - Customizable sleeping actionbar messages + component = Component.translatable("sleep.skipping_night"); + } else { ++ // Purpur start - Customizable sleeping actionbar messages ++ if (org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.isBlank()) { ++ return; ++ } ++ if (!org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent.equalsIgnoreCase("default")) { ++ component = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepingPlayersPercent, ++ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("count", Integer.toString(this.sleepStatus.amountSleeping())), ++ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed("total", Integer.toString(this.sleepStatus.sleepersNeeded(_int))))); ++ } else ++ // Purpur end - Customizable sleeping actionbar messages + component = Component.translatable("sleep.players_sleeping", this.sleepStatus.amountSleeping(), this.sleepStatus.sleepersNeeded(_int)); + } + +@@ -1191,6 +_,7 @@ + @VisibleForTesting + public void resetWeatherCycle() { + // CraftBukkit start ++ if (this.purpurConfig.rainStopsAfterSleep) // Purpur - Option for if rain and thunder should stop on sleep + this.serverLevelData.setRaining(false, org.bukkit.event.weather.WeatherChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents + // If we stop due to everyone sleeping we should reset the weather duration to some other random value. + // Not that everyone ever manages to get the whole server to sleep at the same time.... +@@ -1198,6 +_,7 @@ + this.serverLevelData.setRainTime(0); + } + // CraftBukkit end ++ if (this.purpurConfig.thunderStopsAfterSleep) // Purpur - Option for if rain and thunder should stop on sleep + this.serverLevelData.setThundering(false, org.bukkit.event.weather.ThunderChangeEvent.Cause.SLEEP); // Paper - Add cause to Weather/ThunderChangeEvents + // CraftBukkit start + // If we stop due to everyone sleeping we should reset the weather duration to some other random value. +@@ -2676,7 +_,7 @@ + // Spigot start + if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message + // Paper start - Fix merchant inventory not closing on entity removal +- if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { ++ if (!entity.level().purpurConfig.playerVoidTrading && entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { // Purpur - Allow void trading + merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); + } + // Paper end - Fix merchant inventory not closing on entity removal diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch new file mode 100644 index 000000000..8adf80143 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -0,0 +1,276 @@ +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -393,6 +_,10 @@ + public com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent + public @Nullable String clientBrandName = null; // Paper - Brand support + public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event ++ public boolean purpurClient = false; // Purpur - Purpur client support ++ private boolean tpsBar = false; // Purpur - Implement TPSBar ++ private boolean compassBar = false; // Purpur - Add compass command ++ private boolean ramBar = false; // Purpur - Implement rambar commands + + // Paper start - rewrite chunk system + private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader; +@@ -561,6 +_,10 @@ + if (tag != null) { + BlockPos.CODEC.parse(NbtOps.INSTANCE, tag).resultOrPartial(LOGGER::error).ifPresent(pos -> this.raidOmenPosition = pos); + } ++ ++ if (compound.contains("Purpur.TPSBar")) { this.tpsBar = compound.getBoolean("Purpur.TPSBar"); } // Purpur - Implement TPSBar ++ if (compound.contains("Purpur.CompassBar")) { this.compassBar = compound.getBoolean("Purpur.CompassBar"); } // Purpur - Add compass command ++ if (compound.contains("Purpur.RamBar")) { this.ramBar = compound.getBoolean("Purpur.RamBar"); } // Purpur - Implement rambar command + } + + @Override +@@ -605,6 +_,9 @@ + } + + this.saveEnderPearls(compound); ++ compound.putBoolean("Purpur.TPSBar", this.tpsBar); // Purpur - Implement TPSBar ++ compound.putBoolean("Purpur.CompassBar", this.compassBar); // Purpur - Add compass command ++ compound.putBoolean("Purpur.RamBar", this.ramBar); // Purpur - Add rambar command + } + + private void saveParentVehicle(CompoundTag tag) { +@@ -1124,6 +_,7 @@ + ) + ); + Team team = this.getTeam(); ++ if (org.purpurmc.purpur.PurpurConfig.deathMessageOnlyBroadcastToAffectedPlayer) this.sendSystemMessage(deathMessage); else // Purpur - Configurable broadcast settings + if (team == null || team.getDeathMessageVisibility() == Team.Visibility.ALWAYS) { + this.server.getPlayerList().broadcastSystemMessage(deathMessage, false); + } else if (team.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) { +@@ -1217,6 +_,13 @@ + if (this.isInvulnerableTo(level, damageSource)) { + return false; + } else { ++ // Purpur start - Add boat fall damage config ++ if (damageSource.is(net.minecraft.tags.DamageTypeTags.IS_FALL)) { ++ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.Boat && !level().purpurConfig.boatsDoFallDamage) { ++ return false; ++ } ++ } ++ // Purpur end - Add boat fall damage config + Entity entity = damageSource.getEntity(); + if (!( // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false. + !(entity instanceof Player player && !this.canHarmPlayer(player)) +@@ -1446,6 +_,7 @@ + serverLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); + this.unsetRemoved(); + // CraftBukkit end ++ this.portalPos = io.papermc.paper.util.MCUtil.toBlockPosition(exit); // Purpur - Fix stuck in portals + this.setServerLevel(level); + this.connection.internalTeleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); // CraftBukkit - use internal teleport without event + this.connection.resetPosition(); +@@ -1564,7 +_,7 @@ + new AABB(vec3.x() - 8.0, vec3.y() - 5.0, vec3.z() - 8.0, vec3.x() + 8.0, vec3.y() + 5.0, vec3.z() + 8.0), + monster -> monster.isPreventingPlayerRest(this.serverLevel(), this) + ); +- if (!entitiesOfClass.isEmpty()) { ++ if (!this.level().purpurConfig.playerSleepNearMonsters && !entitiesOfClass.isEmpty()) { // Purpur - Config to ignore nearby mobs when sleeping + return Either.left(Player.BedSleepingProblem.NOT_SAFE); + } + } +@@ -1601,7 +_,19 @@ + CriteriaTriggers.SLEPT_IN_BED.trigger(this); + }); + if (!this.serverLevel().canSleepThroughNights()) { +- this.displayClientMessage(Component.translatable("sleep.not_possible"), true); ++ // Purpur start - Customizable sleeping actionbar messages ++ Component clientMessage; ++ if (org.purpurmc.purpur.PurpurConfig.sleepNotPossible.isBlank()) { ++ clientMessage = null; ++ } else if (!org.purpurmc.purpur.PurpurConfig.sleepNotPossible.equalsIgnoreCase("default")) { ++ clientMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.sleepNotPossible)); ++ } else { ++ clientMessage = Component.translatable("sleep.not_possible"); ++ } ++ if (clientMessage != null) { ++ this.displayClientMessage(clientMessage, true); ++ } ++ // Purpur end - Customizable sleeping actionbar messages + } + + ((ServerLevel)this.level()).updateSleepingPlayerList(); +@@ -1709,6 +_,7 @@ + + @Override + public void openTextEdit(SignBlockEntity signEntity, boolean isFrontText) { ++ if (level().purpurConfig.signAllowColors) this.connection.send(signEntity.getTranslatedUpdatePacket(textFilteringEnabled, isFrontText)); // Purpur - Signs allow color codes + this.connection.send(new ClientboundBlockUpdatePacket(this.level(), signEntity.getBlockPos())); + this.connection.send(new ClientboundOpenSignEditorPacket(signEntity.getBlockPos(), isFrontText)); + } +@@ -2014,6 +_,26 @@ + this.lastSentExp = -1; // CraftBukkit - Added to reset + } + ++ // Purpur start - Component related conveniences ++ public void sendActionBarMessage(@Nullable String message) { ++ if (message != null && !message.isEmpty()) { ++ sendActionBarMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message)); ++ } ++ } ++ ++ public void sendActionBarMessage(@Nullable net.kyori.adventure.text.Component message) { ++ if (message != null) { ++ sendActionBarMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message)); ++ } ++ } ++ ++ public void sendActionBarMessage(@Nullable Component message) { ++ if (message != null) { ++ displayClientMessage(message, true); ++ } ++ } ++ // Purpur end - Component related conveniences ++ + @Override + public void displayClientMessage(Component chatComponent, boolean actionBar) { + this.sendSystemMessage(chatComponent, actionBar); +@@ -2235,6 +_,20 @@ + ); + } + ++ // Purpur start - Component related conveniences ++ public void sendMiniMessage(@Nullable String message) { ++ if (message != null && !message.isEmpty()) { ++ this.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message)); ++ } ++ } ++ ++ public void sendMessage(@Nullable net.kyori.adventure.text.Component message) { ++ if (message != null) { ++ this.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message)); ++ } ++ } ++ // Purpur end - Component related conveniences ++ + public void sendSystemMessage(Component mesage) { + this.sendSystemMessage(mesage, false); + } +@@ -2373,7 +_,67 @@ + + public void resetLastActionTime() { + this.lastActionTime = Util.getMillis(); +- } ++ this.setAfk(false); // Purpur - AFK API ++ } ++ ++ // Purpur start - AFK API ++ private boolean isAfk = false; ++ ++ @Override ++ public void setAfk(boolean afk) { ++ if (this.isAfk == afk) { ++ return; ++ } ++ ++ String msg = afk ? org.purpurmc.purpur.PurpurConfig.afkBroadcastAway : org.purpurmc.purpur.PurpurConfig.afkBroadcastBack; ++ ++ org.purpurmc.purpur.event.PlayerAFKEvent event = new org.purpurmc.purpur.event.PlayerAFKEvent(this.getBukkitEntity(), afk, this.level().purpurConfig.idleTimeoutKick, msg, !org.bukkit.Bukkit.isPrimaryThread()); ++ if (!event.callEvent() || event.shouldKick()) { ++ return; ++ } ++ ++ this.isAfk = afk; ++ ++ if (!afk) { ++ resetLastActionTime(); ++ } ++ ++ msg = event.getBroadcastMsg(); ++ if (msg != null && !msg.isEmpty()) { ++ String playerName = this.getGameProfile().getName(); ++ if (org.purpurmc.purpur.PurpurConfig.afkBroadcastUseDisplayName) { ++ net.kyori.adventure.text.Component playerDisplayNameComponent = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.getBukkitEntity().getDisplayName()); ++ playerName = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(playerDisplayNameComponent); ++ } ++ server.getPlayerList().broadcastMiniMessage(String.format(msg, playerName), false); ++ } ++ ++ if (this.level().purpurConfig.idleTimeoutUpdateTabList) { ++ String scoreboardName = getScoreboardName(); ++ String playerListName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().serialize(getBukkitEntity().playerListName()); ++ String[] split = playerListName.split(scoreboardName); ++ String prefix = (split.length > 0 ? split[0] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix, ""); ++ String suffix = (split.length > 1 ? split[1] : "").replace(org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, ""); ++ if (afk) { ++ getBukkitEntity().setPlayerListName(org.purpurmc.purpur.PurpurConfig.afkTabListPrefix + prefix + scoreboardName + suffix + org.purpurmc.purpur.PurpurConfig.afkTabListSuffix, true); ++ } else { ++ getBukkitEntity().setPlayerListName(prefix + scoreboardName + suffix, true); ++ } ++ } ++ ++ ((ServerLevel) this.level()).updateSleepingPlayerList(); ++ } ++ ++ @Override ++ public boolean isAfk() { ++ return this.isAfk; ++ } ++ ++ @Override ++ public boolean canBeCollidedWith() { ++ return !this.isAfk() && super.canBeCollidedWith(); ++ } ++ // Purpur end - AFK API + + public ServerStatsCounter getStats() { + return this.stats; +@@ -3078,4 +_,56 @@ + return (org.bukkit.craftbukkit.entity.CraftPlayer) super.getBukkitEntity(); + } + // CraftBukkit end ++ ++ // Purpur start - Add option to teleport to spawn if outside world border ++ public void teleport(org.bukkit.Location to) { ++ this.ejectPassengers(); ++ this.stopRiding(true); ++ ++ if (this.isSleeping()) { ++ this.stopSleepInBed(true, false); ++ } ++ ++ if (this.containerMenu != this.inventoryMenu) { ++ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); ++ } ++ ++ ServerLevel toLevel = ((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(); ++ if (this.level() == toLevel) { ++ this.connection.teleport(to); ++ } else { ++ this.server.getPlayerList().respawn(this, true, RemovalReason.KILLED, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.DEATH, to); ++ } ++ } ++ // Purpur end - Add option to teleport to spawn if outside world border ++ ++ // Purpur start - Implement TPSBar ++ public boolean tpsBar() { ++ return this.tpsBar; ++ } ++ ++ public void tpsBar(boolean tpsBar) { ++ this.tpsBar = tpsBar; ++ } ++ // Purpur end - Implement TPSBar ++ ++ // Purpur start - Add compass command ++ public boolean compassBar() { ++ return this.compassBar; ++ } ++ ++ public void compassBar(boolean compassBar) { ++ this.compassBar = compassBar; ++ } ++ // Purpur end - Add compass command ++ ++ // Purpur start - Add rambar command ++ public boolean ramBar() { ++ return this.ramBar; ++ } ++ ++ public void ramBar(boolean ramBar) { ++ this.ramBar = ramBar; ++ } ++ // Purpur end - Add rambar command + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch new file mode 100644 index 000000000..2586f46df --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch @@ -0,0 +1,46 @@ +--- a/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -351,6 +_,7 @@ + } + return false; + } ++ if (this.player.level().purpurConfig.slabHalfBreak && this.player.isShiftKeyDown() && blockState.getBlock() instanceof net.minecraft.world.level.block.SlabBlock && ((net.minecraft.world.level.block.SlabBlock) blockState.getBlock()).halfBreak(blockState, pos, this.player)) return true; // Purpur - Break individual slabs when sneaking + } + // CraftBukkit end + +@@ -464,6 +_,7 @@ + public InteractionHand interactHand; + public ItemStack interactItemStack; + public InteractionResult useItemOn(ServerPlayer player, Level level, ItemStack stack, InteractionHand hand, BlockHitResult hitResult) { ++ if (shiftClickMended(stack)) return InteractionResult.SUCCESS; // Purpur - Shift right click to use exp for mending + BlockPos blockPos = hitResult.getBlockPos(); + BlockState blockState = level.getBlockState(blockPos); + boolean cancelledBlock = false; +@@ -506,7 +_,7 @@ + boolean flag = !player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty(); + boolean flag1 = player.isSecondaryUseActive() && flag; + ItemStack itemStack = stack.copy(); +- if (!flag1) { ++ if (!flag1 || (player.level().purpurConfig.composterBulkProcess && blockState.is(net.minecraft.world.level.block.Blocks.COMPOSTER))) { // Purpur - Sneak to bulk process composter + InteractionResult interactionResult = blockState.useItemOn(player.getItemInHand(hand), level, player, hand, hitResult); + if (interactionResult.consumesAction()) { + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(player, blockPos, itemStack); +@@ -552,4 +_,18 @@ + public void setLevel(ServerLevel serverLevel) { + this.level = serverLevel; + } ++ ++ // Purpur start - Shift right click to use exp for mending ++ public boolean shiftClickMended(ItemStack itemstack) { ++ if (this.player.level().purpurConfig.shiftRightClickRepairsMendingPoints > 0 && this.player.isShiftKeyDown() && this.player.getBukkitEntity().hasPermission("purpur.mending_shift_click")) { ++ int points = Math.min(this.player.totalExperience, this.player.level().purpurConfig.shiftRightClickRepairsMendingPoints); ++ if (points > 0 && itemstack.isDamaged() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.MENDING, itemstack) > 0) { ++ this.player.giveExperiencePoints(-points); ++ this.player.level().addFreshEntity(new net.minecraft.world.entity.ExperienceOrb(this.player.level(), this.player.getX(), this.player.getY(), this.player.getZ(), points, org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN, this.player, this.player)); ++ return true; ++ } ++ } ++ return false; ++ } ++ // Purpur end - Shift right click to use exp for mending + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch new file mode 100644 index 000000000..fe8a95124 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/server/level/WorldGenRegion.java ++++ b/net/minecraft/server/level/WorldGenRegion.java +@@ -312,6 +_,7 @@ + return true; + } else { + // Paper start - Buffer OOB setBlock calls ++ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressSetBlockFarChunk) // Purpur - Logger settings (suppressing pointless logs) + if (!hasSetFarWarned) { + Util.logAndPauseIfInIde( + "Detected setBlock in a far chunk [" diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch new file mode 100644 index 000000000..4405b9245 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -0,0 +1,72 @@ +--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +@@ -41,6 +_,7 @@ + private long keepAliveChallenge; + private long closedListenerTime; + private boolean closed = false; ++ private it.unimi.dsi.fastutil.longs.LongList keepAlives = new it.unimi.dsi.fastutil.longs.LongArrayList(); // Purpur - Alternative Keepalive Handling + private int latency; + private volatile boolean suspendFlushingOnServerThread = false; + // CraftBukkit start +@@ -51,6 +_,7 @@ + public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks + private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit + protected static final net.minecraft.resources.ResourceLocation MINECRAFT_BRAND = net.minecraft.resources.ResourceLocation.withDefaultNamespace("brand"); // Paper - Brand support ++ protected static final net.minecraft.resources.ResourceLocation PURPUR_CLIENT = net.minecraft.resources.ResourceLocation.fromNamespaceAndPath("purpur", "client"); // Purpur - Purpur client support + + public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie, net.minecraft.server.level.ServerPlayer player) { // CraftBukkit + this.server = server; +@@ -118,6 +_,16 @@ + + @Override + public void handleKeepAlive(ServerboundKeepAlivePacket packet) { ++ // Purpur start - Alternative Keepalive Handling ++ if (org.purpurmc.purpur.PurpurConfig.useAlternateKeepAlive) { ++ if (this.keepAlivePending && !keepAlives.isEmpty() && keepAlives.contains(packet.getId())) { ++ int ping = (int) (Util.getMillis() - packet.getId()); ++ this.latency = (this.latency * 3 + ping) / 4; ++ this.keepAlivePending = false; ++ keepAlives.clear(); // we got a valid response, lets roll with it and forget the rest ++ } ++ } else ++ // Purpur end - Alternative Keepalive Handling + if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) { + int i = (int)(Util.getMillis() - this.keepAliveTime); + this.latency = (this.latency * 3 + i) / 4; +@@ -159,6 +_,13 @@ + ServerGamePacketListenerImpl.LOGGER.error("Couldn't register custom payload", ex); + this.disconnect(Component.literal("Invalid payload REGISTER!"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause + } ++ // Purpur start - Purpur client support ++ } else if (identifier.equals(PURPUR_CLIENT)) { ++ try { ++ player.purpurClient = true; ++ } catch (Exception ignore) { ++ } ++ // Purpur end - Purpur client support + } else if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_UNREGISTER)) { + try { + String channels = payload.toString(com.google.common.base.Charsets.UTF_8); +@@ -238,6 +_,22 @@ + // Paper start - give clients a longer time to respond to pings as per pre 1.12.2 timings + // This should effectively place the keepalive handling back to "as it was" before 1.12.2 + final long elapsedTime = millis - this.keepAliveTime; ++ ++ // Purpur start - Alternative Keepalive Handling ++ if (org.purpurmc.purpur.PurpurConfig.useAlternateKeepAlive) { ++ if (elapsedTime >= 1000L) { // 1 second ++ if (this.keepAlivePending && !this.processedDisconnect && keepAlives.size() * 1000L >= KEEPALIVE_LIMIT) { ++ this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); ++ } else if (this.checkIfClosed(millis)) { ++ this.keepAlivePending = true; ++ this.keepAliveTime = millis; // hijack this field for 1 second intervals ++ this.keepAlives.add(millis); // currentTime is ID ++ this.send(new ClientboundKeepAlivePacket(millis)); ++ } ++ } ++ } else ++ // Purpur end - Alternative Keepalive Handling ++ + if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // use vanilla's 15000L between keep alive packets + if (this.keepAlivePending) { + if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch new file mode 100644 index 000000000..8d25c5e92 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -0,0 +1,224 @@ +--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -326,6 +_,20 @@ + this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat + } + ++ // Purpur start - AFK API ++ private final com.google.common.cache.LoadingCache kickPermissionCache = com.google.common.cache.CacheBuilder.newBuilder() ++ .maximumSize(1000) ++ .expireAfterWrite(1, java.util.concurrent.TimeUnit.MINUTES) ++ .build( ++ new com.google.common.cache.CacheLoader<>() { ++ @Override ++ public Boolean load(org.bukkit.craftbukkit.entity.CraftPlayer player) { ++ return player.hasPermission("purpur.bypassIdleKick"); ++ } ++ } ++ ); ++ // Purpur end - AFK API ++ + @Override + public void tick() { + if (this.ackBlockChangesUpTo > -1) { +@@ -384,6 +_,12 @@ + if (this.player.getLastActionTime() > 0L + && this.server.getPlayerIdleTimeout() > 0 + && Util.getMillis() - this.player.getLastActionTime() > this.server.getPlayerIdleTimeout() * 1000L * 60L && !this.player.wonGame) { // Paper - Prevent AFK kick while watching end credits ++ // Purpur start - AFK API ++ this.player.setAfk(true); ++ if (!this.player.level().purpurConfig.idleTimeoutKick || (!Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK")) && kickPermissionCache.getUnchecked(this.player.getBukkitEntity()))) { ++ return; ++ } ++ // Purpur end - AFK API + this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854 + this.disconnect(Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause + } +@@ -629,6 +_,8 @@ + this.lastYaw = to.getYaw(); + this.lastPitch = to.getPitch(); + ++ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur - AFK API ++ + Location oldTo = to.clone(); + PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); + this.cserver.getPluginManager().callEvent(event); +@@ -709,6 +_,7 @@ + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + if (packet.getId() == this.awaitingTeleport) { + if (this.awaitingPositionFromClient == null) { ++ ServerGamePacketListenerImpl.LOGGER.warn("Disconnected on accept teleport packet. Was not expecting position data from client at this time"); // Purpur - Add more logger output for invalid movement kicks + this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause + return; + } +@@ -1176,6 +_,10 @@ + final int maxBookPageSize = pageMax.intValue(); + final double multiplier = Math.clamp(io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.bookSize.totalMultiplier, 0.3D, 1D); + long byteAllowed = maxBookPageSize; ++ // Purpur start - PlayerBookTooLargeEvent ++ int slot = packet.slot(); ++ ItemStack itemstack = Inventory.isHotbarSlot(slot) || slot == Inventory.SLOT_OFFHAND ? this.player.getInventory().getItem(slot) : ItemStack.EMPTY; ++ // Purpur end - PlayerBookTooLargeEvent + for (final String page : pageList) { + final int byteLength = page.getBytes(java.nio.charset.StandardCharsets.UTF_8).length; + byteTotal += byteLength; +@@ -1200,7 +_,8 @@ + } + + if (byteTotal > byteAllowed) { +- ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send a book too large. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size()); ++ ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send too large of a book. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size()); ++ org.purpurmc.purpur.event.player.PlayerBookTooLargeEvent event = new org.purpurmc.purpur.event.player.PlayerBookTooLargeEvent(player.getBukkitEntity(), itemstack.asBukkitCopy()); if (event.shouldKickPlayer()) // Purpur - PlayerBookTooLargeEvent + this.disconnectAsync(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause // Paper - add proper async disconnect + return; + } +@@ -1219,31 +_,45 @@ + Optional optional = packet.title(); + optional.ifPresent(list::add); + list.addAll(packet.pages()); ++ // Purpur start - Allow color codes in books ++ boolean hasEditPerm = getCraftPlayer().hasPermission("purpur.book.color.edit"); ++ boolean hasSignPerm = hasEditPerm || getCraftPlayer().hasPermission("purpur.book.color.sign"); ++ // Purpur end - Allow color codes in books + Consumer> consumer = optional.isPresent() +- ? texts -> this.signBook(texts.get(0), texts.subList(1, texts.size()), slot) +- : texts -> this.updateBookContents(texts, slot); ++ ? texts -> this.signBook(texts.get(0), texts.subList(1, texts.size()), slot, hasSignPerm) // Purpur - Allow color codes in books ++ : texts -> this.updateBookContents(texts, slot, hasEditPerm); // Purpur - Allow color codes in books + this.filterTextPacket(list).thenAcceptAsync(consumer, this.server); + } + } + + private void updateBookContents(List pages, int index) { ++ // Purpur start - Allow color codes in books ++ updateBookContents(pages, index, false); ++ } ++ private void updateBookContents(List pages, int index, boolean hasPerm) { ++ // Purpur end - Allow color codes in books + // CraftBukkit start + ItemStack handItem = this.player.getInventory().getItem(index); + ItemStack item = handItem.copy(); + // CraftBukkit end + if (item.has(DataComponents.WRITABLE_BOOK_CONTENT)) { +- List> list = pages.stream().map(this::filterableFromOutgoing).toList(); ++ List> list = pages.stream().map(filteredText -> filterableFromOutgoing(filteredText).map(s -> color(s, hasPerm))).toList(); // Purpur - Allow color codes in books + item.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(list)); + this.player.getInventory().setItem(index, CraftEventFactory.handleEditBookEvent(this.player, index, handItem, item)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent) + } + } + + private void signBook(FilteredText title, List pages, int index) { ++ // Purpur start - Allow color codes in books ++ signBook(title, pages, index, false); ++ } ++ private void signBook(FilteredText title, List pages, int index, boolean hasPerm) { ++ // Purpur end - Allow color codes in books + ItemStack item = this.player.getInventory().getItem(index); + if (item.has(DataComponents.WRITABLE_BOOK_CONTENT)) { + ItemStack itemStack = item.transmuteCopy(Items.WRITTEN_BOOK); + itemStack.remove(DataComponents.WRITABLE_BOOK_CONTENT); +- List> list = pages.stream().map(filteredText -> this.filterableFromOutgoing(filteredText).map(Component::literal)).toList(); ++ List> list = pages.stream().map((filteredText) -> this.filterableFromOutgoing(filteredText).map(s -> hexColor(s, hasPerm))).toList(); // Purpur - Allow color codes in books + itemStack.set( + DataComponents.WRITTEN_BOOK_CONTENT, + new WrittenBookContent(this.filterableFromOutgoing(title), this.player.getName().getString(), 0, list, true) +@@ -1257,6 +_,16 @@ + return this.player.isTextFilteringEnabled() ? Filterable.passThrough(filteredText.filteredOrEmpty()) : Filterable.from(filteredText); + } + ++ // Purpur start - Allow color codes in books ++ private Component hexColor(String str, boolean hasPerm) { ++ return hasPerm ? PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize(str)) : Component.literal(str); ++ } ++ ++ private String color(String str, boolean hasPerm) { ++ return hasPerm ? org.bukkit.ChatColor.color(str, false) : str; ++ } ++ // Purpur end - Allow color codes in books ++ + @Override + public void handleEntityTagQuery(ServerboundEntityTagQueryPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); +@@ -1292,7 +_,15 @@ + @Override + public void handleMovePlayer(ServerboundMovePlayerPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); +- if (containsInvalidValues(packet.getX(0.0), packet.getY(0.0), packet.getZ(0.0), packet.getYRot(0.0F), packet.getXRot(0.0F))) { ++ // Purpur start - Add more logger output for invalid movement kicks ++ boolean invalidX = Double.isNaN(packet.getX(0.0)); ++ boolean invalidY = Double.isNaN(packet.getY(0.0)); ++ boolean invalidZ = Double.isNaN(packet.getZ(0.0)); ++ boolean invalidYaw = !Floats.isFinite(packet.getYRot(0.0F)); ++ boolean invalidPitch = !Floats.isFinite(packet.getXRot(0.0F)); ++ if (invalidX || invalidY || invalidZ || invalidYaw || invalidPitch) { ++ ServerGamePacketListenerImpl.LOGGER.warn(String.format("Disconnected on move player packet. Invalid data: x=%b, y=%b, z=%b, yaw=%b, pitch=%b", invalidX, invalidY, invalidZ, invalidYaw, invalidPitch)); ++ // Purpur end - Add more logger output for invalid movement kicks + this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause + } else { + ServerLevel serverLevel = this.player.serverLevel(); +@@ -1467,7 +_,7 @@ + movedWrongly = true; + if (event.getLogWarning()) + // Paper end +- LOGGER.warn("{} moved wrongly!", this.player.getName().getString()); ++ LOGGER.warn("{} moved wrongly!, ({})", this.player.getName().getString(), verticalDelta); // Purpur - AFK API + } // Paper + } + +@@ -1533,6 +_,8 @@ + this.lastYaw = to.getYaw(); + this.lastPitch = to.getPitch(); + ++ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetLastActionTime(); // Purpur - AFK API ++ + Location oldTo = to.clone(); + PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); + this.cserver.getPluginManager().callEvent(event); +@@ -1589,6 +_,13 @@ + this.player.tryResetCurrentImpulseContext(); + } + ++ // Purpur start - Dont run with scissors! ++ if (this.player.serverLevel().purpurConfig.dontRunWithScissors && this.player.isSprinting() && !(this.player.serverLevel().purpurConfig.ignoreScissorsInWater && this.player.isInWater()) && !(this.player.serverLevel().purpurConfig.ignoreScissorsInLava && this.player.isInLava()) && (isScissors(this.player.getItemInHand(InteractionHand.MAIN_HAND)) || isScissors(this.player.getItemInHand(InteractionHand.OFF_HAND))) && (int) (Math.random() * 10) == 0) { ++ this.player.hurtServer(this.player.serverLevel(), this.player.damageSources().scissors(), (float) this.player.serverLevel().purpurConfig.scissorsRunningDamage); ++ if (!org.purpurmc.purpur.PurpurConfig.dontRunWithScissors.isBlank()) this.player.sendActionBarMessage(org.purpurmc.purpur.PurpurConfig.dontRunWithScissors); ++ } ++ // Purpur end - Dont run with scissors! ++ + this.player.checkMovementStatistics(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z); + this.lastGoodX = this.player.getX(); + this.lastGoodY = this.player.getY(); +@@ -1637,6 +_,17 @@ + } + } + ++ // Purpur start - Dont run with scissors! ++ public boolean isScissors(ItemStack stack) { ++ if (!stack.is(Items.SHEARS)) return false; ++ ++ ResourceLocation itemModelReference = stack.get(net.minecraft.core.component.DataComponents.ITEM_MODEL); ++ if (itemModelReference != null && itemModelReference.equals(this.player.serverLevel().purpurConfig.dontRunWithScissorsItemModelReference)) return true; ++ ++ return stack.getOrDefault(DataComponents.CUSTOM_MODEL_DATA, net.minecraft.world.item.component.CustomModelData.EMPTY).equals(net.minecraft.world.item.component.CustomModelData.EMPTY); ++ } ++ // Purpur end - Dont run with scissors! ++ + // Paper start - optimise out extra getCubes + private boolean hasNewCollision(final ServerLevel level, final Entity entity, final AABB oldBox, final AABB newBox) { + final List collisionsBB = new java.util.ArrayList<>(); +@@ -2001,6 +_,7 @@ + + boolean cancelled; + if (hitResult == null || hitResult.getType() != HitResult.Type.BLOCK) { ++ if (this.player.gameMode.shiftClickMended(itemInHand)) return; // Purpur - Shift right click to use exp for mending + org.bukkit.event.player.PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.RIGHT_CLICK_AIR, itemInHand, hand); + cancelled = event.useItemInHand() == Event.Result.DENY; + } else { +@@ -2741,6 +_,7 @@ + + AABB boundingBox = target.getBoundingBox(); + if (this.player.canInteractWithEntity(boundingBox, io.papermc.paper.configuration.GlobalConfiguration.get().misc.clientInteractionLeniencyDistance.or(3.0))) { // Paper - configurable lenience value for interact range ++ if (target instanceof net.minecraft.world.entity.Mob mob) mob.ticksSinceLastInteraction = 0; // Purpur - Entity lifespan + packet.dispatch( + new ServerboundInteractPacket.Handler() { + private void performInteraction(InteractionHand hand, ServerGamePacketListenerImpl.EntityInteraction entityInteraction, PlayerInteractEntityEvent event) { // CraftBukkit diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch new file mode 100644 index 000000000..5b3bc1b3f --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -307,7 +_,7 @@ + ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!"); + ServerLoginPacketListenerImpl.this.startClientVerification(ServerLoginPacketListenerImpl.this.createOfflineProfile(string1)); // Spigot + } else { +- ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username")); ++ ServerLoginPacketListenerImpl.this.disconnect(org.purpurmc.purpur.PurpurConfig.unverifiedUsername.equals("default") ? Component.translatable("multiplayer.disconnect.unverified_username") : io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.purpurmc.purpur.PurpurConfig.unverifiedUsername))); // Purpur - Config for unverified username message + ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", string1); + } + } catch (AuthenticationUnavailableException var4) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch new file mode 100644 index 000000000..3fc9d014a --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/server/network/ServerStatusPacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerStatusPacketListenerImpl.java +@@ -37,6 +_,7 @@ + } else { + this.hasRequestedStatus = true; + // this.connection.send(new ClientboundStatusResponsePacket(this.status)); // Paper ++ if (net.minecraft.server.MinecraftServer.getServer().getStatus().version().isEmpty()) return; // Purpur - Fix 'outdated server' showing in ping before server fully boots - do not respond to pings before we know the protocol version + com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(net.minecraft.server.MinecraftServer.getServer(), this.connection); // Paper - handle status request + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch new file mode 100644 index 000000000..1818a74df --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -0,0 +1,56 @@ +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -396,6 +_,7 @@ + scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam); + } + // Paper end - Configurable player collision ++ org.purpurmc.purpur.task.BossBarTask.addToAll(player); // Purpur - Implement TPSBar + PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), loggableAddress, player.getId(), serverLevel.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ()); + // Paper start - Send empty chunk, so players aren't stuck in the world loading screen with our chunk system not sending chunks when dead + if (player.isDeadOrDying()) { +@@ -501,6 +_,7 @@ + } + public net.kyori.adventure.text.Component remove(ServerPlayer player, net.kyori.adventure.text.Component leaveMessage) { + // Paper end - Fix kick event leave message not being sent ++ org.purpurmc.purpur.task.BossBarTask.removeFromAll(player.getBukkitEntity()); // Purpur - Implement TPSBar + ServerLevel serverLevel = player.serverLevel(); + player.awardStat(Stats.LEAVE_GAME); + // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it +@@ -665,7 +_,7 @@ + // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameProfile) + // ? Component.translatable("multiplayer.disconnect.server_full") + // : null; +- if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameProfile)) { ++ if (this.players.size() >= this.maxPlayers && !(player.hasPermission("purpur.joinfullserver") || this.canBypassPlayerLimit(gameProfile))) { // Purpur - Allow player join full server by permission + event.disallow(org.bukkit.event.player.PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure + } + } +@@ -919,6 +_,20 @@ + } + } + ++ // Purpur start - Component related conveniences ++ public void broadcastMiniMessage(@Nullable String message, boolean overlay) { ++ if (message != null && !message.isEmpty()) { ++ this.broadcastMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message), overlay); ++ } ++ } ++ ++ public void broadcastMessage(@Nullable net.kyori.adventure.text.Component message, boolean overlay) { ++ if (message != null) { ++ this.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message), overlay); ++ } ++ } ++ // Purpur end - Component related conveniences ++ + public void broadcastAll(Packet packet, ResourceKey dimension) { + for (ServerPlayer serverPlayer : this.players) { + if (serverPlayer.level().dimension() == dimension) { +@@ -1002,6 +_,7 @@ + } else { + b = (byte)(24 + permLevel); + } ++ if (b < 28 && player.getBukkitEntity().hasPermission("purpur.debug.f3n")) b = 28; // Purpur - Add permission for F3+N debug + + player.connection.send(new ClientboundEntityEventPacket(player, b)); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/server/players/SleepStatus.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/server/players/SleepStatus.java.patch new file mode 100644 index 000000000..998d2f057 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/server/players/SleepStatus.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/server/players/SleepStatus.java ++++ b/net/minecraft/server/players/SleepStatus.java +@@ -15,7 +_,7 @@ + + public boolean areEnoughDeepSleeping(int requiredSleepPercentage, List sleepingPlayers) { + // CraftBukkit start +- int i = (int) sleepingPlayers.stream().filter(player -> player.isSleepingLongEnough() || player.fauxSleeping).count(); ++ int i = (int) sleepingPlayers.stream().filter(player -> player.isSleepingLongEnough() || player.fauxSleeping || (player.level().purpurConfig.idleTimeoutCountAsSleeping && player.isAfk())).count(); // Purpur - AFK API + boolean anyDeepSleep = sleepingPlayers.stream().anyMatch(Player::isSleepingLongEnough); + return anyDeepSleep && i >= this.sleepersNeeded(requiredSleepPercentage); + // CraftBukkit end +@@ -43,7 +_,7 @@ + for (ServerPlayer serverPlayer : players) { + if (!serverPlayer.isSpectator()) { + this.activePlayers++; +- if (serverPlayer.isSleeping() || serverPlayer.fauxSleeping) { // CraftBukkit ++ if (serverPlayer.isSleeping() || serverPlayer.fauxSleeping || (serverPlayer.level().purpurConfig.idleTimeoutCountAsSleeping && serverPlayer.isAfk())) { // CraftBukkit // Purpur - AFK API + this.sleepingPlayers++; + } + // CraftBukkit start diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch new file mode 100644 index 000000000..384d2c33b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/stats/ServerRecipeBook.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/stats/ServerRecipeBook.java ++++ b/net/minecraft/stats/ServerRecipeBook.java +@@ -138,6 +_,7 @@ + try { + ResourceKey> resourceKey = ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(string)); + if (!isRecognized.test(resourceKey)) { ++ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressUnrecognizedRecipeErrors) // Purpur - Logger settings (suppressing pointless logs) + LOGGER.error("Tried to load unrecognized recipe: {} removed now.", resourceKey); + } else { + output.accept(resourceKey); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/util/StringUtil.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/util/StringUtil.java.patch new file mode 100644 index 000000000..b8d231182 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/util/StringUtil.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/util/StringUtil.java ++++ b/net/minecraft/util/StringUtil.java +@@ -87,6 +_,7 @@ + + // Paper start - Username validation + public static boolean isReasonablePlayerName(final String name) { ++ if (true) return org.purpurmc.purpur.PurpurConfig.usernameValidCharactersPattern.matcher(name).matches(); // Purpur - Configurable valid characters for usernames + if (name.isEmpty() || name.length() > 16) { + return false; + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatRules.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatRules.java.patch new file mode 100644 index 000000000..a70c7a253 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatRules.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/damagesource/CombatRules.java ++++ b/net/minecraft/world/damagesource/CombatRules.java +@@ -15,7 +_,7 @@ + + public static float getDamageAfterAbsorb(LivingEntity entity, float damage, DamageSource damageSource, float armorValue, float armorToughness) { + float f = 2.0F + armorToughness / 4.0F; +- float f1 = Mth.clamp(armorValue - damage / f, armorValue * 0.2F, 20.0F); ++ float f1 = Mth.clamp(armorValue - damage / f, armorValue * 0.2F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur - Add attribute clamping and armor limit config + float f2 = f1 / 25.0F; + ItemStack weaponItem = damageSource.getWeaponItem(); + float f3; +@@ -30,7 +_,7 @@ + } + + public static float getDamageAfterMagicAbsorb(float damage, float enchantModifiers) { +- float f = Mth.clamp(enchantModifiers, 0.0F, 20.0F); ++ float f = Mth.clamp(enchantModifiers, 0.0F, org.purpurmc.purpur.PurpurConfig.limitArmor ? 20F : Float.MAX_VALUE); // Purpur - Add attribute clamping and armor limit config + return damage * (1.0F - f / 25.0F); + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch new file mode 100644 index 000000000..0994f6fcd --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/CombatTracker.java.patch @@ -0,0 +1,27 @@ +--- a/net/minecraft/world/damagesource/CombatTracker.java ++++ b/net/minecraft/world/damagesource/CombatTracker.java +@@ -54,7 +_,7 @@ + + private Component getMessageForAssistedFall(Entity entity, Component entityDisplayName, String hasWeaponTranslationKey, String noWeaponTranslationKey) { + ItemStack itemStack = entity instanceof LivingEntity livingEntity ? livingEntity.getMainHandItem() : ItemStack.EMPTY; +- return !itemStack.isEmpty() && itemStack.has(DataComponents.CUSTOM_NAME) ++ return !itemStack.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemStack.has(DataComponents.CUSTOM_NAME)) // Purpur - always show item in player death messages + ? Component.translatable(hasWeaponTranslationKey, this.mob.getDisplayName(), entityDisplayName, itemStack.getDisplayName()) + : Component.translatable(noWeaponTranslationKey, this.mob.getDisplayName(), entityDisplayName); + } +@@ -98,6 +_,15 @@ + Component component = ComponentUtils.wrapInSquareBrackets(Component.translatable(string + ".link")).withStyle(INTENTIONAL_GAME_DESIGN_STYLE); + return Component.translatable(string + ".message", this.mob.getDisplayName(), component); + } else { ++ // Purpur start - Dont run with scissors! ++ if (damageSource.isScissors()) { ++ return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgRunWithScissors, this.mob); ++ // Purpur start - Stonecutter damage ++ } else if (damageSource.isStonecutter()) { ++ return damageSource.getLocalizedDeathMessage(org.purpurmc.purpur.PurpurConfig.deathMsgStonecutter, this.mob); ++ // Purpur end - Stonecutter damage ++ } ++ // Purpur end - Dont run with scissors! + return damageSource.getLocalizedDeathMessage(this.mob); + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSource.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSource.java.patch new file mode 100644 index 000000000..4fe0b6a16 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSource.java.patch @@ -0,0 +1,70 @@ +--- a/net/minecraft/world/damagesource/DamageSource.java ++++ b/net/minecraft/world/damagesource/DamageSource.java +@@ -28,6 +_,8 @@ + private boolean sweep = false; + private boolean melting = false; + private boolean poison = false; ++ private boolean scissors = false; // Purpur - Dont run with scissors! ++ private boolean stonecutter = false; // Purpur - Stonecutter damage + @Nullable + private Entity customEventDamager = null; // This field is a helper for when causing entity damage is not set by vanilla // Paper - fix DamageSource API + +@@ -58,6 +_,27 @@ + return this.poison; + } + ++ // Purpur start - Dont run with scissors! ++ public DamageSource scissors() { ++ this.scissors = true; ++ return this; ++ } ++ ++ public boolean isScissors() { ++ return this.scissors; ++ } ++ // Purpur end - Dont run with scissors! ++ // Purpur start - - Stonecutter damage ++ public DamageSource stonecutter() { ++ this.stonecutter = true; ++ return this; ++ } ++ ++ public boolean isStonecutter() { ++ return this.stonecutter; ++ } ++ // Purpur end - Stonecutter damage ++ + // Paper start - fix DamageSource API + @Nullable + public Entity getCustomEventDamager() { +@@ -118,6 +_,8 @@ + damageSource.sweep = this.isSweep(); + damageSource.poison = this.isPoison(); + damageSource.melting = this.isMelting(); ++ damageSource.scissors = this.isScissors(); // Purpur - Dont run with scissors! ++ damageSource.stonecutter = this.isStonecutter(); // Purpur - Stonecutter damage + return damageSource; + } + // CraftBukkit end +@@ -184,11 +_,20 @@ + } else { + Component component = this.causingEntity == null ? this.directEntity.getDisplayName() : this.causingEntity.getDisplayName(); + ItemStack itemStack = this.causingEntity instanceof LivingEntity livingEntity1 ? livingEntity1.getMainHandItem() : ItemStack.EMPTY; +- return !itemStack.isEmpty() && itemStack.has(DataComponents.CUSTOM_NAME) ++ return !itemStack.isEmpty() && (org.purpurmc.purpur.PurpurConfig.playerDeathsAlwaysShowItem || itemStack.has(DataComponents.CUSTOM_NAME)) // Purpur - always show item in player death messages + ? Component.translatable(string + ".item", livingEntity.getDisplayName(), component, itemStack.getDisplayName()) + : Component.translatable(string, livingEntity.getDisplayName(), component); + } + } ++ ++ // Purpur start - Component related conveniences ++ public Component getLocalizedDeathMessage(String str, LivingEntity entity) { ++ net.kyori.adventure.text.Component name = io.papermc.paper.adventure.PaperAdventure.asAdventure(entity.getDisplayName()); ++ net.kyori.adventure.text.minimessage.tag.resolver.TagResolver template = net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("player", name); ++ net.kyori.adventure.text.Component component = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(str, template); ++ return io.papermc.paper.adventure.PaperAdventure.asVanilla(component); ++ } ++ // Purpur end - Component related conveniences + + public String getMsgId() { + return this.type().msgId(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSources.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSources.java.patch new file mode 100644 index 000000000..9e3c63dab --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/damagesource/DamageSources.java.patch @@ -0,0 +1,36 @@ +--- a/net/minecraft/world/damagesource/DamageSources.java ++++ b/net/minecraft/world/damagesource/DamageSources.java +@@ -45,11 +_,15 @@ + // CraftBukkit start + private final DamageSource melting; + private final DamageSource poison; ++ private final DamageSource scissors; // Purpur - Dont run with scissors! ++ private final DamageSource stonecutter; // Purpur - Stonecutter damage + + public DamageSources(RegistryAccess registry) { + this.damageTypes = registry.lookupOrThrow(Registries.DAMAGE_TYPE); + this.melting = this.source(DamageTypes.ON_FIRE).melting(); + this.poison = this.source(DamageTypes.MAGIC).poison(); ++ this.scissors = this.source(DamageTypes.MAGIC).scissors(); // Purpur - Dont run with scissors! ++ this.stonecutter = this.source(DamageTypes.MAGIC).stonecutter(); // Purpur - Stonecutter damage + // CraftBukkit end + this.inFire = this.source(DamageTypes.IN_FIRE); + this.campfire = this.source(DamageTypes.CAMPFIRE); +@@ -100,6 +_,17 @@ + } + // CraftBukkit end + ++ // Purpur start - Dont run with scissors! ++ public DamageSource scissors() { ++ return this.scissors; ++ } ++ // Purpur end - Dont run with scissors! ++ ++ // Purpur start - Stonecutter damage ++ public DamageSource stonecutter() { ++ return this.stonecutter; ++ } ++ // Purpur end - Stonecutter damage + public DamageSource inFire() { + return this.inFire; + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/HungerMobEffect.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/HungerMobEffect.java.patch new file mode 100644 index 000000000..ea284de7b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/HungerMobEffect.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/effect/HungerMobEffect.java ++++ b/net/minecraft/world/effect/HungerMobEffect.java +@@ -12,7 +_,7 @@ + @Override + public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { + if (entity instanceof Player player) { +- player.causeFoodExhaustion(0.005F * (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent ++ player.causeFoodExhaustion(entity.level().purpurConfig.humanHungerExhaustionAmount * (amplifier + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent // Purpur - Config MobEffect by world + } + + return true; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch new file mode 100644 index 000000000..48b0053a0 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/PoisonMobEffect.java.patch @@ -0,0 +1,13 @@ +--- a/net/minecraft/world/effect/PoisonMobEffect.java ++++ b/net/minecraft/world/effect/PoisonMobEffect.java +@@ -12,8 +_,8 @@ + + @Override + public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { +- if (entity.getHealth() > 1.0F) { +- entity.hurtServer(level, entity.damageSources().poison(), 1.0F); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON ++ if (entity.getHealth() > entity.level().purpurConfig.entityMinimalHealthPoison) { // Purpur ++ entity.hurtServer(level, entity.damageSources().poison(), entity.level().purpurConfig.entityPoisonDegenerationAmount); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON // Purpur - Config MobEffect by world + } + + return true; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/RegenerationMobEffect.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/RegenerationMobEffect.java.patch new file mode 100644 index 000000000..f19f319af --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/RegenerationMobEffect.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/effect/RegenerationMobEffect.java ++++ b/net/minecraft/world/effect/RegenerationMobEffect.java +@@ -11,7 +_,7 @@ + @Override + public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { + if (entity.getHealth() < entity.getMaxHealth()) { +- entity.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit ++ entity.heal(entity.level().purpurConfig.entityHealthRegenAmount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.MAGIC_REGEN); // CraftBukkit // Purpur - Config MobEffect by world + } + + return true; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/SaturationMobEffect.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/SaturationMobEffect.java.patch new file mode 100644 index 000000000..f2d21d380 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/SaturationMobEffect.java.patch @@ -0,0 +1,12 @@ +--- a/net/minecraft/world/effect/SaturationMobEffect.java ++++ b/net/minecraft/world/effect/SaturationMobEffect.java +@@ -16,7 +_,8 @@ + int oldFoodLevel = player.getFoodData().foodLevel; + org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, amplifier + 1 + oldFoodLevel); + if (!event.isCancelled()) { +- player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 1.0F); ++ if (player.level().purpurConfig.playerBurpWhenFull && event.getFoodLevel() == 20 && oldFoodLevel < 20) player.burpDelay = player.level().purpurConfig.playerBurpDelay; // Purpur - Burp delay ++ player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, entity.level().purpurConfig.humanSaturationRegenAmount); // Purpur - Config MobEffect by world + } + + ((org.bukkit.craftbukkit.entity.CraftPlayer) player.getBukkitEntity()).sendHealthUpdate(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/WitherMobEffect.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/WitherMobEffect.java.patch new file mode 100644 index 000000000..767637659 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/effect/WitherMobEffect.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/effect/WitherMobEffect.java ++++ b/net/minecraft/world/effect/WitherMobEffect.java +@@ -12,7 +_,7 @@ + + @Override + public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) { +- entity.hurtServer(level, entity.damageSources().wither(), 1.0F); ++ entity.hurtServer(level, entity.damageSources().wither(), entity.level().purpurConfig.entityWitherDegenerationAmount); // Purpur - Config MobEffect by world + return true; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch new file mode 100644 index 000000000..31b781a7f --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -0,0 +1,186 @@ +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -136,7 +_,7 @@ + import org.slf4j.Logger; + + public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker +- ++ public static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur - Configurable entity base attributes + // CraftBukkit start + private static final int CURRENT_LEVEL = 2; + public boolean preserveMotion = true; // Paper - Fix Entity Teleportation and cancel velocity if teleported; keep initial motion on first setPositionRotation +@@ -253,9 +_,10 @@ + public double xOld; + public double yOld; + public double zOld; ++ public float maxUpStep; // Purpur - Add option to set armorstand step height + public boolean noPhysics; + private boolean wasOnFire; +- public final RandomSource random = SHARED_RANDOM; // Paper - Share random for entities to make them more random ++ public final RandomSource random; // Paper - Share random for entities to make them more random // Add toggle for RNG manipulation + public int tickCount; + private int remainingFireTicks = -this.getFireImmuneTicks(); + public boolean wasTouchingWater; +@@ -289,8 +_,8 @@ + public PortalProcessor portalProcess; + public int portalCooldown; + private boolean invulnerable; +- protected UUID uuid = Mth.createInsecureUUID(this.random); +- protected String stringUUID = this.uuid.toString(); ++ protected UUID uuid; // Purpur - Add toggle for RNG manipulation ++ protected String stringUUID; // Purpur - Add toggle for RNG manipulation + private boolean hasGlowingTag; + private final Set tags = new io.papermc.paper.util.SizeLimitedSet<>(new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(), MAX_ENTITY_TAG_COUNT); // Paper - fully limit tag size - replace set impl + private final double[] pistonDeltas = new double[]{0.0, 0.0, 0.0}; +@@ -342,6 +_,7 @@ + public long activatedTick = Integer.MIN_VALUE; + public boolean isTemporarilyActive; + public long activatedImmunityTick = Integer.MIN_VALUE; ++ public @Nullable Boolean immuneToFire = null; // Purpur - Fire immune API + + public void inactiveTick() { + } +@@ -522,10 +_,21 @@ + } + // Paper end - optimise entity tracker + ++ // Purpur start - Add canSaveToDisk to Entity ++ public boolean canSaveToDisk() { ++ return true; ++ } ++ // Purpur end - Add canSaveToDisk to Entity ++ + public Entity(EntityType entityType, Level level) { + this.type = entityType; + this.level = level; + this.dimensions = entityType.getDimensions(); ++ // Purpur start - Add toggle for RNG manipulation ++ this.random = level == null || level.purpurConfig.entitySharedRandom ? SHARED_RANDOM : RandomSource.create(); ++ this.uuid = Mth.createInsecureUUID(this.random); ++ this.stringUUID = this.uuid.toString(); ++ // Purpur end - Add toggle for RNG manipulation + this.position = Vec3.ZERO; + this.blockPosition = BlockPos.ZERO; + this.chunkPosition = ChunkPos.ZERO; +@@ -904,6 +_,7 @@ + && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> this.getY() >= v) + && (!(this instanceof Player player) || !player.getAbilities().invulnerable))) { + // Paper end - Configurable nether ceiling damage ++ if (this.level.purpurConfig.teleportOnNetherCeilingDamage && this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER && this instanceof ServerPlayer player) player.teleport(io.papermc.paper.util.MCUtil.toLocation(this.level, this.level.getSharedSpawnPos())); else // Purpur - Add option to teleport to spawn on nether ceiling damage + this.onBelowWorld(); + } + } +@@ -1826,7 +_,7 @@ + } + + public boolean fireImmune() { +- return this.getType().fireImmune(); ++ return this.immuneToFire != null ? immuneToFire : this.getType().fireImmune(); // Purpur - add fire immune API + } + + public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) { +@@ -1895,7 +_,7 @@ + return this.isInWater() || flag; + } + +- public void updateInWaterStateAndDoWaterCurrentPushing() { ++ public void updateInWaterStateAndDoWaterCurrentPushing() { // Purpur - Movement options for armor stands - package-private -> public - TODO: use AT file + if (this.getVehicle() instanceof AbstractBoat abstractBoat && !abstractBoat.isUnderWater()) { + this.wasTouchingWater = false; + } else if (this.updateFluidHeightAndDoFluidPushing(FluidTags.WATER, 0.014)) { +@@ -2521,6 +_,13 @@ + compound.putBoolean("Paper.FreezeLock", true); + } + // Paper end ++ ++ // Purpur start - Fire immune API ++ if (immuneToFire != null) { ++ compound.putBoolean("Purpur.FireImmune", immuneToFire); ++ } ++ // Purpur end - Fire immune API ++ + return compound; + } catch (Throwable var9) { + CrashReport crashReport = CrashReport.forThrowable(var9, "Saving entity NBT"); +@@ -2670,6 +_,13 @@ + freezeLocked = compound.getBoolean("Paper.FreezeLock"); + } + // Paper end ++ ++ // Purpur start - Fire immune API ++ if (compound.contains("Purpur.FireImmune")) { ++ immuneToFire = compound.getBoolean("Purpur.FireImmune"); ++ } ++ // Purpur end - Fire immune API ++ + } catch (Throwable var17) { + CrashReport crashReport = CrashReport.forThrowable(var17, "Loading entity NBT"); + CrashReportCategory crashReportCategory = crashReport.addCategory("Entity being loaded"); +@@ -2916,6 +_,7 @@ + if (this.isAlive() && this instanceof Leashable leashable) { + if (leashable.getLeashHolder() == player) { + if (!this.level().isClientSide()) { ++ if (hand == InteractionHand.OFF_HAND && (level().purpurConfig.villagerCanBeLeashed || level().purpurConfig.wanderingTraderCanBeLeashed) && this instanceof net.minecraft.world.entity.npc.AbstractVillager) return InteractionResult.CONSUME; // Purpur - Allow leashing villagers + // CraftBukkit start - fire PlayerUnleashEntityEvent + // Paper start - Expand EntityUnleashEvent + org.bukkit.event.player.PlayerUnleashEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerUnleashEntityEvent(this, player, hand, !player.hasInfiniteMaterials()); +@@ -3241,15 +_,18 @@ + return Vec3.directionFromRotation(this.getRotationVector()); + } + ++ public BlockPos portalPos = BlockPos.ZERO; // Purpur - Fix stuck in portals + public void setAsInsidePortal(Portal portal, BlockPos pos) { + if (this.isOnPortalCooldown()) { ++ if (!(level().purpurConfig.playerFixStuckPortal && this instanceof Player && !pos.equals(this.portalPos))) // Purpur - Fix stuck in portals + this.setPortalCooldown(); +- } else { ++ } else if (this.level.purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer) { // Purpur - Entities can use portals + if (this.portalProcess == null || !this.portalProcess.isSamePortal(portal)) { + this.portalProcess = new PortalProcessor(portal, pos.immutable()); + } else if (!this.portalProcess.isInsidePortalThisTick()) { + this.portalProcess.updateEntryPosition(pos.immutable()); + this.portalProcess.setAsInsidePortalThisTick(true); ++ this.portalPos = BlockPos.ZERO; // Purpur - Fix stuck in portals + } + } + } +@@ -3454,7 +_,7 @@ + } + + public int getMaxAirSupply() { +- return this.maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() ++ return this.level == null? this.maxAirTicks : this.level().purpurConfig.drowningAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() // Purpur - Drowning Settings + } + + public int getAirSupply() { +@@ -3949,7 +_,7 @@ + // CraftBukkit end + + public boolean canUsePortal(boolean allowPassengers) { +- return (allowPassengers || !this.isPassenger()) && this.isAlive(); ++ return (allowPassengers || !this.isPassenger()) && this.isAlive() && (this.level.purpurConfig.entitiesCanUsePortals || this instanceof ServerPlayer); // Purpur - Entities can use portals + } + + public boolean canTeleport(Level fromLevel, Level toLevel) { +@@ -4481,6 +_,12 @@ + return Mth.lerp(partialTick, this.yRotO, this.yRot); + } + ++ // Purpur start - Stop squids floating on top of water ++ public AABB getAxisForFluidCheck() { ++ return this.getBoundingBox().deflate(0.001D); ++ } ++ // Purpur end - Stop squids floating on top of water ++ + // Paper start - optimise collisions + public boolean updateFluidHeightAndDoFluidPushing(final TagKey fluid, final double flowScale) { + if (this.touchingUnloadedChunk()) { +@@ -4879,7 +_,7 @@ + } + + public float maxUpStep() { +- return 0.0F; ++ return maxUpStep; // Purpur - Add option to set armorstand step height + } + + public void onExplosionHit(@Nullable Entity entity) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntitySelector.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntitySelector.java.patch new file mode 100644 index 000000000..ff1e039a1 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntitySelector.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/EntitySelector.java ++++ b/net/minecraft/world/entity/EntitySelector.java +@@ -28,6 +_,8 @@ + return net.minecraft.util.Mth.clamp(serverPlayer.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= playerInsomniaTicks; + }; + // Paper end - Ability to control player's insomnia and phantoms ++ public static Predicate notAfk = (player) -> !player.isAfk(); // Purpur - AFK API ++ + // Paper start - Affects Spawning API + public static final Predicate PLAYER_AFFECTS_SPAWNING = (entity) -> { + return !entity.isSpectator() && entity.isAlive() && entity instanceof Player player && player.affectsSpawning; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntityType.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntityType.java.patch new file mode 100644 index 000000000..6b937ec99 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/EntityType.java.patch @@ -0,0 +1,52 @@ +--- a/net/minecraft/world/entity/EntityType.java ++++ b/net/minecraft/world/entity/EntityType.java +@@ -1083,6 +_,16 @@ + return register(vanillaEntityId(key), builder); + } + ++ // Purpur start - PlayerSetSpawnerTypeWithEggEvent ++ public static EntityType getFromBukkitType(org.bukkit.entity.EntityType bukkitType) { ++ return getFromKey(ResourceLocation.parse(bukkitType.getKey().toString())); ++ } ++ ++ public static EntityType getFromKey(ResourceLocation location) { ++ return BuiltInRegistries.ENTITY_TYPE.getValue(location); ++ } ++ // Purpur end - PlayerSetSpawnerTypeWithEggEvent ++ + public static ResourceLocation getKey(EntityType entityType) { + return BuiltInRegistries.ENTITY_TYPE.getKey(entityType); + } +@@ -1312,6 +_,16 @@ + return this.category; + } + ++ // Purpur start - PlayerSetSpawnerTypeWithEggEvent ++ public String getName() { ++ return BuiltInRegistries.ENTITY_TYPE.getKey(this).getPath(); ++ } ++ ++ public String getTranslatedName() { ++ return getDescription().getString(); ++ } ++ // Purpur end - PlayerSetSpawnerTypeWithEggEvent ++ + public String getDescriptionId() { + return this.descriptionId; + } +@@ -1370,7 +_,14 @@ + entity.load(tag); + }, + // Paper end - Don't fire sync event during generation +- () -> LOGGER.warn("Skipping Entity with id {}", tag.getString("id")) ++ // Purpur start - log skipped entity's position ++ () -> {LOGGER.warn("Skipping Entity with id {}", tag.getString("id")); ++ try { ++ ListTag pos = tag.getList("Pos", 6); ++ EntityType.LOGGER.warn("Location: {} {},{},{}", level.getWorld().getName(), pos.getDouble(0), pos.getDouble(1), pos.getDouble(2)); ++ } catch (Throwable ignore) {} ++ } ++ // Purpur end - log skipped entity's position + ); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch new file mode 100644 index 000000000..a14e7f6a5 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/entity/ExperienceOrb.java ++++ b/net/minecraft/world/entity/ExperienceOrb.java +@@ -323,7 +_,7 @@ + public void playerTouch(Player entity) { + if (entity instanceof ServerPlayer serverPlayer) { + if (entity.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent +- entity.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(entity, 2, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; ++ entity.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(entity, this.level().purpurConfig.playerExpPickupDelay, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; // Purpur - Configurable player pickup exp delay + entity.take(this, 1); + int i = this.repairPlayerItems(serverPlayer, this.value); + if (i > 0) { +@@ -339,7 +_,7 @@ + } + + private int repairPlayerItems(ServerPlayer player, int value) { +- Optional randomItemWith = EnchantmentHelper.getRandomItemWith( ++ Optional randomItemWith = level().purpurConfig.useBetterMending ? EnchantmentHelper.getMostDamagedItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player) : EnchantmentHelper.getRandomItemWith( // Purpur - Add option to mend the most damaged equipment first + EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged + ); + if (randomItemWith.isPresent()) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/GlowSquid.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/GlowSquid.java.patch new file mode 100644 index 000000000..61c07231e --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/GlowSquid.java.patch @@ -0,0 +1,16 @@ +--- a/net/minecraft/world/entity/GlowSquid.java ++++ b/net/minecraft/world/entity/GlowSquid.java +@@ -25,6 +_,13 @@ + super(entityType, level); + } + ++ // Purpur start - Flying squids! Oh my! ++ @Override ++ public boolean canFly() { ++ return this.level().purpurConfig.glowSquidsCanFly; ++ } ++ // Purpur end - Flying squids! Oh my! ++ + @Override + protected ParticleOptions getInkParticle() { + return ParticleTypes.GLOW_SQUID_INK; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch new file mode 100644 index 000000000..bf89dba4b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -0,0 +1,177 @@ +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -459,6 +_,12 @@ + if (d < 0.0) { + double damagePerBlock = this.level().getWorldBorder().getDamagePerBlock(); + if (damagePerBlock > 0.0) { ++ // Purpur start - Add option to teleport to spawn if outside world border ++ if (this.level().purpurConfig.teleportIfOutsideBorder && this instanceof ServerPlayer serverPlayer) { ++ serverPlayer.teleport(io.papermc.paper.util.MCUtil.toLocation(this.level(), this.level().getSharedSpawnPos())); ++ return; ++ } ++ // Purpur end - Add option to teleport to spawn if outside world border + this.hurtServer(serverLevel1, this.damageSources().outOfBorder(), Math.max(1, Mth.floor(-d * damagePerBlock))); + } + } +@@ -472,7 +_,7 @@ + && (!flag || !((Player)this).getAbilities().invulnerable); + if (flag1) { + this.setAirSupply(this.decreaseAirSupply(this.getAirSupply())); +- if (this.getAirSupply() == -20) { ++ if (this.getAirSupply() == -this.level().purpurConfig.drowningDamageInterval) { // Purpur - Drowning Settings + this.setAirSupply(0); + Vec3 deltaMovement = this.getDeltaMovement(); + +@@ -492,7 +_,7 @@ + ); + } + +- this.hurt(this.damageSources().drown(), 2.0F); ++ this.hurt(this.damageSources().drown(), (float) this.level().purpurConfig.damageFromDrowning); // Purpur - Drowning Settings + } + } else if (this.getAirSupply() < this.getMaxAirSupply()) { + this.setAirSupply(this.increaseAirSupply(this.getAirSupply())); +@@ -1009,14 +_,32 @@ + if (lookingEntity != null) { + ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD); + EntityType type = lookingEntity.getType(); +- if (type == EntityType.SKELETON && itemBySlot.is(Items.SKELETON_SKULL) +- || type == EntityType.ZOMBIE && itemBySlot.is(Items.ZOMBIE_HEAD) +- || type == EntityType.PIGLIN && itemBySlot.is(Items.PIGLIN_HEAD) +- || type == EntityType.PIGLIN_BRUTE && itemBySlot.is(Items.PIGLIN_HEAD) +- || type == EntityType.CREEPER && itemBySlot.is(Items.CREEPER_HEAD)) { +- d *= 0.5; +- } +- } ++ // Purpur start - Mob head visibility percent ++ if (type == EntityType.SKELETON && itemBySlot.is(Items.SKELETON_SKULL)) { ++ d *= lookingEntity.level().purpurConfig.skeletonHeadVisibilityPercent; ++ } ++ else if (type == EntityType.ZOMBIE && itemBySlot.is(Items.ZOMBIE_HEAD)) { ++ d *= lookingEntity.level().purpurConfig.zombieHeadVisibilityPercent; ++ } ++ else if ((type == EntityType.PIGLIN || type == EntityType.PIGLIN_BRUTE) && itemBySlot.is(Items.PIGLIN_HEAD)) { ++ d *= lookingEntity.level().purpurConfig.piglinHeadVisibilityPercent; ++ } ++ else if (type == EntityType.CREEPER && itemBySlot.is(Items.CREEPER_HEAD)) { ++ d *= lookingEntity.level().purpurConfig.creeperHeadVisibilityPercent; ++ } ++ // Purpur end - Mob head visibility percent ++ } ++ ++ // Purpur start - Configurable mob blindness ++ if (lookingEntity instanceof LivingEntity entityliving) { ++ if (entityliving.hasEffect(MobEffects.BLINDNESS)) { ++ int amplifier = entityliving.getEffect(MobEffects.BLINDNESS).getAmplifier(); ++ for (int i = 0; i < amplifier; i++) { ++ d *= this.level().purpurConfig.mobsBlindnessMultiplier; ++ } ++ } ++ } ++ // Purpur end - Configurable mob blindness + + return d; + } +@@ -1063,6 +_,7 @@ + Iterator iterator = this.activeEffects.values().iterator(); + while (iterator.hasNext()) { + MobEffectInstance effect = iterator.next(); ++ if (cause == EntityPotionEffectEvent.Cause.MILK && !this.level().purpurConfig.milkClearsBeneficialEffects && effect.getEffect().value().isBeneficial()) continue; // Purpur - Milk Keeps Beneficial Effects + EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause, EntityPotionEffectEvent.Action.CLEARED); + if (event.isCancelled()) { + continue; +@@ -1372,6 +_,24 @@ + this.stopSleeping(); + } + ++ // Purpur start - One Punch Man! ++ if (damageSource.getEntity() instanceof net.minecraft.world.entity.player.Player player && damageSource.getEntity().level().purpurConfig.creativeOnePunch && !damageSource.is(DamageTypeTags.IS_PROJECTILE)) { ++ if (player.isCreative()) { ++ org.apache.commons.lang3.mutable.MutableDouble attackDamage = new org.apache.commons.lang3.mutable.MutableDouble(); ++ player.getMainHandItem().forEachModifier(EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> { ++ if (attributeModifier.operation() == AttributeModifier.Operation.ADD_VALUE) { ++ attackDamage.addAndGet(attributeModifier.amount()); ++ } ++ }); ++ ++ if (attackDamage.doubleValue() == 0.0D) { ++ // One punch! ++ amount = 9999F; ++ } ++ } ++ } ++ // Purpur end - One Punch Man! ++ + this.noActionTime = 0; + if (amount < 0.0F) { + amount = 0.0F; +@@ -1536,11 +_,11 @@ + protected Player resolvePlayerResponsibleForDamage(DamageSource damageSource) { + Entity entity = damageSource.getEntity(); + if (entity instanceof Player player) { +- this.lastHurtByPlayerTime = 100; ++ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur - Config for mob last hurt by player time + this.lastHurtByPlayer = player; + return player; + } else if (entity instanceof Wolf wolf && wolf.isTame()) { +- this.lastHurtByPlayerTime = 100; ++ this.lastHurtByPlayerTime = this.level().purpurConfig.mobLastHurtByPlayerTime; // Purpur - Config for mob last hurt by player time + if (wolf.getOwner() instanceof Player player1) { + this.lastHurtByPlayer = player1; + } else { +@@ -1594,6 +_,18 @@ + } + } + ++ // Purpur start - Totems work in inventory ++ if (level().purpurConfig.totemOfUndyingWorksInInventory && this instanceof ServerPlayer player && (itemStack == null || itemStack.getItem() != Items.TOTEM_OF_UNDYING) && player.getBukkitEntity().hasPermission("purpur.inventory_totem")) { ++ for (ItemStack item : player.getInventory().items) { ++ if (item.getItem() == Items.TOTEM_OF_UNDYING) { ++ itemInHand = item; ++ itemStack = item.copy(); ++ break; ++ } ++ } ++ } ++ // Purpur end - Totems work in inventory ++ + final org.bukkit.inventory.EquipmentSlot handSlot = (hand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand) : null; + final EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot); + event.setCancelled(itemStack == null); +@@ -1790,6 +_,7 @@ + boolean flag = this.lastHurtByPlayerTime > 0; + this.dropEquipment(level); // CraftBukkit - from below + if (this.shouldDropLoot() && level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { ++ if (!(damageSource.is(net.minecraft.world.damagesource.DamageTypes.CRAMMING) && level().purpurConfig.disableDropsOnCrammingDeath)) { // Purpur - Disable loot drops on death by cramming + this.dropFromLootTable(level, damageSource, flag); + // Paper start + final boolean prev = this.clearEquipmentSlots; +@@ -1798,6 +_,7 @@ + // Paper end + this.dropCustomDeathLoot(level, damageSource, flag); + this.clearEquipmentSlots = prev; // Paper ++ } // Purpur - Disable loot drops on death by cramming + } + + // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment +@@ -2989,6 +_,7 @@ + float f = (float)(d * 10.0 - 3.0); + if (f > 0.0F) { + this.playSound(this.getFallDamageSound((int)f), 1.0F, 1.0F); ++ if (level().purpurConfig.elytraKineticDamage) // Purpur - Toggle for kinetic damage + this.hurt(this.damageSources().flyIntoWall(), f); + } + } +@@ -4398,6 +_,12 @@ + ? slot == EquipmentSlot.MAINHAND && this.canUseSlot(EquipmentSlot.MAINHAND) + : slot == equippable.slot() && this.canUseSlot(equippable.slot()) && equippable.canBeEquippedBy(this.getType()); + } ++ ++ // Purpur start - Dispenser curse of binding protection ++ public @Nullable EquipmentSlot getEquipmentSlotForDispenserItem(ItemStack itemstack) { ++ return EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.BINDING_CURSE, itemstack) > 0 ? null : this.getEquipmentSlotForItem(itemstack); ++ } ++ // Purpur end - Dispenser curse of binding protection + + private static SlotAccess createEquipmentSlotAccess(LivingEntity entity, EquipmentSlot slot) { + return slot != EquipmentSlot.HEAD && slot != EquipmentSlot.MAINHAND && slot != EquipmentSlot.OFFHAND diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Mob.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Mob.java.patch new file mode 100644 index 000000000..918032262 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/Mob.java.patch @@ -0,0 +1,84 @@ +--- a/net/minecraft/world/entity/Mob.java ++++ b/net/minecraft/world/entity/Mob.java +@@ -145,6 +_,7 @@ + private BlockPos restrictCenter = BlockPos.ZERO; + private float restrictRadius = -1.0F; + public boolean aware = true; // CraftBukkit ++ public int ticksSinceLastInteraction; // Purpur - Entity lifespan + + protected Mob(EntityType entityType, Level level) { + super(entityType, level); +@@ -294,6 +_,7 @@ + target = null; + } + } ++ if (target instanceof net.minecraft.server.level.ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur - Entity lifespan + this.target = target; + return true; + // CraftBukkit end +@@ -337,7 +_,27 @@ + } + + profilerFiller.pop(); +- } ++ incrementTicksSinceLastInteraction(); // Purpur - Entity lifespan ++ } ++ ++ // Purpur start - Entity lifespan ++ private void incrementTicksSinceLastInteraction() { ++ ++this.ticksSinceLastInteraction; ++ if (getRider() != null) { ++ this.ticksSinceLastInteraction = 0; ++ return; ++ } ++ if (this.level().purpurConfig.entityLifeSpan <= 0) { ++ return; // feature disabled ++ } ++ if (!this.removeWhenFarAway(0) || isPersistenceRequired() || requiresCustomPersistence() || hasCustomName()) { ++ return; // mob persistent ++ } ++ if (this.ticksSinceLastInteraction > this.level().purpurConfig.entityLifeSpan) { ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); ++ } ++ } ++ // Purpur end - Entity lifespan + + @Override + protected void playHurtSound(DamageSource source) { +@@ -486,6 +_,7 @@ + compound.putBoolean("NoAI", this.isNoAi()); + } + compound.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit ++ compound.putInt("Purpur.ticksSinceLastInteraction", this.ticksSinceLastInteraction); // Purpur - Entity lifespan + } + + @Override +@@ -568,6 +_,11 @@ + this.aware = compound.getBoolean("Bukkit.Aware"); + } + // CraftBukkit end ++ // Purpur start - Entity lifespan ++ if (compound.contains("Purpur.ticksSinceLastInteraction")) { ++ this.ticksSinceLastInteraction = compound.getInt("Purpur.ticksSinceLastInteraction"); ++ } ++ // Purpur end - Entity lifespan + } + + @Override +@@ -1280,7 +_,7 @@ + ); + } + +- this.setLeftHanded(random.nextFloat() < 0.05F); ++ this.setLeftHanded(random.nextFloat() < level.getLevel().purpurConfig.entityLeftHandedChance); // Purpur - Changeable Mob Left Handed Chance + return spawnGroupData; + } + +@@ -1619,6 +_,7 @@ + this.playAttackSound(); + } + ++ if (target instanceof net.minecraft.server.level.ServerPlayer) this.ticksSinceLastInteraction = 0; // Purpur - Entity lifespan + return flag; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/attributes/RangedAttribute.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/attributes/RangedAttribute.java.patch new file mode 100644 index 000000000..4cd99d012 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/attributes/RangedAttribute.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/entity/ai/attributes/RangedAttribute.java ++++ b/net/minecraft/world/entity/ai/attributes/RangedAttribute.java +@@ -29,6 +_,7 @@ + + @Override + public double sanitizeValue(double value) { ++ if (!org.purpurmc.purpur.PurpurConfig.clampAttributes) return Double.isNaN(value) ? this.minValue : value; // Purpur - Add attribute clamping and armor limit config + return Double.isNaN(value) ? this.minValue : Mth.clamp(value, this.minValue, this.maxValue); + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch new file mode 100644 index 000000000..c457ae742 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java ++++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +@@ -86,7 +_,7 @@ + }; + // Paper start - optimise POI access + final java.util.List, BlockPos>> poiposes = new java.util.ArrayList<>(); +- io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, acquirablePois, predicate1, mob.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes); ++ io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, acquirablePois, predicate1, mob.blockPosition(), level.purpurConfig.villagerAcquirePoiSearchRadius, level.purpurConfig.villagerAcquirePoiSearchRadius*level.purpurConfig.villagerAcquirePoiSearchRadius, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes); // Purpur - Configurable villager search radius + final Set, BlockPos>> set = new java.util.HashSet<>(poiposes.size()); + for (final Pair, BlockPos> poiPose : poiposes) { + if (predicate.test(level, poiPose.getSecond())) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java.patch new file mode 100644 index 000000000..f90e63ebd --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java ++++ b/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java +@@ -55,7 +_,7 @@ + Node nextNode = path.getNextNode(); + BlockPos blockPos = previousNode.asBlockPos(); + BlockState blockState = level.getBlockState(blockPos); +- if (blockState.is(BlockTags.MOB_INTERACTABLE_DOORS, state -> state.getBlock() instanceof DoorBlock)) { ++ if (blockState.is(BlockTags.MOB_INTERACTABLE_DOORS, state -> state.getBlock() instanceof DoorBlock)&& !DoorBlock.requiresRedstone(entity.level(), blockState, blockPos)) { // Purpur - Option to make doors require redstone + DoorBlock doorBlock = (DoorBlock)blockState.getBlock(); + if (!doorBlock.isOpen(blockState)) { + // CraftBukkit start - entities opening doors +@@ -72,7 +_,7 @@ + + BlockPos blockPos1 = nextNode.asBlockPos(); + BlockState blockState1 = level.getBlockState(blockPos1); +- if (blockState1.is(BlockTags.MOB_INTERACTABLE_DOORS, state -> state.getBlock() instanceof DoorBlock)) { ++ if (blockState1.is(BlockTags.MOB_INTERACTABLE_DOORS, state -> state.getBlock() instanceof DoorBlock) && !DoorBlock.requiresRedstone(entity.level(), blockState1, blockPos1)) { // Purpur - Option to make doors require redstone + DoorBlock doorBlock1 = (DoorBlock)blockState1.getBlock(); + if (!doorBlock1.isOpen(blockState1)) { + // CraftBukkit start - entities opening doors +@@ -118,7 +_,7 @@ + iterator.remove(); + } else { + BlockState blockState = level.getBlockState(blockPos); +- if (!blockState.is(BlockTags.MOB_INTERACTABLE_DOORS, state -> state.getBlock() instanceof DoorBlock)) { ++ if (!blockState.is(BlockTags.MOB_INTERACTABLE_DOORS, state -> state.getBlock() instanceof DoorBlock) || DoorBlock.requiresRedstone(entity.level(), blockState, blockPos)) { // Purpur - Option to make doors require redstone + iterator.remove(); + } else { + DoorBlock doorBlock = (DoorBlock)blockState.getBlock(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java.patch new file mode 100644 index 000000000..2bbc2776e --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java ++++ b/net/minecraft/world/entity/ai/behavior/ShowTradesToPlayer.java +@@ -46,6 +_,7 @@ + + @Override + public boolean canStillUse(ServerLevel level, Villager entity, long gameTime) { ++ if (!entity.level().purpurConfig.villagerDisplayTradeItem) return false; // Purpur - Option for villager display trade item + return this.checkExtraStartConditions(level, entity) + && this.lookTime > 0 + && entity.getBrain().getMemory(MemoryModuleType.INTERACTION_TARGET).isPresent(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java.patch new file mode 100644 index 000000000..6fbb7bf98 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java ++++ b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java +@@ -22,6 +_,7 @@ + + @Override + public boolean canUse() { ++ if (!this.llama.level().purpurConfig.llamaJoinCaravans || !this.llama.shouldJoinCaravan) return false; // Purpur - Llama API // Purpur - Config to disable Llama caravans + if (!this.llama.isLeashed() && !this.llama.inCaravan()) { + List entities = this.llama.level().getEntities(this.llama, this.llama.getBoundingBox().inflate(9.0, 4.0, 9.0), entity1 -> { + EntityType type = entity1.getType(); +@@ -71,6 +_,7 @@ + + @Override + public boolean canContinueToUse() { ++ if (!this.llama.shouldJoinCaravan) return false; // Purpur - Llama API + if (this.llama.inCaravan() && this.llama.getCaravanHead().isAlive() && this.firstIsLeashed(this.llama, 0)) { + double d = this.llama.distanceToSqr(this.llama.getCaravanHead()); + if (d > 676.0) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java.patch new file mode 100644 index 000000000..f623c03a9 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java ++++ b/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java +@@ -116,9 +_,9 @@ + } + + this.mob.lookAt(target, 30.0F, 30.0F); +- } else { ++ } //else { // Purpur - MC-121706 - Fix mobs not looking up and down when strafing + this.mob.getLookControl().setLookAt(target, 30.0F, 30.0F); +- } ++ //} // Purpur - MC-121706 - Fix mobs not looking up and down when strafing + + if (this.mob.isUsingItem()) { + if (!hasLineOfSight && this.seeTime < -60) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch new file mode 100644 index 000000000..f321637d7 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java ++++ b/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java +@@ -58,7 +_,7 @@ + if (firstPassenger instanceof Player player) { + int temper = this.horse.getTemper(); + int maxTemper = this.horse.getMaxTemper(); +- if (maxTemper > 0 && this.horse.getRandom().nextInt(maxTemper) < temper && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this.horse, ((org.bukkit.craftbukkit.entity.CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent ++ if (this.horse.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials() || maxTemper > 0 && this.horse.getRandom().nextInt(maxTemper) < temper && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this.horse, ((org.bukkit.craftbukkit.entity.CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent // Purpur - Config to always tame in Creative + this.horse.tameWithName(player); + return; + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch new file mode 100644 index 000000000..b072c14f4 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/SwellGoal.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/entity/ai/goal/SwellGoal.java ++++ b/net/minecraft/world/entity/ai/goal/SwellGoal.java +@@ -55,6 +_,14 @@ + this.creeper.setSwellDir(-1); + } else { + this.creeper.setSwellDir(1); ++ // Purpur start - option to allow creeper to encircle target when fusing ++ if (this.creeper.level().purpurConfig.creeperEncircleTarget) { ++ net.minecraft.world.phys.Vec3 relative = this.creeper.position().subtract(this.target.position()); ++ relative = relative.yRot((float) Math.PI / 3).normalize().multiply(2, 2, 2); ++ net.minecraft.world.phys.Vec3 destination = this.target.position().add(relative); ++ this.creeper.getNavigation().moveTo(destination.x, destination.y, destination.z, 1); ++ } ++ // Purpur end - option to allow creeper to encircle target when fusing + } + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java.patch new file mode 100644 index 000000000..7e2366a32 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java ++++ b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java +@@ -56,7 +_,7 @@ + // Paper start - optimise POI access + java.util.List, BlockPos>> poiposes = new java.util.ArrayList<>(); + // don't ask me why it's unbounded. ask mojang. +- io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), 48, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); ++ io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), level.purpurConfig.villagerNearestBedSensorSearchRadius, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); // Purpur - Configurable villager search radius + Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes)); + // Paper end - optimise POI access + if (path != null && path.canReach()) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/targeting/TargetingConditions.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/targeting/TargetingConditions.java.patch new file mode 100644 index 000000000..df5fd519b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ai/targeting/TargetingConditions.java.patch @@ -0,0 +1,13 @@ +--- a/net/minecraft/world/entity/ai/targeting/TargetingConditions.java ++++ b/net/minecraft/world/entity/ai/targeting/TargetingConditions.java +@@ -64,6 +_,10 @@ + return false; + } else if (this.selector != null && !this.selector.test(target, level)) { + return false; ++ // Purpur start - AFK API ++ } else if (!level.purpurConfig.idleTimeoutTargetPlayer && target instanceof net.minecraft.server.level.ServerPlayer player && player.isAfk()) { ++ return false; ++ // Purpur end - AFK API + } else { + if (entity == null) { + if (this.isCombat && (!target.canBeSeenAsEnemy() || level.getDifficulty() == Difficulty.PEACEFUL)) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch new file mode 100644 index 000000000..fc1ce3bb3 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/world/entity/ambient/Bat.java ++++ b/net/minecraft/world/entity/ambient/Bat.java +@@ -231,7 +_,7 @@ + } else { + int maxLocalRawBrightness = level.getMaxLocalRawBrightness(pos); + int i = 4; +- if (isHalloween()) { ++ if (Bat.isHalloweenSeason(level.getMinecraftWorld())) { // Purpur - Halloween options and optimizations + i = 7; + } else if (randomSource.nextBoolean()) { + return false; +@@ -243,6 +_,11 @@ + } + } + ++ // Pufferfish start - only check for spooky season once an hour ++ //private static boolean isSpookySeason = false; ++ //private static final int ONE_HOUR = 20 * 60 * 60; ++ //private static int lastSpookyCheck = -ONE_HOUR; ++ public static boolean isHalloweenSeason(Level level) { return level.purpurConfig.forceHalloweenSeason || isHalloween(); } // Purpur - Halloween options and optimizations + private static boolean isHalloween() { + LocalDate localDate = LocalDate.now(); + int i = localDate.get(ChronoField.DAY_OF_MONTH); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch new file mode 100644 index 000000000..56a99c436 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch @@ -0,0 +1,34 @@ +--- a/net/minecraft/world/entity/animal/Animal.java ++++ b/net/minecraft/world/entity/animal/Animal.java +@@ -142,7 +_,7 @@ + ItemStack itemInHand = player.getItemInHand(hand); + if (this.isFood(itemInHand)) { + int age = this.getAge(); +- if (!this.level().isClientSide && age == 0 && this.canFallInLove()) { ++ if (!this.level().isClientSide && age == 0 && this.canFallInLove() && (this.level().purpurConfig.animalBreedingCooldownSeconds <= 0 || !this.level().hasBreedingCooldown(player.getUUID(), this.getClass()))) { // Purpur - Add adjustable breeding cooldown to config + final ItemStack breedCopy = itemInHand.copy(); // Paper - Fix EntityBreedEvent copying + this.usePlayerItem(player, hand, itemInHand); + this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying +@@ -239,10 +_,20 @@ + public void spawnChildFromBreeding(ServerLevel level, Animal mate) { + AgeableMob breedOffspring = this.getBreedOffspring(level, mate); + if (breedOffspring != null) { +- breedOffspring.setBaby(true); +- breedOffspring.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); ++ //breedOffspring.setBaby(true); // Purpur - Add adjustable breeding cooldown to config - moved down ++ //breedOffspring.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); // Purpur - Add adjustable breeding cooldown to config - moved down + // CraftBukkit start - call EntityBreedEvent + ServerPlayer breeder = Optional.ofNullable(this.getLoveCause()).or(() -> Optional.ofNullable(mate.getLoveCause())).orElse(null); ++ // Purpur start - Add adjustable breeding cooldown to config ++ if (breeder != null && level.purpurConfig.animalBreedingCooldownSeconds > 0) { ++ if (level.hasBreedingCooldown(breeder.getUUID(), this.getClass())) { ++ return; ++ } ++ level.addBreedingCooldown(breeder.getUUID(), this.getClass()); ++ } ++ breedOffspring.setBaby(true); ++ breedOffspring.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); ++ // Purpur end - Add adjustable breeding cooldown to config + int experience = this.getRandom().nextInt(7) + 1; + org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(breedOffspring, this, mate, breeder, this.breedItem, experience); + if (entityBreedEvent.isCancelled()) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Bee.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Bee.java.patch new file mode 100644 index 000000000..b25618ac3 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Bee.java.patch @@ -0,0 +1,43 @@ +--- a/net/minecraft/world/entity/animal/Bee.java ++++ b/net/minecraft/world/entity/animal/Bee.java +@@ -365,7 +_,7 @@ + } + + public static boolean isNightOrRaining(Level level) { +- return level.dimensionType().hasSkyLight() && (level.isNight() || level.isRaining()); ++ return level.dimensionType().hasSkyLight() && (level.isNight() && !level.purpurConfig.beeCanWorkAtNight || level.isRaining() && !level.purpurConfig.beeCanWorkInRain); // Purpur - Bee can work when raining or at night + } + + public void setStayOutOfHiveCountdown(int stayOutOfHiveCountdown) { +@@ -398,6 +_,7 @@ + this.hurtServer(level, this.damageSources().drown(), 1.0F); + } + ++ if (hasStung && !this.level().purpurConfig.beeDiesAfterSting) setHasStung(false); else // Purpur - Stop bees from dying after stinging + if (hasStung) { + this.timeSinceSting++; + if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) { +@@ -1136,6 +_,7 @@ + Bee.this.savedFlowerPos = optional.get(); + Bee.this.navigation + .moveTo(Bee.this.savedFlowerPos.getX() + 0.5, Bee.this.savedFlowerPos.getY() + 0.5, Bee.this.savedFlowerPos.getZ() + 0.5, 1.2F); ++ new org.purpurmc.purpur.event.entity.BeeFoundFlowerEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos)).callEvent(); // Purpur - Bee API + return true; + } else { + Bee.this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(Bee.this.random, 20, 60); +@@ -1182,6 +_,7 @@ + this.pollinating = false; + Bee.this.navigation.stop(); + Bee.this.remainingCooldownBeforeLocatingNewFlower = 200; ++ new org.purpurmc.purpur.event.entity.BeeStopPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), Bee.this.savedFlowerPos == null ? null : io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos), Bee.this.hasNectar()).callEvent(); // Purpur - Bee API + } + + @Override +@@ -1228,6 +_,7 @@ + this.setWantedPos(); + } + ++ if (this.successfulPollinatingTicks == 0) new org.purpurmc.purpur.event.entity.BeeStartedPollinatingEvent((org.bukkit.entity.Bee) Bee.this.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(Bee.this.level(), Bee.this.savedFlowerPos)).callEvent(); // Purpur - Bee API + this.successfulPollinatingTicks++; + if (Bee.this.random.nextFloat() < 0.05F && this.successfulPollinatingTicks > this.lastSoundPlayedTick + 60) { + this.lastSoundPlayedTick = this.successfulPollinatingTicks; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cat.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cat.java.patch new file mode 100644 index 000000000..e2dcf1d10 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cat.java.patch @@ -0,0 +1,26 @@ +--- a/net/minecraft/world/entity/animal/Cat.java ++++ b/net/minecraft/world/entity/animal/Cat.java +@@ -332,6 +_,14 @@ + return this.isTame() && otherAnimal instanceof Cat cat && cat.isTame() && super.canMate(otherAnimal); + } + ++ // Purpur start - Configurable default collar color ++ @Override ++ public void tame(Player player) { ++ setCollarColor(level().purpurConfig.catDefaultCollarColor); ++ super.tame(player); ++ } ++ // Purpur end - Configurable default collar color ++ + @Nullable + @Override + public SpawnGroupData finalizeSpawn( +@@ -438,7 +_,7 @@ + } + + private void tryToTame(Player player) { +- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit ++ if (this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials() || this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit // Purpur - Config to always tame in Creative + this.tame(player); + this.setOrderedToSit(true); + this.level().broadcastEntityEvent(this, (byte)7); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cow.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cow.java.patch new file mode 100644 index 000000000..61b3e9983 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Cow.java.patch @@ -0,0 +1,90 @@ +--- a/net/minecraft/world/entity/animal/Cow.java ++++ b/net/minecraft/world/entity/animal/Cow.java +@@ -43,7 +_,7 @@ + this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(1, new PanicGoal(this, 2.0)); + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); +- this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, itemStack -> itemStack.is(ItemTags.COW_FOOD), false)); ++ this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, itemStack -> level().purpurConfig.cowFeedMushrooms > 0 && (itemStack.is(net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem()) || itemStack.is(net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem())) || itemStack.is(ItemTags.COW_FOOD), false)); // Purpur - Cows eat mushrooms + this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); +@@ -99,6 +_,10 @@ + ItemStack itemStack = ItemUtils.createFilledResult(itemInHand, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit + player.setItemInHand(hand, itemStack); + return InteractionResult.SUCCESS; ++ // Purpur start - Cows eat mushrooms - feed mushroom to change to mooshroom ++ } else if (level().purpurConfig.cowFeedMushrooms > 0 && this.getType() != EntityType.MOOSHROOM && isMushroom(itemInHand)) { ++ return this.feedMushroom(player, itemInHand); ++ // Purpur end - Cows eat mushrooms + } else { + return super.mobInteract(player, hand); + } +@@ -114,4 +_,67 @@ + public EntityDimensions getDefaultDimensions(Pose pose) { + return this.isBaby() ? BABY_DIMENSIONS : super.getDefaultDimensions(pose); + } ++ ++ // Purpur start - Cows eat mushrooms - feed mushroom to change to mooshroom ++ private int redMushroomsFed = 0; ++ private int brownMushroomsFed = 0; ++ ++ private boolean isMushroom(ItemStack stack) { ++ return stack.getItem() == net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem() || stack.getItem() == net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem(); ++ } ++ ++ private int incrementFeedCount(ItemStack stack) { ++ if (stack.getItem() == net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem()) { ++ return ++redMushroomsFed; ++ } else { ++ return ++brownMushroomsFed; ++ } ++ } ++ ++ private InteractionResult feedMushroom(Player player, ItemStack stack) { ++ level().broadcastEntityEvent(this, (byte) 18); // hearts ++ playSound(SoundEvents.COW_MILK, 1.0F, 1.0F); ++ if (incrementFeedCount(stack) < level().purpurConfig.cowFeedMushrooms) { ++ if (!player.getAbilities().instabuild) { ++ stack.shrink(1); ++ } ++ return InteractionResult.CONSUME; // require 5 mushrooms to transform (prevents mushroom duping) ++ } ++ MushroomCow mooshroom = EntityType.MOOSHROOM.create(level(), EntitySpawnReason.CONVERSION); ++ if (mooshroom == null) { ++ return InteractionResult.PASS; ++ } ++ if (stack.getItem() == net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem()) { ++ mooshroom.setVariant(MushroomCow.Variant.BROWN); ++ } else { ++ mooshroom.setVariant(MushroomCow.Variant.RED); ++ } ++ mooshroom.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); ++ mooshroom.setHealth(this.getHealth()); ++ mooshroom.setAge(getAge()); ++ mooshroom.copyPosition(this); ++ mooshroom.setYBodyRot(this.yBodyRot); ++ mooshroom.setYHeadRot(this.getYHeadRot()); ++ mooshroom.yRotO = this.yRotO; ++ mooshroom.xRotO = this.xRotO; ++ if (this.hasCustomName()) { ++ mooshroom.setCustomName(this.getCustomName()); ++ } ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, mooshroom, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ this.level().addFreshEntity(mooshroom); ++ this.remove(RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); ++ if (!player.getAbilities().instabuild) { ++ stack.shrink(1); ++ } ++ for (int i = 0; i < 15; ++i) { ++ ((ServerLevel) level()).sendParticlesSource(((ServerLevel) level()).players(), null, net.minecraft.core.particles.ParticleTypes.HAPPY_VILLAGER, ++ false, true, ++ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1, ++ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0); ++ } ++ return InteractionResult.SUCCESS; ++ } ++ // Purpur end - Cows eat mushrooms + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Dolphin.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Dolphin.java.patch new file mode 100644 index 000000000..7a3ebe2c4 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Dolphin.java.patch @@ -0,0 +1,47 @@ +--- a/net/minecraft/world/entity/animal/Dolphin.java ++++ b/net/minecraft/world/entity/animal/Dolphin.java +@@ -71,6 +_,7 @@ + private static final int TOTAL_MOISTNESS_LEVEL = 2400; + public static final Predicate ALLOWED_ITEMS = itemEntity -> !itemEntity.hasPickUpDelay() && itemEntity.isAlive() && itemEntity.isInWater(); + public static final float BABY_SCALE = 0.65F; ++ private boolean isNaturallyAggressiveToPlayers; // Purpur - Dolphins naturally aggressive to players chance + + public Dolphin(EntityType entityType, Level level) { + super(entityType, level); +@@ -87,6 +_,7 @@ + this.setAirSupply(this.getMaxAirSupply()); + this.setXRot(0.0F); + SpawnGroupData spawnGroupData1 = Objects.requireNonNullElseGet(spawnGroupData, () -> new AgeableMob.AgeableMobGroupData(0.1F)); ++ this.isNaturallyAggressiveToPlayers = level.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance > 0.0D && random.nextDouble() <= level.getLevel().purpurConfig.dolphinNaturallyAggressiveToPlayersChance; // Purpur - Dolphins naturally aggressive to players chance + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData1); + } + +@@ -169,17 +_,19 @@ + protected void registerGoals() { + this.goalSelector.addGoal(0, new BreathAirGoal(this)); + this.goalSelector.addGoal(0, new TryFindWaterGoal(this)); ++ this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - Dolphins naturally aggressive to players chance + this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this)); + this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0)); + this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0, 10)); + this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); + this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(5, new DolphinJumpGoal(this, 10)); +- this.goalSelector.addGoal(6, new MeleeAttackGoal(this, 1.2F, true)); ++ //this.goalSelector.addGoal(6, new MeleeAttackGoal(this, 1.2F, true)); // Purpur - moved up - Dolphins naturally aggressive to players chance + this.goalSelector.addGoal(8, new Dolphin.PlayWithItemsGoal()); + this.goalSelector.addGoal(8, new FollowBoatGoal(this)); + this.goalSelector.addGoal(9, new AvoidEntityGoal<>(this, Guardian.class, 8.0F, 1.0, 1.0)); + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Guardian.class).setAlertOthers()); ++ this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur - Dolphins naturally aggressive to players chance + } + + public static AttributeSupplier.Builder createAttributes() { +@@ -412,6 +_,7 @@ + + @Override + public boolean canUse() { ++ if (this.dolphin.level().purpurConfig.dolphinDisableTreasureSearching) return false; // Purpur - Add option to disable dolphin treasure searching + return this.dolphin.gotFish() && this.dolphin.getAirSupply() >= 100; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Fox.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Fox.java.patch new file mode 100644 index 000000000..c0f401ee5 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Fox.java.patch @@ -0,0 +1,52 @@ +--- a/net/minecraft/world/entity/animal/Fox.java ++++ b/net/minecraft/world/entity/animal/Fox.java +@@ -335,6 +_,11 @@ + } + + private void setTargetGoals() { ++ // Purpur start - Tulips change fox type - do not add duplicate goals ++ this.targetSelector.removeGoal(this.landTargetGoal); ++ this.targetSelector.removeGoal(this.turtleEggTargetGoal); ++ this.targetSelector.removeGoal(this.fishTargetGoal); ++ // Purpur end - Tulips change fox type + if (this.getVariant() == Fox.Variant.RED) { + this.targetSelector.addGoal(4, this.landTargetGoal); + this.targetSelector.addGoal(4, this.turtleEggTargetGoal); +@@ -364,6 +_,7 @@ + @Override + public void setVariant(Fox.Variant variant) { + this.entityData.set(DATA_TYPE_ID, variant.getId()); ++ this.setTargetGoals(); // Purpur - Tulips change fox type - fix API bug not updating pathfinders on type change + } + + List getTrustedUUIDs() { +@@ -684,6 +_,29 @@ + return slot == EquipmentSlot.MAINHAND; + } + // Paper end ++ ++ // Purpur start - Tulips change fox type ++ @Override ++ public net.minecraft.world.InteractionResult mobInteract(Player player, net.minecraft.world.InteractionHand hand) { ++ if (level().purpurConfig.foxTypeChangesWithTulips) { ++ ItemStack itemstack = player.getItemInHand(hand); ++ if (getVariant() == Variant.RED && itemstack.getItem() == Items.WHITE_TULIP) { ++ setVariant(Variant.SNOW); ++ if (!player.getAbilities().instabuild) { ++ itemstack.shrink(1); ++ } ++ return net.minecraft.world.InteractionResult.SUCCESS; ++ } else if (getVariant() == Variant.SNOW && itemstack.getItem() == Items.ORANGE_TULIP) { ++ setVariant(Variant.RED); ++ if (!player.getAbilities().instabuild) { ++ itemstack.shrink(1); ++ } ++ return net.minecraft.world.InteractionResult.SUCCESS; ++ } ++ } ++ return super.mobInteract(player, hand); ++ } ++ // Purpur end - Tulips change fox type + + @Override + // Paper start - Cancellable death event diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/IronGolem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/IronGolem.java.patch new file mode 100644 index 000000000..176e8f9bc --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/IronGolem.java.patch @@ -0,0 +1,53 @@ +--- a/net/minecraft/world/entity/animal/IronGolem.java ++++ b/net/minecraft/world/entity/animal/IronGolem.java +@@ -56,13 +_,26 @@ + private int remainingPersistentAngerTime; + @Nullable + private UUID persistentAngerTarget; ++ @Nullable private UUID summoner; // Purpur - Summoner API + + public IronGolem(EntityType entityType, Level level) { + super(entityType, level); + } + ++ // Purpur start - Summoner API ++ @Nullable ++ public UUID getSummoner() { ++ return summoner; ++ } ++ ++ public void setSummoner(@Nullable UUID summoner) { ++ this.summoner = summoner; ++ } ++ // Purpur end - Summoner API ++ + @Override + protected void registerGoals() { ++ if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options + this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true)); + this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9, 32.0F)); + this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6, false)); +@@ -140,6 +_,7 @@ + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putBoolean("PlayerCreated", this.isPlayerCreated()); ++ if (getSummoner() != null) compound.putUUID("Purpur.Summoner", getSummoner()); // Purpur - Summoner API + this.addPersistentAngerSaveData(compound); + } + +@@ -147,6 +_,7 @@ + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.setPlayerCreated(compound.getBoolean("PlayerCreated")); ++ if (compound.contains("Purpur.Summoner")) setSummoner(compound.getUUID("Purpur.Summoner")); // Purpur - Summoner API + this.readPersistentAngerSaveData(this.level(), compound); + } + +@@ -266,6 +_,7 @@ + float f = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F; + this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f); + itemInHand.consume(1, player); ++ if (this.level().purpurConfig.ironGolemHealCalm && isAngry() && getHealth() == getMaxHealth()) stopBeingAngry(); // Purpur - Iron golem calm anger options + return InteractionResult.SUCCESS; + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/MushroomCow.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/MushroomCow.java.patch new file mode 100644 index 000000000..1d6651865 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/MushroomCow.java.patch @@ -0,0 +1,16 @@ +--- a/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/net/minecraft/world/entity/animal/MushroomCow.java +@@ -192,6 +_,13 @@ + level.playSound(null, this, SoundEvents.MOOSHROOM_SHEAR, soundSource, 1.0F, 1.0F); + this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), mob -> { + level.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5), this.getZ(), 1, 0.0, 0.0, 0.0, 0.0); ++ // Purpur start - Fix cow rotation when shearing mooshroom ++ mob.copyPosition(this); ++ mob.yBodyRot = this.yBodyRot; ++ mob.setYHeadRot(this.getYHeadRot()); ++ mob.yRotO = this.yRotO; ++ mob.xRotO = this.xRotO; ++ // Purpur end - Fix cow rotation when shearing mooshroom + // Paper start - custom shear drops; moved drop generation to separate method + drops.forEach(drop -> { + this.spawnAtLocation(level, new ItemEntity(this.level(), this.getX(), this.getY(1.0), this.getZ(), drop)); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Ocelot.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Ocelot.java.patch new file mode 100644 index 000000000..419638b78 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Ocelot.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/animal/Ocelot.java ++++ b/net/minecraft/world/entity/animal/Ocelot.java +@@ -232,7 +_,7 @@ + public boolean checkSpawnObstruction(LevelReader level) { + if (level.isUnobstructed(this) && !level.containsAnyLiquid(this.getBoundingBox())) { + BlockPos blockPos = this.blockPosition(); +- if (blockPos.getY() < level.getSeaLevel()) { ++ if (!level().purpurConfig.ocelotSpawnUnderSeaLevel && blockPos.getY() < level.getSeaLevel()) { // Purpur - Option Ocelot Spawn Under Sea Level + return false; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Parrot.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Parrot.java.patch new file mode 100644 index 000000000..04548f96b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Parrot.java.patch @@ -0,0 +1,52 @@ +--- a/net/minecraft/world/entity/animal/Parrot.java ++++ b/net/minecraft/world/entity/animal/Parrot.java +@@ -152,6 +_,7 @@ + protected void registerGoals() { + this.goalSelector.addGoal(0, new TamableAnimal.TamableAnimalPanicGoal(1.25)); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ if (this.level().purpurConfig.parrotBreedable) this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.BreedGoal(this, 1.0D)); // Purpur - Breedable parrots + this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); + this.goalSelector.addGoal(2, new FollowOwnerGoal(this, 1.0, 5.0F, 1.0F)); +@@ -257,7 +_,7 @@ + } + + if (!this.level().isClientSide) { +- if (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit ++ if (this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials() || (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled())) { // CraftBukkit // Purpur - Config to always tame in Creative + this.tame(player); + this.level().broadcastEntityEvent(this, (byte)7); + } else { +@@ -265,6 +_,7 @@ + } + } + ++ if (this.level().purpurConfig.parrotBreedable) return super.mobInteract(player, hand); // Purpur - Breedable parrots + return InteractionResult.SUCCESS; + } else if (!itemInHand.is(ItemTags.PARROT_POISONOUS_FOOD)) { + if (!this.isFlying() && this.isTame() && this.isOwnedBy(player)) { +@@ -289,7 +_,7 @@ + + @Override + public boolean isFood(ItemStack stack) { +- return false; ++ return this.level().purpurConfig.parrotBreedable && stack.is(ItemTags.PARROT_FOOD); // Purpur - Breedable parrots + } + + public static boolean checkParrotSpawnRules( +@@ -304,13 +_,13 @@ + + @Override + public boolean canMate(Animal otherAnimal) { +- return false; ++ return super.canMate(otherAnimal); // Purpur - Breedable parrots + } + + @Nullable + @Override + public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) { +- return null; ++ return level.purpurConfig.parrotBreedable ? EntityType.PARROT.create(level, EntitySpawnReason.BREEDING) : null; // Purpur - Breedable parrots + } + + @Nullable diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Pig.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Pig.java.patch new file mode 100644 index 000000000..7ae89deb5 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Pig.java.patch @@ -0,0 +1,22 @@ +--- a/net/minecraft/world/entity/animal/Pig.java ++++ b/net/minecraft/world/entity/animal/Pig.java +@@ -132,6 +_,19 @@ + @Override + public InteractionResult mobInteract(Player player, InteractionHand hand) { + boolean isFood = this.isFood(player.getItemInHand(hand)); ++ // Purpur start - Pigs give saddle back ++ if (level().purpurConfig.pigGiveSaddleBack && player.isSecondaryUseActive() && !isFood && isSaddled() && !isVehicle()) { ++ this.steering.setSaddle(false); ++ if (!player.getAbilities().instabuild) { ++ ItemStack saddle = new ItemStack(Items.SADDLE); ++ if (!player.getInventory().add(saddle)) { ++ player.drop(saddle, false); ++ } ++ } ++ return InteractionResult.SUCCESS; ++ } ++ // Purpur end - Pigs give saddle back ++ + if (!isFood && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) { + if (!this.level().isClientSide) { + player.startRiding(this); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/PolarBear.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/PolarBear.java.patch new file mode 100644 index 000000000..775a03fbe --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/PolarBear.java.patch @@ -0,0 +1,54 @@ +--- a/net/minecraft/world/entity/animal/PolarBear.java ++++ b/net/minecraft/world/entity/animal/PolarBear.java +@@ -64,6 +_,29 @@ + super(entityType, level); + } + ++ // Purpur start - Breedable Polar Bears ++ public boolean canMate(Animal other) { ++ if (other == this) { ++ return false; ++ } else if (this.isStanding()) { ++ return false; ++ } else if (this.getTarget() != null) { ++ return false; ++ } else if (!(other instanceof PolarBear)) { ++ return false; ++ } else { ++ PolarBear bear = (PolarBear) other; ++ if (bear.isStanding()) { ++ return false; ++ } ++ if (bear.getTarget() != null) { ++ return false; ++ } ++ return this.isInLove() && bear.isInLove(); ++ } ++ } ++ // Purpur end - Breedable Polar Bears ++ + @Nullable + @Override + public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) { +@@ -72,7 +_,7 @@ + + @Override + public boolean isFood(ItemStack stack) { +- return false; ++ return level().purpurConfig.polarBearBreedableItem != null && stack.getItem() == level().purpurConfig.polarBearBreedableItem; // Purpur - Breedable Polar Bears + } + + @Override +@@ -81,6 +_,12 @@ + this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal()); + this.goalSelector.addGoal(1, new PanicGoal(this, 2.0, mob -> mob.isBaby() ? DamageTypeTags.PANIC_CAUSES : DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES)); ++ // Purpur start - Breedable Polar Bears ++ if (level().purpurConfig.polarBearBreedableItem != null) { ++ this.goalSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.BreedGoal(this, 1.0D)); ++ this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, net.minecraft.world.item.crafting.Ingredient.of(level().purpurConfig.polarBearBreedableItem), false)); ++ } ++ // Purpur end - Breedable Polar Bears + this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25)); + this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Rabbit.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Rabbit.java.patch new file mode 100644 index 000000000..ed0b1c6aa --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Rabbit.java.patch @@ -0,0 +1,26 @@ +--- a/net/minecraft/world/entity/animal/Rabbit.java ++++ b/net/minecraft/world/entity/animal/Rabbit.java +@@ -376,10 +_,23 @@ + } + + this.setVariant(randomRabbitVariant); ++ ++ // Purpur start - Special mobs naturally spawn ++ if (randomRabbitVariant != Variant.EVIL && level.getLevel().purpurConfig.rabbitNaturalToast > 0D && random.nextDouble() <= level.getLevel().purpurConfig.rabbitNaturalToast) { ++ setCustomName(Component.translatable("Toast")); ++ } ++ // Purpur end - Special mobs naturally spawn ++ + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + } + + private static Rabbit.Variant getRandomRabbitVariant(LevelAccessor level, BlockPos pos) { ++ // Purpur start - Special mobs naturally spawn ++ Level world = level.getMinecraftWorld(); ++ if (world.purpurConfig.rabbitNaturalKiller > 0D && world.getRandom().nextDouble() <= world.purpurConfig.rabbitNaturalKiller) { ++ return Rabbit.Variant.EVIL; ++ } ++ // Purpur end - Special mobs naturally spawn + Holder biome = level.getBiome(pos); + int randomInt = level.getRandom().nextInt(100); + if (biome.is(BiomeTags.SPAWNS_WHITE_RABBITS)) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/SnowGolem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/SnowGolem.java.patch new file mode 100644 index 000000000..b6401d764 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/SnowGolem.java.patch @@ -0,0 +1,63 @@ +--- a/net/minecraft/world/entity/animal/SnowGolem.java ++++ b/net/minecraft/world/entity/animal/SnowGolem.java +@@ -44,15 +_,27 @@ + public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackMob { + private static final EntityDataAccessor DATA_PUMPKIN_ID = SynchedEntityData.defineId(SnowGolem.class, EntityDataSerializers.BYTE); + private static final byte PUMPKIN_FLAG = 16; ++ @Nullable private java.util.UUID summoner; // Purpur - Summoner API + + public SnowGolem(EntityType entityType, Level level) { + super(entityType, level); + } + ++ // Purpur start - Summoner API ++ @Nullable ++ public java.util.UUID getSummoner() { ++ return summoner; ++ } ++ ++ public void setSummoner(@Nullable java.util.UUID summoner) { ++ this.summoner = summoner; ++ } ++ // Purpur end - Summoner API ++ + @Override + protected void registerGoals() { +- this.goalSelector.addGoal(1, new RangedAttackGoal(this, 1.25, 20, 10.0F)); +- this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0, 1.0000001E-5F)); ++ this.goalSelector.addGoal(1, new RangedAttackGoal(this, level().purpurConfig.snowGolemAttackDistance, level().purpurConfig.snowGolemSnowBallMin, level().purpurConfig.snowGolemSnowBallMax, level().purpurConfig.snowGolemSnowBallModifier)); // Purpur - Snow Golem rate of fire config ++ this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F)); + this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entity, level) -> entity instanceof Enemy)); +@@ -72,6 +_,7 @@ + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putBoolean("Pumpkin", this.hasPumpkin()); ++ if (getSummoner() != null) compound.putUUID("Purpur.Summoner", getSummoner()); // Purpur - Summoner API + } + + @Override +@@ -80,6 +_,7 @@ + if (compound.contains("Pumpkin")) { + this.setPumpkin(compound.getBoolean("Pumpkin")); + } ++ if (compound.contains("Purpur.Summoner")) setSummoner(compound.getUUID("Purpur.Summoner")); // Purpur - Summoner API + } + + @Override +@@ -153,6 +_,14 @@ + } + + return InteractionResult.SUCCESS; ++ // Purpur start - Snowman drop and put back pumpkin ++ } else if (level().purpurConfig.snowGolemPutPumpkinBack && !hasPumpkin() && itemInHand.getItem() == Blocks.CARVED_PUMPKIN.asItem()) { ++ setPumpkin(true); ++ if (!player.getAbilities().instabuild) { ++ itemInHand.shrink(1); ++ } ++ return InteractionResult.SUCCESS; ++ // Purpur end - Snowman drop and put back pumpkin + } else { + return InteractionResult.PASS; + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Squid.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Squid.java.patch new file mode 100644 index 000000000..af92a24dd --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Squid.java.patch @@ -0,0 +1,50 @@ +--- a/net/minecraft/world/entity/animal/Squid.java ++++ b/net/minecraft/world/entity/animal/Squid.java +@@ -46,10 +_,29 @@ + + public Squid(EntityType entityType, Level level) { + super(entityType, level); +- //this.random.setSeed(this.getId()); // Paper - Share random for entities to make them more random ++ if (!level.purpurConfig.entitySharedRandom) this.random.setSeed(this.getId()); // Paper - Share random for entities to make them more random // Purpur - Add toggle for RNG manipulation + this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; + } + ++ // Purpur start - Stop squids floating on top of water ++ @Override ++ public net.minecraft.world.phys.AABB getAxisForFluidCheck() { ++ // Stops squids from floating just over the water ++ return super.getAxisForFluidCheck().offsetY(level().purpurConfig.squidOffsetWaterCheck); ++ } ++ // Purpur end - Stop squids floating on top of water ++ ++ // Purpur start - Flying squids! Oh my! ++ public boolean canFly() { ++ return this.level().purpurConfig.squidsCanFly; ++ } ++ ++ @Override ++ public boolean isInWater() { ++ return this.wasTouchingWater || canFly(); ++ } ++ // Purpur end - Flying squids! Oh my! ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); +@@ -127,6 +_,7 @@ + } + + if (this.isInWaterOrBubble()) { ++ if (canFly()) setNoGravity(!wasTouchingWater); // Purpur - Flying squids! Oh my! + if (this.tentacleMovement < (float) Math.PI) { + float f = this.tentacleMovement / (float) Math.PI; + this.tentacleAngle = Mth.sin(f * f * (float) Math.PI) * (float) Math.PI * 0.25F; +@@ -310,7 +_,7 @@ + int noActionTime = this.squid.getNoActionTime(); + if (noActionTime > 100) { + this.squid.movementVector = Vec3.ZERO; +- } else if (this.squid.getRandom().nextInt(reducedTickDelay(50)) == 0 || !this.squid.wasTouchingWater || !this.squid.hasMovementVector()) { ++ } else if (this.squid.getRandom().nextInt(reducedTickDelay(50)) == 0 || !this.squid.isInWater() || !this.squid.hasMovementVector()) { // Purpur - Flying squids! Oh my! + float f = this.squid.getRandom().nextFloat() * (float) (Math.PI * 2); + this.squid.movementVector = new Vec3(Mth.cos(f) * 0.2F, -0.1F + this.squid.getRandom().nextFloat() * 0.2F, Mth.sin(f) * 0.2F); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/WaterAnimal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/WaterAnimal.java.patch new file mode 100644 index 000000000..b42850fc8 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/WaterAnimal.java.patch @@ -0,0 +1,12 @@ +--- a/net/minecraft/world/entity/animal/WaterAnimal.java ++++ b/net/minecraft/world/entity/animal/WaterAnimal.java +@@ -74,8 +_,7 @@ + seaLevel = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(seaLevel); + i = level.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(i); + // Paper end - Make water animal spawn height configurable +- return pos.getY() >= i +- && pos.getY() <= seaLevel ++ return ((spawnReason == EntitySpawnReason.SPAWNER && level.getMinecraftWorld().purpurConfig.spawnerFixMC238526) || (pos.getY() >= i && pos.getY() <= seaLevel)) // Purpur - MC-238526 - Fix spawner not spawning water animals correctly + && level.getFluidState(pos.below()).is(FluidTags.WATER) + && level.getBlockState(pos.above()).is(Blocks.WATER); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Wolf.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Wolf.java.patch new file mode 100644 index 000000000..4c48e990c --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Wolf.java.patch @@ -0,0 +1,168 @@ +--- a/net/minecraft/world/entity/animal/Wolf.java ++++ b/net/minecraft/world/entity/animal/Wolf.java +@@ -94,6 +_,37 @@ + EntityType type = entity.getType(); + return type == EntityType.SHEEP || type == EntityType.RABBIT || type == EntityType.FOX; + }; ++ // Purpur start - Configurable chance for wolves to spawn rabid ++ private boolean isRabid = false; ++ private static final TargetingConditions.Selector RABID_PREDICATE = (entity, ignored) -> entity instanceof net.minecraft.server.level.ServerPlayer || entity instanceof net.minecraft.world.entity.Mob; ++ private final net.minecraft.world.entity.ai.goal.Goal PATHFINDER_VANILLA = new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR); ++ private final net.minecraft.world.entity.ai.goal.Goal PATHFINDER_RABID = new NonTameRandomTargetGoal<>(this, LivingEntity.class, false, RABID_PREDICATE); ++ private static final class AvoidRabidWolfGoal extends AvoidEntityGoal { ++ private final Wolf wolf; ++ ++ public AvoidRabidWolfGoal(Wolf wolf, float distance, double minSpeed, double maxSpeed) { ++ super(wolf, Wolf.class, distance, minSpeed, maxSpeed); ++ this.wolf = wolf; ++ } ++ ++ @Override ++ public boolean canUse() { ++ return super.canUse() && !this.wolf.isRabid() && this.toAvoid != null && this.toAvoid.isRabid(); // wolves which are not rabid run away from rabid wolves ++ } ++ ++ @Override ++ public void start() { ++ this.wolf.setTarget(null); ++ super.start(); ++ } ++ ++ @Override ++ public void tick() { ++ this.wolf.setTarget(null); ++ super.tick(); ++ } ++ } ++ // Purpur end - Configurable chance for wolves to spawn rabid + private static final float START_HEALTH = 8.0F; + private static final float TAME_HEALTH = 40.0F; + private static final float ARMOR_REPAIR_UNIT = 0.125F; +@@ -115,12 +_,47 @@ + this.setPathfindingMalus(PathType.DANGER_POWDER_SNOW, -1.0F); + } + ++ // Purpur start - Configurable chance for wolves to spawn rabid ++ public boolean isRabid() { ++ return this.isRabid; ++ } ++ ++ public void setRabid(boolean isRabid) { ++ this.isRabid = isRabid; ++ updatePathfinders(true); ++ } ++ ++ public void updatePathfinders(boolean modifyEffects) { ++ this.targetSelector.removeGoal(PATHFINDER_VANILLA); ++ this.targetSelector.removeGoal(PATHFINDER_RABID); ++ if (this.isRabid) { ++ setOwnerUUID(null); ++ setTame(false, true); ++ this.targetSelector.addGoal(5, PATHFINDER_RABID); ++ if (modifyEffects) this.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.CONFUSION, 1200)); ++ } else { ++ this.targetSelector.addGoal(5, PATHFINDER_VANILLA); ++ this.stopBeingAngry(); ++ if (modifyEffects) this.removeEffect(net.minecraft.world.effect.MobEffects.CONFUSION); ++ } ++ } ++ // Purpur end - Configurable chance for wolves to spawn rabid ++ ++ // Purpur start - Configurable default collar color ++ @Override ++ public void tame(Player player) { ++ setCollarColor(level().purpurConfig.wolfDefaultCollarColor); ++ super.tame(player); ++ } ++ // Purpur end - Configurable default collar color ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new TamableAnimal.TamableAnimalPanicGoal(1.5, DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES)); + this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); + this.goalSelector.addGoal(3, new Wolf.WolfAvoidEntityGoal<>(this, Llama.class, 24.0F, 1.5, 1.5)); ++ this.goalSelector.addGoal(3, new AvoidRabidWolfGoal(this, 24.0F, 1.5D, 1.5D)); // Purpur - Configurable chance for wolves to spawn rabid + this.goalSelector.addGoal(4, new LeapAtTargetGoal(this, 0.4F)); + this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0, true)); + this.goalSelector.addGoal(6, new FollowOwnerGoal(this, 1.0, 10.0F, 2.0F)); +@@ -133,7 +_,7 @@ + this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this)); + this.targetSelector.addGoal(3, new HurtByTargetGoal(this).setAlertOthers()); + this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); +- this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR)); ++ // this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR)); // Purpur - Configurable chance for wolves to spawn rabid - moved to updatePathfinders() + this.targetSelector.addGoal(6, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR)); + this.targetSelector.addGoal(7, new NearestAttackableTargetGoal<>(this, AbstractSkeleton.class, false)); + this.targetSelector.addGoal(8, new ResetUniversalAngerTargetGoal<>(this, true)); +@@ -182,6 +_,7 @@ + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putByte("CollarColor", (byte)this.getCollarColor().getId()); ++ compound.putBoolean("Purpur.IsRabid", this.isRabid); // Purpur - Configurable chance for wolves to spawn rabid + this.getVariant().unwrapKey().ifPresent(resourceKey -> compound.putString("variant", resourceKey.location().toString())); + this.addPersistentAngerSaveData(compound); + } +@@ -196,6 +_,10 @@ + if (compound.contains("CollarColor", 99)) { + this.setCollarColor(DyeColor.byId(compound.getInt("CollarColor"))); + } ++ // Purpur start - Configurable chance for wolves to spawn rabid ++ this.isRabid = compound.getBoolean("Purpur.IsRabid"); ++ this.updatePathfinders(false); ++ // Purpur end - Configurable chance for wolves to spawn rabid + + this.readPersistentAngerSaveData(this.level(), compound); + } +@@ -215,6 +_,10 @@ + } + + this.setVariant(holder); ++ // Purpur start - Configurable chance for wolves to spawn rabid ++ this.isRabid = level.getLevel().purpurConfig.wolfNaturalRabid > 0.0D && random.nextDouble() <= level.getLevel().purpurConfig.wolfNaturalRabid; ++ this.updatePathfinders(false); ++ // Purpur end - Configurable chance for wolves to spawn rabid + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + } + +@@ -263,6 +_,11 @@ + public void tick() { + super.tick(); + if (this.isAlive()) { ++ // Purpur start - Configurable chance for wolves to spawn rabid ++ if (this.age % 300 == 0 && this.isRabid()) { ++ this.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.CONFUSION, 400)); ++ } ++ // Purpur end - Configurable chance for wolves to spawn rabid + this.interestedAngleO = this.interestedAngle; + if (this.isInterested()) { + this.interestedAngle = this.interestedAngle + (1.0F - this.interestedAngle) * 0.4F; +@@ -481,13 +_,27 @@ + itemInHand.consume(1, player); + this.tryToTame(player); + return InteractionResult.SUCCESS_SERVER; ++ // Purpur start - Configurable chance for wolves to spawn rabid ++ } else if (this.level().purpurConfig.wolfMilkCuresRabies && itemInHand.getItem() == Items.MILK_BUCKET && this.isRabid()) { ++ if (!player.isCreative()) { ++ player.setItemInHand(hand, new ItemStack(Items.BUCKET)); ++ } ++ this.setRabid(false); ++ for (int i = 0; i < 10; ++i) { ++ ((ServerLevel) level()).sendParticlesSource(((ServerLevel) level()).players(), null, ParticleTypes.HAPPY_VILLAGER, ++ false, true, ++ getX() + random.nextFloat(), getY() + (random.nextFloat() * 1.5), getZ() + random.nextFloat(), 1, ++ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0); ++ } ++ return InteractionResult.SUCCESS_SERVER; ++ // Purpur end - Configurable chance for wolves to spawn rabid + } + + return super.mobInteract(player, hand); + } + + private void tryToTame(Player player) { +- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call and isCancelled check. ++ if (this.level().purpurConfig.alwaysTameInCreative && player.hasInfiniteMaterials() || this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call and isCancelled check. // Purpur - Config to always tame in Creative + this.tame(player); + this.navigation.stop(); + this.setTarget(null); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch new file mode 100644 index 000000000..11559576e --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/net/minecraft/world/entity/animal/goat/Goat.java +@@ -392,6 +_,7 @@ + + // Paper start - Goat ram API + public void ram(net.minecraft.world.entity.LivingEntity entity) { ++ if(!new org.purpurmc.purpur.event.entity.GoatRamEntityEvent((org.bukkit.entity.Goat) getBukkitEntity(), entity.getBukkitLivingEntity()).callEvent()) return; // Purpur - Added goat ram event + Brain brain = this.getBrain(); + brain.setMemory(MemoryModuleType.RAM_TARGET, entity.position()); + brain.eraseMemory(MemoryModuleType.RAM_COOLDOWN_TICKS); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/horse/Llama.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/horse/Llama.java.patch new file mode 100644 index 000000000..c0e613a83 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/animal/horse/Llama.java.patch @@ -0,0 +1,42 @@ +--- a/net/minecraft/world/entity/animal/horse/Llama.java ++++ b/net/minecraft/world/entity/animal/horse/Llama.java +@@ -72,6 +_,7 @@ + private Llama caravanHead; + @Nullable + public Llama caravanTail; // Paper ++ public boolean shouldJoinCaravan = true; // Purpur - Llama API + + public Llama(EntityType entityType, Level level) { + super(entityType, level); +@@ -106,6 +_,7 @@ + super.addAdditionalSaveData(compound); + compound.putInt("Variant", this.getVariant().id); + compound.putInt("Strength", this.getStrength()); ++ compound.putBoolean("Purpur.ShouldJoinCaravan", shouldJoinCaravan); // Purpur - Llama API + } + + @Override +@@ -113,6 +_,7 @@ + this.setStrength(compound.getInt("Strength")); + super.readAdditionalSaveData(compound); + this.setVariant(Llama.Variant.byId(compound.getInt("Variant"))); ++ if (compound.contains("Purpur.ShouldJoinCaravan")) this.shouldJoinCaravan = compound.getBoolean("Purpur.ShouldJoinCaravan"); // Purpur - Llama API + } + + @Override +@@ -386,6 +_,7 @@ + + public void leaveCaravan() { + if (this.caravanHead != null) { ++ new org.purpurmc.purpur.event.entity.LlamaLeaveCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity()).callEvent(); // Purpur - Llama API + this.caravanHead.caravanTail = null; + } + +@@ -393,6 +_,7 @@ + } + + public void joinCaravan(Llama caravanHead) { ++ if (!this.level().purpurConfig.llamaJoinCaravans || !shouldJoinCaravan || !new org.purpurmc.purpur.event.entity.LlamaJoinCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity(), (org.bukkit.entity.Llama) caravanHead.getBukkitEntity()).callEvent()) return; // Purpur - Llama API // Purpur - Config to disable Llama caravans + this.caravanHead = caravanHead; + this.caravanHead.caravanTail = this; + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch new file mode 100644 index 000000000..5deaa74ba --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch @@ -0,0 +1,56 @@ +--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java ++++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java +@@ -38,6 +_,24 @@ + this.setPos(x, y, z); + } + ++ // Purpur start - End crystal explosion options ++ public boolean shouldExplode() { ++ return showsBottom() ? level().purpurConfig.basedEndCrystalExplode : level().purpurConfig.baselessEndCrystalExplode; ++ } ++ ++ public float getExplosionPower() { ++ return (float) (showsBottom() ? level().purpurConfig.basedEndCrystalExplosionPower : level().purpurConfig.baselessEndCrystalExplosionPower); ++ } ++ ++ public boolean hasExplosionFire() { ++ return showsBottom() ? level().purpurConfig.basedEndCrystalExplosionFire : level().purpurConfig.baselessEndCrystalExplosionFire; ++ } ++ ++ public Level.ExplosionInteraction getExplosionEffect() { ++ return showsBottom() ? level().purpurConfig.basedEndCrystalExplosionEffect : level().purpurConfig.baselessEndCrystalExplosionEffect; ++ } ++ // Purpur end - End crystal explosion options ++ + @Override + protected Entity.MovementEmission getMovementEmission() { + return Entity.MovementEmission.NONE; +@@ -74,6 +_,8 @@ + } + } + // Paper end - Fix invulnerable end crystals ++ if (this.level().purpurConfig.endCrystalCramming > 0 && this.level().getEntitiesOfClass(EndCrystal.class, getBoundingBox()).size() > this.level().purpurConfig.endCrystalCramming) this.hurt(this.damageSources().cramming(), 6.0F); // Purpur - End Crystal Cramming ++ + } + + @Override +@@ -119,15 +_,17 @@ + } + // CraftBukkit end + if (!damageSource.is(DamageTypeTags.IS_EXPLOSION)) { ++ if (shouldExplode()) {// Purpur - End crystal explosion options + DamageSource damageSource1 = damageSource.getEntity() != null ? this.damageSources().explosion(this, damageSource.getEntity()) : null; + // CraftBukkit start +- org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false); ++ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, getExplosionPower(), hasExplosionFire()); // Purpur - End crystal explosion options + if (event.isCancelled()) { + return false; + } + + this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // Paper - add Bukkit remove cause +- level.explode(this, damageSource1, null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); ++ level.explode(this, damageSource1, null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), getExplosionEffect()); // Purpur - End crystal explosion options ++ } else this.unsetRemoved(); // Purpur - End crystal explosion options + } else { + this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // Paper - add Bukkit remove cause + // CraftBukkit end diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch new file mode 100644 index 000000000..e07733ccf --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java ++++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +@@ -974,6 +_,7 @@ + + @Override + protected boolean canRide(Entity entity) { ++ if (this.level().purpurConfig.enderDragonCanRideVehicles) return this.boardingCooldown <= 0; // Purpur - Configs for if Wither/Ender Dragon can ride vehicles + return false; + } + +@@ -1009,7 +_,7 @@ + boolean flag = worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT); + int i = 500; + +- if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) { ++ if (this.dragonFight != null && (level().purpurConfig.enderDragonAlwaysDropsFullExp || !this.dragonFight.hasPreviouslyKilledDragon())) { // Purpur - Ender dragon always drop full exp + i = 12000; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch new file mode 100644 index 000000000..30e1ffb25 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch @@ -0,0 +1,74 @@ +--- a/net/minecraft/world/entity/boss/wither/WitherBoss.java ++++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -77,6 +_,7 @@ + private static final TargetingConditions.Selector LIVING_ENTITY_SELECTOR = (entity, level) -> !entity.getType().is(EntityTypeTags.WITHER_FRIENDS) + && entity.attackable(); + private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0).selector(LIVING_ENTITY_SELECTOR); ++ @Nullable private java.util.UUID summoner; // Purpur - Summoner API + + public WitherBoss(EntityType entityType, Level level) { + super(entityType, level); +@@ -85,6 +_,17 @@ + this.xpReward = 50; + } + ++ // Purpur start - Summoner API ++ @Nullable ++ public java.util.UUID getSummoner() { ++ return summoner; ++ } ++ ++ public void setSummoner(@Nullable java.util.UUID summoner) { ++ this.summoner = summoner; ++ } ++ // Purpur end - Summoner API ++ + @Override + protected PathNavigation createNavigation(Level level) { + FlyingPathNavigation flyingPathNavigation = new FlyingPathNavigation(this, level); +@@ -117,6 +_,7 @@ + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("Invul", this.getInvulnerableTicks()); ++ if (getSummoner() != null) compound.putUUID("Purpur.Summoner", getSummoner()); // Purpur - Summoner API + } + + @Override +@@ -126,6 +_,7 @@ + if (this.hasCustomName()) { + this.bossEvent.setName(this.getDisplayName()); + } ++ if (compound.contains("Purpur.Summoner")) setSummoner(compound.getUUID("Purpur.Summoner")); // Purpur - Summoner API + } + + @Override +@@ -269,7 +_,7 @@ + level.explode(this, this.getX(), this.getEyeY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); + } + // CraftBukkit end +- if (!this.isSilent()) { ++ if (!this.isSilent() && level.purpurConfig.witherPlaySpawnSound) { // Purpur - Toggle for Wither's spawn sound + // CraftBukkit start - Use relative location for far away sounds + // level.globalLevelEvent(1023, this.blockPosition(), 0); + int viewDistance = level.getCraftServer().getViewDistance() * 16; +@@ -376,8 +_,10 @@ + } + } + +- if (this.tickCount % 20 == 0) { +- this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit ++ // Purpur start - Customizable wither health and healing - customizable heal rate and amount ++ if (this.tickCount % level().purpurConfig.witherHealthRegenDelay == 0) { ++ this.heal(level().purpurConfig.witherHealthRegenAmount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit ++ // Purpur end - Customizable wither health and healing + } + + this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); +@@ -574,6 +_,7 @@ + + @Override + protected boolean canRide(Entity entity) { ++ if (this.level().purpurConfig.witherCanRideVehicles) return this.boardingCooldown <= 0; // Purpur - Configs for if Wither/Ender Dragon can ride vehicles + return false; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch new file mode 100644 index 000000000..1ac4c29b0 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch @@ -0,0 +1,43 @@ +--- a/net/minecraft/world/entity/decoration/ArmorStand.java ++++ b/net/minecraft/world/entity/decoration/ArmorStand.java +@@ -93,10 +_,13 @@ + private boolean noTickPoseDirty = false; + private boolean noTickEquipmentDirty = false; + // Paper end - Allow ArmorStands not to tick ++ public boolean canMovementTick = true; // Purpur - Movement options for armor stands + + public ArmorStand(EntityType entityType, Level level) { + super(entityType, level); + if (level != null) this.canTick = level.paperConfig().entities.armorStands.tick; // Paper - Allow ArmorStands not to tick ++ if (level != null) this.canMovementTick = level.purpurConfig.armorstandMovement; // Purpur - Movement options for armor stands ++ this.setShowArms(level != null && level.purpurConfig.armorstandPlaceWithArms); // Purpur - Config to show Armor Stand arms on spawn + } + + public ArmorStand(Level level, double x, double y, double z) { +@@ -620,6 +_,7 @@ + + @Override + public void tick() { ++ maxUpStep = level().purpurConfig.armorstandStepHeight; // Purpur - Add option to set armorstand step height + // Paper start - Allow ArmorStands not to tick + if (!this.canTick) { + if (this.noTickPoseDirty) { +@@ -949,4 +_,18 @@ + } + } + // Paper end ++ ++ // Purpur start - Movement options for armor stands ++ @Override ++ public void updateInWaterStateAndDoWaterCurrentPushing() { ++ if (this.level().purpurConfig.armorstandWaterMovement && ++ (this.level().purpurConfig.armorstandWaterFence || !(level().getBlockState(blockPosition().below()).getBlock() instanceof net.minecraft.world.level.block.FenceBlock))) ++ super.updateInWaterStateAndDoWaterCurrentPushing(); ++ } ++ ++ @Override ++ public void aiStep() { ++ if (this.canMovementTick && this.canMove) super.aiStep(); ++ } ++ // Purpur end - Movement options for armor stands + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch new file mode 100644 index 000000000..024469799 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch @@ -0,0 +1,46 @@ +--- a/net/minecraft/world/entity/item/ItemEntity.java ++++ b/net/minecraft/world/entity/item/ItemEntity.java +@@ -52,6 +_,12 @@ + public boolean canMobPickup = true; // Paper - Item#canEntityPickup + private int despawnRate = -1; // Paper - Alternative item-despawn-rate + public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API ++ // Purpur start - Item entity immunities ++ public boolean immuneToCactus = false; ++ public boolean immuneToExplosion = false; ++ public boolean immuneToFire = false; ++ public boolean immuneToLightning = false; ++ // Purpur end - Item entity immunities + + public ItemEntity(EntityType entityType, Level level) { + super(entityType, level); +@@ -337,7 +_,16 @@ + + @Override + public final boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { +- if (this.isInvulnerableToBase(damageSource)) { ++ // Purpur start - Item entity immunities ++ if ( ++ (immuneToCactus && damageSource.is(net.minecraft.world.damagesource.DamageTypes.CACTUS)) || ++ (immuneToFire && (damageSource.is(net.minecraft.tags.DamageTypeTags.IS_FIRE) || damageSource.is(net.minecraft.world.damagesource.DamageTypes.ON_FIRE) || damageSource.is(net.minecraft.world.damagesource.DamageTypes.IN_FIRE))) || ++ (immuneToLightning && damageSource.is(net.minecraft.world.damagesource.DamageTypes.LIGHTNING_BOLT)) || ++ (immuneToExplosion && damageSource.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION)) ++ ) { ++ return false; ++ } else if (this.isInvulnerableToBase(damageSource)) { ++ // Purpur end - Item entity immunities + return false; + } else if (!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && damageSource.getEntity() instanceof Mob) { + return false; +@@ -539,6 +_,12 @@ + public void setItem(ItemStack stack) { + this.getEntityData().set(DATA_ITEM, stack); + this.despawnRate = this.level().paperConfig().entities.spawning.altItemDespawnRate.enabled ? this.level().paperConfig().entities.spawning.altItemDespawnRate.items.getOrDefault(stack.getItem(), this.level().spigotConfig.itemDespawnRate) : this.level().spigotConfig.itemDespawnRate; // Paper - Alternative item-despawn-rate ++ // Purpur start - Item entity immunities ++ if (level().purpurConfig.itemImmuneToCactus.contains(stack.getItem())) immuneToCactus = true; ++ if (level().purpurConfig.itemImmuneToExplosion.contains(stack.getItem())) immuneToExplosion = true; ++ if (level().purpurConfig.itemImmuneToFire.contains(stack.getItem())) immuneToFire = true; ++ if (level().purpurConfig.itemImmuneToLightning.contains(stack.getItem())) immuneToLightning = true; ++ // level end - Item entity immunities + } + + @Override diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch new file mode 100644 index 000000000..eb0ed35f3 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch @@ -0,0 +1,35 @@ +--- a/net/minecraft/world/entity/item/PrimedTnt.java ++++ b/net/minecraft/world/entity/item/PrimedTnt.java +@@ -251,4 +_,32 @@ + return !this.level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid(); + } + // Paper end - Option to prevent TNT from moving in water ++ ++ // Purpur start - Shears can defuse TNT ++ @Override ++ public net.minecraft.world.InteractionResult interact(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) { ++ Level world = this.level(); ++ ++ if (world instanceof ServerLevel serverWorld && level().purpurConfig.shearsCanDefuseTnt) { ++ final net.minecraft.world.item.ItemStack inHand = player.getItemInHand(hand); ++ ++ if (!inHand.is(net.minecraft.world.item.Items.SHEARS) || !player.getBukkitEntity().hasPermission("purpur.tnt.defuse") || ++ serverWorld.random.nextFloat() > serverWorld.purpurConfig.shearsCanDefuseTntChance) return net.minecraft.world.InteractionResult.PASS; ++ ++ net.minecraft.world.entity.item.ItemEntity tntItem = new net.minecraft.world.entity.item.ItemEntity(serverWorld, getX(), getY(), getZ(), ++ new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.TNT)); ++ tntItem.setPickUpDelay(10); ++ ++ inHand.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand)); ++ serverWorld.addFreshEntity(tntItem, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CUSTOM); ++ ++ this.playSound(net.minecraft.sounds.SoundEvents.SHEEP_SHEAR); ++ ++ this.kill(serverWorld); ++ return net.minecraft.world.InteractionResult.SUCCESS; ++ } ++ ++ return super.interact(player, hand); ++ } ++ // Purpur end - Shears can defuse TNT + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch new file mode 100644 index 000000000..37349cc6c --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -158,10 +_,7 @@ + this.reassessWeaponGoal(); + this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || random.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot + if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { +- LocalDate localDate = LocalDate.now(); +- int i = localDate.get(ChronoField.DAY_OF_MONTH); +- int i1 = localDate.get(ChronoField.MONTH_OF_YEAR); +- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) { ++ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(level.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur - Halloween options and optimizations + this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); + this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; + } +@@ -217,7 +_,7 @@ + if (event.getProjectile() == arrow.getBukkitEntity()) { + // CraftBukkit end + Projectile.spawnProjectileUsingShoot( +- arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4 ++ arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, serverLevel.purpurConfig.skeletonBowAccuracyMap.getOrDefault(serverLevel.getDifficulty().getId(), (float) (14 - serverLevel.getDifficulty().getId() * 4)) // Purpur - skeleton bow accuracy option + ); + } // CraftBukkit + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch new file mode 100644 index 000000000..c3719371c --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch @@ -0,0 +1,64 @@ +--- a/net/minecraft/world/entity/monster/Creeper.java ++++ b/net/minecraft/world/entity/monster/Creeper.java +@@ -50,6 +_,7 @@ + public int explosionRadius = 3; + private int droppedSkulls; + public Entity entityIgniter; // CraftBukkit ++ private boolean exploding = false; // Purpur - Config to make Creepers explode on death + + public Creeper(EntityType entityType, Level level) { + super(entityType, level); +@@ -161,6 +_,26 @@ + } + } + ++ // Purpur start - Special mobs naturally spawn ++ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.EntitySpawnReason spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData entityData) { ++ double chance = world.getLevel().purpurConfig.creeperChargedChance; ++ if (chance > 0D && random.nextDouble() <= chance) { ++ setPowered(true); ++ } ++ return super.finalizeSpawn(world, difficulty, spawnReason, entityData); ++ } ++ // Purpur end - Special mobs naturally spawn ++ ++ // Purpur start - Config to make Creepers explode on death ++ @Override ++ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) { ++ if (!this.exploding && this.level().purpurConfig.creeperExplodeWhenKilled && damageSource.getEntity() instanceof net.minecraft.server.level.ServerPlayer) { ++ this.explodeCreeper(); ++ } ++ return super.dropAllDeathLoot(world, damageSource); ++ } ++ // Purpur end - Config to make Creepers explode on death ++ + @Override + protected SoundEvent getHurtSound(DamageSource damageSource) { + return SoundEvents.CREEPER_HURT; +@@ -243,14 +_,16 @@ + } + + public void explodeCreeper() { ++ this.exploding = true; // Purpur - Config to make Creepers explode on death + if (this.level() instanceof ServerLevel serverLevel) { + float f = this.isPowered() ? 2.0F : 1.0F; ++ float multiplier = serverLevel.purpurConfig.creeperHealthRadius ? this.getHealth() / this.getMaxHealth() : 1; // Purpur - Config for health to impact Creeper explosion radius + // CraftBukkit start +- org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, this.explosionRadius * f, false); ++ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, (this.explosionRadius * f) * multiplier, false); // Purpur - Config for health to impact Creeper explosion radius + if (!event.isCancelled()) { + // CraftBukkit end + this.dead = true; +- serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) ++ serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) && level().purpurConfig.creeperAllowGriefing ? Level.ExplosionInteraction.MOB : Level.ExplosionInteraction.NONE); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) // Purpur - Add enderman and creeper griefing controls + this.spawnLingeringCloud(); + this.triggerOnDeathMobEffects(serverLevel, Entity.RemovalReason.KILLED); + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause +@@ -261,6 +_,7 @@ + } + // CraftBukkit end + } ++ this.exploding = false; // Purpur - Config to make Creepers explode on death + } + + private void spawnLingeringCloud() { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch new file mode 100644 index 000000000..3d8569ee4 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch @@ -0,0 +1,27 @@ +--- a/net/minecraft/world/entity/monster/Drowned.java ++++ b/net/minecraft/world/entity/monster/Drowned.java +@@ -82,10 +_,23 @@ + this.goalSelector.addGoal(2, new Drowned.DrownedAttackGoal(this, 1.0, false)); + this.goalSelector.addGoal(5, new Drowned.DrownedGoToBeachGoal(this, 1.0)); + this.goalSelector.addGoal(6, new Drowned.DrownedSwimUpGoal(this, 1.0, this.level().getSeaLevel())); ++ if (level().purpurConfig.drownedBreakDoors) this.goalSelector.addGoal(6, new net.minecraft.world.entity.ai.goal.MoveThroughVillageGoal(this, 1.0D, true, 4, this::canBreakDoors)); // Purpur - Option to make drowned break doors + this.goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0)); + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Drowned.class).setAlertOthers(ZombifiedPiglin.class)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> this.okTarget(entity))); +- if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Paper - Check drowned for villager aggression config ++ // Purpur start - Add option to disable zombie aggressiveness towards villagers ++ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false) { // Paper - Check drowned for villager aggression config ++ @Override ++ public boolean canUse() { ++ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canUse(); ++ } ++ ++ @Override ++ public boolean canContinueToUse() { ++ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canContinueToUse(); ++ } ++ }); ++ // Purpur end - Add option to disable zombie aggressiveness towards villagers + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Axolotl.class, true, false)); + this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch new file mode 100644 index 000000000..bac97afe7 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch @@ -0,0 +1,61 @@ +--- a/net/minecraft/world/entity/monster/EnderMan.java ++++ b/net/minecraft/world/entity/monster/EnderMan.java +@@ -102,7 +_,7 @@ + this.goalSelector.addGoal(11, new EnderMan.EndermanTakeBlockGoal(this)); + this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt)); + this.targetSelector.addGoal(2, new HurtByTargetGoal(this)); +- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, true, false)); ++ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, 10, true, false, (entityliving, ignored) -> entityliving.level().purpurConfig.endermanAggroEndermites && entityliving instanceof Endermite endermite && (!entityliving.level().purpurConfig.endermanAggroEndermitesOnlyIfPlayerSpawned || endermite.isPlayerSpawned()))); // Purpur + this.targetSelector.addGoal(4, new ResetUniversalAngerTargetGoal<>(this, false)); + } + +@@ -230,7 +_,7 @@ + + boolean isBeingStaredBy(Player player) { + // Paper start - EndermanAttackPlayerEvent +- final boolean shouldAttack = isBeingStaredBy0(player); ++ final boolean shouldAttack = !this.level().purpurConfig.endermanDisableStareAggro && isBeingStaredBy0(player); // Purpur - Config to ignore Dragon Head wearers and stare aggro + final com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) player.getBukkitEntity()); + event.setCancelled(!shouldAttack); + return event.callEvent(); +@@ -385,6 +_,7 @@ + public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { + if (this.isInvulnerableTo(level, damageSource)) { + return false; ++ } else if (org.purpurmc.purpur.PurpurConfig.endermanShortHeight && damageSource.is(net.minecraft.world.damagesource.DamageTypes.IN_WALL)) { return false; // Purpur - no suffocation damage if short height - Short enderman height + } else { + boolean flag = damageSource.getDirectEntity() instanceof ThrownPotion; + if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && !flag) { +@@ -397,6 +_,7 @@ + } else { + boolean flag1 = flag && this.hurtWithCleanWater(level, damageSource, (ThrownPotion)damageSource.getDirectEntity(), amount); + ++ if (!flag1 && level.purpurConfig.endermanIgnoreProjectiles) return super.hurtServer(level, damageSource, amount); // Purpur - Config to disable Enderman teleport on projectile hit + if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent + for (int i = 0; i < 64; i++) { + if (this.teleport()) { +@@ -440,7 +_,7 @@ + + @Override + public boolean requiresCustomPersistence() { +- return super.requiresCustomPersistence() || this.getCarriedBlock() != null; ++ return super.requiresCustomPersistence() || (!this.level().purpurConfig.endermanDespawnEvenWithBlock && this.getCarriedBlock() != null); // Purpur - Add config for allowing Endermen to despawn even while holding a block + } + + static class EndermanFreezeWhenLookedAt extends Goal { +@@ -484,6 +_,7 @@ + + @Override + public boolean canUse() { ++ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls + return this.enderman.getCarriedBlock() != null + && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) + && this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0; +@@ -633,6 +_,7 @@ + + @Override + public boolean canUse() { ++ if (!enderman.level().purpurConfig.endermanAllowGriefing) return false; // Purpur - Add enderman and creeper griefing controls + return this.enderman.getCarriedBlock() == null + && getServerLevel(this.enderman).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) + && this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch new file mode 100644 index 000000000..9965430e8 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch @@ -0,0 +1,41 @@ +--- a/net/minecraft/world/entity/monster/Endermite.java ++++ b/net/minecraft/world/entity/monster/Endermite.java +@@ -28,12 +_,23 @@ + public class Endermite extends Monster { + private static final int MAX_LIFE = 2400; + public int life; ++ private boolean isPlayerSpawned; // Purpur - Add back player spawned endermite API + + public Endermite(EntityType entityType, Level level) { + super(entityType, level); + this.xpReward = 3; + } + ++ // Purpur start - Add back player spawned endermite API ++ public boolean isPlayerSpawned() { ++ return this.isPlayerSpawned; ++ } ++ ++ public void setPlayerSpawned(boolean playerSpawned) { ++ this.isPlayerSpawned = playerSpawned; ++ } ++ // Purpur end - Add back player spawned endermite API ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); +@@ -79,12 +_,14 @@ + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.life = compound.getInt("Lifetime"); ++ this.isPlayerSpawned = compound.getBoolean("PlayerSpawned"); // Purpur - Add back player spawned endermite API + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("Lifetime", this.life); ++ compound.putBoolean("PlayerSpawned", this.isPlayerSpawned); // Purpur - Add back player spawned endermite API + } + + @Override diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Monster.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Monster.java.patch new file mode 100644 index 000000000..c833d4fc6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Monster.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/entity/monster/Monster.java ++++ b/net/minecraft/world/entity/monster/Monster.java +@@ -88,6 +_,14 @@ + } + + public static boolean isDarkEnoughToSpawn(ServerLevelAccessor level, BlockPos pos, RandomSource random) { ++ // Purpur start - Config to disable hostile mob spawn on ice ++ if (!level.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce || !level.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce) { ++ net.minecraft.world.level.block.state.BlockState spawnBlock = level.getBlockState(pos.below()); ++ if ((!level.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.PACKED_ICE)) || (!level.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce && spawnBlock.is(net.minecraft.world.level.block.Blocks.BLUE_ICE))) { ++ return false; ++ } ++ } ++ // Purpur end - Config to disable hostile mob spawn on ice + if (level.getBrightness(LightLayer.SKY, pos) > random.nextInt(32)) { + return false; + } else { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch new file mode 100644 index 000000000..acec89121 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -158,7 +_,11 @@ + ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData spawnGroupData + ) { + this.anchorPoint = this.blockPosition().above(5); +- this.setPhantomSize(0); ++ // Purpur start - Configurable phantom size ++ int min = level.getLevel().purpurConfig.phantomMinSize; ++ int max = level.getLevel().purpurConfig.phantomMaxSize; ++ this.setPhantomSize(min == max ? min : level.getRandom().nextInt(max + 1 - min) + min); ++ // Purpur end - Configurable phantom size + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch new file mode 100644 index 000000000..6e2afb392 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/entity/monster/Ravager.java ++++ b/net/minecraft/world/entity/monster/Ravager.java +@@ -70,6 +_,7 @@ + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur - option to make ravagers afraid of rabbits + this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, true)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); +@@ -150,7 +_,7 @@ + )) { + BlockState blockState = serverLevel.getBlockState(blockPos); + Block block = blockState.getBlock(); +- if (block instanceof LeavesBlock) { ++ if (this.level().purpurConfig.ravagerGriefableBlocks.contains(block)) { // Purpur - Configurable ravager griefable blocks list + // CraftBukkit start + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockPos, blockState.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state + continue; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch new file mode 100644 index 000000000..eee30bbe5 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch @@ -0,0 +1,67 @@ +--- a/net/minecraft/world/entity/monster/Shulker.java ++++ b/net/minecraft/world/entity/monster/Shulker.java +@@ -50,6 +_,7 @@ + import net.minecraft.world.level.ServerLevelAccessor; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.BlockState; ++import net.minecraft.world.level.entity.EntityTypeTest; + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; +@@ -88,6 +_,21 @@ + this.lookControl = new Shulker.ShulkerLookControl(this); + } + ++ // Purpur start - Shulker change color with dye ++ @Override ++ protected net.minecraft.world.InteractionResult mobInteract(Player player, net.minecraft.world.InteractionHand hand) { ++ net.minecraft.world.item.ItemStack itemstack = player.getItemInHand(hand); ++ if (player.level().purpurConfig.shulkerChangeColorWithDye && itemstack.getItem() instanceof net.minecraft.world.item.DyeItem dye && dye.getDyeColor() != this.getColor()) { ++ this.setVariant(Optional.of(dye.getDyeColor())); ++ if (!player.getAbilities().instabuild) { ++ itemstack.shrink(1); ++ } ++ return net.minecraft.world.InteractionResult.SUCCESS; ++ } ++ return super.mobInteract(player, hand); ++ } ++ // Purpur end - Shulker change color with dye ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F, 0.02F, true)); +@@ -459,11 +_,21 @@ + private void hitByShulkerBullet() { + Vec3 vec3 = this.position(); + AABB boundingBox = this.getBoundingBox(); +- if (!this.isClosed() && this.teleportSomewhere()) { +- int size = this.level().getEntities(EntityType.SHULKER, boundingBox.inflate(8.0), Entity::isAlive).size(); +- float f = (size - 1) / 5.0F; +- if (!(this.level().random.nextFloat() < f)) { ++ // Purpur start - Shulker spawn from bullet options ++ if ((!this.level().purpurConfig.shulkerSpawnFromBulletRequireOpenLid || !this.isClosed()) && this.teleportSomewhere()) { ++ float chance = this.level().purpurConfig.shulkerSpawnFromBulletBaseChance; ++ if (!this.level().purpurConfig.shulkerSpawnFromBulletNearbyEquation.isBlank()) { ++ int nearby = this.level().getEntities((EntityTypeTest) EntityType.SHULKER, boundingBox.inflate(this.level().purpurConfig.shulkerSpawnFromBulletNearbyRange), Entity::isAlive).size(); ++ try { ++ chance -= ((Number) scriptEngine.eval("let nearby = " + nearby + "; " + this.level().purpurConfig.shulkerSpawnFromBulletNearbyEquation)).floatValue(); ++ } catch (javax.script.ScriptException e) { ++ e.printStackTrace(); ++ chance -= (nearby - 1) / 5.0F; ++ } ++ } ++ if (this.level().random.nextFloat() <= chance) { + Shulker shulker = EntityType.SHULKER.create(this.level(), EntitySpawnReason.BREEDING); ++ // Purpur end - Shulker spawn from bullet options + if (shulker != null) { + shulker.setVariant(this.getVariant()); + shulker.moveTo(vec3); +@@ -573,7 +_,7 @@ + + @Override + public Optional getVariant() { +- return Optional.ofNullable(this.getColor()); ++ return Optional.ofNullable(this.level().purpurConfig.shulkerSpawnFromBulletRandomColor ? DyeColor.random(this.level().random) : this.getColor()); // Purpur - Shulker spawn from bullet options + } + + @Nullable diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch new file mode 100644 index 000000000..bba419b18 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch @@ -0,0 +1,67 @@ +--- a/net/minecraft/world/entity/monster/Skeleton.java ++++ b/net/minecraft/world/entity/monster/Skeleton.java +@@ -135,4 +_,64 @@ + this.spawnAtLocation(level, Items.SKELETON_SKULL); + } + } ++ ++ // Purpur start - Skeletons eat wither roses ++ private int witherRosesFed = 0; ++ ++ @Override ++ public net.minecraft.world.InteractionResult mobInteract(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) { ++ net.minecraft.world.item.ItemStack stack = player.getItemInHand(hand); ++ ++ if (level().purpurConfig.skeletonFeedWitherRoses > 0 && this.getType() != EntityType.WITHER_SKELETON && stack.getItem() == net.minecraft.world.level.block.Blocks.WITHER_ROSE.asItem()) { ++ return this.feedWitherRose(player, stack); ++ } ++ ++ return super.mobInteract(player, hand); ++ } ++ ++ private net.minecraft.world.InteractionResult feedWitherRose(net.minecraft.world.entity.player.Player player, net.minecraft.world.item.ItemStack stack) { ++ if (++witherRosesFed < level().purpurConfig.skeletonFeedWitherRoses) { ++ if (!player.getAbilities().instabuild) { ++ stack.shrink(1); ++ } ++ return net.minecraft.world.InteractionResult.CONSUME; ++ } ++ ++ WitherSkeleton skeleton = EntityType.WITHER_SKELETON.create(level(), net.minecraft.world.entity.EntitySpawnReason.CONVERSION); ++ if (skeleton == null) { ++ return net.minecraft.world.InteractionResult.PASS; ++ } ++ ++ skeleton.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); ++ skeleton.setHealth(this.getHealth()); ++ skeleton.setAggressive(this.isAggressive()); ++ skeleton.copyPosition(this); ++ skeleton.setYBodyRot(this.yBodyRot); ++ skeleton.setYHeadRot(this.getYHeadRot()); ++ skeleton.yRotO = this.yRotO; ++ skeleton.xRotO = this.xRotO; ++ ++ if (this.hasCustomName()) { ++ skeleton.setCustomName(this.getCustomName()); ++ } ++ ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, skeleton, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) { ++ return net.minecraft.world.InteractionResult.PASS; ++ } ++ ++ this.level().addFreshEntity(skeleton); ++ this.remove(RemovalReason.DISCARDED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); ++ if (!player.getAbilities().instabuild) { ++ stack.shrink(1); ++ } ++ ++ for (int i = 0; i < 15; ++i) { ++ ((ServerLevel) level()).sendParticlesSource(((ServerLevel) level()).players(), null, net.minecraft.core.particles.ParticleTypes.HAPPY_VILLAGER, ++ false, true, ++ getX() + random.nextFloat(), getY() + (random.nextFloat() * 2), getZ() + random.nextFloat(), 1, ++ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0); ++ } ++ return net.minecraft.world.InteractionResult.SUCCESS; ++ } ++ // Purpur end - Skeletons eat wither roses + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Strider.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Strider.java.patch new file mode 100644 index 000000000..efb04f5ac --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Strider.java.patch @@ -0,0 +1,22 @@ +--- a/net/minecraft/world/entity/monster/Strider.java ++++ b/net/minecraft/world/entity/monster/Strider.java +@@ -414,6 +_,19 @@ + @Override + public InteractionResult mobInteract(Player player, InteractionHand hand) { + boolean isFood = this.isFood(player.getItemInHand(hand)); ++ // Purpur start ++ if (level().purpurConfig.striderGiveSaddleBack && player.isSecondaryUseActive() && !isFood && isSaddled() && !isVehicle()) { ++ this.steering.setSaddle(false); ++ if (!player.getAbilities().instabuild) { ++ ItemStack saddle = new ItemStack(Items.SADDLE); ++ if (!player.getInventory().add(saddle)) { ++ player.drop(saddle, false); ++ } ++ } ++ return InteractionResult.SUCCESS; ++ } ++ // Purpur end ++ + if (!isFood && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) { + if (!this.level().isClientSide) { + player.startRiding(this); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch new file mode 100644 index 000000000..fe07bf809 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/entity/monster/Vindicator.java ++++ b/net/minecraft/world/entity/monster/Vindicator.java +@@ -132,6 +_,11 @@ + RandomSource random = level.getRandom(); + this.populateDefaultEquipmentSlots(random, difficulty); + this.populateDefaultEquipmentEnchantments(level, random, difficulty); ++ // Purpur start - Special mobs naturally spawn ++ if (level().purpurConfig.vindicatorJohnnySpawnChance > 0D && random.nextDouble() <= level().purpurConfig.vindicatorJohnnySpawnChance) { ++ setCustomName(Component.translatable("Johnny")); ++ } ++ // Purpur end - Special mobs naturally spawn + return spawnGroupData1; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch new file mode 100644 index 000000000..ba29551ef --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch @@ -0,0 +1,35 @@ +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -114,7 +_,19 @@ + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); +- if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Spigot ++ // Purpur start - Add option to disable zombie aggressiveness towards villagers ++ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false) { // Spigot ++ @Override ++ public boolean canUse() { ++ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canUse(); ++ } ++ ++ @Override ++ public boolean canContinueToUse() { ++ return (level().purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !level().getServer().server.isLagging()) && super.canContinueToUse(); ++ } ++ }); ++ // Purpur end - Add option to disable zombie aggressiveness towards villagers + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); + this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); + } +@@ -550,10 +_,7 @@ + } + + if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { +- LocalDate localDate = LocalDate.now(); +- int i = localDate.get(ChronoField.DAY_OF_MONTH); +- int i1 = localDate.get(ChronoField.MONTH_OF_YEAR); +- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) { ++ if (net.minecraft.world.entity.ambient.Bat.isHalloweenSeason(level.getMinecraftWorld()) && this.random.nextFloat() < this.level().purpurConfig.chanceHeadHalloweenOnEntity) { // Purpur - Halloween options and optimizations + this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); + this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch new file mode 100644 index 000000000..e5517a82e --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -156,10 +_,10 @@ + public InteractionResult mobInteract(Player player, InteractionHand hand) { + ItemStack itemInHand = player.getItemInHand(hand); + if (itemInHand.is(Items.GOLDEN_APPLE)) { +- if (this.hasEffect(MobEffects.WEAKNESS)) { ++ if (this.hasEffect(MobEffects.WEAKNESS) && level().purpurConfig.zombieVillagerCureEnabled) { // Purpur - Add option to disable zombie villagers cure + itemInHand.consume(1, player); + if (!this.level().isClientSide) { +- this.startConverting(player.getUUID(), this.random.nextInt(2401) + 3600); ++ this.startConverting(player.getUUID(), this.random.nextInt(level().purpurConfig.zombieVillagerCuringTimeMax - level().purpurConfig.zombieVillagerCuringTimeMin + 1) + level().purpurConfig.zombieVillagerCuringTimeMin); // Purpur - Customizable Zombie Villager curing times + } + + return InteractionResult.SUCCESS_SERVER; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch new file mode 100644 index 000000000..e1a87265f --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -112,7 +_,7 @@ + this.maybeAlertOthers(); + } + +- if (this.isAngry()) { ++ if (this.isAngry() && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur - Toggle for Zombified Piglin death always counting as player kill when angry + this.lastHurtByPlayerTime = this.tickCount; + } + +@@ -163,7 +_,7 @@ + this.ticksUntilNextAlert = ALERT_INTERVAL.sample(this.random); + } + +- if (livingEntity instanceof Player) { ++ if (livingEntity instanceof Player && this.level().purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur - Toggle for Zombified Piglin death always counting as player kill when angry + this.setLastHurtByPlayer((Player)livingEntity); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch new file mode 100644 index 000000000..c7ccb700d --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch @@ -0,0 +1,32 @@ +--- a/net/minecraft/world/entity/monster/piglin/PiglinAi.java ++++ b/net/minecraft/world/entity/monster/piglin/PiglinAi.java +@@ -4,6 +_,7 @@ + import com.google.common.collect.ImmutableSet; + import com.mojang.datafixers.util.Pair; + import java.util.Collections; ++import java.util.Iterator; + import java.util.List; + import java.util.Optional; + import net.minecraft.server.level.ServerLevel; +@@ -666,13 +_,20 @@ + + public static boolean isWearingSafeArmor(LivingEntity entity) { + for (ItemStack itemStack : entity.getArmorAndBodyArmorSlots()) { +- if (itemStack.is(ItemTags.PIGLIN_SAFE_ARMOR)) { ++ if (itemStack.is(ItemTags.PIGLIN_SAFE_ARMOR) || (entity.level().purpurConfig.piglinIgnoresArmorWithGoldTrim && isWearingGoldTrim(itemStack.getItem()))) { // Purpur - piglins ignore gold-trimmed armor + return true; + } + } + + return false; + } ++ ++ // Purpur start - piglins ignore gold-trimmed armor ++ private static boolean isWearingGoldTrim(Item itemstack) { ++ net.minecraft.world.item.equipment.trim.ArmorTrim armorTrim = itemstack.components().get(net.minecraft.core.component.DataComponents.TRIM); ++ return armorTrim != null && armorTrim.material().is(net.minecraft.world.item.equipment.trim.TrimMaterials.GOLD); ++ } ++ // Purpur end - piglins ignore gold-trimmed armor + + private static void stopWalking(Piglin piglin) { + piglin.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch new file mode 100644 index 000000000..d5c870866 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/CatSpawner.java.patch @@ -0,0 +1,39 @@ +--- a/net/minecraft/world/entity/npc/CatSpawner.java ++++ b/net/minecraft/world/entity/npc/CatSpawner.java +@@ -27,7 +_,7 @@ + if (this.nextTick > 0) { + return 0; + } else { +- this.nextTick = 1200; ++ this.nextTick = level.purpurConfig.catSpawnDelay; // Purpur - Cat spawning options + Player randomPlayer = level.getRandomPlayer(); + if (randomPlayer == null) { + return 0; +@@ -61,8 +_,12 @@ + + private int spawnInVillage(ServerLevel serverLevel, BlockPos pos) { + int i = 48; +- if (serverLevel.getPoiManager().getCountInRange(holder -> holder.is(PoiTypes.HOME), pos, 48, PoiManager.Occupancy.IS_OCCUPIED) > 4L) { +- List entitiesOfClass = serverLevel.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(48.0, 8.0, 48.0)); ++ // Purpur start - Cat spawning options ++ int range = serverLevel.purpurConfig.catSpawnVillageScanRange; ++ if (range <= 0) return 0; ++ if (serverLevel.getPoiManager().getCountInRange(holder -> holder.is(PoiTypes.HOME), pos, range, PoiManager.Occupancy.IS_OCCUPIED) > 4L) { ++ List entitiesOfClass = serverLevel.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(range, 8.0, range)); ++ // Purpur end - Cat spawning options + if (entitiesOfClass.size() < 5) { + return this.spawnCat(pos, serverLevel); + } +@@ -73,7 +_,11 @@ + + private int spawnInHut(ServerLevel serverLevel, BlockPos pos) { + int i = 16; +- List entitiesOfClass = serverLevel.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(16.0, 8.0, 16.0)); ++ // Purpur start - Cat spawning options ++ int range = serverLevel.purpurConfig.catSpawnSwampHutScanRange; ++ if (range <= 0) return 0; ++ List entitiesOfClass = serverLevel.getEntitiesOfClass(Cat.class, new AABB(pos).inflate(range, 8.0, range)); ++ // Purpur end - Cat spawning options + return entitiesOfClass.size() < 1 ? this.spawnCat(pos, serverLevel) : 0; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/Villager.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/Villager.java.patch new file mode 100644 index 000000000..d475ebf09 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/Villager.java.patch @@ -0,0 +1,143 @@ +--- a/net/minecraft/world/entity/npc/Villager.java ++++ b/net/minecraft/world/entity/npc/Villager.java +@@ -179,6 +_,8 @@ + MemoryModuleType.MEETING_POINT, + (villager, holder) -> holder.is(PoiTypes.MEETING) + ); ++ private boolean isLobotomized = false; public boolean isLobotomized() { return this.isLobotomized; } // Purpur - Lobotomize stuck villagers ++ private int notLobotomizedCount = 0; // Purpur - Lobotomize stuck villagers + + public Villager(EntityType entityType, Level level) { + this(entityType, level, VillagerType.PLAINS); +@@ -193,6 +_,57 @@ + this.setVillagerData(this.getVillagerData().setType(villagerType).setProfession(VillagerProfession.NONE)); + } + ++ // Purpur start - Allow leashing villagers ++ @Override ++ public boolean canBeLeashed() { ++ return level().purpurConfig.villagerCanBeLeashed; ++ } ++ // Purpur end - Allow leashing villagers ++ ++ // Purpur start - Lobotomize stuck villagers ++ private boolean checkLobotomized() { ++ int interval = this.level().purpurConfig.villagerLobotomizeCheckInterval; ++ boolean shouldCheckForTradeLocked = this.level().purpurConfig.villagerLobotomizeWaitUntilTradeLocked; ++ if (this.notLobotomizedCount > 3) { ++ // check half as often if not lobotomized for the last 3+ consecutive checks ++ interval *= 2; ++ } ++ if (this.level().getGameTime() % interval == 0) { ++ // offset Y for short blocks like dirt_path/farmland ++ this.isLobotomized = !(shouldCheckForTradeLocked && this.getVillagerXp() == 0) && !canTravelFrom(BlockPos.containing(this.position().x, this.getBoundingBox().minY + 0.0625D, this.position().z)); ++ ++ if (this.isLobotomized) { ++ this.notLobotomizedCount = 0; ++ } else { ++ this.notLobotomizedCount++; ++ } ++ } ++ return this.isLobotomized; ++ } ++ ++ private boolean canTravelFrom(BlockPos pos) { ++ return canTravelTo(pos.east()) || canTravelTo(pos.west()) || canTravelTo(pos.north()) || canTravelTo(pos.south()); ++ } ++ ++ private boolean canTravelTo(BlockPos pos) { ++ net.minecraft.world.level.block.state.BlockState state = this.level().getBlockStateIfLoaded(pos); ++ if (state == null) { ++ // chunk not loaded ++ return false; ++ } ++ net.minecraft.world.level.block.Block bottom = state.getBlock(); ++ if (bottom instanceof net.minecraft.world.level.block.FenceBlock || ++ bottom instanceof net.minecraft.world.level.block.FenceGateBlock || ++ bottom instanceof net.minecraft.world.level.block.WallBlock) { ++ // bottom block is too tall to get over ++ return false; ++ } ++ net.minecraft.world.level.block.Block top = level().getBlockState(pos.above()).getBlock(); ++ // only if both blocks have no collision ++ return !bottom.hasCollision && !top.hasCollision; ++ } ++ // Purpur end - Lobotomize stuck villagers ++ + @Override + public Brain getBrain() { + return (Brain)super.getBrain(); +@@ -289,11 +_,24 @@ + // Paper start - EAR 2 + this.customServerAiStep(level, false); + } +- protected void customServerAiStep(ServerLevel level, final boolean inactive) { ++ protected void customServerAiStep(ServerLevel level, boolean inactive) { // Purpur - Lobotomize stuck villagers - not final + // Paper end - EAR 2 + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("villagerBrain"); +- if (!inactive) this.getBrain().tick(level, this); // Paper - EAR 2 ++ // Purpur start - Lobotomize stuck villagers ++ if (this.level().purpurConfig.villagerLobotomizeEnabled) { ++ // treat as inactive if lobotomized ++ inactive = inactive || checkLobotomized(); ++ } else { ++ this.isLobotomized = false; ++ } ++ // Purpur end - Lobotomize stuck villagers ++ // Pufferfish start ++ if (!inactive /*&& this.behaviorTick++ % this.activatedPriority == 0*/) { ++ this.getBrain().tick(level, this); // Paper - EAR 2 ++ } ++ else if (this.isLobotomized && shouldRestock()) restock(); // Purpur - Lobotomize stuck villagers ++ // Pufferfish end + profilerFiller.pop(); + if (this.assignProfessionWhenSpawned) { + this.assignProfessionWhenSpawned = false; +@@ -365,6 +_,7 @@ + return InteractionResult.CONSUME; + } + ++ if (this.level().purpurConfig.villagerAllowTrading) // Purpur - Add config for villager trading + this.startTrading(player); + } + +@@ -503,7 +_,7 @@ + + private void updateDemand() { + for (MerchantOffer merchantOffer : this.getOffers()) { +- merchantOffer.updateDemand(); ++ merchantOffer.updateDemand(this.level().purpurConfig.villagerMinimumDemand); // Purpur - Configurable minimum demand for trades + } + } + +@@ -707,7 +_,7 @@ + + @Override + public boolean canBreed() { +- return this.foodLevel + this.countFoodPointsInInventory() >= 12 && !this.isSleeping() && this.getAge() == 0; ++ return this.level().purpurConfig.villagerCanBreed && this.foodLevel + this.countFoodPointsInInventory() >= 12 && !this.isSleeping() && this.getAge() == 0; // Purpur - Configurable villager breeding + } + + private boolean hungry() { +@@ -928,6 +_,7 @@ + } + + public void spawnGolemIfNeeded(ServerLevel serverLevel, long gameTime, int minVillagerAmount) { ++ if (serverLevel.purpurConfig.villagerSpawnIronGolemRadius > 0 && serverLevel.getEntitiesOfClass(net.minecraft.world.entity.animal.IronGolem.class, getBoundingBox().inflate(serverLevel.purpurConfig.villagerSpawnIronGolemRadius)).size() > serverLevel.purpurConfig.villagerSpawnIronGolemLimit) return; // Purpur - Implement configurable search radius for villagers to spawn iron golems + if (this.wantsToSpawnGolem(gameTime)) { + AABB aabb = this.getBoundingBox().inflate(10.0, 10.0, 10.0); + List entitiesOfClass = serverLevel.getEntitiesOfClass(Villager.class, aabb); +@@ -1001,6 +_,12 @@ + + @Override + public void startSleeping(BlockPos pos) { ++ // Purpur start - Option for beds to explode on villager sleep ++ if (level().purpurConfig.bedExplodeOnVillagerSleep && this.level().getBlockState(pos).getBlock() instanceof net.minecraft.world.level.block.BedBlock) { ++ this.level().explode(null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (float) this.level().purpurConfig.bedExplosionPower, this.level().purpurConfig.bedExplosionFire, this.level().purpurConfig.bedExplosionEffect); ++ return; ++ } ++ // Purpur end - Option for beds to explode on villager sleep + super.startSleeping(pos); + this.brain.setMemory(MemoryModuleType.LAST_SLEPT, this.level().getGameTime()); + this.brain.eraseMemory(MemoryModuleType.WALK_TARGET); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTrader.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTrader.java.patch new file mode 100644 index 000000000..e1ca1ac52 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTrader.java.patch @@ -0,0 +1,36 @@ +--- a/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -69,6 +_,13 @@ + super(entityType, level); + } + ++ // Purpur start - Allow leashing villagers ++ @Override ++ public boolean canBeLeashed() { ++ return level().purpurConfig.wanderingTraderCanBeLeashed; ++ } ++ // Purpur end - Allow leashing villagers ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); +@@ -89,7 +_,7 @@ + this, + new ItemStack(Items.MILK_BUCKET), + SoundEvents.WANDERING_TRADER_REAPPEARED, +- wanderingTrader -> this.canDrinkMilk && this.level().isDay() && wanderingTrader.isInvisible() // Paper - Add more WanderingTrader API ++ wanderingTrader -> level().purpurConfig.milkClearsBeneficialEffects && this.canDrinkMilk && this.level().isDay() && wanderingTrader.isInvisible() // Paper - Add more WanderingTrader API // // Purpur - Milk Keeps Beneficial Effects + ) + ); + this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this)); +@@ -133,8 +_,10 @@ + return InteractionResult.CONSUME; + } + ++ if (this.level().purpurConfig.wanderingTraderAllowTrading) { // Purpur - Add config for villager trading + this.setTradingPlayer(player); + this.openTradingScreen(player, this.getDisplayName(), 1); ++ } // Purpur - Add config for villager trading + } + + return InteractionResult.SUCCESS; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch new file mode 100644 index 000000000..f1ac7fc15 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java ++++ b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +@@ -147,7 +_,17 @@ + int i1 = pos.getX() + this.random.nextInt(maxDistance * 2) - maxDistance; + int i2 = pos.getZ() + this.random.nextInt(maxDistance * 2) - maxDistance; + int height = level.getHeight(Heightmap.Types.WORLD_SURFACE, i1, i2); +- BlockPos blockPos1 = new BlockPos(i1, height, i2); ++ // Purpur start - Allow toggling special MobSpawners per world - allow traders to spawn below nether roof ++ BlockPos.MutableBlockPos blockPos1 = new BlockPos.MutableBlockPos(i1, height, i2); ++ if (level.dimensionType().hasCeiling()) { ++ do { ++ blockPos1.relative(net.minecraft.core.Direction.DOWN); ++ } while (!level.getBlockState(blockPos1).isAir()); ++ do { ++ blockPos1.relative(net.minecraft.core.Direction.DOWN); ++ } while (level.getBlockState(blockPos1).isAir() && blockPos1.getY() > 0); ++ } ++ // Purpur end - Allow toggling special MobSpawners per world + if (placementType.isSpawnPositionOk(level, blockPos1, EntityType.WANDERING_TRADER)) { + blockPos = blockPos1; + break; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch new file mode 100644 index 000000000..9cd3b72ab --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -0,0 +1,111 @@ +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -200,11 +_,20 @@ + private int currentImpulseContextResetGraceTime; + public boolean affectsSpawning = true; // Paper - Affects Spawning API + public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage ++ public int burpDelay = 0; // Purpur - Burp delay ++ public boolean canPortalInstant = false; // Purpur - Add portal permission bypass + + // CraftBukkit start + public boolean fauxSleeping; + public int oldLevel = -1; + ++ // Purpur start - AFK API ++ public abstract void setAfk(boolean afk); ++ ++ public boolean isAfk() { ++ return false; ++ } ++ // Purpur end - AFK API + @Override + public org.bukkit.craftbukkit.entity.CraftHumanEntity getBukkitEntity() { + return (org.bukkit.craftbukkit.entity.CraftHumanEntity) super.getBukkitEntity(); +@@ -262,6 +_,12 @@ + + @Override + public void tick() { ++ // Purpur start - Burp delay ++ if (this.burpDelay > 0 && --this.burpDelay == 0) { ++ this.level().playSound(null, getX(), getY(), getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 1.0F, this.level().random.nextFloat() * 0.1F + 0.9F); ++ } ++ // Purpur end - Burp delay ++ + this.noPhysics = this.isSpectator(); + if (this.isSpectator() || this.isPassenger()) { + this.setOnGround(false); +@@ -340,6 +_,17 @@ + this.turtleHelmetTick(); + } + ++ // Purpur start - Full netherite armor grants fire resistance ++ if (this.level().purpurConfig.playerNetheriteFireResistanceDuration > 0 && this.level().getGameTime() % 20 == 0) { ++ if (this.getItemBySlot(EquipmentSlot.HEAD).is(Items.NETHERITE_HELMET) ++ && this.getItemBySlot(EquipmentSlot.CHEST).is(Items.NETHERITE_CHESTPLATE) ++ && this.getItemBySlot(EquipmentSlot.LEGS).is(Items.NETHERITE_LEGGINGS) ++ && this.getItemBySlot(EquipmentSlot.FEET).is(Items.NETHERITE_BOOTS)) { ++ this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, this.level().purpurConfig.playerNetheriteFireResistanceDuration, this.level().purpurConfig.playerNetheriteFireResistanceAmplifier, this.level().purpurConfig.playerNetheriteFireResistanceAmbient, this.level().purpurConfig.playerNetheriteFireResistanceShowParticles, this.level().purpurConfig.playerNetheriteFireResistanceShowIcon), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.NETHERITE_ARMOR); ++ } ++ } ++ // Purpur end - Full netherite armor grants fire resistance ++ + this.cooldowns.tick(); + this.updatePlayerPose(); + if (this.currentImpulseContextResetGraceTime > 0) { +@@ -610,7 +_,7 @@ + List list = Lists.newArrayList(); + + for (Entity entity : entities) { +- if (entity.getType() == EntityType.EXPERIENCE_ORB) { ++ if (entity.getType() == EntityType.EXPERIENCE_ORB && entity.level().purpurConfig.playerExpPickupDelay >= 0) { // Purpur - Configurable player pickup exp delay + list.add(entity); + } else if (!entity.isRemoved()) { + this.touch(entity); +@@ -1269,7 +_,7 @@ + flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits + if (flag2) { + damageSource = damageSource.critical(true); // Paper start - critical damage API +- f *= 1.5F; ++ f *= this.level().purpurConfig.playerCriticalDamageMultiplier; // Purpur - Add config change multiplier critical damage value + } + + float f2 = f + f1; +@@ -1882,7 +_,23 @@ + + @Override + protected int getBaseExperienceReward(ServerLevel level) { +- return !level.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator() ? Math.min(this.experienceLevel * 7, 100) : 0; ++ // Purpur start - Add player death exp control options ++ if (!level.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator()) { ++ int toDrop; ++ try { ++ toDrop = Math.round(((Number) scriptEngine.eval("let expLevel = " + experienceLevel + "; " + ++ "let expTotal = " + totalExperience + "; " + ++ "let exp = " + experienceProgress + "; " + ++ level().purpurConfig.playerDeathExpDropEquation)).floatValue()); ++ } catch (javax.script.ScriptException e) { ++ e.printStackTrace(); ++ toDrop = experienceLevel * 7; ++ } ++ return Math.min(toDrop, level().purpurConfig.playerDeathExpDropMax); ++ } else { ++ return 0; ++ } ++ // Purpur end - Add player death exp control options + } + + @Override +@@ -1965,6 +_,13 @@ + public boolean canUseSlot(EquipmentSlot slot) { + return slot != EquipmentSlot.BODY; + } ++ ++ // Purpur start - Player ridable in water option ++ @Override ++ public boolean dismountsUnderwater() { ++ return !level().purpurConfig.playerRidableInWater; ++ } ++ // Purpur end - Player ridable in water option + + public boolean setEntityOnShoulder(CompoundTag entityCompound) { + if (this.isPassenger() || !this.onGround() || this.isInWater() || this.isInPowderSnow) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch new file mode 100644 index 000000000..1a88cefdc --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/AbstractArrow.java.patch @@ -0,0 +1,32 @@ +--- a/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -74,6 +_,7 @@ + public ItemStack pickupItemStack = this.getDefaultPickupItem(); // Paper - private -> public + @Nullable + public ItemStack firedFromWeapon = null; // Paper - private -> public ++ public net.minecraft.world.item.enchantment.ItemEnchantments actualEnchantments = net.minecraft.world.item.enchantment.ItemEnchantments.EMPTY; // Purpur - Add an option to fix MC-3304 projectile looting + + protected AbstractArrow(EntityType entityType, Level level) { + super(entityType, level); +@@ -347,7 +_,7 @@ + this.setInGround(false); + Vec3 deltaMovement = this.getDeltaMovement(); + this.setDeltaMovement(deltaMovement.multiply(this.random.nextFloat() * 0.2F, this.random.nextFloat() * 0.2F, this.random.nextFloat() * 0.2F)); +- this.life = 0; ++ if (this.level().purpurConfig.arrowMovementResetsDespawnCounter) this.life = 0; // Purpur - Arrows should not reset despawn counter + } + + public boolean isInGround() { // Paper - protected -> public +@@ -559,6 +_,12 @@ + public ItemStack getWeaponItem() { + return this.firedFromWeapon; + } ++ ++ // Purpur start - Add an option to fix MC-3304 projectile looting ++ public void setActualEnchantments(net.minecraft.world.item.enchantment.ItemEnchantments actualEnchantments) { ++ this.actualEnchantments = actualEnchantments; ++ } ++ // Purpur end - Add an option to fix MC-3304 projectile looting + + protected SoundEvent getDefaultHitGroundSoundEvent() { + return SoundEvents.ARROW_HIT; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/Snowball.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/Snowball.java.patch new file mode 100644 index 000000000..7215ffe71 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/Snowball.java.patch @@ -0,0 +1,43 @@ +--- a/net/minecraft/world/entity/projectile/Snowball.java ++++ b/net/minecraft/world/entity/projectile/Snowball.java +@@ -52,9 +_,39 @@ + protected void onHitEntity(EntityHitResult result) { + super.onHitEntity(result); + Entity entity = result.getEntity(); +- int i = entity instanceof Blaze ? 3 : 0; ++ int i = entity.level().purpurConfig.snowballDamage >= 0 ? entity.level().purpurConfig.snowballDamage : entity instanceof Blaze ? 3 : 0; // Purpur - Add configurable snowball damage + entity.hurt(this.damageSources().thrown(this, this.getOwner()), i); + } ++ ++ // Purpur start - options to extinguish fire blocks with snowballs - borrowed and modified code from ThrownPotion#onHitBlock and ThrownPotion#dowseFire ++ @Override ++ protected void onHitBlock(net.minecraft.world.phys.BlockHitResult blockHitResult) { ++ super.onHitBlock(blockHitResult); ++ ++ if (!this.level().isClientSide) { ++ net.minecraft.core.BlockPos pos = blockHitResult.getBlockPos(); ++ net.minecraft.core.BlockPos relativePos = pos.relative(blockHitResult.getDirection()); ++ ++ net.minecraft.world.level.block.state.BlockState blockState = this.level().getBlockState(pos); ++ ++ if (this.level().purpurConfig.snowballExtinguishesFire && this.level().getBlockState(relativePos).is(net.minecraft.world.level.block.Blocks.FIRE)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, relativePos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) { ++ this.level().removeBlock(relativePos, false); ++ } ++ } else if (this.level().purpurConfig.snowballExtinguishesCandles && net.minecraft.world.level.block.AbstractCandleBlock.isLit(blockState)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.setValue(net.minecraft.world.level.block.AbstractCandleBlock.LIT, false))) { ++ net.minecraft.world.level.block.AbstractCandleBlock.extinguish(null, blockState, this.level(), pos); ++ } ++ } else if (this.level().purpurConfig.snowballExtinguishesCampfires && net.minecraft.world.level.block.CampfireBlock.isLitCampfire(blockState)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, pos, blockState.setValue(net.minecraft.world.level.block.CampfireBlock.LIT, false))) { ++ this.level().levelEvent(null, 1009, pos, 0); ++ net.minecraft.world.level.block.CampfireBlock.dowse(this.getOwner(), this.level(), pos, blockState); ++ this.level().setBlockAndUpdate(pos, blockState.setValue(net.minecraft.world.level.block.CampfireBlock.LIT, false)); ++ } ++ } ++ } ++ } ++ // Purpur end - options to extinguish fire blocks with snowballs + + @Override + protected void onHit(HitResult result) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch new file mode 100644 index 000000000..f0ac6ccbf --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/world/entity/projectile/ThrownEnderpearl.java ++++ b/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +@@ -133,9 +_,10 @@ + return; + } + // CraftBukkit end +- if (this.random.nextFloat() < 0.05F && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { ++ if (this.random.nextFloat() < serverLevel.purpurConfig.enderPearlEndermiteChance && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { // Purpur - Configurable Ender Pearl RNG + Endermite endermite = EntityType.ENDERMITE.create(serverLevel, EntitySpawnReason.TRIGGERED); + if (endermite != null) { ++ endermite.setPlayerSpawned(true); // Purpur - Add back player spawned endermite API + endermite.moveTo(owner.getX(), owner.getY(), owner.getZ(), owner.getYRot(), owner.getXRot()); + serverLevel.addFreshEntity(endermite, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.ENDER_PEARL); + } +@@ -155,7 +_,7 @@ + if (serverPlayer1 != null) { + serverPlayer1.resetFallDistance(); + serverPlayer1.resetCurrentImpulseContext(); +- serverPlayer1.hurtServer(serverPlayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), 5.0F); // CraftBukkit // Paper - fix DamageSource API ++ serverPlayer1.hurtServer(serverPlayer.serverLevel(), this.damageSources().enderPearl().customEventDamager(this), this.level().purpurConfig.enderPearlDamage); // CraftBukkit // Paper - fix DamageSource API // Purpur - Configurable Ender Pearl damage + } + + this.playSound(serverLevel, vec3); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownTrident.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownTrident.java.patch new file mode 100644 index 000000000..982cc0205 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownTrident.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/projectile/ThrownTrident.java ++++ b/net/minecraft/world/entity/projectile/ThrownTrident.java +@@ -64,7 +_,7 @@ + + Entity owner = this.getOwner(); + int i = this.entityData.get(ID_LOYALTY); +- if (i > 0 && (this.dealtDamage || this.isNoPhysics()) && owner != null) { ++ if (i > 0 && (this.dealtDamage || this.isNoPhysics() || (level().purpurConfig.tridentLoyaltyVoidReturnHeight < 0.0D && getY() < level().purpurConfig.tridentLoyaltyVoidReturnHeight)) && owner != null) { // Purpur - Add option to allow loyalty on tridents to work in the void + if (!this.isAcceptibleReturnOwner()) { + if (this.level() instanceof ServerLevel serverLevel && this.pickup == AbstractArrow.Pickup.ALLOWED) { + this.spawnAtLocation(serverLevel, this.getPickupItem(), 0.1F); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/WitherSkull.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/WitherSkull.java.patch new file mode 100644 index 000000000..deea12ae5 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/WitherSkull.java.patch @@ -0,0 +1,25 @@ +--- a/net/minecraft/world/entity/projectile/WitherSkull.java ++++ b/net/minecraft/world/entity/projectile/WitherSkull.java +@@ -92,7 +_,7 @@ + super.onHit(result); + if (!this.level().isClientSide) { + // CraftBukkit start +- org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent(this.getBukkitEntity(), 1.0F, false); ++ org.bukkit.event.entity.ExplosionPrimeEvent event = new org.bukkit.event.entity.ExplosionPrimeEvent(this.getBukkitEntity(), this.level().purpurConfig.witherExplosionRadius, false); // Purpur - Config for wither explosion radius + this.level().getCraftServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { +@@ -102,6 +_,13 @@ + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause + } + } ++ ++ // Purpur start - Add canSaveToDisk to Entity ++ @Override ++ public boolean canSaveToDisk() { ++ return false; ++ } ++ // Purpur end - Add canSaveToDisk to Entity + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/raid/Raids.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/raid/Raids.java.patch new file mode 100644 index 000000000..de4dbac7a --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/raid/Raids.java.patch @@ -0,0 +1,42 @@ +--- a/net/minecraft/world/entity/raid/Raids.java ++++ b/net/minecraft/world/entity/raid/Raids.java +@@ -25,6 +_,7 @@ + + public class Raids extends SavedData { + private static final String RAID_FILE_ID = "raids"; ++ public final Map playerCooldowns = Maps.newHashMap(); // Purpur - Raid cooldown setting + public final Map raidMap = Maps.newHashMap(); + private final ServerLevel level; + private int nextAvailableID; +@@ -46,6 +_,17 @@ + + public void tick() { + this.tick++; ++ // Purpur start - Raid cooldown setting ++ if (level.purpurConfig.raidCooldownSeconds != 0 && this.tick % 20 == 0) { ++ com.google.common.collect.ImmutableMap.copyOf(playerCooldowns).forEach((uuid, i) -> { ++ if (i < 1) { ++ playerCooldowns.remove(uuid); ++ } else { ++ playerCooldowns.put(uuid, i - 1); ++ } ++ }); ++ } ++ // Purpur end - Raid cooldown setting + Iterator iterator = this.raidMap.values().iterator(); + + while (iterator.hasNext()) { +@@ -119,11 +_,13 @@ + */ + + if (!raid.isStarted() || (raid.isInProgress() && raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel())) { // CraftBukkit - fixed a bug with raid: players could add up Bad Omen level even when the raid had finished ++ if (level.purpurConfig.raidCooldownSeconds != 0 && playerCooldowns.containsKey(player.getUUID())) return null; // Purpur - Raid cooldown setting + // CraftBukkit start + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(raid, player)) { + player.removeEffect(net.minecraft.world.effect.MobEffects.RAID_OMEN); + return null; + } ++ if (level.purpurConfig.raidCooldownSeconds != 0) playerCooldowns.put(player.getUUID(), level.purpurConfig.raidCooldownSeconds); // Purpur - Raid cooldown setting + + if (!raid.isStarted() && !this.raidMap.containsKey(raid.getId())) { + this.raidMap.put(raid.getId(), raid); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/AbstractBoat.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/AbstractBoat.java.patch new file mode 100644 index 000000000..430b15eb4 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/AbstractBoat.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/entity/vehicle/AbstractBoat.java ++++ b/net/minecraft/world/entity/vehicle/AbstractBoat.java +@@ -483,6 +_,7 @@ + float groundFriction = this.getGroundFriction(); + if (groundFriction > 0.0F) { + this.landFriction = groundFriction; ++ if (level().purpurConfig.boatEjectPlayersOnLand) ejectPassengers(); // Purpur - Add option for boats to eject players on land + return AbstractBoat.Status.ON_LAND; + } else { + return AbstractBoat.Status.IN_AIR; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java.patch new file mode 100644 index 000000000..dfb044e11 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java ++++ b/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java +@@ -391,7 +_,7 @@ + private Vec3 calculateBoostTrackSpeed(Vec3 speed, BlockPos pos, BlockState state) { + if (state.is(Blocks.POWERED_RAIL) && state.getValue(PoweredRailBlock.POWERED)) { + if (speed.length() > 0.01) { +- return speed.normalize().scale(speed.length() + 0.06); ++ return speed.normalize().scale(speed.length() + this.level().purpurConfig.poweredRailBoostModifier); // Purpur - Configurable powered rail boost modifier + } else { + Vec3 redstoneDirection = this.minecart.getRedstoneDirection(pos); + return redstoneDirection.lengthSqr() <= 0.0 ? speed : redstoneDirection.scale(speed.length() + 0.2); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java.patch new file mode 100644 index 000000000..c8ae0ce13 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java.patch @@ -0,0 +1,13 @@ +--- a/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java ++++ b/net/minecraft/world/entity/vehicle/OldMinecartBehavior.java +@@ -279,8 +_,8 @@ + Vec3 deltaMovement1 = this.getDeltaMovement(); + double d13 = deltaMovement1.horizontalDistance(); + if (d13 > 0.01) { +- double d14 = 0.06; +- this.setDeltaMovement(deltaMovement1.add(deltaMovement1.x / d13 * 0.06, 0.0, deltaMovement1.z / d13 * 0.06)); ++ double d14 = level.purpurConfig.poweredRailBoostModifier; // Purpur - Configurable powered rail boost modifier ++ this.setDeltaMovement(deltaMovement1.add(deltaMovement1.x / d13 * level.purpurConfig.poweredRailBoostModifier, 0.0, deltaMovement1.z / d13 * level.purpurConfig.poweredRailBoostModifier)); // Purpur - Configurable powered rail boost modifier + } else { + Vec3 deltaMovement2 = this.getDeltaMovement(); + double d15 = deltaMovement2.x; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/food/FoodData.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/food/FoodData.java.patch new file mode 100644 index 000000000..bca1c3085 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/food/FoodData.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/food/FoodData.java ++++ b/net/minecraft/world/food/FoodData.java +@@ -36,6 +_,7 @@ + int oldFoodLevel = this.foodLevel; + org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(serverPlayer, foodProperties.nutrition() + oldFoodLevel, stack); + if (!event.isCancelled()) { ++ if (serverPlayer.level().purpurConfig.playerBurpWhenFull && event.getFoodLevel() == 20 && oldFoodLevel < 20) serverPlayer.burpDelay = serverPlayer.level().purpurConfig.playerBurpDelay; // Purpur - Burp after eating food fills hunger bar completely + this.add(event.getFoodLevel() - oldFoodLevel, foodProperties.saturation()); + } + serverPlayer.getBukkitEntity().sendHealthUpdate(); +@@ -84,7 +_,7 @@ + this.tickTimer++; + if (this.tickTimer >= this.starvationRate) { // CraftBukkit - add regen rate manipulation + if (player.getHealth() > 10.0F || difficulty == Difficulty.HARD || player.getHealth() > 1.0F && difficulty == Difficulty.NORMAL) { +- player.hurtServer(serverLevel, player.damageSources().starve(), 1.0F); ++ player.hurtServer(serverLevel, player.damageSources().starve(), player.level().purpurConfig.hungerStarvationDamage); // Purpur - Configurable hunger starvation damage + } + + this.tickTimer = 0; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/food/FoodProperties.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/food/FoodProperties.java.patch new file mode 100644 index 000000000..87515c815 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/food/FoodProperties.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/food/FoodProperties.java ++++ b/net/minecraft/world/food/FoodProperties.java +@@ -42,9 +_,11 @@ + level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), consumable.sound().value(), SoundSource.NEUTRAL, 1.0F, random.triangle(1.0F, 0.4F)); + if (entity instanceof Player player) { + player.getFoodData().eat(this, stack, (net.minecraft.server.level.ServerPlayer) player); // CraftBukkit +- level.playSound( +- null, player.getX(), player.getY(), player.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, Mth.randomBetween(random, 0.9F, 1.0F) +- ); ++ // Purpur start - Burp delay - moved to Player#tick() ++ //level.playSound( ++ // null, player.getX(), player.getY(), player.getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 0.5F, Mth.randomBetween(random, 0.9F, 1.0F) ++ //); ++ // Purpur end - Burp delay - moved to Player#tick() + } + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch new file mode 100644 index 000000000..bca7321cd --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/inventory/AbstractContainerMenu.java ++++ b/net/minecraft/world/inventory/AbstractContainerMenu.java +@@ -65,6 +_,7 @@ + @Nullable + private ContainerSynchronizer synchronizer; + private boolean suppressRemoteUpdates; ++ @Nullable protected ItemStack activeQuickItem = null; // Purpur - Anvil API + // CraftBukkit start + public boolean checkReachable = true; + public abstract org.bukkit.inventory.InventoryView getBukkitView(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch new file mode 100644 index 000000000..1626289f6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/inventory/AbstractFurnaceMenu.java ++++ b/net/minecraft/world/inventory/AbstractFurnaceMenu.java +@@ -121,7 +_,13 @@ + } else if (index != 1 && index != 0) { + if (this.canSmelt(item)) { + if (!this.moveItemStackTo(item, 0, 1, false)) { +- return ItemStack.EMPTY; ++ // Purpur start - Added the ability to add combustible items ++ if (this.isFuel(item)) { ++ if (!this.moveItemStackTo(item, 1, 2, false)) { ++ return ItemStack.EMPTY; ++ } ++ } ++ // Purpur end - Added the ability to add combustible items + } + } else if (this.isFuel(item)) { + if (!this.moveItemStackTo(item, 1, 2, false)) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AnvilMenu.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AnvilMenu.java.patch new file mode 100644 index 000000000..71cd41ca4 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AnvilMenu.java.patch @@ -0,0 +1,200 @@ +--- a/net/minecraft/world/inventory/AnvilMenu.java ++++ b/net/minecraft/world/inventory/AnvilMenu.java +@@ -20,6 +_,12 @@ + import net.minecraft.world.level.block.state.BlockState; + import org.slf4j.Logger; + ++// Purpur start - Anvil API ++import net.minecraft.network.protocol.game.ClientboundContainerSetDataPacket; ++import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; ++import net.minecraft.server.level.ServerPlayer; ++// Purpur end - Anvil API ++ + public class AnvilMenu extends ItemCombinerMenu { + public static final int INPUT_SLOT = 0; + public static final int ADDITIONAL_SLOT = 1; +@@ -49,6 +_,10 @@ + private org.bukkit.craftbukkit.inventory.view.CraftAnvilView bukkitEntity; + // CraftBukkit end + public boolean bypassEnchantmentLevelRestriction = false; // Paper - bypass anvil level restrictions ++ // Purpur start - Anvil API ++ public boolean bypassCost = false; ++ public boolean canDoUnsafeEnchants = false; ++ // Purpur end - Anvil API + + public AnvilMenu(int containerId, Inventory playerInventory) { + this(containerId, playerInventory, ContainerLevelAccess.NULL); +@@ -74,12 +_,17 @@ + + @Override + protected boolean mayPickup(Player player, boolean hasStack) { +- return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && hasStack; // CraftBukkit - allow cost 0 like a free item ++ return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && (this.bypassCost || this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST) && hasStack; // CraftBukkit - allow cost 0 like a free item // Purpur - Anvil API + } + + @Override + protected void onTake(Player player, ItemStack stack) { ++ // Purpur start - Anvil API ++ ItemStack itemstack = this.activeQuickItem != null ? this.activeQuickItem : stack; ++ if (org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)).callEvent(); ++ // Purpur end - Anvil API + if (!player.getAbilities().instabuild) { ++ if (this.bypassCost) ((ServerPlayer) player).lastSentExp = -1; else // Purpur - Anvil API + player.giveExperienceLevels(-this.cost.get()); + } + +@@ -126,13 +_,19 @@ + + @Override + public void createResult() { ++ // Purpur start - Anvil API ++ this.bypassCost = false; ++ this.canDoUnsafeEnchants = false; ++ if (org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent(getBukkitView()).callEvent(); ++ // Purpur end - Anvil API ++ + ItemStack item = this.inputSlots.getItem(0); + this.onlyRenaming = false; + this.cost.set(1); + int i = 0; + long l = 0L; + int i1 = 0; +- if (!item.isEmpty() && EnchantmentHelper.canStoreEnchantments(item)) { ++ if (!item.isEmpty() && this.canDoUnsafeEnchants || EnchantmentHelper.canStoreEnchantments(item)) { // Purpur - Anvil API + ItemStack itemStack = item.copy(); + ItemStack item1 = this.inputSlots.getItem(1); + ItemEnchantments.Mutable mutable = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(itemStack)); +@@ -191,23 +_,36 @@ + int intValue = entry.getIntValue(); + intValue = level == intValue ? intValue + 1 : Math.max(intValue, level); + Enchantment enchantment = holder.value(); +- boolean canEnchant = enchantment.canEnchant(item); ++ // Purpur start - Config to allow unsafe enchants ++ boolean canEnchant = this.canDoUnsafeEnchants || org.purpurmc.purpur.PurpurConfig.allowInapplicableEnchants || enchantment.canEnchant(item); // whether the enchantment can be applied on specific item type ++ boolean canEnchant1 = true; // whether two incompatible enchantments can be applied on a single item ++ // Purpur end - Config to allow unsafe enchants + if (this.player.getAbilities().instabuild || item.is(Items.ENCHANTED_BOOK)) { + canEnchant = true; + } + +- for (Holder holder1 : mutable.keySet()) { ++ // Purpur start - Config to allow unsafe enchants ++ java.util.Iterator> mutableIterator = mutable.keySet().iterator(); ++ while (mutableIterator.hasNext()) { ++ Holder holder1 = mutableIterator.next(); ++ // Purpur end - Config to allow unsafe enchants + if (!holder1.equals(holder) && !Enchantment.areCompatible(holder, holder1)) { +- canEnchant = false; +- i++; ++ canEnchant1 = this.canDoUnsafeEnchants || org.purpurmc.purpur.PurpurConfig.allowIncompatibleEnchants; // Purpur - Anvil API // Purpur - flag3 -> canEnchant1 - Config to allow unsafe enchants ++ // Purpur start - Config to allow unsafe enchants ++ if (!canEnchant1 && org.purpurmc.purpur.PurpurConfig.replaceIncompatibleEnchants) { ++ mutableIterator.remove(); // replace current enchant with the incompatible one trying to be applied // TODO: is this needed? ++ canEnchant1 = true; ++ } ++ // Purpur end - Config to allow unsafe enchants ++ ++i; + } + } + +- if (!canEnchant) { ++ if (!canEnchant || !canEnchant1) { // Purpur - Config to allow unsafe enchants + flag1 = true; + } else { + flag = true; +- if (intValue > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions ++ if (!org.purpurmc.purpur.PurpurConfig.allowHigherEnchantsLevels && intValue > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions // Purpur - Config to allow unsafe enchants + intValue = enchantment.getMaxLevel(); + } + +@@ -236,6 +_,54 @@ + if (!this.itemName.equals(item.getHoverName().getString())) { + i1 = 1; + i += i1; ++ // Purpur start - Allow anvil colors ++ if (this.player != null) { ++ org.bukkit.craftbukkit.entity.CraftHumanEntity player = this.player.getBukkitEntity(); ++ String name = this.itemName; ++ boolean removeItalics = false; ++ if (player.hasPermission("purpur.anvil.remove_italics")) { ++ if (name.startsWith("&r")) { ++ name = name.substring(2); ++ removeItalics = true; ++ } else if (name.startsWith("")) { ++ name = name.substring(3); ++ removeItalics = true; ++ } else if (name.startsWith("")) { ++ name = name.substring(7); ++ removeItalics = true; ++ } ++ } ++ if (this.player.level().purpurConfig.anvilAllowColors) { ++ if (player.hasPermission("purpur.anvil.color")) { ++ java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("(?i)&([0-9a-fr])").matcher(name); ++ while (matcher.find()) { ++ String match = matcher.group(1); ++ name = name.replace("&" + match, "\u00a7" + match.toLowerCase(java.util.Locale.ROOT)); ++ } ++ //name = name.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1"); ++ } ++ if (player.hasPermission("purpur.anvil.format")) { ++ java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("(?i)&([k-or])").matcher(name); ++ while (matcher.find()) { ++ String match = matcher.group(1); ++ name = name.replace("&" + match, "\u00a7" + match.toLowerCase(java.util.Locale.ROOT)); ++ } ++ //name = name.replaceAll("(?i)&([l-or])", "\u00a7$1"); ++ } ++ } ++ net.kyori.adventure.text.Component component; ++ if (this.player.level().purpurConfig.anvilColorsUseMiniMessage && player.hasPermission("purpur.anvil.minimessage")) { ++ component = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(org.bukkit.ChatColor.stripColor(name)); ++ } else { ++ component = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(name); ++ } ++ if (removeItalics) { ++ component = component.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); ++ } ++ itemStack.set(DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(component)); ++ } ++ else ++ // Purpur end - Allow anvil colors + itemStack.set(DataComponents.CUSTOM_NAME, Component.literal(this.itemName)); + } + } else if (item.has(DataComponents.CUSTOM_NAME)) { +@@ -260,6 +_,12 @@ + this.onlyRenaming = true; + } + ++ // Purpur start - Anvil API ++ if (this.bypassCost && this.cost.get() >= this.maximumRepairCost) { ++ this.cost.set(this.maximumRepairCost - 1); ++ } ++ // Purpur end - Anvil API ++ + if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit + itemStack = ItemStack.EMPTY; + } +@@ -280,6 +_,13 @@ + + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemStack); // CraftBukkit + this.broadcastChanges(); ++ ++ // Purpur start - Anvil API ++ if ((this.canDoUnsafeEnchants || org.purpurmc.purpur.PurpurConfig.allowInapplicableEnchants || org.purpurmc.purpur.PurpurConfig.allowIncompatibleEnchants) && itemStack != ItemStack.EMPTY) { // Purpur - Config to allow unsafe enchants ++ ((ServerPlayer) this.player).connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), 2, itemStack)); ++ ((ServerPlayer) this.player).connection.send(new ClientboundContainerSetDataPacket(this.containerId, 0, this.cost.get())); ++ } ++ // Purpur end - Anvil API + } else { + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit + this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item +@@ -288,7 +_,7 @@ + } + + public static int calculateIncreasedRepairCost(int oldRepairCost) { +- return (int)Math.min(oldRepairCost * 2L + 1L, 2147483647L); ++ return org.purpurmc.purpur.PurpurConfig.anvilCumulativeCost ? (int)Math.min(oldRepairCost * 2L + 1L, 2147483647L) : 0; // Purpur - Make anvil cumulative cost configurable + } + + public boolean setItemName(String itemName) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ArmorSlot.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ArmorSlot.java.patch new file mode 100644 index 000000000..c7b2ace18 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ArmorSlot.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/inventory/ArmorSlot.java ++++ b/net/minecraft/world/inventory/ArmorSlot.java +@@ -42,7 +_,7 @@ + @Override + public boolean mayPickup(Player player) { + ItemStack item = this.getItem(); +- return (item.isEmpty() || player.isCreative() || !EnchantmentHelper.has(item, EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE)) ++ return (item.isEmpty() || player.isCreative() || (!EnchantmentHelper.has(item, EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE) || player.level().purpurConfig.playerRemoveBindingWithWeakness && player.hasEffect(net.minecraft.world.effect.MobEffects.WEAKNESS))) // Purpur - Config to remove curse of binding with weakness + && super.mayPickup(player); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch new file mode 100644 index 000000000..8f9902689 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch @@ -0,0 +1,51 @@ +--- a/net/minecraft/world/inventory/EnchantmentMenu.java ++++ b/net/minecraft/world/inventory/EnchantmentMenu.java +@@ -63,6 +_,22 @@ + return access.getLocation(); + } + // CraftBukkit end ++ ++ // Purpur start - Enchantment Table Persists Lapis ++ @Override ++ public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { ++ super.onClose(who); ++ ++ if (who.getHandle().level().purpurConfig.enchantmentTableLapisPersists) { ++ access.execute((level, pos) -> { ++ net.minecraft.world.level.block.entity.BlockEntity blockEntity = level.getBlockEntity(pos); ++ if (blockEntity instanceof net.minecraft.world.level.block.entity.EnchantingTableBlockEntity enchantmentTable) { ++ enchantmentTable.setLapis(this.getItem(1).getCount()); ++ } ++ }); ++ } ++ } ++ // Purpur end - Enchantment Table Persists Lapis + }; + // Paper end - Add missing InventoryHolders + this.access = access; +@@ -83,6 +_,16 @@ + return EnchantmentMenu.EMPTY_SLOT_LAPIS_LAZULI; + } + }); ++ // Purpur start - Enchantment Table Persists Lapis ++ access.execute((level, pos) -> { ++ if (level.purpurConfig.enchantmentTableLapisPersists) { ++ net.minecraft.world.level.block.entity.BlockEntity blockEntity = level.getBlockEntity(pos); ++ if (blockEntity instanceof net.minecraft.world.level.block.entity.EnchantingTableBlockEntity enchantmentTable) { ++ this.getSlot(1).set(new ItemStack(Items.LAPIS_LAZULI, enchantmentTable.getLapis())); ++ } ++ } ++ }); ++ // Purpur end - Enchantment Table Persists Lapis + this.addStandardInventorySlots(playerInventory, 8, 84); + this.addDataSlot(DataSlot.shared(this.costs, 0)); + this.addDataSlot(DataSlot.shared(this.costs, 1)); +@@ -294,7 +_,7 @@ + @Override + public void removed(Player player) { + super.removed(player); +- this.access.execute((level, blockPos) -> this.clearContainer(player, this.enchantSlots)); ++ this.access.execute((level, blockPos) -> {if (level.purpurConfig.enchantmentTableLapisPersists) this.getSlot(1).set(ItemStack.EMPTY);this.clearContainer(player, this.enchantSlots);}); // Purpur - Enchantment Table Persists Lapis + } + + @Override diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch new file mode 100644 index 000000000..1af1db846 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch @@ -0,0 +1,138 @@ +--- a/net/minecraft/world/inventory/GrindstoneMenu.java ++++ b/net/minecraft/world/inventory/GrindstoneMenu.java +@@ -91,11 +_,13 @@ + @Override + public void onTake(Player player, ItemStack stack) { + access.execute((level, blockPos) -> { ++ ItemStack itemstack = activeQuickItem == null ? stack : activeQuickItem; // Purpur - Grindstone API + if (level instanceof ServerLevel) { + // Paper start - Fire BlockExpEvent on grindstone use + org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), this.getExperienceAmount(level)); + event.callEvent(); +- ExperienceOrb.award((ServerLevel) level, Vec3.atCenterOf(blockPos), event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); ++ org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent grindstoneTakeResultEvent = new org.purpurmc.purpur.event.inventory.GrindstoneTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), event.getExpToDrop()); grindstoneTakeResultEvent.callEvent(); // Purpur - Grindstone API ++ ExperienceOrb.award((ServerLevel) level, Vec3.atCenterOf(blockPos), grindstoneTakeResultEvent.getExperienceAmount(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Purpur - Grindstone API + // Paper end - Fire BlockExpEvent on grindstone use + } + +@@ -124,7 +_,7 @@ + for (Entry> entry : enchantmentsForCrafting.entrySet()) { + Holder holder = entry.getKey(); + int intValue = entry.getIntValue(); +- if (!holder.is(EnchantmentTags.CURSE)) { ++ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value())) { // Purpur - Config for grindstones + i += holder.value().getMinCost(intValue); + } + } +@@ -202,15 +_,75 @@ + + for (Entry> entry : enchantmentsForCrafting.entrySet()) { + Holder holder = entry.getKey(); +- if (!holder.is(EnchantmentTags.CURSE) || mutable.getLevel(holder) == 0) { ++ if (!org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value()) || mutable.getLevel(holder) == 0) { // Purpur - Config for grindstones + mutable.upgrade(holder, entry.getIntValue()); + } + } + }); + } + ++ // Purpur start - Config for grindstones ++ private java.util.List> GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST = java.util.List.of( ++ // DataComponents.MAX_STACK_SIZE, ++ // DataComponents.DAMAGE, ++ // DataComponents.BLOCK_STATE, ++ DataComponents.CUSTOM_DATA, ++ // DataComponents.MAX_DAMAGE, ++ // DataComponents.UNBREAKABLE, ++ // DataComponents.CUSTOM_NAME, ++ // DataComponents.ITEM_NAME, ++ // DataComponents.LORE, ++ // DataComponents.RARITY, ++ // DataComponents.ENCHANTMENTS, ++ // DataComponents.CAN_PLACE_ON, ++ // DataComponents.CAN_BREAK, ++ DataComponents.ATTRIBUTE_MODIFIERS, ++ DataComponents.CUSTOM_MODEL_DATA, ++ // DataComponents.HIDE_ADDITIONAL_TOOLTIP, ++ // DataComponents.HIDE_TOOLTIP, ++ // DataComponents.REPAIR_COST, ++ // DataComponents.CREATIVE_SLOT_LOCK, ++ // DataComponents.ENCHANTMENT_GLINT_OVERRIDE, ++ // DataComponents.INTANGIBLE_PROJECTILE, ++ // DataComponents.FOOD, ++ // DataComponents.FIRE_RESISTANT, ++ // DataComponents.TOOL, ++ // DataComponents.STORED_ENCHANTMENTS, ++ DataComponents.DYED_COLOR, ++ // DataComponents.MAP_COLOR, ++ // DataComponents.MAP_ID, ++ // DataComponents.MAP_DECORATIONS, ++ // DataComponents.MAP_POST_PROCESSING, ++ // DataComponents.CHARGED_PROJECTILES, ++ // DataComponents.BUNDLE_CONTENTS, ++ // DataComponents.POTION_CONTENTS, ++ DataComponents.SUSPICIOUS_STEW_EFFECTS ++ // DataComponents.WRITABLE_BOOK_CONTENT, ++ // DataComponents.WRITTEN_BOOK_CONTENT, ++ // DataComponents.TRIM, ++ // DataComponents.DEBUG_STICK_STATE, ++ // DataComponents.ENTITY_DATA, ++ // DataComponents.BUCKET_ENTITY_DATA, ++ // DataComponents.BLOCK_ENTITY_DATA, ++ // DataComponents.INSTRUMENT, ++ // DataComponents.OMINOUS_BOTTLE_AMPLIFIER, ++ // DataComponents.RECIPES, ++ // DataComponents.LODESTONE_TRACKER, ++ // DataComponents.FIREWORK_EXPLOSION, ++ // DataComponents.FIREWORKS, ++ // DataComponents.PROFILE, ++ // DataComponents.NOTE_BLOCK_SOUND, ++ // DataComponents.BANNER_PATTERNS, ++ // DataComponents.BASE_COLOR, ++ // DataComponents.POT_DECORATIONS, ++ // DataComponents.CONTAINER, ++ // DataComponents.BEES, ++ // DataComponents.LOCK, ++ // DataComponents.CONTAINER_LOOT, ++ ); ++ // Purpur end - Config for grindstones + private ItemStack removeNonCursesFrom(ItemStack item) { +- ItemEnchantments itemEnchantments = EnchantmentHelper.updateEnchantments(item, mutable -> mutable.removeIf(holder -> !holder.is(EnchantmentTags.CURSE))); ++ ItemEnchantments itemEnchantments = EnchantmentHelper.updateEnchantments(item, mutable -> mutable.removeIf(holder -> !org.purpurmc.purpur.PurpurConfig.grindstoneIgnoredEnchants.contains(holder.value()))); // Purpur - Config for grindstones + if (item.is(Items.ENCHANTED_BOOK) && itemEnchantments.isEmpty()) { + item = item.transmuteCopy(Items.BOOK); + } +@@ -222,6 +_,23 @@ + } + + item.set(DataComponents.REPAIR_COST, i); ++ ++ // Purpur start - Config for grindstones ++ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder(); ++ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveAttributes) { ++ item.getComponents().forEach(typedDataComponent -> { ++ if (GRINDSTONE_REMOVE_ATTRIBUTES_REMOVAL_LIST.contains(typedDataComponent.type())) { ++ builder.remove(typedDataComponent.type()); ++ } ++ }); ++ } ++ if (org.purpurmc.purpur.PurpurConfig.grindstoneRemoveDisplay) { ++ builder.remove(DataComponents.CUSTOM_NAME); ++ builder.remove(DataComponents.LORE); ++ } ++ item.applyComponents(builder.build()); ++ // Purpur end - Config for grindstones ++ + return item; + } + +@@ -278,7 +_,9 @@ + return ItemStack.EMPTY; + } + ++ this.activeQuickItem = itemStack; // Purpur - Grindstone API + slot.onTake(player, item); ++ this.activeQuickItem = null; // Purpur - Grindstone API + } + + return itemStack; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch new file mode 100644 index 000000000..9899e30a5 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch @@ -0,0 +1,12 @@ +--- a/net/minecraft/world/inventory/ItemCombinerMenu.java ++++ b/net/minecraft/world/inventory/ItemCombinerMenu.java +@@ -156,7 +_,9 @@ + return ItemStack.EMPTY; + } + ++ this.activeQuickItem = itemStack; // Purpur - Anvil API + slot.onTake(player, item); ++ this.activeQuickItem = null; // Purpur - Anvil API + } + + return itemStack; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/AxeItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/AxeItem.java.patch new file mode 100644 index 000000000..c50f80b33 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/AxeItem.java.patch @@ -0,0 +1,71 @@ +--- a/net/minecraft/world/item/AxeItem.java ++++ b/net/minecraft/world/item/AxeItem.java +@@ -62,13 +_,15 @@ + if (playerHasShieldUseIntent(context)) { + return InteractionResult.PASS; + } else { +- Optional optional = this.evaluateNewBlockState(level, clickedPos, player, level.getBlockState(clickedPos)); ++ Optional optional = this.evaluateActionable(level, clickedPos, player, level.getBlockState(clickedPos)); // Purpur - Tool actionable options + if (optional.isEmpty()) { + return InteractionResult.PASS; + } else { ++ org.purpurmc.purpur.tool.Actionable actionable = optional.get(); // Purpur - Tool actionable options ++ BlockState state = actionable.into().withPropertiesOf(level.getBlockState(clickedPos)); // Purpur - Tool actionable options + ItemStack itemInHand = context.getItemInHand(); + // Paper start - EntityChangeBlockEvent +- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, optional.get())) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, clickedPos, state)) { // Purpur - Tool actionable options + return InteractionResult.PASS; + } + // Paper end +@@ -76,8 +_,15 @@ + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, clickedPos, itemInHand); + } + +- level.setBlock(clickedPos, optional.get(), 11); +- level.gameEvent(GameEvent.BLOCK_CHANGE, clickedPos, GameEvent.Context.of(player, optional.get())); ++ // Purpur start - Tool actionable options ++ level.setBlock(clickedPos, state, 11); ++ actionable.drops().forEach((drop, chance) -> { ++ if (level.random.nextDouble() < chance) { ++ Block.popResourceFromFace(level, clickedPos, context.getClickedFace(), new ItemStack(drop)); ++ } ++ }); ++ level.gameEvent(GameEvent.BLOCK_CHANGE, clickedPos, GameEvent.Context.of(player, state)); ++ // Purpur end - Tool actionable options + if (player != null) { + itemInHand.hurtAndBreak(1, player, LivingEntity.getSlotForHand(context.getHand())); + } +@@ -92,22 +_,24 @@ + return context.getHand().equals(InteractionHand.MAIN_HAND) && player.getOffhandItem().is(Items.SHIELD) && !player.isSecondaryUseActive(); + } + +- private Optional evaluateNewBlockState(Level level, BlockPos pos, @Nullable Player player, BlockState state) { +- Optional stripped = this.getStripped(state); ++ private Optional evaluateActionable(Level level, BlockPos pos, @Nullable Player player, BlockState state) { // Purpur - Tool actionable options ++ Optional stripped = Optional.ofNullable(level.purpurConfig.axeStrippables.get(state.getBlock())); // Purpur - Tool actionable options + if (stripped.isPresent()) { +- level.playSound(player, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F); ++ level.playSound(STRIPPABLES.containsKey(state.getBlock()) ? player : null, pos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - force sound + return stripped; + } else { +- Optional previous = WeatheringCopper.getPrevious(state); ++ Optional previous = Optional.ofNullable(level.purpurConfig.axeWeatherables.get(state.getBlock())); // Purpur - Tool actionable options + if (previous.isPresent()) { +- level.playSound(player, pos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F); ++ level.playSound(WeatheringCopper.getPrevious(state).isPresent() ? player : null, pos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - Tool actionable options - force sound + level.levelEvent(player, 3005, pos, 0); + return previous; + } else { +- Optional optional = Optional.ofNullable(HoneycombItem.WAX_OFF_BY_BLOCK.get().get(state.getBlock())) +- .map(block -> block.withPropertiesOf(state)); ++ // Purpur start - Tool actionable options ++ Optional optional = Optional.ofNullable(level.purpurConfig.axeWaxables.get(state.getBlock())); ++ // .map(block -> block.withPropertiesOf(state)); ++ // Purpur end - Tool actionable options + if (optional.isPresent()) { +- level.playSound(player, pos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F); ++ level.playSound(HoneycombItem.WAX_OFF_BY_BLOCK.get().containsKey(state.getBlock()) ? player : null, pos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - Tool actionable options - force sound + level.levelEvent(player, 3004, pos, 0); + return optional; + } else { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BlockItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BlockItem.java.patch new file mode 100644 index 000000000..855b75b34 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BlockItem.java.patch @@ -0,0 +1,36 @@ +--- a/net/minecraft/world/item/BlockItem.java ++++ b/net/minecraft/world/item/BlockItem.java +@@ -152,7 +_,16 @@ + } + + protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, @Nullable Player player, ItemStack stack, BlockState state) { +- return updateCustomBlockEntityTag(level, player, pos, stack); ++ // Purpur start - Persistent BlockEntity Lore and DisplayName ++ boolean handled = updateCustomBlockEntityTag(level, player, pos, stack); ++ if (level.purpurConfig.persistentTileEntityLore) { ++ BlockEntity blockEntity1 = level.getBlockEntity(pos); ++ if (blockEntity1 != null) { ++ blockEntity1.setPersistentLore(stack.getOrDefault(DataComponents.LORE, net.minecraft.world.item.component.ItemLore.EMPTY)); ++ } ++ } ++ return handled; ++ // Purpur end - Persistent BlockEntity Lore and DisplayName + } + + @Nullable +@@ -217,6 +_,7 @@ + } + + if (!type.onlyOpCanSetNbt() || player != null && (player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place")))) { // Spigot - add permission ++ if (!(level.purpurConfig.silkTouchEnabled && blockEntity instanceof net.minecraft.world.level.block.entity.SpawnerBlockEntity && player.getBukkitEntity().hasPermission("purpur.drop.spawners"))) // Purpur - Silk touch spawners + return customData.loadInto(blockEntity, level.registryAccess()); + } + +@@ -264,6 +_,7 @@ + public void onDestroyed(ItemEntity itemEntity) { + ItemContainerContents itemContainerContents = itemEntity.getItem().set(DataComponents.CONTAINER, ItemContainerContents.EMPTY); + if (itemContainerContents != null) { ++ if (itemEntity.level().purpurConfig.shulkerBoxItemDropContentsWhenDestroyed && this.getBlock() instanceof ShulkerBoxBlock) // Purpur - option to disable shulker box items from dropping contents when destroyed + ItemUtils.onContainerDestroyed(itemEntity, itemContainerContents.nonEmptyItemsCopy()); + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BowItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BowItem.java.patch new file mode 100644 index 000000000..2cad5634b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BowItem.java.patch @@ -0,0 +1,32 @@ +--- a/net/minecraft/world/item/BowItem.java ++++ b/net/minecraft/world/item/BowItem.java +@@ -28,6 +_,11 @@ + return false; + } else { + ItemStack projectile = player.getProjectile(stack); ++ // Purpur start - Infinity bow settings ++ if (level.purpurConfig.infinityWorksWithoutArrows && projectile.isEmpty() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, stack) > 0) { ++ projectile = new ItemStack(Items.ARROW); ++ } ++ // Purpur end - Infinity bow settings + if (projectile.isEmpty()) { + return false; + } else { +@@ -38,7 +_,7 @@ + } else { + List list = draw(stack, projectile, player); + if (level instanceof ServerLevel serverLevel && !list.isEmpty()) { +- this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, 1.0F, powerForTime == 1.0F, null); ++ this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, powerForTime * 3.0F, (float) serverLevel.purpurConfig.bowProjectileOffset, powerForTime == 1.0F, null); // Purpur - Projectile offset config + } + + level.playSound( +@@ -89,7 +_,7 @@ + public InteractionResult use(Level level, Player player, InteractionHand hand) { + ItemStack itemInHand = player.getItemInHand(hand); + boolean flag = !player.getProjectile(itemInHand).isEmpty(); +- if (!player.hasInfiniteMaterials() && !flag) { ++ if (!player.hasInfiniteMaterials() && !flag && !(level.purpurConfig.infinityWorksWithoutArrows && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, itemInHand) > 0)) { // Purpur - Infinity bow settings + return InteractionResult.FAIL; + } else { + player.startUsingItem(hand); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BucketItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BucketItem.java.patch new file mode 100644 index 000000000..15d7ab056 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/BucketItem.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/item/BucketItem.java ++++ b/net/minecraft/world/item/BucketItem.java +@@ -147,7 +_,7 @@ + // CraftBukkit end + if (!flag) { + return result != null && this.emptyContents(player, level, result.getBlockPos().relative(result.getDirection()), null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit +- } else if (level.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) { ++ } else if ((level.dimensionType().ultraWarm() || (level.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) && this.content.is(FluidTags.WATER)) { // Purpur - Add allow water in end world option + int x = pos.getX(); + int y = pos.getY(); + int z = pos.getZ(); +@@ -156,7 +_,7 @@ + ); + + for (int i = 0; i < 8; i++) { +- level.addParticle(ParticleTypes.LARGE_SMOKE, x + Math.random(), y + Math.random(), z + Math.random(), 0.0, 0.0, 0.0); ++ ((net.minecraft.server.level.ServerLevel) level).sendParticlesSource(null, ParticleTypes.LARGE_SMOKE, false, true, x + Math.random(), y + Math.random(), z + Math.random(), 1, 0.0D, 0.0D, 0.0D, 0.0D); // Purpur - Add allow water in end world option + } + + return true; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/CrossbowItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/CrossbowItem.java.patch new file mode 100644 index 000000000..bcb821757 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/CrossbowItem.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/item/CrossbowItem.java ++++ b/net/minecraft/world/item/CrossbowItem.java +@@ -70,7 +_,7 @@ + ItemStack itemInHand = player.getItemInHand(hand); + ChargedProjectiles chargedProjectiles = itemInHand.get(DataComponents.CHARGED_PROJECTILES); + if (chargedProjectiles != null && !chargedProjectiles.isEmpty()) { +- this.performShooting(level, player, hand, itemInHand, getShootingPower(chargedProjectiles), 1.0F, null); ++ this.performShooting(level, player, hand, itemInHand, getShootingPower(chargedProjectiles), (float) level.purpurConfig.crossbowProjectileOffset, null); // Purpur - Projectile offset config + return InteractionResult.CONSUME; + } else if (!player.getProjectile(itemInHand).isEmpty()) { + this.startSoundPlayed = false; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/DyeColor.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/DyeColor.java.patch new file mode 100644 index 000000000..f18d71793 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/DyeColor.java.patch @@ -0,0 +1,13 @@ +--- a/net/minecraft/world/item/DyeColor.java ++++ b/net/minecraft/world/item/DyeColor.java +@@ -123,4 +_,10 @@ + private static CraftingInput makeCraftColorInput(DyeColor first, DyeColor second) { + return CraftingInput.of(2, 1, List.of(new ItemStack(DyeItem.byColor(first)), new ItemStack(DyeItem.byColor(second)))); + } ++ ++ // Purpur start - Shulker spawn from bullet options ++ public static DyeColor random(net.minecraft.util.RandomSource random) { ++ return values()[random.nextInt(values().length)]; ++ } ++ // Purpur end - Shulker spawn from bullet options + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EggItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EggItem.java.patch new file mode 100644 index 000000000..fe21990b3 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EggItem.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/item/EggItem.java ++++ b/net/minecraft/world/item/EggItem.java +@@ -26,7 +_,7 @@ + if (level instanceof ServerLevel serverLevel) { + // CraftBukkit start + // Paper start - PlayerLaunchProjectileEvent +- final Projectile.Delayed thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, serverLevel, itemInHand, player, 0.0F, EggItem.PROJECTILE_SHOOT_POWER, 1.0F); ++ final Projectile.Delayed thrownEgg = Projectile.spawnProjectileFromRotationDelayed(ThrownEgg::new, serverLevel, itemInHand, player, 0.0F, EggItem.PROJECTILE_SHOOT_POWER, (float) serverLevel.purpurConfig.eggProjectileOffset); // Purpur - Projectile offset config + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownEgg.projectile().getBukkitEntity()); + if (event.callEvent() && thrownEgg.attemptSpawn()) { + if (event.shouldConsume()) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch new file mode 100644 index 000000000..d46e5ccc9 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/item/EndCrystalItem.java ++++ b/net/minecraft/world/item/EndCrystalItem.java +@@ -24,7 +_,7 @@ + Level level = context.getLevel(); + BlockPos clickedPos = context.getClickedPos(); + BlockState blockState = level.getBlockState(clickedPos); +- if (!blockState.is(Blocks.OBSIDIAN) && !blockState.is(Blocks.BEDROCK)) { ++ if (!level.purpurConfig.endCrystalPlaceAnywhere && !blockState.is(Blocks.OBSIDIAN) && !blockState.is(Blocks.BEDROCK)) { // Purpur - place end crystal on any block + return InteractionResult.FAIL; + } else { + BlockPos blockPos = clickedPos.above(); final BlockPos aboveBlockPosition = blockPos; // Paper - OBFHELPER diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EnderpearlItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EnderpearlItem.java.patch new file mode 100644 index 000000000..faeb98db1 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/EnderpearlItem.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/item/EnderpearlItem.java ++++ b/net/minecraft/world/item/EnderpearlItem.java +@@ -24,7 +_,7 @@ + if (level instanceof ServerLevel serverLevel) { + // CraftBukkit start + // Paper start - PlayerLaunchProjectileEvent +- final Projectile.Delayed thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemInHand, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, 1.0F); ++ final Projectile.Delayed thrownEnderpearl = Projectile.spawnProjectileFromRotationDelayed(ThrownEnderpearl::new, serverLevel, itemInHand, player, 0.0F, EnderpearlItem.PROJECTILE_SHOOT_POWER, (float) serverLevel.purpurConfig.enderPearlProjectileOffset); // Purpur - Projectile offset config + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownEnderpearl.projectile().getBukkitEntity()); + if (event.callEvent() && thrownEnderpearl.attemptSpawn()) { + if (event.shouldConsume()) { +@@ -44,6 +_,7 @@ + 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F) + ); + player.awardStat(Stats.ITEM_USED.get(this)); ++ player.getCooldowns().addCooldown(itemInHand, player.getAbilities().instabuild ? level.purpurConfig.enderPearlCooldownCreative : level.purpurConfig.enderPearlCooldown); // Purpur - Configurable Ender Pearl cooldown + } else { + // Paper end - PlayerLaunchProjectileEvent + player.containerMenu.sendAllDataToRemote(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/HoeItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/HoeItem.java.patch new file mode 100644 index 000000000..4e6e9ca20 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/HoeItem.java.patch @@ -0,0 +1,33 @@ +--- a/net/minecraft/world/item/HoeItem.java ++++ b/net/minecraft/world/item/HoeItem.java +@@ -46,15 +_,25 @@ + public InteractionResult useOn(UseOnContext context) { + Level level = context.getLevel(); + BlockPos clickedPos = context.getClickedPos(); +- Pair, Consumer> pair = TILLABLES.get(level.getBlockState(clickedPos).getBlock()); +- if (pair == null) { ++ // Purpur start - Tool actionable options ++ Block clickedBlock = level.getBlockState(clickedPos).getBlock(); ++ org.purpurmc.purpur.tool.Tillable tillable = level.purpurConfig.hoeTillables.get(clickedBlock); ++ if (tillable == null) { + return InteractionResult.PASS; + } else { +- Predicate predicate = pair.getFirst(); +- Consumer consumer = pair.getSecond(); ++ Predicate predicate = tillable.condition().predicate(); ++ Consumer consumer = (ctx) -> { ++ level.setBlock(clickedPos, tillable.into().defaultBlockState(), 11); ++ tillable.drops().forEach((drop, chance) -> { ++ if (level.random.nextDouble() < chance) { ++ Block.popResourceFromFace(level, clickedPos, ctx.getClickedFace(), new ItemStack(drop)); ++ } ++ }); ++ }; ++ // Purpur end - Tool actionable options + if (predicate.test(context)) { + Player player = context.getPlayer(); +- level.playSound(player, clickedPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F); ++ if (!TILLABLES.containsKey(clickedBlock)) level.playSound(null, clickedPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F); // Purpur - Tool actionable options - force sound + if (!level.isClientSide) { + consumer.accept(context); + if (player != null) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ItemStack.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ItemStack.java.patch new file mode 100644 index 000000000..d8595672c --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ItemStack.java.patch @@ -0,0 +1,58 @@ +--- a/net/minecraft/world/item/ItemStack.java ++++ b/net/minecraft/world/item/ItemStack.java +@@ -461,6 +_,7 @@ + serverLevel.isBlockPlaceCancelled = true; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent + for (org.bukkit.block.BlockState blockstate : blocks) { + blockstate.update(true, false); ++ ((org.bukkit.craftbukkit.block.CraftBlock) blockstate.getBlock()).getNMS().getBlock().forgetPlacer(); // Purpur - Store placer on Block when placed + } + serverLevel.isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent + serverLevel.preventPoiUpdated = false; +@@ -486,6 +_,7 @@ + if (!(block.getBlock() instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // Containers get placed automatically + block.onPlace(serverLevel, newPos, oldBlock, true, context); + } ++ block.getBlock().forgetPlacer(); // Purpur - Store placer on Block when placed + + serverLevel.notifyAndUpdatePhysics(newPos, null, oldBlock, block, serverLevel.getBlockState(newPos), updateFlag, net.minecraft.world.level.block.Block.UPDATE_LIMIT); // send null chunk as chunk.k() returns false by this point + } +@@ -627,6 +_,26 @@ + return this.isDamageableItem() && this.getDamageValue() > 0; + } + ++ // Purpur start - Add option to mend the most damaged equipment first ++ public float getDamagePercent() { ++ if (this.has(DataComponents.UNBREAKABLE)) { ++ return 0.0F; ++ } ++ ++ final int maxDamage = this.getOrDefault(DataComponents.MAX_DAMAGE, 0); ++ if (maxDamage == 0) { ++ return 0.0F; ++ } ++ ++ final int damage = this.getOrDefault(DataComponents.DAMAGE, 0); ++ if (damage == 0) { ++ return 0.0F; ++ } ++ ++ return (float) damage / maxDamage; ++ } ++ // Purpur end - Add option to mend the most damaged equipment first ++ + public int getDamageValue() { + return Mth.clamp(this.getOrDefault(DataComponents.DAMAGE, Integer.valueOf(0)), 0, this.getMaxDamage()); + } +@@ -1251,6 +_,12 @@ + public boolean isEnchanted() { + return !this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).isEmpty(); + } ++ ++ // Purpur start - Config to allow unsafe enchants ++ public boolean hasEnchantment(Holder enchantment) { ++ return this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).getLevel(enchantment) > 0; ++ } ++ // Purpur end - Config to allow unsafe enchants + + public ItemEnchantments getEnchantments() { + return this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/Items.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/Items.java.patch new file mode 100644 index 000000000..618da92d7 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/Items.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/item/Items.java ++++ b/net/minecraft/world/item/Items.java +@@ -367,7 +_,7 @@ + public static final Item PURPUR_BLOCK = registerBlock(Blocks.PURPUR_BLOCK); + public static final Item PURPUR_PILLAR = registerBlock(Blocks.PURPUR_PILLAR); + public static final Item PURPUR_STAIRS = registerBlock(Blocks.PURPUR_STAIRS); +- public static final Item SPAWNER = registerBlock(Blocks.SPAWNER); ++ public static final Item SPAWNER = registerBlock(Blocks.SPAWNER, org.purpurmc.purpur.item.SpawnerItem::new, new Item.Properties().rarity(Rarity.EPIC)); // Purpur - Silk touch spawners + public static final Item CREAKING_HEART = registerBlock(Blocks.CREAKING_HEART); + public static final Item CHEST = registerBlock(Blocks.CHEST, properties -> properties.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY)); + public static final Item CRAFTING_TABLE = registerBlock(Blocks.CRAFTING_TABLE); +@@ -2010,7 +_,7 @@ + "sweet_berries", createBlockItemWithCustomItemName(Blocks.SWEET_BERRY_BUSH), new Item.Properties().food(Foods.SWEET_BERRIES) + ); + public static final Item GLOW_BERRIES = registerItem( +- "glow_berries", createBlockItemWithCustomItemName(Blocks.CAVE_VINES), new Item.Properties().food(Foods.GLOW_BERRIES) ++ "glow_berries", settings -> new org.purpurmc.purpur.item.GlowBerryItem(Blocks.CAVE_VINES, settings.useItemDescriptionPrefix()), new Item.Properties().food(Foods.GLOW_BERRIES) // Purpur - Eating glow berries adds glow effect + ); + public static final Item CAMPFIRE = registerBlock( + Blocks.CAMPFIRE, properties -> properties.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY) diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/MapItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/MapItem.java.patch new file mode 100644 index 000000000..c7332498c --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/MapItem.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/item/MapItem.java ++++ b/net/minecraft/world/item/MapItem.java +@@ -196,6 +_,7 @@ + public static void renderBiomePreviewMap(ServerLevel serverLevel, ItemStack stack) { + MapItemSavedData savedData = getSavedData(stack, serverLevel); + if (savedData != null) { ++ savedData.isExplorerMap = true; // Purpur - Explorer Map API + if (serverLevel.dimension() == savedData.dimension) { + int i = 1 << savedData.scale; + int i1 = savedData.centerX; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/NameTagItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/NameTagItem.java.patch new file mode 100644 index 000000000..2a8639361 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/NameTagItem.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/item/NameTagItem.java ++++ b/net/minecraft/world/item/NameTagItem.java +@@ -24,6 +_,7 @@ + + LivingEntity newEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle(); + newEntity.setCustomName(event.getName() != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(event.getName()) : null); ++ if (player.level().purpurConfig.armorstandFixNametags && target instanceof net.minecraft.world.entity.decoration.ArmorStand) target.setCustomNameVisible(true); // Purpur - Set name visible when using a Name Tag on an Armor Stand + if (event.isPersistent() && newEntity instanceof Mob mob) { + // Paper end - Add PlayerNameEntityEvent + mob.setPersistenceRequired(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch new file mode 100644 index 000000000..0da20a68d --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/item/ProjectileWeaponItem.java ++++ b/net/minecraft/world/item/ProjectileWeaponItem.java +@@ -108,6 +_,8 @@ + abstractArrow.setCritArrow(true); + } + ++ abstractArrow.setActualEnchantments(weapon.getEnchantments()); // Purpur - Add an option to fix MC-3304 projectile looting ++ + return abstractArrow; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ShovelItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ShovelItem.java.patch new file mode 100644 index 000000000..2a462f3a6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ShovelItem.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/item/ShovelItem.java ++++ b/net/minecraft/world/item/ShovelItem.java +@@ -47,9 +_,12 @@ + BlockState blockState1 = FLATTENABLES.get(blockState.getBlock()); + BlockState blockState2 = null; + Runnable afterAction = null; // Paper ++ org.purpurmc.purpur.tool.Flattenable flattenable = level.purpurConfig.shovelFlattenables.get(blockState.getBlock()); // Purpur - Tool actionable options + if (blockState1 != null && level.getBlockState(clickedPos.above()).isAir()) { +- afterAction = () -> level.playSound(player, clickedPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper +- blockState2 = blockState1; ++ // Purpur start - Tool actionable options ++ afterAction = () -> {if (!FLATTENABLES.containsKey(blockState.getBlock())) level.playSound(player, clickedPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F);}; // Paper ++ blockState2 = flattenable.into().defaultBlockState(); ++ // Purpur end - Tool actionable options + } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { + afterAction = () -> { // Paper + if (!level.isClientSide()) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/SnowballItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/SnowballItem.java.patch new file mode 100644 index 000000000..9c09ecb72 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/SnowballItem.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/item/SnowballItem.java ++++ b/net/minecraft/world/item/SnowballItem.java +@@ -26,7 +_,7 @@ + // CraftBukkit start - moved down + if (level instanceof ServerLevel serverLevel) { + // Paper start - PlayerLaunchProjectileEvent +- final Projectile.Delayed snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, serverLevel, itemInHand, player, 0.0F, SnowballItem.PROJECTILE_SHOOT_POWER, 1.0F); ++ final Projectile.Delayed snowball = Projectile.spawnProjectileFromRotationDelayed(Snowball::new, serverLevel, itemInHand, player, 0.0F, SnowballItem.PROJECTILE_SHOOT_POWER, (float) serverLevel.purpurConfig.snowballProjectileOffset); // Purpur - Projectile offset config + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) snowball.projectile().getBukkitEntity()); + if (event.callEvent() && snowball.attemptSpawn()) { + player.awardStat(Stats.ITEM_USED.get(this)); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch new file mode 100644 index 000000000..7a0553a75 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch @@ -0,0 +1,26 @@ +--- a/net/minecraft/world/item/SpawnEggItem.java ++++ b/net/minecraft/world/item/SpawnEggItem.java +@@ -57,6 +_,23 @@ + if (level.getBlockEntity(clickedPos) instanceof Spawner spawner) { + if (level.paperConfig().entities.spawning.disableMobSpawnerSpawnEggTransformation) return InteractionResult.FAIL; // Paper - Allow disabling mob spawner spawn egg transformation + EntityType type = this.getType(level.registryAccess(), itemInHand); ++ // Purpur start - PlayerSetSpawnerTypeWithEggEvent ++ if (spawner instanceof net.minecraft.world.level.block.entity.SpawnerBlockEntity) { ++ org.bukkit.block.Block bukkitBlock = level.getWorld().getBlockAt(clickedPos.getX(), clickedPos.getY(), clickedPos.getZ()); ++ org.purpurmc.purpur.event.PlayerSetSpawnerTypeWithEggEvent event = new org.purpurmc.purpur.event.PlayerSetSpawnerTypeWithEggEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), bukkitBlock, (org.bukkit.block.CreatureSpawner) bukkitBlock.getState(), org.bukkit.entity.EntityType.fromName(type.getName())); ++ if (!event.callEvent()) { ++ return InteractionResult.FAIL; ++ } ++ type = EntityType.getFromBukkitType(event.getEntityType()); ++ } else if (spawner instanceof net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity) { ++ org.bukkit.block.Block bukkitBlock = level.getWorld().getBlockAt(clickedPos.getX(), clickedPos.getY(), clickedPos.getZ()); ++ org.purpurmc.purpur.event.PlayerSetTrialSpawnerTypeWithEggEvent event = new org.purpurmc.purpur.event.PlayerSetTrialSpawnerTypeWithEggEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), bukkitBlock, (org.bukkit.block.TrialSpawner) bukkitBlock.getState(), org.bukkit.entity.EntityType.fromName(type.getName())); ++ if (!event.callEvent()) { ++ return InteractionResult.FAIL; ++ } ++ type = EntityType.getFromBukkitType(event.getEntityType()); ++ } ++ // Purpur end - PlayerSetSpawnerTypeWithEggEvent + spawner.setEntityId(type, level.getRandom()); + level.sendBlockUpdated(clickedPos, blockState, blockState, 3); + level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, clickedPos); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ThrowablePotionItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ThrowablePotionItem.java.patch new file mode 100644 index 000000000..e2154c3b8 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/ThrowablePotionItem.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/item/ThrowablePotionItem.java ++++ b/net/minecraft/world/item/ThrowablePotionItem.java +@@ -23,7 +_,7 @@ + ItemStack itemInHand = player.getItemInHand(hand); + if (level instanceof ServerLevel serverLevel) { + // Paper start - PlayerLaunchProjectileEvent +- final Projectile.Delayed thrownPotion = Projectile.spawnProjectileFromRotationDelayed(ThrownPotion::new, serverLevel, itemInHand, player, -20.0F, PROJECTILE_SHOOT_POWER, 1.0F); ++ final Projectile.Delayed thrownPotion = Projectile.spawnProjectileFromRotationDelayed(ThrownPotion::new, serverLevel, itemInHand, player, -20.0F, PROJECTILE_SHOOT_POWER, (float) serverLevel.purpurConfig.throwablePotionProjectileOffset); // Purpur - Projectile offset config + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemInHand), (org.bukkit.entity.Projectile) thrownPotion.projectile().getBukkitEntity()); + if (event.callEvent() && thrownPotion.attemptSpawn()) { + if (event.shouldConsume()) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/TridentItem.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/TridentItem.java.patch new file mode 100644 index 000000000..3f37caa58 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/TridentItem.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/world/item/TridentItem.java ++++ b/net/minecraft/world/item/TridentItem.java +@@ -90,7 +_,7 @@ + // stack.hurtWithoutBreaking(1, player); // CraftBukkit - moved down + if (tridentSpinAttackStrength == 0.0F) { + Projectile.Delayed tridentDelayed = Projectile.spawnProjectileFromRotationDelayed( // Paper - PlayerLaunchProjectileEvent +- ThrownTrident::new, serverLevel, stack, player, 0.0F, 2.5F, 1.0F ++ ThrownTrident::new, serverLevel, stack, player, 0.0F, 2.5F, (float) serverLevel.purpurConfig.tridentProjectileOffset // Purpur - Projectile offset config + ); + // Paper start - PlayerLaunchProjectileEvent + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) tridentDelayed.projectile().getBukkitEntity()); +@@ -101,6 +_,9 @@ + return false; + } + ThrownTrident thrownTrident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent ++ ++ thrownTrident.setActualEnchantments(stack.getEnchantments()); // Purpur - Add an option to fix MC-3304 projectile looting ++ + if (event.shouldConsume()) stack.hurtWithoutBreaking(1, player); // Paper - PlayerLaunchProjectileEvent + thrownTrident.pickupItemStack = stack.copy(); // SPIGOT-4511 update since damage call moved + // CraftBukkit end diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java.patch new file mode 100644 index 000000000..65243f097 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java ++++ b/net/minecraft/world/item/consume_effects/ClearAllStatusEffectsConsumeEffect.java +@@ -20,6 +_,12 @@ + @Override + // CraftBukkit start + public boolean apply(Level level, ItemStack stack, LivingEntity entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { ++ // Purpur start - Option to toggle milk curing bad omen ++ net.minecraft.world.effect.MobEffectInstance badOmen = entity.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN); ++ if (!level.purpurConfig.milkCuresBadOmen && stack.is(net.minecraft.world.item.Items.MILK_BUCKET) && badOmen != null) { ++ return entity.removeAllEffects(cause) && entity.addEffect(badOmen); ++ } ++ // Purpur end - Option to toggle milk curing bad omen + return entity.removeAllEffects(cause); + // CraftBukkit end + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch new file mode 100644 index 000000000..188d2cfb2 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch @@ -0,0 +1,22 @@ +--- a/net/minecraft/world/item/crafting/Ingredient.java ++++ b/net/minecraft/world/item/crafting/Ingredient.java +@@ -36,6 +_,7 @@ + // CraftBukkit start + @javax.annotation.Nullable + private java.util.Set itemStacks; // Paper - Improve exact choice recipe ingredients ++ public Predicate predicate; // Purpur - Add predicate to recipe's ExactChoice ingredient + + public boolean isExact() { + return this.itemStacks != null; +@@ -87,6 +_,11 @@ + if (this.isExact()) { + return this.itemStacks.contains(stack); // Paper - Improve exact choice recipe ingredients (hashing FTW!) + } ++ // Purpur start - Add predicate to recipe's ExactChoice ingredient ++ if (predicate != null) { ++ return predicate.test(stack.asBukkitCopy()); ++ } ++ // Purpur end - Add predicate to recipe's ExactChoice ingredient + // CraftBukkit end + return stack.is(this.values); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch new file mode 100644 index 000000000..918c41cec --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch @@ -0,0 +1,61 @@ +--- a/net/minecraft/world/item/enchantment/EnchantmentHelper.java ++++ b/net/minecraft/world/item/enchantment/EnchantmentHelper.java +@@ -602,4 +_,58 @@ + interface EnchantmentVisitor { + void accept(Holder enchantment, int level); + } ++ ++ // Purpur start - Enchantment convenience methods ++ public static Holder.Reference getEnchantmentHolder(ResourceKey enchantment) { ++ return net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(enchantment); ++ } ++ ++ public static int getItemEnchantmentLevel(ResourceKey enchantment, ItemStack stack) { ++ return getItemEnchantmentLevel(getEnchantmentHolder(enchantment), stack); ++ } ++ // Purpur end - Enchantment convenience methods ++ ++ // Purpur start - Add option to mend the most damaged equipment first ++ public static Optional getMostDamagedItemWith(DataComponentType componentType, LivingEntity entity) { ++ ItemStack maxStack = null; ++ EquipmentSlot maxSlot = null; ++ float maxPercent = 0.0F; ++ ++ equipmentSlotLoop: ++ for (EquipmentSlot equipmentSlot : EquipmentSlot.values()) { ++ ItemStack stack = entity.getItemBySlot(equipmentSlot); ++ ++ // do not even check enchantments for item with lower or equal damage percent ++ float percent = stack.getDamagePercent(); ++ if (percent <= maxPercent) { ++ continue; ++ } ++ ++ ItemEnchantments itemEnchantments = stack.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); ++ ++ for (Entry> entry : itemEnchantments.entrySet()) { ++ Enchantment enchantment = entry.getKey().value(); ++ ++ net.minecraft.core.component.DataComponentMap effects = enchantment.effects(); ++ if (!effects.has(componentType)) { ++ // try with another enchantment ++ continue; ++ } ++ ++ if (enchantment.matchingSlot(equipmentSlot)) { ++ maxStack = stack; ++ maxSlot = equipmentSlot; ++ maxPercent = percent; ++ ++ // check another slot now ++ continue equipmentSlotLoop; ++ } ++ } ++ } ++ ++ return maxStack != null ++ ? Optional.of(new EnchantedItemInUse(maxStack, maxSlot, entity)) ++ : Optional.empty(); ++ } ++ // Purpur end - Add option to mend the most damaged equipment first + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/enchantment/ItemEnchantments.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/enchantment/ItemEnchantments.java.patch new file mode 100644 index 000000000..acab23bbb --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/enchantment/ItemEnchantments.java.patch @@ -0,0 +1,36 @@ +--- a/net/minecraft/world/item/enchantment/ItemEnchantments.java ++++ b/net/minecraft/world/item/enchantment/ItemEnchantments.java +@@ -32,7 +_,7 @@ + private static final java.util.Comparator> ENCHANTMENT_ORDER = java.util.Comparator.comparing(Holder::getRegisteredName); + public static final ItemEnchantments EMPTY = new ItemEnchantments(new it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap<>(ENCHANTMENT_ORDER), true); + // Paper end +- private static final Codec LEVEL_CODEC = Codec.intRange(1, 255); ++ private static final Codec LEVEL_CODEC = Codec.intRange(1, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)); // Purpur - Add toggle for enchant level clamping + // Paper start - sort enchantments + private static final Codec>> LEVELS_CODEC = Codec.unboundedMap(Enchantment.CODEC, LEVEL_CODEC) + .xmap(m -> { +@@ -65,7 +_,7 @@ + + for (Entry> entry : enchantments.object2IntEntrySet()) { + int intValue = entry.getIntValue(); +- if (intValue < 0 || intValue > 255) { ++ if (intValue < 0 || intValue > (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)) { // Purpur - Add toggle for enchant level clamping + throw new IllegalArgumentException("Enchantment " + entry.getKey() + " has invalid level " + intValue); + } + } +@@ -160,13 +_,13 @@ + if (level <= 0) { + this.enchantments.removeInt(enchantment); + } else { +- this.enchantments.put(enchantment, Math.min(level, 255)); ++ this.enchantments.put(enchantment, Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767))); // Purpur - Add toggle for enchant level clamping + } + } + + public void upgrade(Holder enchantment, int level) { + if (level > 0) { +- this.enchantments.merge(enchantment, Math.min(level, 255), Integer::max); ++ this.enchantments.merge(enchantment, Math.min(level, (org.purpurmc.purpur.PurpurConfig.clampEnchantLevels ? 255 : 32767)), Integer::max); // Purpur - Add toggle for enchant level clamping + } + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch new file mode 100644 index 000000000..6a3b114a8 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch @@ -0,0 +1,16 @@ +--- a/net/minecraft/world/item/trading/MerchantOffer.java ++++ b/net/minecraft/world/item/trading/MerchantOffer.java +@@ -143,7 +_,12 @@ + } + + public void updateDemand() { +- this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962 ++ // Purpur start - Configurable minimum demand for trades ++ this.updateDemand(0); ++ } ++ public void updateDemand(int minimumDemand) { ++ this.demand = Math.max(minimumDemand, this.demand + this.uses - (this.maxUses - this.uses)); // Paper - Fix MC-163962 ++ // Purpur end - Configurable minimum demand for trades + } + + public ItemStack assemble() { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/BaseSpawner.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/BaseSpawner.java.patch new file mode 100644 index 000000000..99446bb5a --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/BaseSpawner.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/BaseSpawner.java ++++ b/net/minecraft/world/level/BaseSpawner.java +@@ -52,6 +_,7 @@ + } + + public boolean isNearPlayer(Level level, BlockPos pos) { ++ if (level.purpurConfig.spawnerDeactivateByRedstone && level.hasNeighborSignal(pos)) return false; // Purpur - Redstone deactivates spawners + return level.hasNearbyAlivePlayerThatAffectsSpawning(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, this.requiredPlayerRange); // Paper - Affects Spawning API + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/EntityGetter.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/EntityGetter.java.patch new file mode 100644 index 000000000..73e6f74b1 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/EntityGetter.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/EntityGetter.java ++++ b/net/minecraft/world/level/EntityGetter.java +@@ -185,7 +_,7 @@ + + default boolean hasNearbyAlivePlayer(double x, double y, double z, double distance) { + for (Player player : this.players()) { +- if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) { ++ if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player) && EntitySelector.notAfk.test(player)) { // Purpur - AFK API + double d = player.distanceToSqr(x, y, z); + if (distance < 0.0 || d < distance * distance) { + return true; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch new file mode 100644 index 000000000..cfd4c384e --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch @@ -0,0 +1,84 @@ +--- a/net/minecraft/world/level/Level.java ++++ b/net/minecraft/world/level/Level.java +@@ -170,6 +_,7 @@ + // Paper end - add paper world config + + public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray ++ public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - Purpur config files + public static BlockPos lastPhysicsProblem; // Spigot + private org.spigotmc.TickLimiter entityLimiter; + private org.spigotmc.TickLimiter tileLimiter; +@@ -177,6 +_,49 @@ + public final Map explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions + public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here + ++ // Purpur start - Add adjustable breeding cooldown to config ++ private com.google.common.cache.Cache playerBreedingCooldowns; ++ ++ private com.google.common.cache.Cache getNewBreedingCooldownCache() { ++ return com.google.common.cache.CacheBuilder.newBuilder().expireAfterWrite(this.purpurConfig.animalBreedingCooldownSeconds, java.util.concurrent.TimeUnit.SECONDS).build(); ++ } ++ ++ public void resetBreedingCooldowns() { ++ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); ++ } ++ ++ public boolean hasBreedingCooldown(java.util.UUID player, Class animalType) { // Purpur ++ return this.playerBreedingCooldowns.getIfPresent(new BreedingCooldownPair(player, animalType)) != null; ++ } ++ ++ public void addBreedingCooldown(java.util.UUID player, Class animalType) { ++ this.playerBreedingCooldowns.put(new BreedingCooldownPair(player, animalType), new Object()); ++ } ++ ++ private static final class BreedingCooldownPair { ++ private final java.util.UUID playerUUID; ++ private final Class animalType; ++ ++ public BreedingCooldownPair(java.util.UUID playerUUID, Class animalType) { ++ this.playerUUID = playerUUID; ++ this.animalType = animalType; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ BreedingCooldownPair that = (BreedingCooldownPair) o; ++ return playerUUID.equals(that.playerUUID) && animalType.equals(that.animalType); ++ } ++ ++ @Override ++ public int hashCode() { ++ return java.util.Objects.hash(playerUUID, animalType); ++ } ++ } ++ // Purpur end - Add adjustable breeding cooldown to config ++ + public CraftWorld getWorld() { + return this.world; + } +@@ -853,6 +_,8 @@ + // Paper end - getblock optimisations - cache world height/sections + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot + this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config ++ this.purpurConfig = new org.purpurmc.purpur.PurpurWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), env); // Purpur - Purpur config files ++ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur - Add adjustable breeding cooldown to config + this.generator = gen; + this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); + +@@ -2130,4 +_,14 @@ + return this.id; + } + } ++ ++ // Purpur start - Add allow water in end world option ++ public boolean isNether() { ++ return getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER; ++ } ++ ++ public boolean isTheEnd() { ++ return getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END; ++ } ++ // Purpur end - Add allow water in end world option + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch new file mode 100644 index 000000000..958b8eb2a --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/NaturalSpawner.java ++++ b/net/minecraft/world/level/NaturalSpawner.java +@@ -267,7 +_,7 @@ + mutableBlockPos.set(x, y, z); + double d = x + 0.5; + double d1 = z + 0.5; +- Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, false); ++ Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, level.purpurConfig.mobSpawningIgnoreCreativePlayers); // Purpur - mob spawning option to ignore creative players + if (nearestPlayer != null) { + double d2 = nearestPlayer.distanceToSqr(d, y, d1); + if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/ServerExplosion.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/ServerExplosion.java.patch new file mode 100644 index 000000000..102f56ead --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/ServerExplosion.java.patch @@ -0,0 +1,40 @@ +--- a/net/minecraft/world/level/ServerExplosion.java ++++ b/net/minecraft/world/level/ServerExplosion.java +@@ -319,7 +_,7 @@ + ) { + this.level = level; + this.source = source; +- this.radius = (float) Math.max(radius, 0.0); // CraftBukkit - clamp bad values ++ this.radius = (float) (level == null || level.purpurConfig.explosionClampRadius ? Math.max(radius, 0.0) : radius); // CraftBukkit - clamp bad values // Purpur - Config to remove explosion radius clamp + this.center = center; + this.fire = fire; + this.blockInteraction = blockInteraction; +@@ -649,10 +_,27 @@ + + public void explode() { + // CraftBukkit start +- if (this.radius < 0.1F) { ++ if ((this.level == null || this.level.purpurConfig.explosionClampRadius) && this.radius < 0.1F) { // Purpur - Config to remove explosion radius clamp + return; + } + // CraftBukkit end ++ // Purpur start - add PreExplodeEvents ++ if (this.source != null) { ++ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z); ++ if(!new org.purpurmc.purpur.event.entity.PreEntityExplodeEvent(this.source.getBukkitEntity(), location, this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, org.bukkit.craftbukkit.CraftExplosionResult.toBukkit(getBlockInteraction())).callEvent()) { ++ this.wasCanceled = true; ++ return; ++ } ++ } else { ++ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z); ++ org.bukkit.block.Block block = location.getBlock(); ++ org.bukkit.block.BlockState blockState = (this.damageSource.getDirectBlockState() != null) ? this.damageSource.getDirectBlockState() : block.getState(); ++ if(!new org.purpurmc.purpur.event.PreBlockExplodeEvent(location.getBlock(), this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, blockState, org.bukkit.craftbukkit.CraftExplosionResult.toBukkit(getBlockInteraction())).callEvent()) { ++ this.wasCanceled = true; ++ return; ++ } ++ } ++ // Purpur end - Add PreExplodeEvents + // Paper start - collision optimisations + this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>(); + this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH]; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/AnvilBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/AnvilBlock.java.patch new file mode 100644 index 000000000..7522ef907 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/AnvilBlock.java.patch @@ -0,0 +1,56 @@ +--- a/net/minecraft/world/level/block/AnvilBlock.java ++++ b/net/minecraft/world/level/block/AnvilBlock.java +@@ -59,6 +_,53 @@ + return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getClockWise()); + } + ++ // Purpur start - Anvil repair/damage options ++ @Override ++ protected net.minecraft.world.InteractionResult useItemOn(final net.minecraft.world.item.ItemStack stack, final BlockState state, final Level world, final BlockPos pos, final Player player, final net.minecraft.world.InteractionHand hand, final BlockHitResult hit) { ++ if (world.purpurConfig.anvilRepairIngotsAmount > 0 && stack.is(net.minecraft.world.item.Items.IRON_INGOT)) { ++ if (stack.getCount() < world.purpurConfig.anvilRepairIngotsAmount) { ++ // not enough iron ingots, play "error" sound and consume ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.InteractionResult.CONSUME; ++ } ++ if (state.is(Blocks.DAMAGED_ANVIL)) { ++ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); ++ } else if (state.is(Blocks.CHIPPED_ANVIL)) { ++ world.setBlock(pos, Blocks.ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); ++ } else if (state.is(Blocks.ANVIL)) { ++ // anvil is already fully repaired, play "error" sound and consume ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.InteractionResult.CONSUME; ++ } ++ if (!player.getAbilities().instabuild) { ++ stack.shrink(world.purpurConfig.anvilRepairIngotsAmount); ++ } ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_PLACE, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.InteractionResult.CONSUME; ++ } ++ if (world.purpurConfig.anvilDamageObsidianAmount > 0 && stack.is(net.minecraft.world.item.Items.OBSIDIAN)) { ++ if (stack.getCount() < world.purpurConfig.anvilDamageObsidianAmount) { ++ // not enough obsidian, play "error" sound and consume ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.InteractionResult.CONSUME; ++ } ++ if (state.is(Blocks.DAMAGED_ANVIL)) { ++ world.destroyBlock(pos, false); ++ } else if (state.is(Blocks.CHIPPED_ANVIL)) { ++ world.setBlock(pos, Blocks.DAMAGED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); ++ } else if (state.is(Blocks.ANVIL)) { ++ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3); ++ } ++ if (!player.getAbilities().instabuild) { ++ stack.shrink(world.purpurConfig.anvilDamageObsidianAmount); ++ } ++ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_LAND, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F); ++ return net.minecraft.world.InteractionResult.CONSUME; ++ } ++ return net.minecraft.world.InteractionResult.TRY_WITH_EMPTY_HAND; ++ } ++ // Purpur end - Anvil repair/damage options ++ + @Override + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + if (!level.isClientSide) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/AzaleaBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/AzaleaBlock.java.patch new file mode 100644 index 000000000..066e2cfd6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/AzaleaBlock.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/world/level/block/AzaleaBlock.java ++++ b/net/minecraft/world/level/block/AzaleaBlock.java +@@ -50,6 +_,20 @@ + + @Override + public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { ++ // Purpur start - Chance for azalea blocks to grow into trees naturally ++ growTree(level, random, pos, state); ++ } ++ ++ @Override ++ public void randomTick(net.minecraft.world.level.block.state.BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { ++ double chance = state.getBlock() == Blocks.FLOWERING_AZALEA ? world.purpurConfig.floweringAzaleaGrowthChance : world.purpurConfig.azaleaGrowthChance; ++ if (chance > 0.0D && world.getMaxLocalRawBrightness(pos.above()) > 9 && random.nextDouble() < chance) { ++ growTree(world, random, pos, state); ++ } ++ } ++ ++ private void growTree(ServerLevel level, RandomSource random, BlockPos pos, net.minecraft.world.level.block.state.BlockState state) { ++ // Purpur end - Chance for azalea blocks to grow into trees naturally + TreeGrower.AZALEA.growTree(level, level.getChunkSource().getGenerator(), pos, state, random); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java.patch new file mode 100644 index 000000000..fd6497469 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java ++++ b/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java +@@ -39,6 +_,7 @@ + } + + protected static boolean scanForWater(BlockState state, BlockGetter level, BlockPos pos) { ++ if (!((net.minecraft.world.level.LevelAccessor) level).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur - Config to not let coral die + if (state.getValue(WATERLOGGED)) { + return true; + } else { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BedBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BedBlock.java.patch new file mode 100644 index 000000000..69cb91158 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BedBlock.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/level/block/BedBlock.java ++++ b/net/minecraft/world/level/block/BedBlock.java +@@ -100,7 +_,7 @@ + } + + Vec3 center = pos.getCenter(); +- level.explode(null, level.damageSources().badRespawnPointExplosion(center), null, center, 5.0F, true, Level.ExplosionInteraction.BLOCK); ++ if (level.purpurConfig.bedExplode) level.explode(null, level.damageSources().badRespawnPointExplosion(center), null, center, (float) level.purpurConfig.bedExplosionPower, level.purpurConfig.bedExplosionFire, level.purpurConfig.bedExplosionEffect); // Purpur - Implement bed explosion options + return InteractionResult.SUCCESS_SERVER; + } else if (state.getValue(OCCUPIED)) { + if (!BedBlock.canSetSpawn(level)) return this.explodeBed(state, level, pos); // Paper - check explode first +@@ -148,7 +_,7 @@ + } + + Vec3 center = pos.getCenter(); +- level.explode(null, level.damageSources().badRespawnPointExplosion(center, blockState), null, center, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state ++ if (level.purpurConfig.bedExplode) level.explode(null, level.damageSources().badRespawnPointExplosion(center, blockState), null, center, (float) level.purpurConfig.bedExplosionPower, level.purpurConfig.bedExplosionFire, level.purpurConfig.bedExplosionEffect); // CraftBukkit - add state // Purpur - Implement bed explosion options + return InteractionResult.SUCCESS_SERVER; + } + // CraftBukkit end +@@ -169,7 +_,7 @@ + + @Override + public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) { +- super.fallOn(level, state, pos, entity, fallDistance * 0.5F); ++ super.fallOn(level, state, pos, entity, fallDistance); // Purpur - Configurable block fall damage modifiers + } + + @Override diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BigDripleafBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BigDripleafBlock.java.patch new file mode 100644 index 000000000..45532dcb8 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BigDripleafBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/BigDripleafBlock.java ++++ b/net/minecraft/world/level/block/BigDripleafBlock.java +@@ -261,7 +_,7 @@ + playTiltSound(level, pos, sound); + } + +- int _int = DELAY_UNTIL_NEXT_TILT_STATE.getInt(tilt); ++ int _int = level.purpurConfig.bigDripleafTiltDelay.getOrDefault(tilt, -1); // Purpur - Big dripleaf tilt delay + if (_int != -1) { + level.scheduleTick(pos, this, _int); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/Block.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/Block.java.patch new file mode 100644 index 000000000..7b348e9e6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/Block.java.patch @@ -0,0 +1,89 @@ +--- a/net/minecraft/world/level/block/Block.java ++++ b/net/minecraft/world/level/block/Block.java +@@ -90,6 +_,10 @@ + public static final int UPDATE_LIMIT = 512; + protected final StateDefinition stateDefinition; + private BlockState defaultBlockState; ++ // Purpur start - Configurable block fall damage modifiers ++ public float fallDamageMultiplier = 1.0F; ++ public float fallDistanceMultiplier = 1.0F; ++ // Purpur end - Configurable block fall damage modifiers + // Paper start - Protect Bedrock and End Portal/Frames from being destroyed + public final boolean isDestroyable() { + return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || +@@ -299,7 +_,7 @@ + event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping + event.callEvent(); + for (org.bukkit.inventory.ItemStack drop : event.getDrops()) { +- popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop)); ++ popResource(serverLevel, pos, applyLoreFromTile(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop), blockEntity)); // Purpur - Persistent BlockEntity Lore and DisplayName + } + state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping + block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping +@@ -317,7 +_,7 @@ + + public static void dropResources(BlockState state, LevelAccessor level, BlockPos pos, @Nullable BlockEntity blockEntity) { + if (level instanceof ServerLevel) { +- getDrops(state, (ServerLevel)level, pos, blockEntity).forEach(itemStack -> popResource((ServerLevel)level, pos, itemStack)); ++ getDrops(state, (ServerLevel)level, pos, blockEntity).forEach(itemStack -> popResource((ServerLevel)level, pos, applyLoreFromTile(itemStack, blockEntity))); // Purpur - Persistent BlockEntity Lore and DisplayName + state.spawnAfterBreak((ServerLevel)level, pos, ItemStack.EMPTY, true); + } + } +@@ -329,11 +_,30 @@ + public static void dropResources(BlockState state, Level level, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool, boolean dropExperience) { + // Paper end - Properly handle xp dropping + if (level instanceof ServerLevel) { +- getDrops(state, (ServerLevel)level, pos, blockEntity, entity, tool).forEach(itemStack -> popResource(level, pos, itemStack)); ++ getDrops(state, (ServerLevel)level, pos, blockEntity, entity, tool).forEach(itemStack -> popResource(level, pos, applyLoreFromTile(itemStack, blockEntity))); // Purpur - Persistent BlockEntity Lore and DisplayName + state.spawnAfterBreak((ServerLevel) level, pos, tool, dropExperience); // Paper - Properly handle xp dropping + } + } + ++ // Purpur start - Persistent BlockEntity Lore and DisplayName ++ private static ItemStack applyLoreFromTile(ItemStack stack, @Nullable BlockEntity blockEntity) { ++ if (stack.getItem() instanceof BlockItem) { ++ if (blockEntity != null && blockEntity.getLevel() instanceof ServerLevel) { ++ net.minecraft.world.item.component.ItemLore lore = blockEntity.getPersistentLore(); ++ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder(); ++ if (blockEntity.getLevel().purpurConfig.persistentTileEntityLore && lore != null) { ++ builder.set(net.minecraft.core.component.DataComponents.LORE, lore); ++ } ++ if (!blockEntity.getLevel().purpurConfig.persistentTileEntityDisplayName) { ++ builder.remove(net.minecraft.core.component.DataComponents.CUSTOM_NAME); ++ } ++ stack.applyComponents(builder.build()); ++ } ++ } ++ return stack; ++ } ++ // Purpur end - Persistent BlockEntity Lore and DisplayName ++ + public static void popResource(Level level, BlockPos pos, ItemStack stack) { + double d = EntityType.ITEM.getHeight() / 2.0; + double d1 = pos.getX() + 0.5 + Mth.nextDouble(level.random, -0.25, 0.25); +@@ -412,7 +_,15 @@ + } + + public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { +- } ++ this.placer = placer; // Purpur - Store placer on Block when placed ++ } ++ ++ // Purpur start - Store placer on Block when placed ++ @Nullable protected LivingEntity placer = null; ++ public void forgetPlacer() { ++ this.placer = null; ++ } ++ // Purpur end - Store placer on Block when placed + + public boolean isPossibleToRespawnInThis(BlockState state) { + return !state.isSolid() && !state.liquid(); +@@ -423,7 +_,7 @@ + } + + public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) { +- entity.causeFallDamage(fallDistance, 1.0F, entity.damageSources().fall()); ++ entity.causeFallDamage(fallDistance * fallDistanceMultiplier, fallDamageMultiplier, entity.damageSources().fall()); // Purpur - Configurable block fall damage modifiers + } + + public void updateEntityMovementAfterFallOn(BlockGetter level, Entity entity) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch new file mode 100644 index 000000000..be0a86f42 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/world/level/block/Blocks.java ++++ b/net/minecraft/world/level/block/Blocks.java +@@ -6486,6 +_,7 @@ + BlockBehaviour.Properties.of() + .mapColor(MapColor.PLANT) + .forceSolidOff() ++ .randomTicks() // Purpur - Chance for azalea blocks to grow into trees naturally + .instabreak() + .sound(SoundType.AZALEA) + .noOcclusion() +@@ -6497,6 +_,7 @@ + BlockBehaviour.Properties.of() + .mapColor(MapColor.PLANT) + .forceSolidOff() ++ .randomTicks() // Purpur - Chance for azalea blocks to grow into trees naturally + .instabreak() + .sound(SoundType.FLOWERING_AZALEA) + .noOcclusion() diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BubbleColumnBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BubbleColumnBlock.java.patch new file mode 100644 index 000000000..5b62f1261 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BubbleColumnBlock.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/world/level/block/BubbleColumnBlock.java ++++ b/net/minecraft/world/level/block/BubbleColumnBlock.java +@@ -124,10 +_,10 @@ + if (blockState.is(Blocks.BUBBLE_COLUMN)) { + return blockState; + } else if (blockState.is(Blocks.SOUL_SAND)) { +- return Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(false)); ++ return Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(org.purpurmc.purpur.PurpurConfig.soulSandBlockReverseBubbleColumnFlow)); // Purpur - Config to reverse bubble column flow + } else { + return blockState.is(Blocks.MAGMA_BLOCK) +- ? Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(true)) ++ ? Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(!org.purpurmc.purpur.PurpurConfig.magmaBlockReverseBubbleColumnFlow)) // Purpur - Config to reverse bubble column flow + : Blocks.WATER.defaultBlockState(); + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BushBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BushBlock.java.patch new file mode 100644 index 000000000..b166eb72a --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/BushBlock.java.patch @@ -0,0 +1,27 @@ +--- a/net/minecraft/world/level/block/BushBlock.java ++++ b/net/minecraft/world/level/block/BushBlock.java +@@ -61,4 +_,24 @@ + protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) { + return pathComputationType == PathComputationType.AIR && !this.hasCollision || super.isPathfindable(state, pathComputationType); + } ++ ++ // Purpur start - Ability for hoe to replant crops ++ public void playerDestroyAndReplant(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, net.minecraft.world.item.ItemStack itemInHand, net.minecraft.world.level.ItemLike itemToReplant) { ++ player.awardStat(net.minecraft.stats.Stats.BLOCK_MINED.get(this)); ++ player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); ++ java.util.List dropList = Block.getDrops(state, (net.minecraft.server.level.ServerLevel) world, pos, blockEntity, player, itemInHand); ++ ++ boolean planted = false; ++ for (net.minecraft.world.item.ItemStack itemToDrop : dropList) { ++ if (!planted && itemToDrop.getItem() == itemToReplant) { ++ world.setBlock(pos, defaultBlockState(), 3); ++ itemToDrop.setCount(itemToDrop.getCount() - 1); ++ planted = true; ++ } ++ Block.popResource(world, pos, itemToDrop); ++ } ++ ++ state.spawnAfterBreak((net.minecraft.server.level.ServerLevel) world, pos, itemInHand, true); ++ } ++ // Purpur end - Ability for hoe to replant crops + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch new file mode 100644 index 000000000..64fecea91 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch @@ -0,0 +1,55 @@ +--- a/net/minecraft/world/level/block/CactusBlock.java ++++ b/net/minecraft/world/level/block/CactusBlock.java +@@ -21,7 +_,7 @@ + import net.minecraft.world.phys.shapes.CollisionContext; + import net.minecraft.world.phys.shapes.VoxelShape; + +-public class CactusBlock extends Block { ++public class CactusBlock extends Block implements BonemealableBlock { // Purpur - bonemealable cactus + public static final MapCodec CODEC = simpleCodec(CactusBlock::new); + public static final IntegerProperty AGE = BlockStateProperties.AGE_15; + public static final int MAX_AGE = 15; +@@ -104,7 +_,7 @@ + protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { + for (Direction direction : Direction.Plane.HORIZONTAL) { + BlockState blockState = level.getBlockState(pos.relative(direction)); +- if (blockState.isSolid() || level.getFluidState(pos.relative(direction)).is(FluidTags.LAVA)) { ++ if ((level.getWorldBorder().world.purpurConfig.cactusBreaksFromSolidNeighbors && blockState.isSolid()) || level.getFluidState(pos.relative(direction)).is(FluidTags.LAVA)) { // Purpur - Cactus breaks from solid neighbors config + return false; + } + } +@@ -128,4 +_,34 @@ + protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) { + return false; + } ++ ++ // Purpur start - bonemealable cactus ++ @Override ++ public boolean isValidBonemealTarget(final LevelReader world, final BlockPos pos, final BlockState state) { ++ if (!((Level) world).purpurConfig.cactusAffectedByBonemeal || !world.isEmptyBlock(pos.above())) return false; ++ ++ int cactusHeight = 0; ++ while (world.getBlockState(pos.below(cactusHeight)).is(this)) { ++ cactusHeight++; ++ } ++ ++ return cactusHeight < ((Level) world).paperConfig().maxGrowthHeight.cactus; ++ } ++ ++ @Override ++ public boolean isBonemealSuccess(Level world, RandomSource random, BlockPos pos, BlockState state) { ++ return true; ++ } ++ ++ @Override ++ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { ++ int cactusHeight = 0; ++ while (world.getBlockState(pos.below(cactusHeight)).is(this)) { ++ cactusHeight++; ++ } ++ for (int i = 0; i <= world.paperConfig().maxGrowthHeight.cactus - cactusHeight; i++) { ++ world.setBlockAndUpdate(pos.above(i), state.setValue(CactusBlock.AGE, 0)); ++ } ++ } ++ // Purpur end - bonemealable cactus + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch new file mode 100644 index 000000000..f0b3fec97 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/CakeBlock.java ++++ b/net/minecraft/world/level/block/CakeBlock.java +@@ -119,6 +_,7 @@ + org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, 2 + oldFoodLevel); + + if (!event.isCancelled()) { ++ if (player.level().purpurConfig.playerBurpWhenFull && event.getFoodLevel() == 20 && oldFoodLevel < 20) player.burpDelay = player.level().purpurConfig.playerBurpDelay; // Purpur - Burp after eating food fills hunger bar completely + player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 0.1F); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CampfireBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CampfireBlock.java.patch new file mode 100644 index 000000000..d15f9f5a9 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CampfireBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/CampfireBlock.java ++++ b/net/minecraft/world/level/block/CampfireBlock.java +@@ -141,7 +_,7 @@ + return this.defaultBlockState() + .setValue(WATERLOGGED, Boolean.valueOf(flag)) + .setValue(SIGNAL_FIRE, Boolean.valueOf(this.isSmokeSource(level.getBlockState(clickedPos.below())))) +- .setValue(LIT, Boolean.valueOf(!flag)) ++ .setValue(LIT, Boolean.valueOf(level.getMinecraftWorld().purpurConfig.campFireLitWhenPlaced && !flag)) // Purpur - Campfire option for lit when placed + .setValue(FACING, context.getHorizontalDirection()); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch new file mode 100644 index 000000000..ba95ddd13 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CarvedPumpkinBlock.java.patch @@ -0,0 +1,36 @@ +--- a/net/minecraft/world/level/block/CarvedPumpkinBlock.java ++++ b/net/minecraft/world/level/block/CarvedPumpkinBlock.java +@@ -64,7 +_,7 @@ + if (blockPatternMatch != null) { + SnowGolem snowGolem = EntityType.SNOW_GOLEM.create(level, EntitySpawnReason.TRIGGERED); + if (snowGolem != null) { +- spawnGolemInWorld(level, blockPatternMatch, snowGolem, blockPatternMatch.getBlock(0, 2, 0).getPos()); ++ spawnGolemInWorld(level, blockPatternMatch, snowGolem, blockPatternMatch.getBlock(0, 2, 0).getPos(), this.placer); // Purpur - Summoner API + } + } else { + BlockPattern.BlockPatternMatch blockPatternMatch1 = this.getOrCreateIronGolemFull().find(level, pos); +@@ -72,13 +_,23 @@ + IronGolem ironGolem = EntityType.IRON_GOLEM.create(level, EntitySpawnReason.TRIGGERED); + if (ironGolem != null) { + ironGolem.setPlayerCreated(true); +- spawnGolemInWorld(level, blockPatternMatch1, ironGolem, blockPatternMatch1.getBlock(1, 2, 0).getPos()); ++ spawnGolemInWorld(level, blockPatternMatch1, ironGolem, blockPatternMatch1.getBlock(1, 2, 0).getPos(), this.placer); // Purpur - Summoner API + } + } + } + } + + private static void spawnGolemInWorld(Level level, BlockPattern.BlockPatternMatch patternMatch, Entity golem, BlockPos pos) { ++ // Purpur start - Summoner API ++ spawnGolemInWorld(level, patternMatch, golem, pos, null); ++ } ++ private static void spawnGolemInWorld(Level level, BlockPattern.BlockPatternMatch patternMatch, Entity golem, BlockPos pos, net.minecraft.world.entity.LivingEntity placer) { ++ if (golem instanceof SnowGolem snowGolem) { ++ snowGolem.setSummoner(placer == null ? null : placer.getUUID()); ++ } else if (golem instanceof IronGolem ironGolem) { ++ ironGolem.setSummoner(placer == null ? null : placer.getUUID()); ++ } ++ // Purpur end - Summoner API + // clearPatternBlocks(level, patternMatch); // CraftBukkit - moved down + golem.moveTo(pos.getX() + 0.5, pos.getY() + 0.05, pos.getZ() + 0.5, 0.0F, 0.0F); + if (!level.addFreshEntity(golem, (golem.getType() == EntityType.SNOW_GOLEM) ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM)) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CauldronBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CauldronBlock.java.patch new file mode 100644 index 000000000..6ead2196b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CauldronBlock.java.patch @@ -0,0 +1,13 @@ +--- a/net/minecraft/world/level/block/CauldronBlock.java ++++ b/net/minecraft/world/level/block/CauldronBlock.java +@@ -32,8 +_,8 @@ + + protected static boolean shouldHandlePrecipitation(Level level, Biome.Precipitation precipitation) { + return precipitation == Biome.Precipitation.RAIN +- ? level.getRandom().nextFloat() < 0.05F +- : precipitation == Biome.Precipitation.SNOW && level.getRandom().nextFloat() < 0.1F; ++ ? level.getRandom().nextFloat() < level.purpurConfig.cauldronRainChance // Purpur - Cauldron fill chances ++ : precipitation == Biome.Precipitation.SNOW && level.getRandom().nextFloat() < level.purpurConfig.cauldronPowderSnowChance; // Purpur - Cauldron fill chances + } + + @Override diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CaveVinesBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CaveVinesBlock.java.patch new file mode 100644 index 000000000..829a79ee6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CaveVinesBlock.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/level/block/CaveVinesBlock.java ++++ b/net/minecraft/world/level/block/CaveVinesBlock.java +@@ -92,4 +_,11 @@ + public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { + level.setBlock(pos, state.setValue(BERRIES, Boolean.valueOf(true)), 2); + } ++ ++ // Purpur start - cave vines configurable max growth age ++ @Override ++ public int getMaxGrowthAge() { ++ return org.purpurmc.purpur.PurpurConfig.caveVinesMaxGrowthAge; ++ } ++ // Purpur end - cave vines configurable max growth age + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ChangeOverTimeBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ChangeOverTimeBlock.java.patch new file mode 100644 index 000000000..54d2fa463 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ChangeOverTimeBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/ChangeOverTimeBlock.java ++++ b/net/minecraft/world/level/block/ChangeOverTimeBlock.java +@@ -51,7 +_,7 @@ + } + + float f = (float)(i1 + 1) / (i1 + i + 1); +- float f1 = f * f * this.getChanceModifier(); ++ float f1 = level.purpurConfig.disableOxidationProximityPenalty ? this.getChanceModifier() :f * f * this.getChanceModifier();// Purpur - option to disable the copper oxidation proximity penalty + return random.nextFloat() < f1 ? this.getNext(state) : Optional.empty(); + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch new file mode 100644 index 000000000..c2e63ab56 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/ChestBlock.java ++++ b/net/minecraft/world/level/block/ChestBlock.java +@@ -357,6 +_,7 @@ + } + + public static boolean isBlockedChestByBlock(BlockGetter level, BlockPos pos) { ++ if (level instanceof Level level1 && level1.purpurConfig.chestOpenWithBlockOnTop) return false; // Purpur - Option for chests to open even with a solid block on top + BlockPos blockPos = pos.above(); + return level.getBlockState(blockPos).isRedstoneConductor(level, blockPos); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch new file mode 100644 index 000000000..2be94eb48 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch @@ -0,0 +1,66 @@ +--- a/net/minecraft/world/level/block/ComposterBlock.java ++++ b/net/minecraft/world/level/block/ComposterBlock.java +@@ -241,23 +_,52 @@ + ) { + int levelValue = state.getValue(LEVEL); + if (levelValue < 8 && COMPOSTABLES.containsKey(stack.getItem())) { +- if (levelValue < 7 && !level.isClientSide) { +- BlockState blockState = addItem(player, state, level, pos, stack); +- // Paper start - handle cancelled events +- if (blockState == null) { +- return InteractionResult.PASS; +- } +- // Paper end +- level.levelEvent(1500, pos, state != blockState ? 1 : 0); +- player.awardStat(Stats.ITEM_USED.get(stack.getItem())); +- stack.consume(1, player); +- } ++ // Purpur start - sneak to bulk process composter ++ BlockState newState = process(levelValue, player, state, level, pos, stack); ++ if (newState == null) { ++ return InteractionResult.PASS; ++ } ++ if (level.purpurConfig.composterBulkProcess && player.isShiftKeyDown() && newState != state) { ++ BlockState oldState; ++ int oldCount, newCount, oldLevel, newLevel; ++ do { ++ oldState = newState; ++ oldCount = stack.getCount(); ++ oldLevel = oldState.getValue(ComposterBlock.LEVEL); ++ newState = process(oldLevel, player, oldState, level, pos, stack); ++ if (newState == null) { ++ return InteractionResult.PASS; ++ } ++ newCount = stack.getCount(); ++ newLevel = newState.getValue(ComposterBlock.LEVEL); ++ } while (newCount > 0 && (newCount != oldCount || newLevel != oldLevel || newState != oldState)); ++ } ++ // Purpur end - Sneak to bulk process composter + + return InteractionResult.SUCCESS; + } else { + return super.useItemOn(stack, state, level, pos, player, hand, hitResult); + } + } ++ ++ // Purpur start - sneak to bulk process composter ++ private static @Nullable BlockState process(int levelValue, Player player, BlockState state, Level level, BlockPos pos, ItemStack stack) { ++ if (levelValue < 7 && !level.isClientSide) { ++ BlockState iblockdata1 = ComposterBlock.addItem(player, state, level, pos, stack); ++ // Paper start - handle cancelled events ++ if (iblockdata1 == null) { ++ return null; ++ } ++ // Paper end ++ ++ level.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0); ++ player.awardStat(Stats.ITEM_USED.get(stack.getItem())); ++ stack.consume(1, player); ++ return iblockdata1; ++ } ++ return state; ++ } ++ // Purpur end - Sneak to bulk process composter + + @Override + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CoralBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CoralBlock.java.patch new file mode 100644 index 000000000..690cfe031 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CoralBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/CoralBlock.java ++++ b/net/minecraft/world/level/block/CoralBlock.java +@@ -65,6 +_,7 @@ + } + + protected boolean scanForWater(BlockGetter level, BlockPos pos) { ++ if (!((net.minecraft.world.level.LevelAccessor) level).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur - Config to not let coral die + for (Direction direction : Direction.values()) { + FluidState fluidState = level.getFluidState(pos.relative(direction)); + if (fluidState.is(FluidTags.WATER)) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CropBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CropBlock.java.patch new file mode 100644 index 000000000..f1bbca32a --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/CropBlock.java.patch @@ -0,0 +1,27 @@ +--- a/net/minecraft/world/level/block/CropBlock.java ++++ b/net/minecraft/world/level/block/CropBlock.java +@@ -182,7 +_,7 @@ + @Override + protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent +- if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit ++ if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.purpurConfig.ravagerGriefableBlocks.contains(serverLevel.getBlockState(pos).getBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Purpur - Configurable ravager griefable blocks list + serverLevel.destroyBlock(pos, true, entity); + } + +@@ -217,4 +_,15 @@ + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(AGE); + } ++ ++ // Purpur start - Ability for hoe to replant crops ++ @Override ++ public void playerDestroy(Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) { ++ if (world.purpurConfig.hoeReplantsCrops && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) { ++ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, getBaseSeedId()); ++ } else { ++ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp); ++ } ++ } ++ // Purpur end - Ability for hoe to replant crops + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/DoorBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/DoorBlock.java.patch new file mode 100644 index 000000000..e2733acaa --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/DoorBlock.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/level/block/DoorBlock.java ++++ b/net/minecraft/world/level/block/DoorBlock.java +@@ -206,6 +_,7 @@ + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + if (!this.type.canOpenByHand()) { + return InteractionResult.PASS; ++ } else if (requiresRedstone(level, state, pos)) { return InteractionResult.CONSUME; // Purpur - Option to make doors require redstone + } else { + state = state.cycle(OPEN); + level.setBlock(pos, state, 10); +@@ -294,4 +_,18 @@ + public static boolean isWoodenDoor(BlockState state) { + return state.getBlock() instanceof DoorBlock doorBlock && doorBlock.type().canOpenByHand(); + } ++ ++ // Purpur start - Option to make doors require redstone ++ public static boolean requiresRedstone(Level level, BlockState state, BlockPos pos) { ++ if (level.purpurConfig.doorRequiresRedstone.contains(state.getBlock())) { ++ // force update client ++ BlockPos otherPos = pos.relative(state.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN); ++ BlockState otherState = level.getBlockState(otherPos); ++ level.sendBlockUpdated(pos, state, state, 3); ++ level.sendBlockUpdated(otherPos, otherState, otherState, 3); ++ return true; ++ } ++ return false; ++ } ++ // Purpur end - Option to make doors require redstone + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/DragonEggBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/DragonEggBlock.java.patch new file mode 100644 index 000000000..d08f61da6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/DragonEggBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/DragonEggBlock.java ++++ b/net/minecraft/world/level/block/DragonEggBlock.java +@@ -46,6 +_,7 @@ + } + + private void teleport(BlockState state, Level level, BlockPos pos) { ++ if (!level.purpurConfig.dragonEggTeleport) return; // Purpur - Option to disable dragon egg teleporting + WorldBorder worldBorder = level.getWorldBorder(); + + for (int i = 0; i < 1000; i++) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/EnchantingTableBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/EnchantingTableBlock.java.patch new file mode 100644 index 000000000..6610cced4 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/EnchantingTableBlock.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/world/level/block/EnchantingTableBlock.java ++++ b/net/minecraft/world/level/block/EnchantingTableBlock.java +@@ -119,4 +_,18 @@ + protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) { + return false; + } ++ ++ // Purpur start - Enchantment Table Persists Lapis ++ @Override ++ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean moved) { ++ BlockEntity blockEntity = level.getBlockEntity(pos); ++ ++ if (level.purpurConfig.enchantmentTableLapisPersists && blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) { ++ net.minecraft.world.Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.LAPIS_LAZULI, enchantmentTable.getLapis())); ++ level.updateNeighbourForOutputSignal(pos, this); ++ } ++ ++ super.onRemove(state, level, pos, newState, moved); ++ } ++ // Purpur end - Enchantment Table Persists Lapis + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/FarmBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/FarmBlock.java.patch new file mode 100644 index 000000000..7f0aa19b6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/FarmBlock.java.patch @@ -0,0 +1,48 @@ +--- a/net/minecraft/world/level/block/FarmBlock.java ++++ b/net/minecraft/world/level/block/FarmBlock.java +@@ -112,7 +_,7 @@ + public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) { + super.fallOn(level, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage. + if (level instanceof ServerLevel serverLevel +- && level.random.nextFloat() < fallDistance - 0.5F ++ && (serverLevel.purpurConfig.farmlandTrampleHeight >= 0D ? fallDistance >= serverLevel.purpurConfig.farmlandTrampleHeight : level.random.nextFloat() < fallDistance - 0.5F) // // Purpur - Configurable farmland trample height + && entity instanceof LivingEntity + && (entity instanceof Player || serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) + && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { +@@ -129,6 +_,27 @@ + return; + } + ++ if (level.purpurConfig.farmlandTramplingDisabled) return; // Purpur - Farmland trampling changes ++ if (level.purpurConfig.farmlandTramplingOnlyPlayers && !(entity instanceof Player)) return; // Purpur - Farmland trampling changes ++ ++ // Purpur start - Ability to re-add farmland mechanics from Alpha ++ if (level.purpurConfig.farmlandAlpha) { ++ Block block = level.getBlockState(pos.below()).getBlock(); ++ if (block instanceof FenceBlock || block instanceof WallBlock) { ++ return; ++ } ++ } ++ // Purpur end - Ability to re-add farmland mechanics from Alpha ++ ++ // Purpur start - Farmland trampling changes ++ if (level.purpurConfig.farmlandTramplingFeatherFalling) { ++ java.util.Iterator armor = ((LivingEntity) entity).getArmorSlots().iterator(); ++ if (armor.hasNext() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) >= (int) entity.fallDistance) { ++ return; ++ } ++ } ++ // Purpur end - Farmland trampling changes ++ + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.DIRT.defaultBlockState())) { + return; + } +@@ -174,7 +_,7 @@ + } + } + +- return false; ++ return ((ServerLevel) level).purpurConfig.farmlandGetsMoistFromBelow && level.getFluidState(pos.relative(Direction.DOWN)).is(FluidTags.WATER); // Purpur - Allow soil to moisten from water directly under it + // Paper end - Perf: remove abstract block iteration + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/GrowingPlantHeadBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/GrowingPlantHeadBlock.java.patch new file mode 100644 index 000000000..f9b8e4aac --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/GrowingPlantHeadBlock.java.patch @@ -0,0 +1,63 @@ +--- a/net/minecraft/world/level/block/GrowingPlantHeadBlock.java ++++ b/net/minecraft/world/level/block/GrowingPlantHeadBlock.java +@@ -34,12 +_,12 @@ + + @Override + public BlockState getStateForPlacement(RandomSource random) { +- return this.defaultBlockState().setValue(AGE, Integer.valueOf(random.nextInt(25))); ++ return this.defaultBlockState().setValue(AGE, Integer.valueOf(random.nextInt(getMaxGrowthAge()))); // Purpur - kelp, cave, weeping, and twisting configurable max growth age + } + + @Override + protected boolean isRandomlyTicking(BlockState state) { +- return state.getValue(AGE) < 25; ++ return state.getValue(AGE) < getMaxGrowthAge(); // Purpur - kelp, cave, weeping, and twisting configurable max growth age + } + + @Override +@@ -55,7 +_,7 @@ + } else if (this == Blocks.CAVE_VINES) { + modifier = level.spigotConfig.caveVinesModifier; + } +- if (state.getValue(AGE) < 25 && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution ++ if (state.getValue(AGE) < getMaxGrowthAge() && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution // Purpur - kelp, cave, weeping, and twisting configurable max growth age + // Spigot end + BlockPos blockPos = pos.relative(this.growthDirection); + if (this.canGrowInto(level.getBlockState(blockPos))) { +@@ -75,11 +_,11 @@ + } + + public BlockState getMaxAgeState(BlockState state) { +- return state.setValue(AGE, Integer.valueOf(25)); ++ return state.setValue(AGE, Integer.valueOf(getMaxGrowthAge())); // Purpur - kelp, cave, weeping, and twisting configurable max growth age + } + + public boolean isMaxAge(BlockState state) { +- return state.getValue(AGE) == 25; ++ return state.getValue(AGE) >= getMaxGrowthAge(); // Purpur - kelp, cave, weeping, and twisting configurable max growth age + } + + protected BlockState updateBodyAfterConvertedFromHead(BlockState head, BlockState body) { +@@ -130,13 +_,13 @@ + @Override + public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { + BlockPos blockPos = pos.relative(this.growthDirection); +- int min = Math.min(state.getValue(AGE) + 1, 25); ++ int min = Math.min(state.getValue(AGE) + 1, getMaxGrowthAge()); // Purpur - kelp, cave, weeping, and twisting configurable max growth age + int blocksToGrowWhenBonemealed = this.getBlocksToGrowWhenBonemealed(random); + + for (int i = 0; i < blocksToGrowWhenBonemealed && this.canGrowInto(level.getBlockState(blockPos)); i++) { + level.setBlockAndUpdate(blockPos, state.setValue(AGE, Integer.valueOf(min))); + blockPos = blockPos.relative(this.growthDirection); +- min = Math.min(min + 1, 25); ++ min = Math.min(min + 1, getMaxGrowthAge()); // Purpur - kelp, cave, weeping, and twisting configurable max growth age + } + } + +@@ -148,4 +_,6 @@ + protected GrowingPlantHeadBlock getHeadBlock() { + return this; + } ++ ++ public abstract int getMaxGrowthAge(); // Purpur - kelp, cave, weeping, and twisting configurable max growth age + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/HayBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/HayBlock.java.patch new file mode 100644 index 000000000..d8013d2da --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/HayBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/HayBlock.java ++++ b/net/minecraft/world/level/block/HayBlock.java +@@ -23,6 +_,6 @@ + + @Override + public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) { +- entity.causeFallDamage(fallDistance, 0.2F, level.damageSources().fall()); ++ super.fallOn(level, state, pos, entity, fallDistance); // Purpur - Configurable block fall damage modifiers + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/IceBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/IceBlock.java.patch new file mode 100644 index 000000000..0f5251d57 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/IceBlock.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/level/block/IceBlock.java ++++ b/net/minecraft/world/level/block/IceBlock.java +@@ -40,7 +_,7 @@ + public void afterDestroy(Level level, BlockPos pos, ItemStack stack) { + // Paper end - Improve Block#breakNaturally API + if (!EnchantmentHelper.hasTag(stack, EnchantmentTags.PREVENTS_ICE_MELTING)) { +- if (level.dimensionType().ultraWarm()) { ++ if (level.isNether() || (level.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur - Add allow water in end world option + level.removeBlock(pos, false); + return; + } +@@ -65,7 +_,7 @@ + return; + } + // CraftBukkit end +- if (level.dimensionType().ultraWarm()) { ++ if (level.isNether() || (level.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur - Add allow water in end world option + level.removeBlock(pos, false); + } else { + level.setBlockAndUpdate(pos, meltsInto()); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/KelpBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/KelpBlock.java.patch new file mode 100644 index 000000000..b0ce9ac1a --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/KelpBlock.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/level/block/KelpBlock.java ++++ b/net/minecraft/world/level/block/KelpBlock.java +@@ -72,4 +_,11 @@ + protected FluidState getFluidState(BlockState state) { + return Fluids.WATER.getSource(false); + } ++ ++ // Purpur start - kelp vines configurable max growth age ++ @Override ++ public int getMaxGrowthAge() { ++ return org.purpurmc.purpur.PurpurConfig.kelpMaxGrowthAge; ++ } ++ // Purpur end - kelp vines configurable max growth age + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/LiquidBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/LiquidBlock.java.patch new file mode 100644 index 000000000..ef0559942 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/LiquidBlock.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/level/block/LiquidBlock.java ++++ b/net/minecraft/world/level/block/LiquidBlock.java +@@ -134,7 +_,7 @@ + + @Override + protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) { +- if (this.shouldSpreadLiquid(level, pos, state)) { ++ if (level.purpurConfig.tickFluids && this.shouldSpreadLiquid(level, pos, state)) { // Purpur - Tick fluids config + level.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(level, pos)); // Paper - Configurable speed for water flowing over lava + } + } +@@ -169,7 +_,7 @@ + BlockState neighborState, + RandomSource random + ) { +- if (state.getFluidState().isSource() || neighborState.getFluidState().isSource()) { ++ if (level.getWorldBorder().world.purpurConfig.tickFluids && state.getFluidState().isSource() || neighborState.getFluidState().isSource()) { // Purpur - Tick fluids config + scheduledTickAccess.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(level)); + } + +@@ -178,7 +_,7 @@ + + @Override + protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { +- if (this.shouldSpreadLiquid(level, pos, state)) { ++ if (level.purpurConfig.tickFluids && this.shouldSpreadLiquid(level, pos, state)) { // Purpur - Tick fluids config + level.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(level, pos)); // Paper - Configurable speed for water flowing over lava + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/MagmaBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/MagmaBlock.java.patch new file mode 100644 index 000000000..52ccc7277 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/MagmaBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/MagmaBlock.java ++++ b/net/minecraft/world/level/block/MagmaBlock.java +@@ -28,7 +_,7 @@ + + @Override + public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) { +- if (!entity.isSteppingCarefully() && entity instanceof LivingEntity) { ++ if ((!entity.isSteppingCarefully() || level.purpurConfig.magmaBlockDamageWhenSneaking) && entity instanceof LivingEntity) { // Purpur - Configurable damage settings for magma blocks + entity.hurt(level.damageSources().hotFloor().directBlock(level, pos), 1.0F); // CraftBukkit + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch new file mode 100644 index 000000000..282b160de --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/level/block/NetherPortalBlock.java ++++ b/net/minecraft/world/level/block/NetherPortalBlock.java +@@ -72,7 +_,7 @@ + protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + if (level.spigotConfig.enableZombiePigmenPortalSpawns && level.dimensionType().natural() // Spigot + && level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) +- && random.nextInt(2000) < level.getDifficulty().getId()) { ++ && random.nextInt(level.purpurConfig.piglinPortalSpawnModifier) < level.getDifficulty().getId()) { // Purpur - Piglin portal spawn modifier + while (level.getBlockState(pos).is(this)) { + pos = pos.below(); + } +@@ -129,7 +_,7 @@ + @Override + public int getPortalTransitionTime(ServerLevel level, Entity entity) { + return entity instanceof Player player +- ? Math.max( ++ ? player.canPortalInstant ? 1 : Math.max( // Purpur - Add portal permission bypass + 0, + level.getGameRules() + .getInt( diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NetherWartBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NetherWartBlock.java.patch new file mode 100644 index 000000000..95b1bb2c1 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NetherWartBlock.java.patch @@ -0,0 +1,46 @@ +--- a/net/minecraft/world/level/block/NetherWartBlock.java ++++ b/net/minecraft/world/level/block/NetherWartBlock.java +@@ -16,7 +_,7 @@ + import net.minecraft.world.phys.shapes.CollisionContext; + import net.minecraft.world.phys.shapes.VoxelShape; + +-public class NetherWartBlock extends BushBlock { ++public class NetherWartBlock extends BushBlock implements BonemealableBlock { // Purpur - bonemealable netherwart + public static final MapCodec CODEC = simpleCodec(NetherWartBlock::new); + public static final int MAX_AGE = 3; + public static final IntegerProperty AGE = BlockStateProperties.AGE_3; +@@ -70,4 +_,34 @@ + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(AGE); + } ++ ++ // Purpur start - Ability for hoe to replant nether warts ++ @Override ++ public void playerDestroy(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) { ++ if (world.purpurConfig.hoeReplantsNetherWarts && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) { ++ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, Items.NETHER_WART); ++ } else { ++ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp); ++ } ++ } ++ // Purpur end - Ability for hoe to replant nether warts ++ ++ // Purpur start - bonemealable netherwart ++ @Override ++ public boolean isValidBonemealTarget(final net.minecraft.world.level.LevelReader world, final BlockPos pos, final BlockState state) { ++ return ((net.minecraft.world.level.Level) world).purpurConfig.netherWartAffectedByBonemeal && state.getValue(NetherWartBlock.AGE) < 3; ++ } ++ ++ @Override ++ public boolean isBonemealSuccess(net.minecraft.world.level.Level world, RandomSource random, BlockPos pos, BlockState state) { ++ return true; ++ } ++ ++ @Override ++ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { ++ int i = Math.min(3, state.getValue(NetherWartBlock.AGE) + 1); ++ state = state.setValue(NetherWartBlock.AGE, i); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, state, 2); // CraftBukkit ++ } ++ // Purpur end - bonemealable netherwart + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch new file mode 100644 index 000000000..b9260673f --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/NoteBlock.java ++++ b/net/minecraft/world/level/block/NoteBlock.java +@@ -107,7 +_,7 @@ + } + + private void playNote(@Nullable Entity entity, BlockState state, Level level, BlockPos pos) { +- if (state.getValue(INSTRUMENT).worksAboveNoteBlock() || level.getBlockState(pos.above()).isAir()) { ++ if (level.purpurConfig.noteBlockIgnoreAbove || state.getValue(INSTRUMENT).worksAboveNoteBlock() || level.getBlockState(pos.above()).isAir()) { // Purpur - Config to allow Note Block sounds when blocked + level.blockEvent(pos, this, 0, 0); + level.gameEvent(entity, GameEvent.NOTE_BLOCK_PLAY, pos); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ObserverBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ObserverBlock.java.patch new file mode 100644 index 000000000..3202a8cee --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/ObserverBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/ObserverBlock.java ++++ b/net/minecraft/world/level/block/ObserverBlock.java +@@ -81,6 +_,7 @@ + RandomSource random + ) { + if (state.getValue(FACING) == direction && !state.getValue(POWERED)) { ++ if (!level.getWorldBorder().world.purpurConfig.disableObserverClocks || !(neighborState.getBlock() instanceof ObserverBlock) || neighborState.getValue(ObserverBlock.FACING).getOpposite() != direction) // Purpur - Add Option for disable observer clocks + this.startSignal(level, scheduledTickAccess, pos); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch new file mode 100644 index 000000000..853ec1c3a --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch @@ -0,0 +1,26 @@ +--- a/net/minecraft/world/level/block/PointedDripstoneBlock.java ++++ b/net/minecraft/world/level/block/PointedDripstoneBlock.java +@@ -197,20 +_,20 @@ + + @VisibleForTesting + public static void maybeTransferFluid(BlockState state, ServerLevel level, BlockPos pos, float randChance) { +- if (!(randChance > 0.17578125F) || !(randChance > 0.05859375F)) { ++ if (!(randChance > level.purpurConfig.cauldronDripstoneWaterFillChance) || !(randChance > level.purpurConfig.cauldronDripstoneLavaFillChance)) { // Purpur - Cauldron fill chances + if (isStalactiteStartPos(state, level, pos)) { + Optional fluidAboveStalactite = getFluidAboveStalactite(level, pos, state); + if (!fluidAboveStalactite.isEmpty()) { + Fluid fluid = fluidAboveStalactite.get().fluid; + float f; + if (fluid == Fluids.WATER) { +- f = 0.17578125F; ++ f = level.purpurConfig.cauldronDripstoneWaterFillChance; // Purpur - Cauldron fill chances + } else { + if (fluid != Fluids.LAVA) { + return; + } + +- f = 0.05859375F; ++ f = level.purpurConfig.cauldronDripstoneLavaFillChance; // Purpur - Cauldron fill chances + } + + if (!(randChance >= f)) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch new file mode 100644 index 000000000..2b31f8cfb --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/PoweredRailBlock.java ++++ b/net/minecraft/world/level/block/PoweredRailBlock.java +@@ -34,7 +_,7 @@ + } + + protected boolean findPoweredRailSignal(Level level, BlockPos pos, BlockState state, boolean searchForward, int recursionCount) { +- if (recursionCount >= 8) { ++ if (recursionCount >= level.purpurConfig.railActivationRange) { // Purpur - Config for powered rail activation distance + return false; + } else { + int x = pos.getX(); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch new file mode 100644 index 000000000..d8a78eb77 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/RespawnAnchorBlock.java ++++ b/net/minecraft/world/level/block/RespawnAnchorBlock.java +@@ -159,7 +_,7 @@ + }; + Vec3 center = pos2.getCenter(); + level.explode( +- null, level.damageSources().badRespawnPointExplosion(center, blockState), explosionDamageCalculator, center, 5.0F, true, Level.ExplosionInteraction.BLOCK // CraftBukkit - add state ++ null, level.damageSources().badRespawnPointExplosion(center, blockState), explosionDamageCalculator, center, (float) level.purpurConfig.respawnAnchorExplosionPower, level.purpurConfig.respawnAnchorExplosionFire, level.purpurConfig.respawnAnchorExplosionEffect // CraftBukkit - add state // Purpur - Implement respawn anchor explosion options + ); + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SculkShriekerBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SculkShriekerBlock.java.patch new file mode 100644 index 000000000..db79f0f16 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SculkShriekerBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/SculkShriekerBlock.java ++++ b/net/minecraft/world/level/block/SculkShriekerBlock.java +@@ -134,7 +_,7 @@ + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return this.defaultBlockState() +- .setValue(WATERLOGGED, Boolean.valueOf(context.getLevel().getFluidState(context.getClickedPos()).getType() == Fluids.WATER)); ++ .setValue(WATERLOGGED, Boolean.valueOf(context.getLevel().getFluidState(context.getClickedPos()).getType() == Fluids.WATER)).setValue(SculkShriekerBlock.CAN_SUMMON, context.getLevel().purpurConfig.sculkShriekerCanSummonDefault); // Purpur - Config for sculk shrieker can_summon state + } + + @Override diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SlabBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SlabBlock.java.patch new file mode 100644 index 000000000..ec93007cc --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SlabBlock.java.patch @@ -0,0 +1,28 @@ +--- a/net/minecraft/world/level/block/SlabBlock.java ++++ b/net/minecraft/world/level/block/SlabBlock.java +@@ -150,4 +_,25 @@ + return false; + } + } ++ ++ // Purpur start - Break individual slabs when sneaking ++ public boolean halfBreak(BlockState state, BlockPos pos, net.minecraft.server.level.ServerPlayer player) { ++ if (state.getValue(SlabBlock.TYPE) != SlabType.DOUBLE) { ++ return false; ++ } ++ net.minecraft.world.phys.HitResult result = player.getRayTrace(16, net.minecraft.world.level.ClipContext.Fluid.NONE); ++ if (result.getType() != net.minecraft.world.phys.HitResult.Type.BLOCK) { ++ return false; ++ } ++ double hitY = result.getLocation().y(); ++ int blockY = org.bukkit.util.NumberConversions.floor(hitY); ++ player.level().setBlock(pos, state.setValue(SlabBlock.TYPE, (hitY - blockY > 0.5 || blockY - pos.getY() == 1) ? SlabType.BOTTOM : SlabType.TOP), 3); ++ if (!player.getAbilities().instabuild) { ++ net.minecraft.world.entity.item.ItemEntity item = new net.minecraft.world.entity.item.ItemEntity(player.level(), pos.getX(), pos.getY(), pos.getZ(), new ItemStack(asItem())); ++ item.setDefaultPickUpDelay(); ++ player.level().addFreshEntity(item); ++ } ++ return true; ++ } ++ // Purpur end - Break individual slabs when sneaking + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SnowLayerBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SnowLayerBlock.java.patch new file mode 100644 index 000000000..f6406d510 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SnowLayerBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/SnowLayerBlock.java ++++ b/net/minecraft/world/level/block/SnowLayerBlock.java +@@ -96,6 +_,7 @@ + @Override + protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { + BlockState blockState = level.getBlockState(pos.below()); ++ if (blockState.is(Blocks.BLUE_ICE) && !level.getWorldBorder().world.purpurConfig.snowOnBlueIce) return false; // Purpur - Add config for snow on blue ice + return !blockState.is(BlockTags.SNOW_LAYER_CANNOT_SURVIVE_ON) + && ( + blockState.is(BlockTags.SNOW_LAYER_CAN_SURVIVE_ON) diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SpawnerBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SpawnerBlock.java.patch new file mode 100644 index 000000000..cf68daf1b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SpawnerBlock.java.patch @@ -0,0 +1,68 @@ +--- a/net/minecraft/world/level/block/SpawnerBlock.java ++++ b/net/minecraft/world/level/block/SpawnerBlock.java +@@ -43,6 +_,57 @@ + ); + } + ++ // Purpur start - Silk touch spawners ++ @Override ++ public void playerDestroy(Level level, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) { ++ if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.drop.spawners") && isSilkTouch(level, stack)) { ++ ItemStack item = new ItemStack(Blocks.SPAWNER.asItem()); ++ ++ net.minecraft.world.level.SpawnData nextSpawnData = blockEntity instanceof SpawnerBlockEntity spawnerBlock ? spawnerBlock.getSpawner().nextSpawnData : null; ++ java.util.Optional> type = java.util.Optional.empty(); ++ if (nextSpawnData != null) { ++ type = net.minecraft.world.entity.EntityType.by(nextSpawnData.getEntityToSpawn()); ++ net.minecraft.world.level.SpawnData.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, nextSpawnData).result().ifPresent(tag -> item.set(net.minecraft.core.component.DataComponents.CUSTOM_DATA, net.minecraft.world.item.component.CustomData.EMPTY.update(compoundTag -> compoundTag.put("Purpur.SpawnData", tag)))); ++ } ++ ++ if (type.isPresent()) { ++ final net.kyori.adventure.text.Component mobName = io.papermc.paper.adventure.PaperAdventure.asAdventure(type.get().getDescription()); ++ ++ String name = level.purpurConfig.silkTouchSpawnerName; ++ if (name != null && !name.isEmpty() && !name.equals("Monster Spawner")) { ++ net.kyori.adventure.text.Component displayName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName)); ++ if (name.startsWith("")) { ++ displayName = displayName.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); ++ } ++ item.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName)); ++ } ++ ++ List lore = level.purpurConfig.silkTouchSpawnerLore; ++ if (lore != null && !lore.isEmpty()) { ++ ++ List loreComponentList = new java.util.ArrayList<>(); ++ for (String line : lore) { ++ net.kyori.adventure.text.Component lineComponent = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(line, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName)); ++ if (line.startsWith("")) { ++ lineComponent = lineComponent.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false); ++ } ++ loreComponentList.add(io.papermc.paper.adventure.PaperAdventure.asVanilla(lineComponent)); ++ } ++ ++ item.set(net.minecraft.core.component.DataComponents.LORE, new net.minecraft.world.item.component.ItemLore(loreComponentList, loreComponentList)); ++ } ++ item.set(net.minecraft.core.component.DataComponents.HIDE_ADDITIONAL_TOOLTIP, net.minecraft.util.Unit.INSTANCE); ++ } ++ popResource(level, pos, item); ++ } ++ super.playerDestroy(level, player, pos, state, blockEntity, stack, includeDrops, dropExp); ++ } ++ ++ private boolean isSilkTouch(Level level, ItemStack stack) { ++ return stack != null && level.purpurConfig.silkTouchTools.contains(stack.getItem()) && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.SILK_TOUCH, stack) >= level.purpurConfig.minimumSilkTouchSpawnerRequire; ++ } ++ // Purpur end - Silk touch spawners ++ + @Override + protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { + super.spawnAfterBreak(state, level, pos, stack, dropExperience); +@@ -51,6 +_,7 @@ + + @Override + public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) { ++ if (level.purpurConfig.silkTouchEnabled && isSilkTouch(level, stack)) return 0; // Purpur - Silk touch spawners + if (dropExperience) { + int i = 15 + level.random.nextInt(15) + level.random.nextInt(15); + // this.popExperience(level, pos, i); diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SpongeBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SpongeBlock.java.patch new file mode 100644 index 000000000..ab343ffb3 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SpongeBlock.java.patch @@ -0,0 +1,33 @@ +--- a/net/minecraft/world/level/block/SpongeBlock.java ++++ b/net/minecraft/world/level/block/SpongeBlock.java +@@ -53,8 +_,8 @@ + org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(level); // CraftBukkit - Use BlockStateListPopulator + BlockPos.breadthFirstTraversal( + pos, +- 6, +- 65, ++ level.purpurConfig.spongeAbsorptionRadius, // Purpur - Configurable sponge absorption ++ level.purpurConfig.spongeAbsorptionArea, // Purpur - Configurable sponge absorption + (validPos, queueAdder) -> { + for (Direction direction : ALL_DIRECTIONS) { + queueAdder.accept(validPos.relative(direction)); +@@ -68,7 +_,7 @@ + BlockState blockState = blockList.getBlockState(blockPos); + FluidState fluidState = blockList.getFluidState(blockPos); + // CraftBukkit end +- if (!fluidState.is(FluidTags.WATER)) { ++ if (!fluidState.is(FluidTags.WATER) && (!level.purpurConfig.spongeAbsorbsLava || !fluidState.is(FluidTags.LAVA)) && (!level.purpurConfig.spongeAbsorbsWaterFromMud || !blockState.is(Blocks.MUD))) { // Purpur - Option for sponges to work on lava and mud + return BlockPos.TraversalNodeStatus.SKIP; + } else if (blockState.getBlock() instanceof BucketPickup bucketPickup + && !bucketPickup.pickupBlock(null, blockList, blockPos, blockState).isEmpty()) { // CraftBukkit +@@ -76,6 +_,10 @@ + } else { + if (blockState.getBlock() instanceof LiquidBlock) { + blockList.setBlock(blockPos, Blocks.AIR.defaultBlockState(), 3); // CraftBukkit ++ // Purpur start - Option for sponges to work on lava and mud ++ } else if (blockState.is(Blocks.MUD)) { ++ blockList.setBlock(blockPos, Blocks.CLAY.defaultBlockState(), 3); ++ // Purpur end - Option for sponges to work on lava and mud + } else { + if (!blockState.is(Blocks.KELP) + && !blockState.is(Blocks.KELP_PLANT) diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/StonecutterBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/StonecutterBlock.java.patch new file mode 100644 index 000000000..df3ab7800 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/StonecutterBlock.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/level/block/StonecutterBlock.java ++++ b/net/minecraft/world/level/block/StonecutterBlock.java +@@ -93,4 +_,14 @@ + protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) { + return false; + } ++ ++ // Purpur start - Stonecutter damage ++ @Override ++ public void stepOn(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.Entity entity) { ++ if (level.purpurConfig.stonecutterDamage > 0.0F && entity instanceof net.minecraft.world.entity.LivingEntity) { ++ entity.hurtServer((net.minecraft.server.level.ServerLevel) level, entity.damageSources().stonecutter().directBlock(level, pos), level.purpurConfig.stonecutterDamage); ++ } ++ super.stepOn(level, pos, state, entity); ++ } ++ // Purpur end - Stonecutter damage + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch new file mode 100644 index 000000000..b39dc02a3 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch @@ -0,0 +1,46 @@ +--- a/net/minecraft/world/level/block/SugarCaneBlock.java ++++ b/net/minecraft/world/level/block/SugarCaneBlock.java +@@ -19,7 +_,7 @@ + import net.minecraft.world.phys.shapes.CollisionContext; + import net.minecraft.world.phys.shapes.VoxelShape; + +-public class SugarCaneBlock extends Block { ++public class SugarCaneBlock extends Block implements BonemealableBlock { // Purpur - bonemealable sugarcane + public static final MapCodec CODEC = simpleCodec(SugarCaneBlock::new); + public static final IntegerProperty AGE = BlockStateProperties.AGE_15; + protected static final float AABB_OFFSET = 6.0F; +@@ -113,4 +_,34 @@ + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(AGE); + } ++ ++ // Purpur start - bonemealable sugarcane ++ @Override ++ public boolean isValidBonemealTarget(final LevelReader world, final BlockPos pos, final BlockState state) { ++ if (!((net.minecraft.world.level.Level) world).purpurConfig.sugarCanAffectedByBonemeal || !world.isEmptyBlock(pos.above())) return false; ++ ++ int reedHeight = 0; ++ while (world.getBlockState(pos.below(reedHeight)).is(this)) { ++ reedHeight++; ++ } ++ ++ return reedHeight < ((net.minecraft.world.level.Level) world).paperConfig().maxGrowthHeight.reeds; ++ } ++ ++ @Override ++ public boolean isBonemealSuccess(net.minecraft.world.level.Level world, RandomSource random, BlockPos pos, BlockState state) { ++ return true; ++ } ++ ++ @Override ++ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) { ++ int reedHeight = 0; ++ while (world.getBlockState(pos.below(reedHeight)).is(this)) { ++ reedHeight++; ++ } ++ for (int i = 0; i <= world.paperConfig().maxGrowthHeight.reeds - reedHeight; i++) { ++ world.setBlockAndUpdate(pos.above(i), state.setValue(SugarCaneBlock.AGE, 0)); ++ } ++ } ++ // Purpur end - bonemealable sugarcane + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/TurtleEggBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/TurtleEggBlock.java.patch new file mode 100644 index 000000000..d6e5654f9 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/TurtleEggBlock.java.patch @@ -0,0 +1,47 @@ +--- a/net/minecraft/world/level/block/TurtleEggBlock.java ++++ b/net/minecraft/world/level/block/TurtleEggBlock.java +@@ -157,7 +_,7 @@ + + private boolean shouldUpdateHatchLevel(Level level) { + float timeOfDay = level.getTimeOfDay(1.0F); +- return timeOfDay < 0.69 && timeOfDay > 0.65 || level.random.nextInt(500) == 0; ++ return timeOfDay < 0.69 && timeOfDay > 0.65 || level.random.nextInt(level.purpurConfig.turtleEggsRandomTickCrackChance) == 0; // Purpur - Turtle eggs random tick crack chance + } + + @Override +@@ -192,9 +_,31 @@ + } + + private boolean canDestroyEgg(ServerLevel level, Entity entity) { +- return !(entity instanceof Turtle) +- && !(entity instanceof Bat) +- && entity instanceof LivingEntity +- && (entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)); ++ // Purpur start - Add turtle egg block options ++ if (entity instanceof Turtle || entity instanceof Bat) { ++ return false; ++ } ++ if (level.purpurConfig.turtleEggsBreakFromExpOrbs && entity instanceof net.minecraft.world.entity.ExperienceOrb) { ++ return true; ++ } ++ if (level.purpurConfig.turtleEggsBreakFromItems && entity instanceof net.minecraft.world.entity.item.ItemEntity) { ++ return true; ++ } ++ if (level.purpurConfig.turtleEggsBreakFromMinecarts && entity instanceof net.minecraft.world.entity.vehicle.AbstractMinecart) { ++ return true; ++ } ++ if (!(entity instanceof LivingEntity)) { ++ return false; ++ } ++ // Purpur start - Option to disable turtle egg trampling with feather falling ++ if (level.purpurConfig.turtleEggsTramplingFeatherFalling) { ++ java.util.Iterator armor = ((LivingEntity) entity).getArmorSlots().iterator(); ++ return !armor.hasNext() || net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) < (int) entity.fallDistance; ++ } ++ // Purpur end - Option to disable turtle egg trampling with feather falling ++ if (entity instanceof Player) return true; ++ ++ return level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); ++ // Purpur end - Add turtle egg block options + } + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/TwistingVinesBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/TwistingVinesBlock.java.patch new file mode 100644 index 000000000..89633d8f7 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/TwistingVinesBlock.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/level/block/TwistingVinesBlock.java ++++ b/net/minecraft/world/level/block/TwistingVinesBlock.java +@@ -34,4 +_,11 @@ + protected boolean canGrowInto(BlockState state) { + return NetherVines.isValidGrowthState(state); + } ++ ++ // Purpur start - twisting vines configurable max growth age ++ @Override ++ public int getMaxGrowthAge() { ++ return org.purpurmc.purpur.PurpurConfig.twistingVinesMaxGrowthAge; ++ } ++ // Purpur end - twisting vines configurable max growth age + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/WeepingVinesBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/WeepingVinesBlock.java.patch new file mode 100644 index 000000000..be28707f2 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/WeepingVinesBlock.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/level/block/WeepingVinesBlock.java ++++ b/net/minecraft/world/level/block/WeepingVinesBlock.java +@@ -34,4 +_,11 @@ + protected boolean canGrowInto(BlockState state) { + return NetherVines.isValidGrowthState(state); + } ++ ++ // Purpur start - weeping vines configurable max growth age ++ @Override ++ public int getMaxGrowthAge() { ++ return org.purpurmc.purpur.PurpurConfig.weepingVinesMaxGrowthAge; ++ } ++ // Purpur end - weeping vines configurable max growth age + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/WitherSkullBlock.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/WitherSkullBlock.java.patch new file mode 100644 index 000000000..d92c3e43b --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/WitherSkullBlock.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/block/WitherSkullBlock.java ++++ b/net/minecraft/world/level/block/WitherSkullBlock.java +@@ -71,6 +_,7 @@ + ); + witherBoss.yBodyRot = blockPatternMatch.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F; + witherBoss.makeInvulnerable(); ++ witherBoss.setSummoner(blockState.getBlock().placer == null ? null : blockState.getBlock().placer.getUUID()); // Purpur - Summoner API + // CraftBukkit start + if (!level.addFreshEntity(witherBoss, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_WITHER)) { + return; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch new file mode 100644 index 000000000..71426f386 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch @@ -0,0 +1,33 @@ +--- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +@@ -191,6 +_,21 @@ + } + + ItemStack itemStack = furnace.items.get(1); ++ // Purpur start - Furnace uses lava from underneath ++ boolean usedLavaFromUnderneath = false; ++ if (level.purpurConfig.furnaceUseLavaFromUnderneath && !furnace.isLit() && itemStack.isEmpty() && !furnace.items.get(0).isEmpty() && level.getGameTime() % 20 == 0) { ++ BlockPos below = furnace.getBlockPos().below(); ++ BlockState belowState = level.getBlockStateIfLoaded(below); ++ if (belowState != null && belowState.is(Blocks.LAVA)) { ++ net.minecraft.world.level.material.FluidState fluidState = belowState.getFluidState(); ++ if (fluidState != null && fluidState.isSource()) { ++ level.setBlock(below, Blocks.AIR.defaultBlockState(), 3); ++ itemStack = Items.LAVA_BUCKET.getDefaultInstance(); ++ usedLavaFromUnderneath = true; ++ } ++ } ++ } ++ // Purpur end - Furnace uses lava from underneath + ItemStack itemStack1 = furnace.items.get(0); + boolean flag1 = !itemStack1.isEmpty(); + boolean flag2 = !itemStack.isEmpty(); +@@ -274,6 +_,8 @@ + if (flag) { + setChanged(level, pos, state); + } ++ ++ if (usedLavaFromUnderneath) furnace.items.set(1, ItemStack.EMPTY); // Purpur - Furnace uses lava from underneath + } + + private static boolean canBurn( diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch new file mode 100644 index 000000000..8987119ae --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch @@ -0,0 +1,44 @@ +--- a/net/minecraft/world/level/block/entity/BeaconBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +@@ -139,6 +_,16 @@ + + public double getEffectRange() { + if (this.effectRange < 0) { ++ // Purpur start - Beacon Activation Range Configurable ++ if (this.level != null) { ++ switch (this.levels) { ++ case 1: return this.level.purpurConfig.beaconLevelOne; ++ case 2: return this.level.purpurConfig.beaconLevelTwo; ++ case 3: return this.level.purpurConfig.beaconLevelThree; ++ case 4: return this.level.purpurConfig.beaconLevelFour; ++ } ++ } ++ // Purpur end - Beacon Activation Range Configurable + return this.levels * 10 + 10; + } else { + return effectRange; +@@ -168,6 +_,7 @@ + int y = pos.getY(); + int z = pos.getZ(); + BlockPos blockPos; ++ boolean isTintedGlass = false; // Purpur - allow beacon effects when covered by tinted glass + if (blockEntity.lastCheckY < y) { + blockPos = pos; + blockEntity.checkingBeamSections = Lists.newArrayList(); +@@ -197,6 +_,7 @@ + } + } + } else { ++ if (level.purpurConfig.beaconAllowEffectsWithTintedGlass && blockState.getBlock().equals(Blocks.TINTED_GLASS)) {isTintedGlass = true;} // Purpur - allow beacon effects when covered by tinted glass + if (beaconBeamSection == null || blockState.getLightBlock() >= 15 && !blockState.is(Blocks.BEDROCK)) { + blockEntity.checkingBeamSections.clear(); + blockEntity.lastCheckY = height; +@@ -216,7 +_,7 @@ + blockEntity.levels = updateBase(level, x, y, z); + } + +- if (blockEntity.levels > 0 && !blockEntity.beamSections.isEmpty()) { ++ if (blockEntity.levels > 0 && (!blockEntity.beamSections.isEmpty() || (level.purpurConfig.beaconAllowEffectsWithTintedGlass && isTintedGlass))) { // Purpur - allow beacon effects when covered by tinted glass + applyEffects(level, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower, blockEntity); // Paper - Custom beacon ranges + playSound(level, pos, SoundEvents.BEACON_AMBIENT); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch new file mode 100644 index 000000000..091db9f55 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch @@ -0,0 +1,56 @@ +--- a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java +@@ -76,7 +_,7 @@ + "leash", + "UUID" + ); +- public static final int MAX_OCCUPANTS = 3; ++ public static final int MAX_OCCUPANTS = org.purpurmc.purpur.PurpurConfig.beeInsideBeeHive; // Purpur - Config to change max number of bees + private static final int MIN_TICKS_BEFORE_REENTERING_HIVE = 400; + private static final int MIN_OCCUPATION_TICKS_NECTAR = 2400; + public static final int MIN_OCCUPATION_TICKS_NECTARLESS = 600; +@@ -154,11 +_,33 @@ + return list; + } + ++ // Purpur start - Stored Bee API ++ public List releaseBee(BlockState iblockdata, BeehiveBlockEntity.BeeData data, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, boolean force) { ++ List list = Lists.newArrayList(); ++ ++ BeehiveBlockEntity.releaseOccupant(this.level, this.worldPosition, iblockdata, data.occupant, list, tileentitybeehive_releasestatus, this.savedFlowerPos, force); ++ ++ if (!list.isEmpty()) { ++ stored.remove(data); ++ ++ super.setChanged(); ++ } ++ ++ return list; ++ } ++ // Purpur end - Stored Bee API ++ + @VisibleForDebug + public int getOccupantCount() { + return this.stored.size(); + } + ++ // Purpur start - Stored Bee API ++ public List getStored() { ++ return stored; ++ } ++ // Purpur end - Stored Bee API ++ + // Paper start - Add EntityBlockStorage clearEntities + public void clearBees() { + this.stored.clear(); +@@ -408,8 +_,8 @@ + return this.stored.stream().map(BeehiveBlockEntity.BeeData::toOccupant).toList(); + } + +- static class BeeData { +- private final BeehiveBlockEntity.Occupant occupant; ++ public static class BeeData { // Purpur - make public - Stored Bee API ++ public final BeehiveBlockEntity.Occupant occupant; // Purpur - make public - Stored Bee API + private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts + private int ticksInHive; + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch new file mode 100644 index 000000000..49b53bf98 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch @@ -0,0 +1,50 @@ +--- a/net/minecraft/world/level/block/entity/BlockEntity.java ++++ b/net/minecraft/world/level/block/entity/BlockEntity.java +@@ -84,6 +_,14 @@ + this.persistentDataContainer.putAll((CompoundTag) persistentDataTag); + } + // Paper end - read persistent data container ++ ++ // Purpur start - Persistent BlockEntity Lore and DisplayName ++ if (tag.contains("Purpur.persistentLore")) { ++ net.minecraft.world.item.component.ItemLore.CODEC.decode(net.minecraft.nbt.NbtOps.INSTANCE, tag.getCompound("Purpur.persistentLore")).result() ++ .ifPresent(tag1 -> this.persistentLore = tag1.getFirst()); ++ } ++ // Purpur end - Persistent BlockEntity Lore and DisplayName ++ + } + + public final void loadWithComponents(CompoundTag tag, HolderLookup.Provider registries) { +@@ -98,6 +_,15 @@ + this.loadAdditional(tag, registries); + } + ++ // Purpur start - Persistent BlockEntity Lore and DisplayName ++ protected void saveAdditional(CompoundTag nbt) { ++ if (this.persistentLore != null) { ++ net.minecraft.world.item.component.ItemLore.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, this.persistentLore).result() ++ .ifPresent(tag -> nbt.put("Purpur.persistentLore", tag)); ++ } ++ } ++ // Purpur end - Persistent BlockEntity Lore and DisplayName ++ + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + } + +@@ -378,4 +_,16 @@ + + T getOrDefault(DataComponentType component, T defaultValue); + } ++ // Purpur start - Persistent BlockEntity Lore and DisplayName ++ @Nullable ++ private net.minecraft.world.item.component.ItemLore persistentLore = null; ++ ++ public void setPersistentLore(net.minecraft.world.item.component.ItemLore lore) { ++ this.persistentLore = lore; ++ } ++ ++ public @org.jetbrains.annotations.Nullable net.minecraft.world.item.component.ItemLore getPersistentLore() { ++ return this.persistentLore; ++ } ++ // Purpur end - Persistent BlockEntity Lore and DisplayName + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch new file mode 100644 index 000000000..f9491387f --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch @@ -0,0 +1,74 @@ +--- a/net/minecraft/world/level/block/entity/ConduitBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/ConduitBlockEntity.java +@@ -155,7 +_,7 @@ + BlockPos blockPos1 = pos.offset(i, i1, i2x); + BlockState blockState = level.getBlockState(blockPos1); + +- for (Block block : VALID_BLOCKS) { ++ for (Block block : level.purpurConfig.conduitBlocks) { // Purpur - Conduit behavior configuration + if (blockState.is(block)) { + positions.add(blockPos1); + } +@@ -170,13 +_,13 @@ + + private static void applyEffects(Level level, BlockPos pos, List positions) { + // CraftBukkit start +- ConduitBlockEntity.applyEffects(level, pos, ConduitBlockEntity.getRange(positions)); ++ ConduitBlockEntity.applyEffects(level, pos, ConduitBlockEntity.getRange(positions, level)); // Purpur - Conduit behavior configuration + } + +- public static int getRange(List positions) { ++ public static int getRange(List positions, Level level) { // Purpur - Conduit behavior configuration + // CraftBukkit end + int size = positions.size(); +- int i = size / 7 * 16; ++ int i = size / 7 * level.purpurConfig.conduitDistance; // Purpur - Conduit behavior configuration + // CraftBukkit start + return i; + } +@@ -213,17 +_,17 @@ + blockEntity.destroyTargetUUID = null; + } else if (blockEntity.destroyTarget == null) { + List entitiesOfClass = level.getEntitiesOfClass( +- LivingEntity.class, getDestroyRangeAABB(pos), collidedEntity -> collidedEntity instanceof Enemy && collidedEntity.isInWaterOrRain() ++ LivingEntity.class, getDestroyRangeAABB(pos, level), collidedEntity -> collidedEntity instanceof Enemy && collidedEntity.isInWaterOrRain() // Purpur - Conduit behavior configuration + ); + if (!entitiesOfClass.isEmpty()) { + blockEntity.destroyTarget = entitiesOfClass.get(level.random.nextInt(entitiesOfClass.size())); + } +- } else if (!blockEntity.destroyTarget.isAlive() || !pos.closerThan(blockEntity.destroyTarget.blockPosition(), 8.0)) { ++ } else if (!blockEntity.destroyTarget.isAlive() || !pos.closerThan(blockEntity.destroyTarget.blockPosition(), level.purpurConfig.conduitDamageDistance)) { // Purpur - Conduit behavior configuration + blockEntity.destroyTarget = null; + } + + if (damageTarget && blockEntity.destroyTarget != null) { // CraftBukkit +- if (blockEntity.destroyTarget.hurtServer((net.minecraft.server.level.ServerLevel) level, level.damageSources().magic().directBlock(level, pos), 4.0F)) // CraftBukkit ++ if (blockEntity.destroyTarget.hurtServer((net.minecraft.server.level.ServerLevel) level, level.damageSources().magic().directBlock(level, pos), level.purpurConfig.conduitDamageAmount)) // CraftBukkit // Purpur - Conduit behavior configuration + level.playSound( + null, + blockEntity.destroyTarget.getX(), +@@ -253,16 +_,22 @@ + } + + public static AABB getDestroyRangeAABB(BlockPos pos) { ++ // Purpur start - Conduit behavior configuration ++ return getDestroyRangeAABB(pos, null); ++ } ++ ++ private static AABB getDestroyRangeAABB(BlockPos pos, Level level) { ++ // Purpur end - Conduit behavior configuration + int x = pos.getX(); + int y = pos.getY(); + int z = pos.getZ(); +- return new AABB(x, y, z, x + 1, y + 1, z + 1).inflate(8.0); ++ return new AABB(x, y, z, x + 1, y + 1, z + 1).inflate(level == null ? 8.0 : level.purpurConfig.conduitDamageDistance); // Purpur - Conduit behavior configuration + } + + @Nullable + private static LivingEntity findDestroyTarget(Level level, BlockPos pos, UUID targetId) { + List entitiesOfClass = level.getEntitiesOfClass( +- LivingEntity.class, getDestroyRangeAABB(pos), collidedEntity -> collidedEntity.getUUID().equals(targetId) ++ LivingEntity.class, getDestroyRangeAABB(pos, level), collidedEntity -> collidedEntity.getUUID().equals(targetId) // Purpur - Conduit behavior configuration + ); + return entitiesOfClass.size() == 1 ? entitiesOfClass.get(0) : null; + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java.patch new file mode 100644 index 000000000..5f6a1f407 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java.patch @@ -0,0 +1,41 @@ +--- a/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java +@@ -28,6 +_,7 @@ + private static final RandomSource RANDOM = RandomSource.create(); + @Nullable + private Component name; ++ private int lapis = 0; // Purpur - Enchantment Table Persists Lapis + + public EnchantingTableBlockEntity(BlockPos pos, BlockState state) { + super(BlockEntityType.ENCHANTING_TABLE, pos, state); +@@ -39,6 +_,7 @@ + if (this.hasCustomName()) { + tag.putString("CustomName", Component.Serializer.toJson(this.name, registries)); + } ++ tag.putInt("Purpur.Lapis", this.lapis); // Purpur - Enchantment Table Persists Lapis + } + + @Override +@@ -47,6 +_,7 @@ + if (tag.contains("CustomName", 8)) { + this.name = parseCustomNameSafe(tag.getString("CustomName"), registries); + } ++ this.lapis = tag.getInt("Purpur.Lapis"); // Purpur - Enchantment Table Persists Lapis + } + + public static void bookAnimationTick(Level level, BlockPos pos, BlockState state, EnchantingTableBlockEntity enchantingTable) { +@@ -138,4 +_,14 @@ + public void removeComponentsFromTag(CompoundTag tag) { + tag.remove("CustomName"); + } ++ ++ // Purpur start - Enchantment Table Persists Lapis ++ public int getLapis() { ++ return this.lapis; ++ } ++ ++ public void setLapis(int lapis) { ++ this.lapis = lapis; ++ } ++ // Purpur end - Enchantment Table Persists Lapis + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch new file mode 100644 index 000000000..96784944d --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch @@ -0,0 +1,66 @@ +--- a/net/minecraft/world/level/block/entity/SignBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/SignBlockEntity.java +@@ -163,16 +_,32 @@ + return this.setText(updater.apply(text), isFrontText); + } + ++ // Purpur start - Signs allow color codes ++ private Component translateColors(org.bukkit.entity.Player player, String line, Style style) { ++ if (level.purpurConfig.signAllowColors) { ++ if (player.hasPermission("purpur.sign.color")) line = line.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1"); ++ if (player.hasPermission("purpur.sign.style")) line = line.replaceAll("(?i)&([l-or])", "\u00a7$1"); ++ if (player.hasPermission("purpur.sign.magic")) line = line.replaceAll("(?i)&([kr])", "\u00a7$1"); ++ ++ return io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line)); ++ } else { ++ return Component.literal(line).setStyle(style); ++ } ++ } ++ // Purpur end - Signs allow color codes ++ + private SignText setMessages(Player player, List filteredText, SignText text, boolean front) { // CraftBukkit + SignText originalText = text; // CraftBukkit + for (int i = 0; i < filteredText.size(); i++) { + FilteredText filteredText1 = filteredText.get(i); + Style style = text.getMessage(i, player.isTextFilteringEnabled()).getStyle(); ++ ++ org.bukkit.entity.Player craftPlayer = (org.bukkit.craftbukkit.entity.CraftPlayer) player.getBukkitEntity(); // Purpur - Signs allow color codes + if (player.isTextFilteringEnabled()) { +- text = text.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty())).setStyle(style)); // Paper - filter sign text to chat only ++ text = text.setMessage(i, translateColors(craftPlayer, net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty()), style)); // Paper - filter sign text to chat only // Purpur - Signs allow color codes + } else { + text = text.setMessage( +- i, Component.literal(filteredText1.raw()).setStyle(style), Component.literal(net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty())).setStyle(style) // Paper - filter sign text to chat only ++ i, translateColors(craftPlayer, net.minecraft.util.StringUtil.filterText(filteredText1.raw()), style), translateColors(craftPlayer, net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty()), style) // Paper - filter sign text to chat only // Purpur - Signs allow color codes + ); + } + } +@@ -310,6 +_,28 @@ + // CraftBukkit - this + return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel)level, 2, string, component, level.getServer(), player); // Paper - Fix commands from signs not firing command events + } ++ ++ // Purpur start - Signs allow color codes ++ public ClientboundBlockEntityDataPacket getTranslatedUpdatePacket(boolean filtered, boolean front) { ++ final CompoundTag nbt = new CompoundTag(); ++ this.saveAdditional(nbt, this.getLevel().registryAccess()); ++ final Component[] lines = front ? frontText.getMessages(filtered) : backText.getMessages(filtered); ++ final String side = front ? "front_text" : "back_text"; ++ for (int i = 0; i < 4; i++) { ++ final var component = io.papermc.paper.adventure.PaperAdventure.asAdventure(lines[i]); ++ final String line = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().serialize(component); ++ final var text = net.kyori.adventure.text.Component.text(line); ++ final String json = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(text); ++ if (!nbt.contains(side)) nbt.put(side, new CompoundTag()); ++ final CompoundTag sideNbt = nbt.getCompound(side); ++ if (!sideNbt.contains("messages")) sideNbt.put("messages", new net.minecraft.nbt.ListTag()); ++ final net.minecraft.nbt.ListTag messagesNbt = sideNbt.getList("messages", Tag.TAG_STRING); ++ messagesNbt.set(i, net.minecraft.nbt.StringTag.valueOf(json)); ++ } ++ nbt.putString("PurpurEditor", "true"); ++ return ClientboundBlockEntityDataPacket.create(this, (blockEntity, registryAccess) -> nbt); ++ } ++ // Purpur end - Signs allow color codes + + @Override + public ClientboundBlockEntityDataPacket getUpdatePacket() { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/piston/PistonStructureResolver.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/piston/PistonStructureResolver.java.patch new file mode 100644 index 000000000..bc6293606 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/block/piston/PistonStructureResolver.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/level/block/piston/PistonStructureResolver.java ++++ b/net/minecraft/world/level/block/piston/PistonStructureResolver.java +@@ -81,7 +_,7 @@ + return true; + } else { + int i = 1; +- if (i + this.toPush.size() > 12) { ++ if (i + this.toPush.size() > this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - Configurable piston push limit + return false; + } else { + while (isSticky(blockState)) { +@@ -95,7 +_,7 @@ + break; + } + +- if (++i + this.toPush.size() > 12) { ++ if (++i + this.toPush.size() > this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - Configurable piston push limit + return false; + } + } +@@ -140,7 +_,7 @@ + return true; + } + +- if (this.toPush.size() >= 12) { ++ if (this.toPush.size() >= this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - Configurable piston push limit + return false; + } + diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/chunk/storage/EntityStorage.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/chunk/storage/EntityStorage.java.patch new file mode 100644 index 000000000..262a755d6 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/chunk/storage/EntityStorage.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/chunk/storage/EntityStorage.java ++++ b/net/minecraft/world/level/chunk/storage/EntityStorage.java +@@ -106,6 +_,7 @@ + } + // Paper end - Entity load/save limit per chunk + CompoundTag compoundTag1 = new CompoundTag(); ++ if (!entity.canSaveToDisk()) return; // Purpur - Add canSaveToDisk to Entity + if (entity.save(compoundTag1)) { + listTag.add(compoundTag1); + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch new file mode 100644 index 000000000..aa1888597 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java ++++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +@@ -283,7 +_,7 @@ + + // Paper start + private static void printOversizedLog(String msg, Path file, int x, int z) { +- org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); ++ org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PURPUR - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); // Purpur - Rebrand + } + + private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/PhantomSpawner.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/PhantomSpawner.java.patch new file mode 100644 index 000000000..8c587ee00 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/PhantomSpawner.java.patch @@ -0,0 +1,32 @@ +--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java ++++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java +@@ -43,7 +_,7 @@ + int spawnAttemptMaxSeconds = level.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds; + this.nextTick += (spawnAttemptMinSeconds + randomSource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; + // Paper end - Ability to control player's insomnia and phantoms +- if (level.getSkyDarken() < 5 && level.dimensionType().hasSkyLight()) { ++ if (level.getSkyDarken() < level.purpurConfig.phantomSpawnMinSkyDarkness && level.dimensionType().hasSkyLight()) { // Purpur - Add phantom spawning options + return 0; + } else { + int i = 0; +@@ -51,9 +_,9 @@ + for (ServerPlayer serverPlayer : level.players()) { + if (!serverPlayer.isSpectator() && (!level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !serverPlayer.isCreative())) { // Paper - Add phantom creative and insomniac controls + BlockPos blockPos = serverPlayer.blockPosition(); +- if (!level.dimensionType().hasSkyLight() || blockPos.getY() >= level.getSeaLevel() && level.canSeeSky(blockPos)) { ++ if (!level.dimensionType().hasSkyLight() || (!level.purpurConfig.phantomSpawnOnlyAboveSeaLevel || blockPos.getY() >= level.getSeaLevel()) && (!level.purpurConfig.phantomSpawnOnlyWithVisibleSky || level.canSeeSky(blockPos))) { // Purpur - Add phantom spawning options + DifficultyInstance currentDifficultyAt = level.getCurrentDifficultyAt(blockPos); +- if (currentDifficultyAt.isHarderThan(randomSource.nextFloat() * 3.0F)) { ++ if (currentDifficultyAt.isHarderThan(randomSource.nextFloat() * (float) level.purpurConfig.phantomSpawnLocalDifficultyChance)) { // Purpur - Add phantom spawning options + ServerStatsCounter stats = serverPlayer.getStats(); + int i1 = Mth.clamp(stats.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE); + int i2 = 24000; +@@ -65,7 +_,7 @@ + FluidState fluidState = level.getFluidState(blockPos1); + if (NaturalSpawner.isValidEmptySpawnBlock(level, blockPos1, blockState, fluidState, EntityType.PHANTOM)) { + SpawnGroupData spawnGroupData = null; +- int i3 = 1 + randomSource.nextInt(currentDifficultyAt.getDifficulty().getId() + 1); ++ int i3 = level.purpurConfig.phantomSpawnMinPerAttempt + level.random.nextInt((level.purpurConfig.phantomSpawnMaxPerAttempt < 0 ? currentDifficultyAt.getDifficulty().getId() : level.purpurConfig.phantomSpawnMaxPerAttempt - level.purpurConfig.phantomSpawnMinPerAttempt) + 1); // Purpur - Add phantom spawning options + + for (int i4 = 0; i4 < i3; i4++) { + // Paper start - PhantomPreSpawnEvent diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch new file mode 100644 index 000000000..78e131bae --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch @@ -0,0 +1,24 @@ +--- a/net/minecraft/world/level/material/FlowingFluid.java ++++ b/net/minecraft/world/level/material/FlowingFluid.java +@@ -232,7 +_,7 @@ + } + } + +- if (i1 >= 2 && this.canConvertToSource(level)) { ++ if (i1 >= this.getRequiredSources(level) && this.canConvertToSource(level)) { // Purpur - Implement infinite liquids + BlockState blockState1 = level.getBlockState(mutableBlockPos.setWithOffset(pos, Direction.DOWN)); + FluidState fluidState1 = blockState1.getFluidState(); + if (blockState1.isSolid() || this.isSourceBlockOfThisType(fluidState1)) { +@@ -319,6 +_,12 @@ + } + + protected abstract boolean canConvertToSource(ServerLevel level); ++ ++ // Purpur start - Implement infinite liquids ++ protected int getRequiredSources(Level level) { ++ return 2; ++ } ++ // Purpur end - Implement infinite liquids + + protected void spreadTo(LevelAccessor level, BlockPos pos, BlockState blockState, Direction direction, FluidState fluidState) { + if (blockState.getBlock() instanceof LiquidBlockContainer liquidBlockContainer) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch new file mode 100644 index 000000000..2d7d530ae --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch @@ -0,0 +1,25 @@ +--- a/net/minecraft/world/level/material/LavaFluid.java ++++ b/net/minecraft/world/level/material/LavaFluid.java +@@ -177,7 +_,7 @@ + + @Override + public int getTickDelay(LevelReader level) { +- return level.dimensionType().ultraWarm() ? 10 : 30; ++ return level.dimensionType().ultraWarm() ? level.getWorldBorder().world.purpurConfig.lavaSpeedNether : level.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur - Make lava flow speed configurable + } + + @Override +@@ -198,6 +_,13 @@ + private void fizz(LevelAccessor level, BlockPos pos) { + level.levelEvent(1501, pos, 0); + } ++ ++ // Purpur start - Implement infinite liquids ++ @Override ++ protected int getRequiredSources(Level level) { ++ return level.purpurConfig.lavaInfiniteRequiredSources; ++ } ++ // Purpur end - Implement infinite liquids + + @Override + protected boolean canConvertToSource(ServerLevel level) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/WaterFluid.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/WaterFluid.java.patch new file mode 100644 index 000000000..88d21ec4e --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/material/WaterFluid.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/world/level/material/WaterFluid.java ++++ b/net/minecraft/world/level/material/WaterFluid.java +@@ -74,6 +_,12 @@ + protected boolean canConvertToSource(ServerLevel level) { + return level.getGameRules().getBoolean(GameRules.RULE_WATER_SOURCE_CONVERSION); + } ++ // Purpur start - Implement infinite liquids ++ @Override ++ protected int getRequiredSources(Level level) { ++ return level.purpurConfig.waterInfiniteRequiredSources; ++ } ++ // Purpur end - Implement infinite liquids + // Paper start - Add BlockBreakBlockEvent + @Override + protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state, BlockPos source) { diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch new file mode 100644 index 000000000..ef04724ea --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java ++++ b/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java +@@ -240,7 +_,7 @@ + if ((node == null || node.costMalus < 0.0F) + && verticalDeltaLimit > 0 + && (cachedPathType != PathType.FENCE || this.canWalkOverFences()) +- && cachedPathType != PathType.UNPASSABLE_RAIL ++ && (this.mob.level().purpurConfig.mobsIgnoreRails || cachedPathType != PathType.UNPASSABLE_RAIL) // Purpur - Config to allow mobs to pathfind over rails + && cachedPathType != PathType.TRAPDOOR + && cachedPathType != PathType.POWDER_SNOW) { + node = this.tryJumpOn(x, y, z, verticalDeltaLimit, nodeFloorLevel, direction, pathType, mutableBlockPos); +@@ -493,7 +_,7 @@ + return PathType.TRAPDOOR; + } else if (blockState.is(Blocks.POWDER_SNOW)) { + return PathType.POWDER_SNOW; +- } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH)) { ++ } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH) || blockState.is(Blocks.STONECUTTER)) { // Purpur - Stonecutter damage + return PathType.DAMAGE_OTHER; + } else if (blockState.is(Blocks.HONEY_BLOCK)) { + return PathType.STICKY_HONEY; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch new file mode 100644 index 000000000..925647acc --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/portal/PortalShape.java ++++ b/net/minecraft/world/level/portal/PortalShape.java +@@ -28,7 +_,7 @@ + public static final int MAX_WIDTH = 21; + private static final int MIN_HEIGHT = 3; + public static final int MAX_HEIGHT = 21; +- private static final BlockBehaviour.StatePredicate FRAME = (state, level, pos) -> state.is(Blocks.OBSIDIAN); ++ private static final BlockBehaviour.StatePredicate FRAME = (state, level, pos) -> state.is(Blocks.OBSIDIAN) || (org.purpurmc.purpur.PurpurConfig.cryingObsidianValidForPortalFrame && state.is(Blocks.CRYING_OBSIDIAN)); // Purpur - Crying obsidian valid for portal frames + private static final float SAFE_TRAVEL_MAX_ENTITY_XY = 4.0F; + private static final double SAFE_TRAVEL_MAX_VERTICAL_DELTA = 1.0; + private final Direction.Axis axis; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch new file mode 100644 index 000000000..1260ca9e5 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java ++++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +@@ -68,6 +_,7 @@ + public final Map decorations = Maps.newLinkedHashMap(); + private final Map frameMarkers = Maps.newHashMap(); + private int trackedDecorationCount; ++ public boolean isExplorerMap; // Purpur - Explorer Map API + + // CraftBukkit start + public final org.bukkit.craftbukkit.map.CraftMapView mapView; diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java.patch new file mode 100644 index 000000000..bc7b09181 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java ++++ b/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java +@@ -66,6 +_,11 @@ + Entity entity = context.getOptionalParameter(LootContextParams.ATTACKING_ENTITY); + if (entity instanceof LivingEntity livingEntity) { + int enchantmentLevel = EnchantmentHelper.getEnchantmentLevel(this.enchantment, livingEntity); ++ // Purpur start - Add an option to fix MC-3304 projectile looting ++ if (org.purpurmc.purpur.PurpurConfig.fixProjectileLootingTransfer && context.getOptionalParameter(LootContextParams.DIRECT_ATTACKING_ENTITY) instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) { ++ enchantmentLevel = arrow.actualEnchantments.getLevel(this.enchantment); ++ } ++ // Purpur end - Add an option to fix MC-3304 projectile looting + if (enchantmentLevel == 0) { + return stack; + } diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/phys/AABB.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/phys/AABB.java.patch new file mode 100644 index 000000000..db94aa724 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/phys/AABB.java.patch @@ -0,0 +1,13 @@ +--- a/net/minecraft/world/phys/AABB.java ++++ b/net/minecraft/world/phys/AABB.java +@@ -442,4 +_,10 @@ + center.x - xSize / 2.0, center.y - ySize / 2.0, center.z - zSize / 2.0, center.x + xSize / 2.0, center.y + ySize / 2.0, center.z + zSize / 2.0 + ); + } ++ ++ // Purpur start - Stop squids floating on top of water - tuinity added method ++ public final AABB offsetY(double dy) { ++ return new AABB(this.minX, this.minY + dy, this.minZ, this.maxX, this.maxY + dy, this.maxZ); ++ } ++ // Purpur end - Stop squids floating on top of water + } diff --git a/patches/server/0001-Rebrand.patch b/purpur-server/paper-patches/features/0001-Rebrand.patch similarity index 61% rename from patches/server/0001-Rebrand.patch rename to purpur-server/paper-patches/features/0001-Rebrand.patch index 07e65c2f1..6a8a0f7d5 100644 --- a/patches/server/0001-Rebrand.patch +++ b/purpur-server/paper-patches/features/0001-Rebrand.patch @@ -4,332 +4,6 @@ Date: Sat, 4 May 2019 01:02:11 -0500 Subject: [PATCH] Rebrand -diff --git a/build.gradle.kts b/build.gradle.kts -index 5d448d8a7cf6626a11791f30ad52baf41a099272..81996f00384674b29368e8bea944bdd14d631da3 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -12,8 +12,12 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) { - val alsoShade: Configuration by configurations.creating - - dependencies { -- implementation(project(":paper-api")) -- implementation(project(":paper-mojangapi")) -+ // Purpur start -+ implementation(project(":purpur-api")) -+ implementation("io.papermc.paper:paper-mojangapi:${project.version}") { -+ exclude("io.papermc.paper", "paper-api") -+ } -+ // Purpur end - // Paper start - implementation("org.jline:jline-terminal-jansi:3.21.0") - implementation("net.minecrell:terminalconsoleappender:1.3.0") -@@ -47,6 +51,10 @@ dependencies { - runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") - runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") - -+ implementation("org.mozilla:rhino-runtime:1.7.14") // Purpur -+ implementation("org.mozilla:rhino-engine:1.7.14") // Purpur -+ implementation("dev.omega24:upnp4j:1.0") // Purpur -+ - testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test - testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") - testImplementation("org.hamcrest:hamcrest:2.2") -@@ -79,7 +87,7 @@ tasks.jar { - attributes( - "Main-Class" to "org.bukkit.craftbukkit.Main", - "Implementation-Title" to "CraftBukkit", -- "Implementation-Version" to "git-Paper-$implementationVersion", -+ "Implementation-Version" to "git-Purpur-$implementationVersion", // Pufferfish // Purpur - "Implementation-Vendor" to date, // Paper - "Specification-Title" to "Bukkit", - "Specification-Version" to project.version, -@@ -138,7 +146,7 @@ fun TaskContainer.registerRunTask( - name: String, - block: JavaExec.() -> Unit - ): TaskProvider = register(name) { -- group = "paper" -+ group = "paperweight" // Purpur - mainClass.set("org.bukkit.craftbukkit.Main") - standardInput = System.`in` - workingDir = rootProject.layout.projectDirectory -diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -index 9d687da5bdf398bb3f6c84cdf1249a7213d09f2e..462a6eed350fd660ddaf25d567bb6e97b77d0b2b 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -@@ -19,8 +19,10 @@ import java.util.stream.StreamSupport; - - public class PaperVersionFetcher implements VersionFetcher { - private static final java.util.regex.Pattern VER_PATTERN = java.util.regex.Pattern.compile("^([0-9\\.]*)\\-.*R"); // R is an anchor, will always give '-R' at end -- private static final String GITHUB_BRANCH_NAME = "master"; -- private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads/paper"; -+ // Purpur start -+ private static final String DOWNLOAD_PAGE = "https://purpurmc.org/downloads"; -+ private static int distance = -2; public int distance() { return distance; } -+ // Purpur end - private static @Nullable String mcVer; - - @Override -@@ -31,11 +33,11 @@ public class PaperVersionFetcher implements VersionFetcher { - @Nonnull - @Override - public Component getVersionMessage(@Nonnull String serverVersion) { -- String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]"); -- final Component updateMessage = getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]); -+ String[] parts = serverVersion.substring("git-Purpur-".length()).split("[-\\s]"); // Purpur -+ final Component updateMessage = getUpdateStatusMessage("PurpurMC/Purpur", "ver/" + getMinecraftVersion(), parts[0]); // Purpur - final Component history = getHistory(); - -- return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage; -+ return history != null ? Component.join(net.kyori.adventure.text.JoinConfiguration.separator(Component.newline()), history, updateMessage) : updateMessage; // Purpur - } - - private static @Nullable String getMinecraftVersion() { -@@ -45,7 +47,7 @@ public class PaperVersionFetcher implements VersionFetcher { - String result = matcher.group(); - mcVer = result.substring(0, result.length() - 2); // strip 'R' anchor and trailing '-' - } else { -- org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to PaperMC!"); -+ org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to Purpur!"); // Purpur - org.bukkit.Bukkit.getLogger().warning("Pattern: " + VER_PATTERN.toString()); - org.bukkit.Bukkit.getLogger().warning("Version: " + org.bukkit.Bukkit.getBukkitVersion()); - } -@@ -55,7 +57,7 @@ public class PaperVersionFetcher implements VersionFetcher { - } - - private static Component getUpdateStatusMessage(@Nonnull String repo, @Nonnull String branch, @Nonnull String versionInfo) { -- int distance; -+ //int distance; // Purpur - use field - try { - int jenkinsBuild = Integer.parseInt(versionInfo); - distance = fetchDistanceFromSiteApi(jenkinsBuild, getMinecraftVersion()); -@@ -66,13 +68,13 @@ public class PaperVersionFetcher implements VersionFetcher { - - switch (distance) { - case -1: -- return Component.text("Error obtaining version information", NamedTextColor.YELLOW); -+ return Component.text("* Error obtaining version information", NamedTextColor.RED); // Purpur - case 0: -- return Component.text("You are running the latest version", NamedTextColor.GREEN); -+ return Component.text("* You are running the latest version", NamedTextColor.GREEN); // Purpur - case -2: -- return Component.text("Unknown version", NamedTextColor.YELLOW); -+ return Component.text("* Unknown version", NamedTextColor.YELLOW); // Purpur - default: -- return Component.text("You are " + distance + " version(s) behind", NamedTextColor.YELLOW) -+ return Component.text("* You are " + distance + " version(s) behind", NamedTextColor.YELLOW) // Purpur - .append(Component.newline()) - .append(Component.text("Download the new version at: ") - .append(Component.text(DOWNLOAD_PAGE, NamedTextColor.GOLD) -@@ -85,15 +87,11 @@ public class PaperVersionFetcher implements VersionFetcher { - if (siteApiVersion == null) { return -1; } - try { - try (BufferedReader reader = Resources.asCharSource( -- new URL("https://api.papermc.io/v2/projects/paper/versions/" + siteApiVersion), -+ new URL("https://api.purpurmc.org/v2/purpur/" + siteApiVersion), // Purpur - Charsets.UTF_8 - ).openBufferedStream()) { - JsonObject json = new Gson().fromJson(reader, JsonObject.class); -- JsonArray builds = json.getAsJsonArray("builds"); -- int latest = StreamSupport.stream(builds.spliterator(), false) -- .mapToInt(e -> e.getAsInt()) -- .max() -- .getAsInt(); -+ int latest = json.getAsJsonObject("builds").getAsJsonPrimitive("latest").getAsInt(); // Purpur - return latest - jenkinsBuild; - } catch (JsonSyntaxException ex) { - ex.printStackTrace(); -@@ -144,6 +142,6 @@ public class PaperVersionFetcher implements VersionFetcher { - return null; - } - -- return Component.text("Previous version: " + oldVersion, NamedTextColor.GRAY, TextDecoration.ITALIC); -+ return org.bukkit.ChatColor.parseMM("Previous: %s", oldVersion); // Purpur - } - } -diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -index c5d5648f4ca603ef2b1df723b58f9caf4dd3c722..3cb56595822799926a8141e60a42f5d1edfc6de5 100644 ---- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java -@@ -17,7 +17,7 @@ public final class PaperConsole extends SimpleTerminalConsole { - @Override - protected LineReader buildReader(LineReaderBuilder builder) { - builder -- .appName("Paper") -+ .appName("Purpur") // Purpur - .variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history")) - .completer(new ConsoleCommandCompleter(this.server)) - .option(LineReader.Option.COMPLETE_IN_WORD, true); -diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java -index 4f3cc14d48690bb183d09bb7a5ba1e23e8a0c08a..c366d84518979e842a6f10f969a5951539ecac93 100644 ---- a/src/main/java/net/minecraft/CrashReport.java -+++ b/src/main/java/net/minecraft/CrashReport.java -@@ -125,6 +125,10 @@ public class CrashReport { - StringBuilder stringbuilder = new StringBuilder(); - - stringbuilder.append("---- Minecraft Crash Report ----\n"); -+ // Purpur start -+ stringbuilder.append("// "); -+ stringbuilder.append("// DO NOT REPORT THIS TO PAPER! REPORT TO PURPUR INSTEAD!"); -+ // Purpur end - stringbuilder.append("// "); - stringbuilder.append(CrashReport.getErrorComment()); - stringbuilder.append("\n\n"); -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 8dc2f9df367c849ca333bf1a1fd92ff91617b548..57e6aaa63c1308baa5e2863b82b7521d5f4a4f31 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -960,7 +960,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop // Pufferfish > // Paper - } - - public SystemReport fillSystemReport(SystemReport details) { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 05e304f9fc8d0291fa779da589bd060ef4165b49..62c18b61ee58e76a90938976e9ec96ef28a7106c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -268,7 +268,7 @@ import javax.annotation.Nullable; // Paper - import javax.annotation.Nonnull; // Paper - - public final class CraftServer implements Server { -- private final String serverName = "Paper"; // Paper -+ private final String serverName = "Purpur"; // Paper // Pufferfish // Purpur - private final String serverVersion; - private final String bukkitVersion = Versioning.getBukkitVersion(); - private final Logger logger = Logger.getLogger("Minecraft"); -diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java -index 4e56018b64d11f76c8da43fd8f85c6de72204e36..9607675e6c5bff2183c4420d11fc63eeb5747fb6 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java -@@ -21,7 +21,12 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co - - @Override - public void sendMessage(String message) { -- this.sendRawMessage(message); -+ // Purpur start -+ String[] parts = message.split("\n"); -+ for (String part : parts) { -+ this.sendRawMessage(part); -+ } -+ // Purpur end - } - - @Override -@@ -91,7 +96,7 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co - // Paper start - @Override - public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) { -- this.sendRawMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); -+ this.sendMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); // Purpur - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index e85b9bb3f9c225d289a4959921970b9963881199..c1e2d3a75b9d4710ab6d8b5c62af4bc136a2b668 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -503,7 +503,7 @@ public class CraftScheduler implements BukkitScheduler { - this.parsePending(); - } else { - // this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper -- task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Paper"); // Paper -+ task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Purpur"); // Paper // Purpur - // We don't need to parse pending - // (async tasks must live with race-conditions if they attempt to cancel between these few lines of code) - } -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index a1c9989df460d7ae3666fffe7968750832a30b85..ad7f21566271260270db452e2f15c32f8a829d28 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -507,7 +507,7 @@ public final class CraftMagicNumbers implements UnsafeValues { - - @Override - public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { -- return new com.destroystokyo.paper.PaperVersionFetcher(); -+ return new com.destroystokyo.paper.PaperVersionFetcher(); // Purpur - TODO: Pufferfish - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -index 774556a62eb240da42e84db4502e2ed43495be17..99597258e8e88cd9e2c901c4ac3ff7faeeabee2b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -@@ -11,7 +11,7 @@ public final class Versioning { - public static String getBukkitVersion() { - String result = "Unknown-Version"; - -- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); -+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/org.purpurmc.purpur/purpur-api/pom.properties"); // Pufferfish // Purpur - Properties properties = new Properties(); - - if (stream != null) { -diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index 6db566e3111ec08a99aa429624979cb83a85e272..a353eb9f45af7b7f9bfd92a4a89403335b841840 100644 ---- a/src/main/java/org/spigotmc/WatchdogThread.java -+++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -96,7 +96,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa - - private WatchdogThread(long timeoutTime, boolean restart) - { -- super( "Paper Watchdog Thread" ); -+ super( "Watchdog Thread" ); // Purpur - use a generic name - this.timeoutTime = timeoutTime; - this.restart = restart; - earlyWarningEvery = Math.min(io.papermc.paper.configuration.GlobalConfiguration.get().watchdog.earlyWarningEvery, timeoutTime); // Paper -@@ -155,14 +155,14 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa - if (isLongTimeout) { - // Paper end - log.log( Level.SEVERE, "------------------------------" ); -- log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper -+ log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Purpur bug." ); // Paper // Purpur - log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" ); - log.log( Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring" ); - log.log( Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once" ); - log.log( Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes" ); -- log.log( Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues" ); -+ log.log( Level.SEVERE, "If you are unsure or still think this is a Purpur bug, please report this to https://github.com/PurpurMC/Purpur/issues" ); // Purpur - log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" ); -- log.log( Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion() ); -+ log.log( Level.SEVERE, "Purpur version: " + Bukkit.getServer().getVersion() ); // Purpur - // - if ( net.minecraft.world.level.Level.lastPhysicsProblem != null ) - { -@@ -184,12 +184,12 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa - // Paper end - } else - { -- log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---"); -+ log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PURPUR - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---"); // Purpur - log.log(Level.SEVERE, "The server has not responded for " + (currentTime - lastTick) / 1000 + " seconds! Creating thread dump"); - } - // Paper end - Different message for short timeout - log.log( Level.SEVERE, "------------------------------" ); -- log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper -+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Purpur!):" ); // Paper // Purpur - io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper - rewrite chunk system - this.dumpTickingInfo(); // Paper - log detailed tick information - WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log ); -@@ -205,7 +205,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa - WatchdogThread.dumpThread( thread, log ); - } - } else { -- log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH ---"); -+ log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PURPUR - THIS IS NOT A BUG OR A CRASH ---"); // Purpur - } - - log.log( Level.SEVERE, "------------------------------" ); diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png index 8b924977b7886df9ab8790b1e4ff9b1c04a2af45..518591dd83289e041a16e2c2e7d7e7640d4b2e1b 100644 GIT binary patch diff --git a/purpur-server/paper-patches/features/0002-Ridables.patch b/purpur-server/paper-patches/features/0002-Ridables.patch new file mode 100644 index 000000000..fe101257f --- /dev/null +++ b/purpur-server/paper-patches/features/0002-Ridables.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 5 Jul 2020 22:19:49 -0500 +Subject: [PATCH] Ridables + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index fda26c1695e22812e9de6828322b3252116df9ed..7615f19a3a5271ce27b16f1803f071196327f249 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1345,4 +1345,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + } + // Paper end - broadcast hurt animation ++ ++ // Purpur start - Ridables ++ @Override ++ public org.bukkit.entity.Player getRider() { ++ net.minecraft.world.entity.player.Player rider = getHandle().getRider(); ++ return rider != null ? (org.bukkit.entity.Player) rider.getBukkitEntity() : null; ++ } ++ ++ @Override ++ public boolean hasRider() { ++ return getHandle().getRider() != null; ++ } ++ ++ @Override ++ public boolean isRidable() { ++ return getHandle().isRidable(); ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return !getHandle().dismountsUnderwater(); ++ } ++ // Purpur end - Ridables + } +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index 1bb9a0bb4b1b898c9359d0095d9413a46b5e7630..1b7fdbecf9c28732d5196236980e87fa737a0769 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -602,6 +602,15 @@ public class CraftEventFactory { + // Paper end + craftServer.getPluginManager().callEvent(event); + ++ // Purpur start - Ridables ++ if (who != null) { ++ switch (action) { ++ case LEFT_CLICK_BLOCK, LEFT_CLICK_AIR -> who.processClick(InteractionHand.MAIN_HAND); ++ case RIGHT_CLICK_BLOCK, RIGHT_CLICK_AIR -> who.processClick(InteractionHand.OFF_HAND); ++ } ++ } ++ // Purpur end - Ridables ++ + return event; + } + +@@ -1191,6 +1200,7 @@ public class CraftEventFactory { + EntityDamageEvent event; + if (damager != null) { + event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions, critical); ++ damager.processClick(InteractionHand.MAIN_HAND); // Purpur - Ridables + } else { + event = new EntityDamageEvent(damagee.getBukkitEntity(), cause, bukkitDamageSource, modifiers, modifierFunctions); + } diff --git a/purpur-server/paper-patches/features/0003-Barrels-and-enderchests-6-rows.patch b/purpur-server/paper-patches/features/0003-Barrels-and-enderchests-6-rows.patch new file mode 100644 index 000000000..3ee77592d --- /dev/null +++ b/purpur-server/paper-patches/features/0003-Barrels-and-enderchests-6-rows.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 23 May 2019 21:50:37 -0500 +Subject: [PATCH] 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 1ce328bed5cf3d087a3f7dc9236153381d758493..364afc994443f6c64af4f9ebbe210da63e18681c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java +@@ -145,8 +145,19 @@ public class CraftContainer extends AbstractContainerMenu { + case PLAYER: + case CHEST: + case ENDER_CHEST: ++ // Purpur start - Barrels and enderchests 6 rows ++ this.delegate = new ChestMenu(org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? net.minecraft.world.inventory.MenuType.GENERIC_9x6 : net.minecraft.world.inventory.MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9); ++ break; + case BARREL: +- this.delegate = new ChestMenu(net.minecraft.world.inventory.MenuType.GENERIC_9x3, windowId, bottom, top, top.getContainerSize() / 9); ++ this.delegate = new ChestMenu(switch (org.purpurmc.purpur.PurpurConfig.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; ++ case 2 -> net.minecraft.world.inventory.MenuType.GENERIC_9x2; ++ case 1 -> net.minecraft.world.inventory.MenuType.GENERIC_9x1; ++ default -> net.minecraft.world.inventory.MenuType.GENERIC_9x3; ++ }, windowId, bottom, top, top.getContainerSize() / 9); ++ // Purpur end - Barrels and enderchests 6 rows + break; + case DISPENSER: + case DROPPER: +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +index c6159c70f7a37b9bffe268b91905ce848d1d2927..8b4f8a475faafe3b8a479160888145c4aa603a27 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +@@ -84,7 +84,7 @@ public class CraftInventory implements Inventory { + + @Override + public void setContents(ItemStack[] items) { +- Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize()); ++ // Preconditions.checkArgument(items.length <= this.getSize(), "Invalid inventory size (%s); expected %s or less", items.length, this.getSize()); // Purpur - Barrels and enderchests 6 rows + + for (int i = 0; i < this.getSize(); i++) { + if (i >= items.length) { diff --git a/purpur-server/paper-patches/features/0004-Configurable-void-damage-height-and-damage.patch b/purpur-server/paper-patches/features/0004-Configurable-void-damage-height-and-damage.patch new file mode 100644 index 000000000..700ad9f28 --- /dev/null +++ b/purpur-server/paper-patches/features/0004-Configurable-void-damage-height-and-damage.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 27 Feb 2020 21:42:19 -0600 +Subject: [PATCH] Configurable void damage height and damage + +temporarily migrate to paper's config +drop patch on the next minecraft release + +diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +index e48fa405d92fab221fa8331b65c8f324e801d439..e319d6337811051de478d584a37015c450960701 100644 +--- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java ++++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +@@ -267,6 +267,7 @@ public class PaperConfigurations extends Configurations +Date: Sat, 9 Jan 2021 15:26:04 +0100 +Subject: [PATCH] Add EntityTeleportHinderedEvent + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 7615f19a3a5271ce27b16f1803f071196327f249..5d8b2a917c16458b03067003c06cdf3fb49a682d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -261,6 +261,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + boolean retainPassengers = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS); + // Don't allow teleporting between worlds while keeping passengers + if (flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS) && this.entity.isVehicle() && location.getWorld() != this.getWorld()) { ++ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) // Purpur - Add EntityTeleportHinderedEvent + return false; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index fa850e952a01fbdc0c51ebe4055c82a6c3086fbb..f4d45ef506172c7c8ca65beeee7536f09c0c0284 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1438,6 +1438,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + // Paper start - Teleport passenger API + // Don't allow teleporting between worlds while keeping passengers + if (ignorePassengers && entity.isVehicle() && location.getWorld() != this.getWorld()) { ++ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) // Purpur - Add EntityTeleportHinderedEvent + return false; + } + +@@ -1459,6 +1460,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + + if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API ++ if (!new org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), org.purpurmc.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) // Purpur - Add EntityTeleportHinderedEvent + return false; + } + diff --git a/purpur-server/paper-patches/features/0006-API-for-any-mob-to-burn-daylight.patch b/purpur-server/paper-patches/features/0006-API-for-any-mob-to-burn-daylight.patch new file mode 100644 index 000000000..63ed5b913 --- /dev/null +++ b/purpur-server/paper-patches/features/0006-API-for-any-mob-to-burn-daylight.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Tue, 25 May 2021 16:31:09 -0400 +Subject: [PATCH] API for any mob to burn daylight + +Co-authored by: Encode42 + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 5d8b2a917c16458b03067003c06cdf3fb49a682d..0d46585c0128cea7265870de5fe260681c65d7c3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -102,6 +102,13 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + // Purpur end - Fire Immunity API + ++ // Purpur start - API for any mob to burn daylight ++ @Override ++ public boolean isInDaylight() { ++ return getHandle().isSunBurnTick(); ++ } ++ // Purpur end - API for any mob to burn daylight ++ + public static CraftEntity getEntity(CraftServer server, T entity) { + Preconditions.checkArgument(entity != null, "Unknown entity"); + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 459366331971d09e4cd00fb2035be01b4257477a..3a9d9b7526b2bf0fbd4e0d7886b3d849a6dcfee9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -1211,4 +1211,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + return this.getHandle().canUseSlot(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot)); + } + // Paper end - Expose canUseSlot ++ ++ // Purpur start - API for any mob to burn daylight ++ @Override ++ public boolean shouldBurnInDay() { ++ return this.getHandle().shouldBurnInDay(); ++ } ++ ++ @Override ++ public void setShouldBurnInDay(final boolean shouldBurnInDay) { ++ this.getHandle().setShouldBurnInDay(shouldBurnInDay); ++ } ++ // Purpur end - API for any mob to burn daylight + } diff --git a/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/Metrics.java.patch b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/Metrics.java.patch new file mode 100644 index 000000000..fc55c48ff --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/Metrics.java.patch @@ -0,0 +1,30 @@ +--- a/src/main/java/com/destroystokyo/paper/Metrics.java ++++ b/src/main/java/com/destroystokyo/paper/Metrics.java +@@ -592,7 +_,7 @@ + boolean logFailedRequests = config.getBoolean("logFailedRequests", false); + // Only start Metrics, if it's enabled in the config + if (config.getBoolean("enabled", true)) { +- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger()); ++ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Pufferfish // Purpur - Purpur config files + + metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { + String minecraftVersion = Bukkit.getVersion(); +@@ -601,16 +_,8 @@ + })); + + metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size())); +- metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline")); +- final String paperVersion; +- final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion(); +- if (implVersion != null) { +- final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1); +- paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); +- } else { +- paperVersion = "unknown"; +- } +- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion)); ++ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur - Purpur config files ++ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() != null) ? org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() : "unknown")); // Purpur - Purpur config files + + metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { + Map> map = new HashMap<>(); diff --git a/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java.patch b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java.patch new file mode 100644 index 000000000..bd41fc396 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java.patch @@ -0,0 +1,78 @@ +--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java ++++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +@@ -35,7 +_,10 @@ + private static final Logger LOGGER = LogUtils.getClassLogger(); + private static final int DISTANCE_ERROR = -1; + private static final int DISTANCE_UNKNOWN = -2; +- private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads/paper"; ++ // Purpur start - Rebrand ++ private static final String DOWNLOAD_PAGE = "https://purpurmc.org/downloads"; ++ private static int distance = DISTANCE_UNKNOWN; public int distance() { return distance; } ++ // Purpur end - Rebrand + + @Override + public long getCacheTime() { +@@ -49,7 +_,7 @@ + if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) { + updateMessage = text("You are running a development version without access to version information", color(0xFF5300)); + } else { +- updateMessage = getUpdateStatusMessage("PaperMC/Paper", build); ++ updateMessage = getUpdateStatusMessage("PurpurMC/Purpur", build); // Purpur - Rebrand + } + final @Nullable Component history = this.getHistory(); + +@@ -57,7 +_,7 @@ + } + + private static Component getUpdateStatusMessage(final String repo, final ServerBuildInfo build) { +- int distance = DISTANCE_ERROR; ++ //int distance = DISTANCE_ERROR; // Purpur - use field - Rebrand + + final OptionalInt buildNumber = build.buildNumber(); + if (buildNumber.isPresent()) { +@@ -71,10 +_,10 @@ + } + + return switch (distance) { +- case DISTANCE_ERROR -> text("Error obtaining version information", NamedTextColor.YELLOW); +- case 0 -> text("You are running the latest version", NamedTextColor.GREEN); +- case DISTANCE_UNKNOWN -> text("Unknown version", NamedTextColor.YELLOW); +- default -> text("You are " + distance + " version(s) behind", NamedTextColor.YELLOW) ++ case DISTANCE_ERROR -> text("* Error obtaining version information", NamedTextColor.RED); // Purpur - Rebrand ++ case 0 -> text("* You are running the latest version", NamedTextColor.GREEN); // Purpur - Rebrand ++ case DISTANCE_UNKNOWN -> text("* Unknown version", NamedTextColor.YELLOW); // Purpur - Rebrand ++ default -> text("* You are " + distance + " version(s) behind", NamedTextColor.YELLOW) // Purpur - Rebrand + .append(Component.newline()) + .append(text("Download the new version at: ") + .append(text(DOWNLOAD_PAGE, NamedTextColor.GOLD) +@@ -86,18 +_,15 @@ + private static int fetchDistanceFromSiteApi(final ServerBuildInfo build, final int jenkinsBuild) { + try { + try (final BufferedReader reader = Resources.asCharSource( +- URI.create("https://api.papermc.io/v2/projects/paper/versions/" + build.minecraftVersionId()).toURL(), ++ URI.create("https://api.purpurmc.org/v2/purpur/" + build.minecraftVersionId()).toURL(), // Purpur - Rebrand + Charsets.UTF_8 + ).openBufferedStream()) { + final JsonObject json = new Gson().fromJson(reader, JsonObject.class); +- final JsonArray builds = json.getAsJsonArray("builds"); +- final int latest = StreamSupport.stream(builds.spliterator(), false) +- .mapToInt(JsonElement::getAsInt) +- .max() +- .orElseThrow(); ++ //final JsonArray builds = json.getAsJsonArray("builds"); // Purpur - Rebrand ++ final int latest = json.getAsJsonObject("builds").getAsJsonPrimitive("latest").getAsInt(); // Purpur - Rebrand + return latest - jenkinsBuild; + } catch (final JsonSyntaxException ex) { +- LOGGER.error("Error parsing json from Paper's downloads API", ex); ++ LOGGER.error("Error parsing json from Purpur's downloads API", ex); // Purpur - Rebrand + return DISTANCE_ERROR; + } + } catch (final IOException e) { +@@ -141,6 +_,6 @@ + return null; + } + +- return text("Previous version: " + oldVersion, NamedTextColor.GRAY, TextDecoration.ITALIC); ++ return text("Previous: " + oldVersion, NamedTextColor.GRAY); // Purpur - Rebrand + } + } diff --git a/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/console/PaperConsole.java.patch b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/console/PaperConsole.java.patch new file mode 100644 index 000000000..43b5c7a41 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/console/PaperConsole.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java ++++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java +@@ -20,7 +_,7 @@ + @Override + protected LineReader buildReader(LineReaderBuilder builder) { + builder +- .appName("Paper") ++ .appName("Purpur") // Purpur - Rebrand + .variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history")) + .completer(new ConsoleCommandCompleter(this.server)) + .option(LineReader.Option.COMPLETE_IN_WORD, true); diff --git a/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java.patch b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java.patch new file mode 100644 index 000000000..be4e59d89 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java.patch @@ -0,0 +1,13 @@ +--- a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +@@ -136,6 +_,10 @@ + static { + // TODO these kinda should be checked on each release, in case obfuscation changes + deobfuscationMap.put("abstract_skeleton_1", "abstract_skeleton_melee"); ++ // Purpur start - Add option to disable zombie aggressiveness towards villagers ++ deobfuscationMap.put("zombie_1", "zombie_attack_villager"); ++ deobfuscationMap.put("drowned_1", "drowned_attack_villager"); ++ // Purpur end - Add option to disable zombie aggressiveness towards villagers + + ignored.add("goal_selector_1"); + ignored.add("goal_selector_2"); diff --git a/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java.patch b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java.patch new file mode 100644 index 000000000..e567d82a1 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java.patch @@ -0,0 +1,19 @@ +--- a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java ++++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java +@@ -61,6 +_,7 @@ + + // Follows CraftServer#getTPS + double[] tps = new double[] { ++ server.tps5s.getAverage(), // Purpur - Add 5 second tps average in /tps + server.tps1.getAverage(), + server.tps5.getAverage(), + server.tps15.getAverage() +@@ -73,7 +_,7 @@ + vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)"); + vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb"); + vector.add("Avg tick: " + DECIMAL_FORMAT.format((double)this.server.getAverageTickTimeNanos() / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND) + " ms"); +- vector.add("TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg)); ++ vector.add("TPS from last 5s, 1m, 5m, 15m: " + String.join(", ", tpsAvg)); // Purpur - Add 5 second tps average in /tps + setListData(vector); + } + diff --git a/purpur-server/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java.patch b/purpur-server/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java.patch new file mode 100644 index 000000000..fd95c8364 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java.patch @@ -0,0 +1,31 @@ +--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java ++++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java +@@ -31,6 +_,7 @@ + private static final String ATTRIBUTE_GIT_COMMIT = "Git-Commit"; + + private static final String BRAND_PAPER_NAME = "Paper"; ++ private static final String BRAND_PURPUR_NAME = "Purpur"; // Purpur - Rebrand + + private static final String BUILD_DEV = "DEV"; + +@@ -42,9 +_,9 @@ + this( + getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID) + .map(Key::key) +- .orElse(BRAND_PAPER_ID), ++ .orElse(BRAND_PURPUR_ID), // Purpur - Fix pufferfish issues // Purpur - Rebrand + getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME) +- .orElse(BRAND_PAPER_NAME), ++ .orElse(BRAND_PURPUR_NAME), // Purpur - Fix pufferfish issues // Purpur - Rebrand + SharedConstants.getCurrentVersion().getId(), + SharedConstants.getCurrentVersion().getName(), + getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER) +@@ -61,7 +_,7 @@ + + @Override + public boolean isBrandCompatible(final @NotNull Key brandId) { +- return brandId.equals(this.brandId); ++ return brandId.equals(this.brandId) || brandId.equals(BRAND_PAPER_ID); // Purpur - Fix pufferfish issues // Purpur - Rebrand + } + + @Override diff --git a/patches/server/0281-Improve-output-of-plugins-command.patch b/purpur-server/paper-patches/files/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java.patch similarity index 76% rename from patches/server/0281-Improve-output-of-plugins-command.patch rename to purpur-server/paper-patches/files/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java.patch index acee37c0a..eaeff69ee 100644 --- a/patches/server/0281-Improve-output-of-plugins-command.patch +++ b/purpur-server/paper-patches/files/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java.patch @@ -1,43 +1,33 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Parker Hawke -Date: Sat, 27 Jun 2020 18:43:37 -0400 -Subject: [PATCH] Improve output of plugins command - -Co-authored-by: Oharass -Co-authored-by: granny - -diff --git a/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java b/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java -index f0fce4113fb07c64adbec029d177c236cbdcbae8..e94224ed280247ee69dfdff8dc960f2b8729be33 100644 --- a/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java +++ b/src/main/java/io/papermc/paper/command/PaperPluginsCommand.java -@@ -78,10 +78,10 @@ public class PaperPluginsCommand extends BukkitCommand { +@@ -78,10 +_,10 @@ this.setAliases(Arrays.asList("pl")); } - private static List formatProviders(TreeMap> plugins) { -+ private static List formatProviders(TreeMap> plugins, @NotNull CommandSender sender) { // Purpur ++ private static List formatProviders(TreeMap> plugins, @NotNull CommandSender sender) { // Purpur - Improve output of plugins command List components = new ArrayList<>(plugins.size()); for (PluginProvider entry : plugins.values()) { - components.add(formatProvider(entry)); -+ components.add(formatProvider(entry, sender)); // Purpur ++ components.add(formatProvider(entry, sender)); // Purpur - Improve output of plugins command } boolean isFirst = true; -@@ -109,7 +109,7 @@ public class PaperPluginsCommand extends BukkitCommand { +@@ -109,7 +_,7 @@ return formattedSublists; } - private static Component formatProvider(PluginProvider provider) { -+ private static Component formatProvider(PluginProvider provider, @NotNull CommandSender sender) { // Purpur ++ private static Component formatProvider(PluginProvider provider, @NotNull CommandSender sender) { // Purpur - Improve output of plugins command TextComponent.Builder builder = Component.text(); if (provider instanceof SpigotPluginProvider spigotPluginProvider && CraftMagicNumbers.isLegacy(spigotPluginProvider.getMeta())) { builder.append(LEGACY_PLUGIN_STAR); -@@ -117,12 +117,64 @@ public class PaperPluginsCommand extends BukkitCommand { +@@ -117,13 +_,65 @@ String name = provider.getMeta().getName(); Component pluginName = Component.text(name, fromStatus(provider)) - .clickEvent(ClickEvent.runCommand("/version " + name)); -+ // Purpur start ++ // Purpur start - Improve output of plugins command + .clickEvent(ClickEvent.suggestCommand("/version " + name)); + + if (sender instanceof org.bukkit.entity.Player && sender.hasPermission("bukkit.command.version")) { @@ -69,16 +59,16 @@ index f0fce4113fb07c64adbec029d177c236cbdcbae8..e94224ed280247ee69dfdff8dc960f2b + hover.append(getAuthors(provider.getMeta())); + } + -+ pluginName.hoverEvent(hover.build()); ++ pluginName = pluginName.hoverEvent(hover.build()); + } ++ // Purpur end - Improve output of plugins command builder.append(pluginName); -+ // Purpur end -+ -+ return builder.build(); -+ } -+ -+ // Purpur start + + return builder.build(); + } + ++ // Purpur start - Improve output of plugins command + @NotNull + private static TextComponent getAuthors(@NotNull final PluginMeta pluginMeta) { + TextComponent.Builder builder = Component.text(); @@ -91,41 +81,48 @@ index f0fce4113fb07c64adbec029d177c236cbdcbae8..e94224ed280247ee69dfdff8dc960f2b + + builder.append(Component.text(authors.get(i), NamedTextColor.GREEN)); + } - - return builder.build(); - } -+ // Purpur end - ++ ++ return builder.build(); ++ } ++ // Purpur end - Improve output of plugins command ++ private static Component asPlainComponents(String strings) { net.kyori.adventure.text.TextComponent.Builder builder = Component.text(); -@@ -182,24 +234,24 @@ public class PaperPluginsCommand extends BukkitCommand { + for (String string : strings.split("\n")) { +@@ -182,24 +_,24 @@ } } - Component infoMessage = Component.text("Server Plugins (%s):".formatted(paperPlugins.size() + spigotPlugins.size()), NamedTextColor.WHITE); -+ //Component infoMessage = Component.text("Server Plugins (%s):".formatted(paperPlugins.size() + spigotPlugins.size()), NamedTextColor.WHITE); ++ //Component infoMessage = Component.text("Server Plugins (%s):".formatted(paperPlugins.size() + spigotPlugins.size()), NamedTextColor.WHITE); // Purpur - Improve output of plugins command //.append(INFO_ICON_START.hoverEvent(SERVER_PLUGIN_INFO)); TODO: Add docs - sender.sendMessage(infoMessage); -+ //sender.sendMessage(infoMessage); // Purpur - - if (!paperPlugins.isEmpty()) { +- +- if (!paperPlugins.isEmpty()) { - sender.sendMessage(PAPER_HEADER); -+ sender.sendMessage(PAPER_HEADER.append(Component.text(" (%s):".formatted(paperPlugins.size())))); // Purpur - } - +- } +- - for (Component component : formatProviders(paperPlugins)) { -+ for (Component component : formatProviders(paperPlugins, sender)) { // Purpur ++ //sender.sendMessage(infoMessage); // Purpur - Improve output of plugins command ++ ++ //if (!paperPlugins.isEmpty()) { // Purpur - Improve output of plugins command ++ sender.sendMessage(PAPER_HEADER.append(Component.text(" (%s):".formatted(paperPlugins.size())))); // Purpur - Improve output of plugins command ++ //} // Purpur - Improve output of plugins command ++ ++ for (Component component : formatProviders(paperPlugins, sender)) { // Purpur - Improve output of plugins command sender.sendMessage(component); } - if (!spigotPlugins.isEmpty()) { +- if (!spigotPlugins.isEmpty()) { - sender.sendMessage(BUKKIT_HEADER); -+ sender.sendMessage(BUKKIT_HEADER.append(Component.text(" (%s):".formatted(spigotPlugins.size())))); // Purpur - } +- } ++ //if (!spigotPlugins.isEmpty()) { // Purpur - Improve output of plugins command ++ sender.sendMessage(BUKKIT_HEADER.append(Component.text(" (%s):".formatted(spigotPlugins.size())))); // Purpur - Improve output of plugins command ++ //} // Purpur - Improve output of plugins command - for (Component component : formatProviders(spigotPlugins)) { -+ for (Component component : formatProviders(spigotPlugins, sender)) { // Purpur ++ for (Component component : formatProviders(spigotPlugins, sender)) { // Purpur - Improve output of plugins command sender.sendMessage(component); } diff --git a/patches/server/0180-Enhance-SysoutCatcher.patch b/purpur-server/paper-patches/files/src/main/java/io/papermc/paper/logging/SysoutCatcher.java.patch similarity index 55% rename from patches/server/0180-Enhance-SysoutCatcher.patch rename to purpur-server/paper-patches/files/src/main/java/io/papermc/paper/logging/SysoutCatcher.java.patch index 2a1703e67..d8d9954f6 100644 --- a/patches/server/0180-Enhance-SysoutCatcher.patch +++ b/purpur-server/paper-patches/files/src/main/java/io/papermc/paper/logging/SysoutCatcher.java.patch @@ -1,22 +1,14 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Mon, 28 Jun 2021 13:33:12 -0500 -Subject: [PATCH] Enhance SysoutCatcher - - -diff --git a/src/main/java/io/papermc/paper/logging/SysoutCatcher.java b/src/main/java/io/papermc/paper/logging/SysoutCatcher.java -index a8e813ca89b033f061e695288b3383bdcf128531..1ab65af9359d19530bba7f985a604d2a430ee234 100644 --- a/src/main/java/io/papermc/paper/logging/SysoutCatcher.java +++ b/src/main/java/io/papermc/paper/logging/SysoutCatcher.java -@@ -54,9 +54,9 @@ public final class SysoutCatcher { +@@ -54,9 +_,9 @@ final JavaPlugin plugin = JavaPlugin.getProvidingPlugin(clazz); // Instead of just printing the message, send it to the plugin's logger - plugin.getLogger().log(this.level, this.prefix + line); -+ plugin.getLogger().log(this.level, /*this.prefix +*/ line); // Purpur - prefix not needed ++ plugin.getLogger().log(this.level, /*this.prefix +*/ line); // Purpur - Enhance SysoutCatcher - prefix not needed - if (SysoutCatcher.SUPPRESS_NAGS) { -+ if (true || SysoutCatcher.SUPPRESS_NAGS) { // Purpur - nagging is annoying ++ if (true || SysoutCatcher.SUPPRESS_NAGS) { // Purpur - Enhance SysoutCatcher - nagging is annoying return; } if (SysoutCatcher.NAG_INTERVAL > 0 || SysoutCatcher.NAG_TIMEOUT > 0) { diff --git a/patches/server/0202-Extended-OfflinePlayer-API.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java.patch similarity index 79% rename from patches/server/0202-Extended-OfflinePlayer-API.patch rename to purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java.patch index 92790b03e..e6ecfddea 100644 --- a/patches/server/0202-Extended-OfflinePlayer-API.patch +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java.patch @@ -1,22 +1,14 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: YouHaveTrouble -Date: Sun, 22 Aug 2021 05:12:05 +0200 -Subject: [PATCH] Extended OfflinePlayer API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -index 9d93130f23addb18b97d7f5ec013faef17a74529..29d2fb87a65778926aea2cfc7a5b486cad596515 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java -@@ -335,14 +335,26 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa +@@ -363,14 +_,26 @@ @Override public Location getLocation() { -+ // Purpur start ++ // Purpur start - OfflinePlayer API + if (this.isOnline()) { + return this.getPlayer().getLocation(); + } -+ // Purpur end ++ // Purpur end - OfflinePlayer API + CompoundTag data = this.getData(); if (data == null) { @@ -38,7 +30,7 @@ index 9d93130f23addb18b97d7f5ec013faef17a74529..29d2fb87a65778926aea2cfc7a5b486c UUID uuid = new UUID(data.getLong("WorldUUIDMost"), data.getLong("WorldUUIDLeast")); -@@ -353,9 +365,9 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa +@@ -381,9 +_,9 @@ rotation.getFloat(0), rotation.getFloat(1) ); @@ -50,7 +42,7 @@ index 9d93130f23addb18b97d7f5ec013faef17a74529..29d2fb87a65778926aea2cfc7a5b486c } @Override -@@ -598,4 +610,191 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa +@@ -626,4 +_,191 @@ manager.save(); } } @@ -242,36 +234,3 @@ index 9d93130f23addb18b97d7f5ec013faef17a74529..29d2fb87a65778926aea2cfc7a5b486c + } + // Purpur end - OfflinePlayer API } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 925b8260bb2b1c94e544d6e082ea3b02e613d224..cf5897f8fed0c390ee75ca3b5b1037cfe1bdc43d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2745,6 +2745,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - return this.getHandle().getAbilities().walkingSpeed * 2f; - } - -+ // Purpur start - OfflinePlayer API -+ @Override -+ public boolean teleportOffline(@NotNull Location destination) { -+ return this.teleport(destination); -+ } -+ -+ @Override -+ public boolean teleportOffline(Location destination, PlayerTeleportEvent.TeleportCause cause) { -+ return this.teleport(destination, cause); -+ } -+ -+ @Override -+ public java.util.concurrent.CompletableFuture teleportOfflineAsync(@NotNull Location destination) { -+ return this.teleportAsync(destination); -+ } -+ -+ @Override -+ public java.util.concurrent.CompletableFuture teleportOfflineAsync(@NotNull Location destination, PlayerTeleportEvent.TeleportCause cause) { -+ return this.teleportAsync(destination, cause); -+ } -+ // Purpur end - OfflinePlayer API -+ - private void validateSpeed(float value) { - Preconditions.checkArgument(value <= 1f && value >= -1f, "Speed value (%s) need to be between -1f and 1f", value); - } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch new file mode 100644 index 000000000..7a5ade3e0 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch @@ -0,0 +1,154 @@ +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -427,6 +_,20 @@ + this.paperPluginManager = new io.papermc.paper.plugin.manager.PaperPluginManagerImpl(this, this.commandMap, pluginManager); + this.pluginManager.paperPluginManager = this.paperPluginManager; + // Paper end ++ // Purpur start - Language API ++ org.purpurmc.purpur.language.Language.setLanguage(new org.purpurmc.purpur.language.Language() { ++ private net.minecraft.locale.Language language = net.minecraft.locale.Language.getInstance(); ++ @Override ++ public boolean has(@org.jetbrains.annotations.NotNull String key) { ++ return language.has(key); ++ } ++ ++ @Override ++ public @org.jetbrains.annotations.NotNull String getOrDefault(@org.jetbrains.annotations.NotNull String key) { ++ return language.getOrDefault(key); ++ } ++ }); ++ // Purpur end - Language API + + CraftRegistry.setMinecraftRegistry(console.registryAccess()); + +@@ -1087,6 +_,7 @@ + + org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot + this.console.paperConfigurations.reloadConfigs(this.console); ++ org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur - Purpur config files + for (ServerLevel world : this.console.getAllLevels()) { + // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty + world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) +@@ -1102,6 +_,7 @@ + } + } + world.spigotConfig.init(); // Spigot ++ world.purpurConfig.init(); // Purpur - Purpur config files + } + + Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper +@@ -1119,6 +_,7 @@ + org.spigotmc.SpigotConfig.registerCommands(); // Spigot + io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper + this.spark.registerCommandBeforePlugins(this); // Paper - spark ++ org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur - Purpur config files + this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); + this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); + +@@ -1646,6 +_,60 @@ + return true; + } + ++ // Purpur start - Added the ability to add combustible items ++ @Override ++ public void addFuel(org.bukkit.Material material, int burnTime) { ++ Preconditions.checkArgument(burnTime > 0, "BurnTime must be greater than 0"); ++ ++ net.minecraft.world.item.ItemStack itemStack = net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material)); ++ MinecraftServer.getServer().fuelValues().values.put(itemStack.getItem(), burnTime); ++ } ++ ++ @Override ++ public void removeFuel(org.bukkit.Material material) { ++ net.minecraft.world.item.ItemStack itemStack = net.minecraft.world.item.ItemStack.fromBukkitCopy(new ItemStack(material)); ++ MinecraftServer.getServer().fuelValues().values.keySet().removeIf(itemStack::is); ++ } ++ // Purpur end - Added the ability to add combustible items ++ ++ // Purpur start - Debug Marker API ++ @Override ++ public void sendBlockHighlight(Location location, int duration) { ++ sendBlockHighlight(location, duration, "", 0x6400FF00); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, int argb) { ++ sendBlockHighlight(location, duration, "", argb); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text) { ++ sendBlockHighlight(location, duration, text, 0x6400FF00); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text, int argb) { ++ this.worlds.forEach((name, world) -> world.sendBlockHighlight(location, duration, text, argb)); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) { ++ sendBlockHighlight(location, duration, "", color, transparency); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) { ++ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range"); ++ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB()); ++ } ++ ++ @Override ++ public void clearBlockHighlights() { ++ this.worlds.forEach((name, world) -> clearBlockHighlights()); ++ } ++ // Purpur end - Debug Marker API ++ + @Override + public List getRecipesFor(ItemStack result) { + Preconditions.checkArgument(result != null, "ItemStack cannot be null"); +@@ -3055,6 +_,18 @@ + return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console); + } + ++ // Purpur start - Purpur config files ++ @Override ++ public YamlConfiguration getPurpurConfig() { ++ return org.purpurmc.purpur.PurpurConfig.config; ++ } ++ ++ @Override ++ public java.util.Properties getServerProperties() { ++ return getProperties().properties; ++ } ++ // Purpur end - Purpur config files ++ + @Override + public void restart() { + org.spigotmc.RestartCommand.restart(); +@@ -3084,6 +_,7 @@ + @Override + public double[] getTPS() { + return new double[] { ++ net.minecraft.server.MinecraftServer.getServer().tps5s.getAverage(), // Purpur - Add 5 second tps average in /tps + net.minecraft.server.MinecraftServer.getServer().tps1.getAverage(), + net.minecraft.server.MinecraftServer.getServer().tps5.getAverage(), + net.minecraft.server.MinecraftServer.getServer().tps15.getAverage() +@@ -3294,4 +_,18 @@ + this.console.addPluginAllowingSleep(plugin.getName(), value); + } + // Paper end - API to check if the server is sleeping ++ ++ // Purpur start - Bring back server name ++ @Override ++ public String getServerName() { ++ return this.getProperties().serverName; ++ } ++ // Purpur end - Bring back server name ++ ++ // Purpur start - Lagging threshold ++ @Override ++ public boolean isLagging() { ++ return getServer().lagging; ++ } ++ // Purpur end - Lagging threshold + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftWorld.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftWorld.java.patch new file mode 100644 index 000000000..8c351edf0 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftWorld.java.patch @@ -0,0 +1,53 @@ +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -2373,6 +_,50 @@ + return (this.getHandle().getDragonFight() == null) ? null : new CraftDragonBattle(this.getHandle().getDragonFight()); + } + ++ // Purpur start - Add local difficulty api ++ public float getLocalDifficultyAt(Location location) { ++ return getHandle().getCurrentDifficultyAt(io.papermc.paper.util.MCUtil.toBlockPosition(location)).getEffectiveDifficulty(); ++ } ++ // Purpur end - Add local difficulty api ++ ++ // Purpur start - Debug Marker API ++ @Override ++ public void sendBlockHighlight(Location location, int duration) { ++ sendBlockHighlight(location, duration, "", 0x6400FF00); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, int argb) { ++ sendBlockHighlight(location, duration, "", argb); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text) { ++ sendBlockHighlight(location, duration, text, 0x6400FF00); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text, int argb) { ++ net.minecraft.network.protocol.game.DebugPackets.sendGameTestAddMarker(getHandle(), io.papermc.paper.util.MCUtil.toBlockPosition(location), text, argb, duration); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) { ++ sendBlockHighlight(location, duration, "", color, transparency); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) { ++ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range"); ++ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB()); ++ } ++ ++ @Override ++ public void clearBlockHighlights() { ++ net.minecraft.network.protocol.game.DebugPackets.sendGameTestClearPacket(getHandle()); ++ } ++ // Purpur end - Debug Marker API ++ + @Override + public Collection getStructures(int x, int z) { + return this.getStructures(x, z, struct -> true); diff --git a/patches/server/0020-Disable-outdated-build-check.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/Main.java.patch similarity index 51% rename from patches/server/0020-Disable-outdated-build-check.patch rename to purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/Main.java.patch index a082f35b6..e86001e4b 100644 --- a/patches/server/0020-Disable-outdated-build-check.patch +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/Main.java.patch @@ -1,19 +1,25 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 15 Dec 2019 12:53:59 -0600 -Subject: [PATCH] Disable outdated build check - - -diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 66a3b28d7b943d443ff66fdcfbce6e5260b9463e..222865a3cee62f244a566092a7d814efe478ee01 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -302,7 +302,7 @@ public class Main { +@@ -176,6 +_,13 @@ + .describedAs("Jar file"); + // Paper end + ++ // Purpur start - Purpur config files ++ acceptsAll(asList("purpur", "purpur-settings"), "File for purpur settings") ++ .withRequiredArg() ++ .ofType(File.class) ++ .defaultsTo(new File("purpur.yml")) ++ .describedAs("Yml file"); ++ // Purpur end - Purpur config files + // Paper start + acceptsAll(asList("server-name"), "Name of the server") + .withRequiredArg() +@@ -259,7 +_,7 @@ System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper } - if (Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { -+ if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { // Purpur ++ if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { // Purpur - Disable outdated build check Date buildDate = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(Main.class.getPackage().getImplementationVendor()); // Paper Calendar deadline = Calendar.getInstance(); diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java.patch new file mode 100644 index 000000000..39590b5cd --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java.patch @@ -0,0 +1,81 @@ +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeehive.java +@@ -16,8 +_,15 @@ + + public class CraftBeehive extends CraftBlockEntityState implements Beehive { + ++ private final List> storage = new ArrayList<>(); // Purpur - Stored Bee API ++ + public CraftBeehive(World world, BeehiveBlockEntity tileEntity) { + super(world, tileEntity); ++ // Purpur start - load bees to be able to modify them individually - Stored Bee API ++ for(BeehiveBlockEntity.BeeData data : tileEntity.getStored()) { ++ storage.add(new org.purpurmc.purpur.entity.PurpurStoredBee(data, this)); ++ } ++ // Purpur end - Stored Bee API + } + + protected CraftBeehive(CraftBeehive state, Location location) { +@@ -76,14 +_,54 @@ + } + } + ++ storage.clear(); // Purpur - Stored Bee API + return bees; + } + ++ // Purpur start - Stored Bee API ++ @Override ++ public Bee releaseEntity(org.purpurmc.purpur.entity.StoredEntity entity) { ++ ensureNoWorldGeneration(); ++ ++ if(!getEntities().contains(entity)) { ++ return null; ++ } ++ ++ if(isPlaced()) { ++ BeehiveBlockEntity beehive = ((BeehiveBlockEntity) this.getTileEntityFromWorld()); ++ BeehiveBlockEntity.BeeData data = ((org.purpurmc.purpur.entity.PurpurStoredBee) entity).getHandle(); ++ ++ List list = beehive.releaseBee(getHandle(), data, BeeReleaseStatus.BEE_RELEASED, true); ++ ++ if (list.size() == 1) { ++ storage.remove(entity); ++ ++ return (Bee) list.get(0).getBukkitEntity(); ++ } ++ } ++ ++ return null; ++ } ++ ++ @Override ++ public List> getEntities() { ++ return new ArrayList<>(storage); ++ } ++ // Purpur end - Stored Bee API ++ + @Override + public void addEntity(Bee entity) { + Preconditions.checkArgument(entity != null, "Entity must not be null"); + ++ int length = this.getSnapshot().getStored().size(); // Purpur - Stored Bee API + this.getSnapshot().addOccupant(((CraftBee) entity).getHandle()); ++ ++ // Purpur start - check if new bee was added, and if yes, add to stored bees - Stored Bee API ++ List storedBeeData = this.getSnapshot().getStored(); ++ if(length < storedBeeData.size()) { ++ storage.add(new org.purpurmc.purpur.entity.PurpurStoredBee(storedBeeData.getLast(), this)); ++ } ++ // Purpur end - Stored Bee API + } + + @Override +@@ -100,6 +_,7 @@ + @Override + public void clearEntities() { + getSnapshot().clearBees(); ++ storage.clear(); // Purpur - Stored Bee API + } + // Paper end + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java.patch new file mode 100644 index 000000000..e60687bc8 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftConduit.java +@@ -73,7 +_,7 @@ + public int getRange() { + this.ensureNoWorldGeneration(); + ConduitBlockEntity conduit = (ConduitBlockEntity) this.getTileEntityFromWorld(); +- return (conduit != null) ? ConduitBlockEntity.getRange(conduit.effectBlocks) : 0; ++ return (conduit != null) ? ConduitBlockEntity.getRange(conduit.effectBlocks, this.world.getHandle()) : 0; // Purpur - Conduit behavior configuration + } + + @Override diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java.patch new file mode 100644 index 000000000..411f8ce59 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java.patch @@ -0,0 +1,25 @@ +--- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java +@@ -21,7 +_,12 @@ + + @Override + public void sendMessage(String message) { +- this.sendRawMessage(message); ++ // Purpur start - Rebrand ++ String[] parts = message.split("\n"); ++ for (String part : parts) { ++ this.sendRawMessage(part); ++ } ++ // Purpur end - Rebrand + } + + @Override +@@ -91,7 +_,7 @@ + // Paper start + @Override + public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) { +- this.sendRawMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); ++ this.sendMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); // Purpur - Rebrand + } + + @Override diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java.patch new file mode 100644 index 000000000..195b6492a --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java.patch @@ -0,0 +1,17 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEndermite.java +@@ -21,12 +_,12 @@ + + @Override + public boolean isPlayerSpawned() { +- return false; ++ return getHandle().isPlayerSpawned(); // Purpur - Add back player spawned endermite API + } + + @Override + public void setPlayerSpawned(boolean playerSpawned) { +- // Nop ++ getHandle().setPlayerSpawned(playerSpawned); // Purpur - Add back player spawned endermite API + } + // Paper start + @Override diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java.patch new file mode 100644 index 000000000..fd0fe6186 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java.patch @@ -0,0 +1,21 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -90,6 +_,18 @@ + this.entityType = CraftEntityType.minecraftToBukkit(entity.getType()); + } + ++ // Purpur start - Fire Immunity API ++ @Override ++ public boolean isImmuneToFire() { ++ return getHandle().fireImmune(); ++ } ++ ++ @Override ++ public void setImmuneToFire(Boolean fireImmune) { ++ getHandle().immuneToFire = fireImmune; ++ } ++ // Purpur end - Fire Immunity API ++ + public static CraftEntity getEntity(CraftServer server, T entity) { + Preconditions.checkArgument(entity != null, "Unknown entity"); + diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java.patch new file mode 100644 index 000000000..721712915 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java.patch @@ -0,0 +1,10 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +@@ -281,6 +_,7 @@ + @Override + public void recalculatePermissions() { + this.perm.recalculatePermissions(); ++ getHandle().canPortalInstant = hasPermission("purpur.portal.instant"); // Purpur - Add portal permission bypass + } + + @Override diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java.patch new file mode 100644 index 000000000..d09a7cf6b --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java.patch @@ -0,0 +1,20 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftIronGolem.java +@@ -27,4 +_,17 @@ + public void setPlayerCreated(boolean playerCreated) { + this.getHandle().setPlayerCreated(playerCreated); + } ++ ++ // Purpur start - Summoner API ++ @Override ++ @org.jetbrains.annotations.Nullable ++ public java.util.UUID getSummoner() { ++ return getHandle().getSummoner(); ++ } ++ ++ @Override ++ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) { ++ getHandle().setSummoner(summoner); ++ } ++ // Purpur end - Summoner API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java.patch new file mode 100644 index 000000000..8625ef963 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java.patch @@ -0,0 +1,56 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +@@ -151,4 +_,53 @@ + public String toString() { + return "CraftItem"; + } ++ ++ // Purpur start - Item entity immunities ++ @Override ++ public void setImmuneToCactus(boolean immuneToCactus) { ++ this.getHandle().immuneToCactus = immuneToCactus; ++ } ++ ++ @Override ++ public boolean isImmuneToCactus() { ++ return this.getHandle().immuneToCactus; ++ } ++ ++ @Override ++ public void setImmuneToExplosion(boolean immuneToExplosion) { ++ this.getHandle().immuneToExplosion = immuneToExplosion; ++ } ++ ++ @Override ++ public boolean isImmuneToExplosion() { ++ return this.getHandle().immuneToExplosion; ++ } ++ ++ // Purpur start - Fire Immunity API ++ @Override ++ public void setImmuneToFire(@org.jetbrains.annotations.Nullable Boolean immuneToFire) { ++ this.getHandle().immuneToFire = (immuneToFire != null && immuneToFire); ++ } ++ // Purpur end - Fire Immunity API ++ ++ @Override ++ public void setImmuneToFire(boolean immuneToFire) { ++ this.setImmuneToFire((Boolean) immuneToFire); // Purpur - Fire Immunity API ++ } ++ ++ @Override ++ public boolean isImmuneToFire() { ++ return this.getHandle().immuneToFire; ++ } ++ ++ @Override ++ public void setImmuneToLightning(boolean immuneToLightning) { ++ this.getHandle().immuneToLightning = immuneToLightning; ++ } ++ ++ @Override ++ public boolean isImmuneToLightning() { ++ return this.getHandle().immuneToLightning; ++ } ++ // Purpur end - Item entity immunities + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java.patch new file mode 100644 index 000000000..defd314c0 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -523,7 +_,7 @@ + net.minecraft.server.level.ServerPlayer entityPlayer = killer == null ? null : ((CraftPlayer) killer).getHandle(); + getHandle().lastHurtByPlayer = entityPlayer; + getHandle().lastHurtByMob = entityPlayer; +- getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : 100; // 100 value taken from EntityLiving#damageEntity ++ getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : getHandle().level().purpurConfig.mobLastHurtByPlayerTime; // 100 value taken from EntityLiving#damageEntity // Purpur - Config for mob last hurt by player time + } + // Paper end + diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java.patch new file mode 100644 index 000000000..57cca6a07 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java.patch @@ -0,0 +1,19 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java +@@ -90,4 +_,16 @@ + return this.getHandle().caravanTail == null ? null : (Llama) this.getHandle().caravanTail.getBukkitEntity(); + } + // Paper end ++ ++ // Purpur start - Llama API ++ @Override ++ public boolean shouldJoinCaravan() { ++ return getHandle().shouldJoinCaravan; ++ } ++ ++ @Override ++ public void setShouldJoinCaravan(boolean shouldJoinCaravan) { ++ getHandle().shouldJoinCaravan = shouldJoinCaravan; ++ } ++ // Purpur end - Llama API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch new file mode 100644 index 000000000..42b6bb715 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch @@ -0,0 +1,125 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -591,10 +_,15 @@ + + @Override + public void setPlayerListName(String name) { ++ // Purpur start - AFK API ++ setPlayerListName(name, false); ++ } ++ public void setPlayerListName(String name, boolean useMM) { ++ // Purpur end - AFK API + if (name == null) { + name = this.getName(); + } +- this.getHandle().listName = name.equals(this.getName()) ? null : CraftChatMessage.fromStringOrNull(name); ++ this.getHandle().listName = name.equals(this.getName()) ? null : useMM ? io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name)) : CraftChatMessage.fromStringOrNull(name); // Purpur - AFK API + if (this.getHandle().connection == null) return; // Paper - Updates are possible before the player has fully joined + for (ServerPlayer player : (List) this.server.getHandle().players) { + if (player.getBukkitEntity().canSee(this)) { +@@ -2752,6 +_,28 @@ + return this.getHandle().getAbilities().walkingSpeed * 2f; + } + ++ // Purpur start - OfflinePlayer API ++ @Override ++ public boolean teleportOffline(@NotNull Location destination) { ++ return this.teleport(destination); ++ } ++ ++ @Override ++ public boolean teleportOffline(Location destination, PlayerTeleportEvent.TeleportCause cause) { ++ return this.teleport(destination, cause); ++ } ++ ++ @Override ++ public java.util.concurrent.CompletableFuture teleportOfflineAsync(@NotNull Location destination) { ++ return this.teleportAsync(destination); ++ } ++ ++ @Override ++ public java.util.concurrent.CompletableFuture teleportOfflineAsync(@NotNull Location destination, PlayerTeleportEvent.TeleportCause cause) { ++ return this.teleportAsync(destination, cause); ++ } ++ // Purpur end - OfflinePlayer API ++ + private void validateSpeed(float value) { + Preconditions.checkArgument(value <= 1f && value >= -1f, "Speed value (%s) need to be between -1f and 1f", value); + } +@@ -3581,4 +_,76 @@ + handle.containerMenu.broadcastChanges(); + return new PaperPlayerGiveResult(leftovers.build(), drops.build()); + } ++ ++ // Purpur start - Purpur client support ++ @Override ++ public boolean usesPurpurClient() { ++ return getHandle().purpurClient; ++ } ++ // Purpur end - Purpur client support ++ ++ // Purpur start - AFK API ++ @Override ++ public boolean isAfk() { ++ return getHandle().isAfk(); ++ } ++ ++ @Override ++ public void setAfk(boolean setAfk) { ++ getHandle().setAfk(setAfk); ++ } ++ ++ @Override ++ public void resetIdleTimer() { ++ getHandle().resetLastActionTime(); ++ } ++ // Purpur end - AFK API ++ ++ // Purpur start - Debug Marker API ++ @Override ++ public void sendBlockHighlight(Location location, int duration) { ++ sendBlockHighlight(location, duration, "", 0x6400FF00); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, int argb) { ++ sendBlockHighlight(location, duration, "", argb); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text) { ++ sendBlockHighlight(location, duration, text, 0x6400FF00); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text, int argb) { ++ if (this.getHandle().connection == null) return; ++ this.getHandle().connection.send(new net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket(new net.minecraft.network.protocol.common.custom.GameTestAddMarkerDebugPayload(io.papermc.paper.util.MCUtil.toBlockPosition(location), argb, text, duration))); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, org.bukkit.Color color, int transparency) { ++ sendBlockHighlight(location, duration, "", color, transparency); ++ } ++ ++ @Override ++ public void sendBlockHighlight(Location location, int duration, String text, org.bukkit.Color color, int transparency) { ++ if (transparency < 0 || transparency > 255) throw new IllegalArgumentException("transparency is outside of 0-255 range"); ++ sendBlockHighlight(location, duration, text, transparency << 24 | color.asRGB()); ++ } ++ ++ @Override ++ public void clearBlockHighlights() { ++ if (this.getHandle().connection == null) return; ++ this.getHandle().connection.send(new net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket(new net.minecraft.network.protocol.common.custom.GameTestClearMarkersDebugPayload())); ++ } ++ // Purpur end - Debug Marker API ++ ++ // Purpur start - Death screen API ++ @Override ++ public void sendDeathScreen(net.kyori.adventure.text.Component message) { ++ if (this.getHandle().connection == null) return; ++ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundPlayerCombatKillPacket(getEntityId(), io.papermc.paper.adventure.PaperAdventure.asVanilla(message))); ++ } ++ // Purpur end - Death screen API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java.patch new file mode 100644 index 000000000..44a2a5b99 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java.patch @@ -0,0 +1,20 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java +@@ -28,4 +_,17 @@ + public String toString() { + return "CraftSnowman"; + } ++ ++ // Purpur start - Summoner API ++ @Override ++ @org.jetbrains.annotations.Nullable ++ public java.util.UUID getSummoner() { ++ return getHandle().getSummoner(); ++ } ++ ++ @Override ++ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) { ++ getHandle().setSummoner(summoner); ++ } ++ // Purpur end - Summoner API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java.patch new file mode 100644 index 000000000..9f16640c4 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java.patch @@ -0,0 +1,14 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +@@ -373,4 +_,11 @@ + getHandle().getGossips().gossips.clear(); + } + // Paper end ++ ++ // Purpur start - Lobotomize stuck villagers ++ @Override ++ public boolean isLobotomized() { ++ return getHandle().isLobotomized(); ++ } ++ // Purpur end - Lobotomize stuck villagers + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java.patch new file mode 100644 index 000000000..d1bf807f1 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java.patch @@ -0,0 +1,20 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java +@@ -99,4 +_,17 @@ + this.getHandle().makeInvulnerable(); + } + // Paper end ++ ++ // Purpur start - Summoner API ++ @Override ++ @org.jetbrains.annotations.Nullable ++ public java.util.UUID getSummoner() { ++ return getHandle().getSummoner(); ++ } ++ ++ @Override ++ public void setSummoner(@org.jetbrains.annotations.Nullable java.util.UUID summoner) { ++ getHandle().setSummoner(summoner); ++ } ++ // Purpur end - Summoner API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java.patch new file mode 100644 index 000000000..a85fb1dbd --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java.patch @@ -0,0 +1,18 @@ +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java +@@ -145,4 +_,15 @@ + return this.getKey().hashCode(); + } + } ++ // Purpur start - Configurable chance for wolves to spawn rabid ++ @Override ++ public boolean isRabid() { ++ return getHandle().isRabid(); ++ } ++ ++ @Override ++ public void setRabid(boolean isRabid) { ++ getHandle().setRabid(isRabid); ++ } ++ // Purpur end - Configurable chance for wolves to spawn rabid + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java.patch new file mode 100644 index 000000000..ce3a906ab --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1131,7 +_,7 @@ + return CraftEventFactory.callEntityDamageEvent(source.getDirectBlock(), source.getDirectBlockState(), entity, DamageCause.LAVA, bukkitDamageSource, modifiers, modifierFunctions, cancelled); + } else if (source.getDirectBlock() != null) { + DamageCause cause; +- if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL)) { ++ if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL) || source.isStonecutter()) { // Purpur - Stonecutter damage + cause = DamageCause.CONTACT; + } else if (source.is(DamageTypes.HOT_FLOOR)) { + cause = DamageCause.HOT_FLOOR; diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java.patch new file mode 100644 index 000000000..58b895e59 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java.patch @@ -0,0 +1,55 @@ +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java +@@ -19,6 +_,10 @@ + private int repairCost; + private int repairCostAmount; + private int maximumRepairCost; ++ // Purpur start - Anvil API ++ private boolean bypassCost; ++ private boolean canDoUnsafeEnchants; ++ // Purpur end - Anvil API + + public CraftInventoryAnvil(Location location, Container inventory, Container resultInventory) { + super(inventory, resultInventory); +@@ -27,6 +_,10 @@ + this.repairCost = CraftInventoryAnvil.DEFAULT_REPAIR_COST; + this.repairCostAmount = CraftInventoryAnvil.DEFAULT_REPAIR_COST_AMOUNT; + this.maximumRepairCost = CraftInventoryAnvil.DEFAULT_MAXIMUM_REPAIR_COST; ++ // Purpur start - Anvil API ++ this.bypassCost = false; ++ this.canDoUnsafeEnchants = false; ++ // Purpur end - Anvil API + } + + @Override +@@ -113,4 +_,30 @@ + consumer.accept(cav); + } + } ++ ++ // Purpur start - Anvil API ++ @Override ++ public boolean canBypassCost() { ++ this.syncWithArbitraryViewValue((cav) -> this.bypassCost = cav.canBypassCost()); ++ return this.bypassCost; ++ } ++ ++ @Override ++ public void setBypassCost(boolean bypassCost) { ++ this.bypassCost = bypassCost; ++ this.syncViews((cav) -> cav.setBypassCost(bypassCost)); ++ } ++ ++ @Override ++ public boolean canDoUnsafeEnchants() { ++ this.syncWithArbitraryViewValue((cav) -> this.canDoUnsafeEnchants = cav.canDoUnsafeEnchants()); ++ return this.canDoUnsafeEnchants; ++ } ++ ++ @Override ++ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) { ++ this.canDoUnsafeEnchants = canDoUnsafeEnchants; ++ this.syncViews((cav) -> cav.setDoUnsafeEnchants(canDoUnsafeEnchants)); ++ } ++ // Purpur end - Anvil API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java.patch new file mode 100644 index 000000000..458f702dd --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java.patch @@ -0,0 +1,288 @@ +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -666,4 +_,285 @@ + } + + // Paper end - data component API ++ ++ // Purpur start - ItemStack convenience methods ++ @Override ++ public String getDisplayName() { ++ return getItemMeta().getDisplayName(); ++ } ++ ++ @Override ++ public void setDisplayName(String name) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setDisplayName(name); ++ setItemMeta(itemMeta); ++ } ++ ++ @Override ++ public boolean hasDisplayName() { ++ return hasItemMeta() && getItemMeta().hasDisplayName(); ++ } ++ ++ @Override ++ public String getLocalizedName() { ++ return getItemMeta().getLocalizedName(); ++ } ++ ++ @Override ++ public void setLocalizedName(String name) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setLocalizedName(name); ++ setItemMeta(itemMeta); ++ } ++ ++ @Override ++ public boolean hasLocalizedName() { ++ return hasItemMeta() && getItemMeta().hasLocalizedName(); ++ } ++ ++ @Override ++ public boolean hasLore() { ++ return hasItemMeta() && getItemMeta().hasLore(); ++ } ++ ++ @Override ++ public boolean hasEnchant(Enchantment ench) { ++ return hasItemMeta() && getItemMeta().hasEnchant(ench); ++ } ++ ++ @Override ++ public int getEnchantLevel(Enchantment ench) { ++ return getItemMeta().getEnchantLevel(ench); ++ } ++ ++ @Override ++ public Map getEnchants() { ++ return getItemMeta().getEnchants(); ++ } ++ ++ @Override ++ public boolean addEnchant(Enchantment ench, int level, boolean ignoreLevelRestriction) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.addEnchant(ench, level, ignoreLevelRestriction); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ @Override ++ public boolean removeEnchant(Enchantment ench) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.removeEnchant(ench); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ @Override ++ public boolean hasEnchants() { ++ return hasItemMeta() && getItemMeta().hasEnchants(); ++ } ++ ++ @Override ++ public boolean hasConflictingEnchant(Enchantment ench) { ++ return hasItemMeta() && getItemMeta().hasConflictingEnchant(ench); ++ } ++ ++ @Override ++ public void setCustomModelData(Integer data) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setCustomModelData(data); ++ setItemMeta(itemMeta); ++ } ++ ++ @Override ++ public int getCustomModelData() { ++ return getItemMeta().getCustomModelData(); ++ } ++ ++ @Override ++ public boolean hasCustomModelData() { ++ return hasItemMeta() && getItemMeta().hasCustomModelData(); ++ } ++ ++ @Override ++ public boolean hasBlockData() { ++ return hasItemMeta() && ((org.bukkit.inventory.meta.BlockDataMeta) getItemMeta()).hasBlockData(); ++ } ++ ++ @Override ++ public org.bukkit.block.data.BlockData getBlockData(Material material) { ++ return ((org.bukkit.inventory.meta.BlockDataMeta) getItemMeta()).getBlockData(material); ++ } ++ ++ @Override ++ public void setBlockData(org.bukkit.block.data.BlockData blockData) { ++ ItemMeta itemMeta = getItemMeta(); ++ ((org.bukkit.inventory.meta.BlockDataMeta) itemMeta).setBlockData(blockData); ++ setItemMeta(itemMeta); ++ } ++ ++ @Override ++ public int getRepairCost() { ++ return ((org.bukkit.inventory.meta.Repairable) getItemMeta()).getRepairCost(); ++ } ++ ++ @Override ++ public void setRepairCost(int cost) { ++ ItemMeta itemMeta = getItemMeta(); ++ ((org.bukkit.inventory.meta.Repairable) itemMeta).setRepairCost(cost); ++ setItemMeta(itemMeta); ++ } ++ ++ @Override ++ public boolean hasRepairCost() { ++ return hasItemMeta() && ((org.bukkit.inventory.meta.Repairable) getItemMeta()).hasRepairCost(); ++ } ++ ++ @Override ++ public boolean isUnbreakable() { ++ return hasItemMeta() && getItemMeta().isUnbreakable(); ++ } ++ ++ @Override ++ public void setUnbreakable(boolean unbreakable) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setUnbreakable(unbreakable); ++ setItemMeta(itemMeta); ++ } ++ ++ @Override ++ public boolean hasAttributeModifiers() { ++ return hasItemMeta() && getItemMeta().hasAttributeModifiers(); ++ } ++ ++ @Override ++ public com.google.common.collect.Multimap getAttributeModifiers() { ++ return getItemMeta().getAttributeModifiers(); ++ } ++ ++ @Override ++ public com.google.common.collect.Multimap getAttributeModifiers(org.bukkit.inventory.EquipmentSlot slot) { ++ return getItemMeta().getAttributeModifiers(slot); ++ } ++ ++ @Override ++ public java.util.Collection getAttributeModifiers(org.bukkit.attribute.Attribute attribute) { ++ return getItemMeta().getAttributeModifiers(attribute); ++ } ++ ++ @Override ++ public boolean addAttributeModifier(org.bukkit.attribute.Attribute attribute, org.bukkit.attribute.AttributeModifier modifier) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.addAttributeModifier(attribute, modifier); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ @Override ++ public void setAttributeModifiers(com.google.common.collect.Multimap attributeModifiers) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setAttributeModifiers(attributeModifiers); ++ setItemMeta(itemMeta); ++ } ++ ++ @Override ++ public boolean removeAttributeModifier(org.bukkit.attribute.Attribute attribute) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.removeAttributeModifier(attribute); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ @Override ++ public boolean removeAttributeModifier(org.bukkit.inventory.EquipmentSlot slot) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.removeAttributeModifier(slot); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ @Override ++ public boolean removeAttributeModifier(org.bukkit.attribute.Attribute attribute, org.bukkit.attribute.AttributeModifier modifier) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.removeAttributeModifier(attribute, modifier); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ @Override ++ public boolean hasDamage() { ++ return hasItemMeta() && ((org.bukkit.inventory.meta.Damageable) getItemMeta()).hasDamage(); ++ } ++ ++ @Override ++ public int getDamage() { ++ return ((org.bukkit.inventory.meta.Damageable) getItemMeta()).getDamage(); ++ } ++ ++ @Override ++ public void setDamage(int damage) { ++ ItemMeta itemMeta = getItemMeta(); ++ ((org.bukkit.inventory.meta.Damageable) itemMeta).setDamage(damage); ++ setItemMeta(itemMeta); ++ } ++ ++ @Override ++ public void repair() { ++ repair(1); ++ } ++ ++ @Override ++ public boolean damage() { ++ return damage(1); ++ } ++ ++ @Override ++ public void repair(int amount) { ++ damage(-amount); ++ } ++ ++ @Override ++ public boolean damage(int amount) { ++ return damage(amount, false); ++ } ++ ++ @Override ++ public boolean damage(int amount, boolean ignoreUnbreaking) { ++ org.bukkit.inventory.meta.Damageable damageable = (org.bukkit.inventory.meta.Damageable) getItemMeta(); ++ if (amount > 0) { ++ int unbreaking = getEnchantLevel(Enchantment.UNBREAKING); ++ int reduce = 0; ++ for (int i = 0; unbreaking > 0 && i < amount; ++i) { ++ if (reduceDamage(java.util.concurrent.ThreadLocalRandom.current(), unbreaking)) { ++ ++reduce; ++ } ++ } ++ amount -= reduce; ++ if (amount <= 0) { ++ return isBroke(damageable.getDamage()); ++ } ++ } ++ int damage = damageable.getDamage() + amount; ++ damageable.setDamage(damage); ++ setItemMeta((ItemMeta) damageable); ++ return isBroke(damage); ++ } ++ ++ private boolean isBroke(int damage) { ++ if (damage > getType().getMaxDurability()) { ++ if (getAmount() > 0) { ++ // ensure it "breaks" ++ setAmount(0); ++ } ++ return true; ++ } ++ return false; ++ } ++ ++ private boolean reduceDamage(java.util.Random random, int unbreaking) { ++ if (getType().isArmor()) { ++ return random.nextFloat() < 0.6F; ++ } ++ return random.nextInt(unbreaking + 1) > 0; ++ } ++ // Purpur end - ItemStack convenience methods + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java.patch new file mode 100644 index 000000000..b3042e1f5 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java.patch @@ -0,0 +1,10 @@ +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +@@ -36,6 +_,7 @@ + stack = Ingredient.of(((RecipeChoice.MaterialChoice) bukkit).getChoices().stream().map((mat) -> CraftItemType.bukkitToMinecraft(mat))); + } else if (bukkit instanceof RecipeChoice.ExactChoice) { + stack = Ingredient.ofStacks(((RecipeChoice.ExactChoice) bukkit).getChoices().stream().map((mat) -> CraftItemStack.asNMSCopy(mat)).toList()); ++ stack.predicate = ((RecipeChoice.ExactChoice) bukkit).getPredicate(); // Purpur - Add predicate to recipe's ExactChoice ingredient + // Paper start - support "empty" choices - legacy method that spigot might incorrectly call + // Their impl of Ingredient.of() will error, ingredients need at least one entry. + // Callers running into this exception may have passed an incorrect empty() recipe choice to a non-empty slot or diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java.patch new file mode 100644 index 000000000..f2659f49e --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java.patch @@ -0,0 +1,29 @@ +--- a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java +@@ -75,4 +_,26 @@ + this.setMaximumRepairCost(legacy.getMaximumRepairCost()); + } + } ++ ++ // Purpur start - Anvil API ++ @Override ++ public boolean canBypassCost() { ++ return this.container.bypassCost; ++ } ++ ++ @Override ++ public void setBypassCost(boolean bypassCost) { ++ this.container.bypassCost = bypassCost; ++ } ++ ++ @Override ++ public boolean canDoUnsafeEnchants() { ++ return this.container.canDoUnsafeEnchants; ++ } ++ ++ @Override ++ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) { ++ this.container.canDoUnsafeEnchants = canDoUnsafeEnchants; ++ } ++ // Purpur end - Anvil API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java.patch new file mode 100644 index 000000000..9061089d2 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java.patch @@ -0,0 +1,10 @@ +--- a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java ++++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java +@@ -265,6 +_,7 @@ + } + + static { ++ if (!org.purpurmc.purpur.PurpurConfig.loggerSuppressInitLegacyMaterialError) // Purpur - Logger settings (suppressing pointless logs) + LOGGER.warn("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); // Paper - Improve logging and errors; doesn't need to be an error + if (MinecraftServer.getServer() != null && MinecraftServer.getServer().isDebugging()) { + new Exception().printStackTrace(); diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java.patch new file mode 100644 index 000000000..74a359244 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java.patch @@ -0,0 +1,35 @@ +--- a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java ++++ b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java +@@ -708,4 +_,32 @@ + meta.setCanPlaceOn(materials); + } + // Paper end ++ // Purpur start - Adopt MaterialRerouting ++ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/pull/570) ++ public static void addFuel(Server server, Material material, int burnTime) { ++ server.addFuel(material, burnTime); ++ } ++ ++ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/pull/570) ++ public static void removeFuel(Server server, Material material) { ++ server.removeFuel(material); ++ } ++ ++ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/pull/570) ++ @RerouteStatic("org/bukkit/Bukkit") ++ public static void addFuel(Material material, int burnTime) { ++ Bukkit.addFuel(material, burnTime); ++ } ++ ++ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/pull/570) ++ @RerouteStatic("org/bukkit/Bukkit") ++ public static void removeFuel(Material material) { ++ Bukkit.removeFuel(material); ++ } ++ ++ // Method added post 1.13, no-op (https://github.com/PurpurMC/Purpur/commit/607d909efba516893072b782c0393c53d048210e) ++ public static BlockData getBlockData(ItemStack itemStack, Material material) { ++ return itemStack.getBlockData(MaterialRerouting.transformToBlockType(material)); ++ } ++ // Purpur end - Adopt MaterialRerouting + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java.patch new file mode 100644 index 000000000..c9e34b3ad --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java.patch @@ -0,0 +1,13 @@ +--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java ++++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapRenderer.java +@@ -49,4 +_,10 @@ + } + } + ++ // Purpur start - Explorer Map API ++ @Override ++ public boolean isExplorerMap() { ++ return this.worldMap.isExplorerMap; ++ } ++ // Purpur end - Explorer Map API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java.patch new file mode 100644 index 000000000..46d23c417 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +@@ -491,7 +_,7 @@ + this.parsePending(); + } else { + // this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(this.currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper +- task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Paper"); // Paper ++ task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Purpur"); // Paper // Purpur - Rebrand + // We don't need to parse pending + // (async tasks must live with race-conditions if they attempt to cancel between these few lines of code) + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java.patch new file mode 100644 index 000000000..2f747707b --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -508,7 +_,7 @@ + // Paper start + @Override + public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { +- return new com.destroystokyo.paper.PaperVersionFetcher(); ++ return new com.destroystokyo.paper.PaperVersionFetcher(); // Pufferfish // Purpur - Rebrand + } + + @Override diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/Versioning.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/Versioning.java.patch new file mode 100644 index 000000000..a560ff72a --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/Versioning.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java +@@ -11,7 +_,7 @@ + public static String getBukkitVersion() { + String result = "Unknown-Version"; + +- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); ++ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/org.purpurmc.purpur/purpur-api/pom.properties"); // Pufferfish // Purpur - Rebrand + Properties properties = new Properties(); + + if (stream != null) { diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java.patch new file mode 100644 index 000000000..6106785b3 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java.patch @@ -0,0 +1,19 @@ +--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java +@@ -23,7 +_,15 @@ + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "kick", "Allows the user to kick players", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "stop", "Allows the user to stop the server", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "list", "Allows the user to list all online players", PermissionDefault.OP, commands); +- DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "gamemode", "Allows the user to change the gamemode of another player", PermissionDefault.OP, commands); ++ // Purpur start - Gamemode extra permissions ++ Permission gamemodeVanilla = DefaultPermissions.registerPermission(PREFIX + "gamemode", "Allows the user to change the gamemode", PermissionDefault.OP, commands); ++ for (net.minecraft.world.level.GameType gametype : net.minecraft.world.level.GameType.values()) { ++ Permission gamemodeSelf = DefaultPermissions.registerPermission(PREFIX + "gamemode." + gametype.getName(), "Allows the user to set " + gametype.getName() + " gamemode for self", PermissionDefault.OP); ++ Permission gamemodeOther = DefaultPermissions.registerPermission(PREFIX + "gamemode." + gametype.getName() + ".other", "Allows the user to set " + gametype.getName() + " gamemode for other players", PermissionDefault.OP); ++ gamemodeSelf.addParent(gamemodeOther, true); ++ gamemodeVanilla.addParent(gamemodeSelf, true); ++ } ++ // Purpur end - Gamemode extra permissions + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "experience", "Allows the user to give themselves or others arbitrary values of experience", PermissionDefault.OP, commands); // Paper - wrong permission; redirects are de-redirected and the root literal name is used, so xp -> experience + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "defaultgamemode", "Allows the user to change the default gamemode of the server", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(CommandPermissions.PREFIX + "seed", "Allows the user to view the seed of the world", PermissionDefault.OP, commands); diff --git a/purpur-server/paper-patches/files/src/main/java/org/spigotmc/TicksPerSecondCommand.java.patch b/purpur-server/paper-patches/files/src/main/java/org/spigotmc/TicksPerSecondCommand.java.patch new file mode 100644 index 000000000..423a40206 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/spigotmc/TicksPerSecondCommand.java.patch @@ -0,0 +1,11 @@ +--- a/src/main/java/org/spigotmc/TicksPerSecondCommand.java ++++ b/src/main/java/org/spigotmc/TicksPerSecondCommand.java +@@ -43,7 +_,7 @@ + } + + TextComponent.Builder builder = text(); +- builder.append(text("TPS from last 1m, 5m, 15m: ", NamedTextColor.GOLD)); ++ builder.append(text("TPS from last 5s, 1m, 5m, 15m: ", NamedTextColor.GOLD)); // Purpur - Add 5 second tps average in /tps + builder.append(Component.join(JoinConfiguration.commas(true), tpsAvg)); + sender.sendMessage(builder.asComponent()); + if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) { diff --git a/purpur-server/paper-patches/files/src/main/java/org/spigotmc/WatchdogThread.java.patch b/purpur-server/paper-patches/files/src/main/java/org/spigotmc/WatchdogThread.java.patch new file mode 100644 index 000000000..03e3a05ad --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/spigotmc/WatchdogThread.java.patch @@ -0,0 +1,53 @@ +--- a/src/main/java/org/spigotmc/WatchdogThread.java ++++ b/src/main/java/org/spigotmc/WatchdogThread.java +@@ -25,7 +_,7 @@ + private volatile boolean stopping; + + private WatchdogThread(long timeoutTime, boolean restart) { +- super("Paper Watchdog Thread"); ++ super("Watchdog Thread"); // Purpur - use a generic name - Rebrand + this.timeoutTime = timeoutTime; + this.restart = restart; + this.earlyWarningEvery = Math.min(GlobalConfiguration.get().watchdog.earlyWarningEvery, timeoutTime); // Paper +@@ -77,14 +_,14 @@ + if (isLongTimeout) { + // Paper end + logger.log(Level.SEVERE, "------------------------------"); +- logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug."); // Paper ++ logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Purpur bug."); // Paper // Purpur - Rebrand + logger.log(Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author"); + logger.log(Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring"); + logger.log(Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once"); + logger.log(Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes"); +- logger.log(Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues"); ++ logger.log(Level.SEVERE, "If you are unsure or still think this is a Purpur bug, please report this to https://github.com/PurpurMC/Purpur/issues"); // Purpur - Rebrand + logger.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports"); +- logger.log(Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion()); ++ logger.log(Level.SEVERE, "Purpur version: " + Bukkit.getServer().getVersion()); // Purpur - Rebrand + + if (net.minecraft.world.level.Level.lastPhysicsProblem != null) { + logger.log(Level.SEVERE, "------------------------------"); +@@ -104,12 +_,12 @@ + } + // Paper end + } else { +- logger.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---"); ++ logger.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PURPUR - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---"); // Purpur - Rebrand + logger.log(Level.SEVERE, "The server has not responded for " + (currentTime - lastTick) / 1000 + " seconds! Creating thread dump"); + } + // Paper end - Different message for short timeout + logger.log(Level.SEVERE, "------------------------------"); +- logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):"); // Paper ++ logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Purpur!):" ); // Paper // Purpur - Rebrand + FeatureHooks.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - log detailed tick information + WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE), logger); + logger.log(Level.SEVERE, "------------------------------"); +@@ -122,7 +_,7 @@ + WatchdogThread.dumpThread(thread, logger); + } + } else { +- logger.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH ---"); ++ logger.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PURPUR - THIS IS NOT A BUG OR A CRASH ---"); // Purpur - Rebrand + } + + logger.log(Level.SEVERE, "------------------------------"); diff --git a/purpur-server/paper-patches/files/src/main/resources/log4j2.xml.patch b/purpur-server/paper-patches/files/src/main/resources/log4j2.xml.patch new file mode 100644 index 000000000..8b4a31032 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/resources/log4j2.xml.patch @@ -0,0 +1,20 @@ +--- a/src/main/resources/log4j2.xml ++++ b/src/main/resources/log4j2.xml +@@ -2,7 +_,16 @@ + + + +- ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + diff --git a/patches/server/0241-Skip-junit-tests-for-purpur-commands.patch b/purpur-server/paper-patches/files/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java.patch similarity index 59% rename from patches/server/0241-Skip-junit-tests-for-purpur-commands.patch rename to purpur-server/paper-patches/files/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java.patch index d8c96ae4a..6fb471079 100644 --- a/patches/server/0241-Skip-junit-tests-for-purpur-commands.patch +++ b/purpur-server/paper-patches/files/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java.patch @@ -1,26 +1,18 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: BillyGalbreath -Date: Thu, 8 Dec 2022 19:13:26 -0600 -Subject: [PATCH] Skip junit tests for purpur commands - - -diff --git a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java -index 2f3ff50bf3f70b6b404d02d5ffcc079162a63bc1..4e57fdf21d4b7789cd7c3d3a18ddc6227bc77792 100644 --- a/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java +++ b/src/test/java/io/papermc/paper/permissions/MinecraftCommandPermissionsTest.java -@@ -48,6 +48,7 @@ public class MinecraftCommandPermissionsTest extends AbstractTestingBase { - if ("bukkit.command.paper.pgive".equals(vanillaPerm)) { // skip our custom give command - continue; - } -+ if (TO_SKIP.contains(vanillaPerm)) continue; // Purpur +@@ -46,6 +_,7 @@ + Set foundPerms = new HashSet<>(); + for (CommandNode child : root.getChildren()) { + final String vanillaPerm = VanillaCommandWrapper.getPermission(child); ++ if (TO_SKIP.contains(vanillaPerm)) continue; // Purpur - Skip junit tests for purpur commands if (!perms.contains(vanillaPerm)) { missing.add("Missing permission for " + child.getName() + " (" + vanillaPerm + ") command"); } else { -@@ -60,6 +61,25 @@ public class MinecraftCommandPermissionsTest extends AbstractTestingBase { +@@ -58,6 +_,25 @@ } private static final List TO_SKIP = List.of( -+ // Purpur start ++ // Purpur start - Skip junit tests for purpur commands + "minecraft.command.compass", + "minecraft.command.credits", + "minecraft.command.demo", @@ -38,7 +30,7 @@ index 2f3ff50bf3f70b6b404d02d5ffcc079162a63bc1..4e57fdf21d4b7789cd7c3d3a18ddc622 + "minecraft.command.gamemode.spectator.other", + "minecraft.command.gamemode.survival", + "minecraft.command.gamemode.survival.other", -+ // Purpur end ++ // Purpur end - Skip junit tests for purpur commands "minecraft.command.selector" ); diff --git a/purpur-server/src/log4jPlugins/java/org/purpurmc/purpur/gui/util/HighlightErrorConverter.java b/purpur-server/src/log4jPlugins/java/org/purpurmc/purpur/gui/util/HighlightErrorConverter.java new file mode 100644 index 000000000..ede7cb766 --- /dev/null +++ b/purpur-server/src/log4jPlugins/java/org/purpurmc/purpur/gui/util/HighlightErrorConverter.java @@ -0,0 +1,85 @@ +package org.purpurmc.purpur.gui.util; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.core.pattern.ConverterKeys; +import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; +import org.apache.logging.log4j.core.pattern.PatternConverter; +import org.apache.logging.log4j.core.pattern.PatternFormatter; +import org.apache.logging.log4j.core.pattern.PatternParser; +import org.apache.logging.log4j.util.PerformanceSensitive; + +import java.util.List; + +@Plugin(name = "highlightGUIError", category = PatternConverter.CATEGORY) +@ConverterKeys({"highlightGUIError"}) +@PerformanceSensitive("allocation") +public final class HighlightErrorConverter extends LogEventPatternConverter { + private static final String ERROR = "\u00A74\u00A7l"; // Bold Red + private static final String WARN = "\u00A7e\u00A7l"; // Bold Yellow + + private final List formatters; + + private HighlightErrorConverter(List formatters) { + super("highlightGUIError", null); + this.formatters = formatters; + } + + @Override + public void format(LogEvent event, StringBuilder toAppendTo) { + Level level = event.getLevel(); + if (level.isMoreSpecificThan(Level.ERROR)) { + format(ERROR, event, toAppendTo); + return; + } else if (level.isMoreSpecificThan(Level.WARN)) { + format(WARN, event, toAppendTo); + return; + } + for (PatternFormatter formatter : formatters) { + formatter.format(event, toAppendTo); + } + } + + private void format(String style, LogEvent event, StringBuilder toAppendTo) { + int start = toAppendTo.length(); + toAppendTo.append(style); + int end = toAppendTo.length(); + + for (PatternFormatter formatter : formatters) { + formatter.format(event, toAppendTo); + } + + if (toAppendTo.length() == end) { + toAppendTo.setLength(start); + } + } + + @Override + public boolean handlesThrowable() { + for (final PatternFormatter formatter : formatters) { + if (formatter.handlesThrowable()) { + return true; + } + } + return false; + } + + public static HighlightErrorConverter newInstance(Configuration config, String[] options) { + if (options.length != 1) { + LOGGER.error("Incorrect number of options on highlightGUIError. Expected 1 received " + options.length); + return null; + } + + if (options[0] == null) { + LOGGER.error("No pattern supplied on highlightGUIError"); + return null; + } + + PatternParser parser = PatternLayout.createPatternParser(config); + List formatters = parser.parse(options[0]); + return new HighlightErrorConverter(formatters); + } +} \ No newline at end of file diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/purpur-server/src/main/java/org/purpurmc/purpur/PurpurConfig.java new file mode 100644 index 000000000..959641751 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/PurpurConfig.java @@ -0,0 +1,602 @@ +package org.purpurmc.purpur; + +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockBehaviour; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.purpurmc.purpur.command.PurpurCommand; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import org.purpurmc.purpur.task.TPSBarTask; + +@SuppressWarnings("unused") +public class PurpurConfig { + private static final String HEADER = "This is the main configuration file for Purpur.\n" + + "As you can see, there's tons to configure. Some options may impact gameplay, so use\n" + + "with caution, and make sure you know what each option does before configuring.\n" + + "\n" + + "If you need help with the configuration or have any questions related to Purpur,\n" + + "join us in our Discord guild.\n" + + "\n" + + "Website: https://purpurmc.org \n" + + "Docs: https://purpurmc.org/docs \n"; + private static File CONFIG_FILE; + public static YamlConfiguration config; + + private static Map commands; + + public static int version; + static boolean verbose; + + public static void init(File configFile) { + CONFIG_FILE = configFile; + config = new YamlConfiguration(); + try { + config.load(CONFIG_FILE); + } catch (IOException ignore) { + } catch (InvalidConfigurationException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Could not load purpur.yml, please correct your syntax errors", ex); + throw Throwables.propagate(ex); + } + config.options().header(HEADER); + config.options().copyDefaults(true); + verbose = getBoolean("verbose", false); + + commands = new HashMap<>(); + commands.put("purpur", new PurpurCommand("purpur")); + + version = getInt("config-version", 39); + set("config-version", 39); + + readConfig(PurpurConfig.class, null); + + Block.BLOCK_STATE_REGISTRY.forEach(BlockBehaviour.BlockStateBase::initCache); + } + + protected static void log(String s) { + if (verbose) { + log(Level.INFO, s); + } + } + + protected static void log(Level level, String s) { + Bukkit.getLogger().log(level, s); + } + + public static void registerCommands() { + for (Map.Entry entry : commands.entrySet()) { + MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Purpur", entry.getValue()); + } + } + + static void readConfig(Class clazz, Object instance) { + for (Method method : clazz.getDeclaredMethods()) { + if (Modifier.isPrivate(method.getModifiers())) { + if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { + try { + method.setAccessible(true); + method.invoke(instance); + } catch (InvocationTargetException ex) { + throw Throwables.propagate(ex.getCause()); + } catch (Exception ex) { + Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex); + } + } + } + } + + try { + config.save(CONFIG_FILE); + } catch (IOException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex); + } + } + + private static void set(String path, Object val) { + config.addDefault(path, val); + config.set(path, val); + } + + private static String getString(String path, String def) { + config.addDefault(path, def); + return config.getString(path, config.getString(path)); + } + + private static boolean getBoolean(String path, boolean def) { + config.addDefault(path, def); + return config.getBoolean(path, config.getBoolean(path)); + } + + private static double getDouble(String path, double def) { + config.addDefault(path, def); + return config.getDouble(path, config.getDouble(path)); + } + + private static int getInt(String path, int def) { + config.addDefault(path, def); + return config.getInt(path, config.getInt(path)); + } + + private static List getList(String path, T def) { + config.addDefault(path, def); + return config.getList(path, config.getList(path)); + } + + static Map getMap(String path, Map def) { + if (def != null && config.getConfigurationSection(path) == null) { + config.addDefault(path, def); + return def; + } + return toMap(config.getConfigurationSection(path)); + } + + private static Map toMap(ConfigurationSection section) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + if (section != null) { + for (String key : section.getKeys(false)) { + Object obj = section.get(key); + if (obj != null) { + builder.put(key, obj instanceof ConfigurationSection val ? toMap(val) : obj); + } + } + } + return builder.build(); + } + + public static String cannotRideMob = "You cannot mount that mob"; + public static String afkBroadcastAway = "%s is now AFK"; + public static String afkBroadcastBack = "%s is no longer AFK"; + public static boolean afkBroadcastUseDisplayName = false; + public static String afkTabListPrefix = "[AFK] "; + public static String afkTabListSuffix = ""; + public static String creditsCommandOutput = "%s has been shown the end credits"; + public static String demoCommandOutput = "%s has been shown the demo screen"; + public static String pingCommandOutput = "%s's ping is %sms"; + public static String ramCommandOutput = "Ram Usage: / ()"; + public static String rambarCommandOutput = "Rambar toggled for "; + public static String tpsbarCommandOutput = "Tpsbar toggled for "; + public static String dontRunWithScissors = "Don't run with scissors!"; + public static String uptimeCommandOutput = "Server uptime is "; + public static String unverifiedUsername = "default"; + public static String sleepSkippingNight = "default"; + public static String sleepingPlayersPercent = "default"; + public static String sleepNotPossible = "default"; + private static void messages() { + cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); + afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); + afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); + afkBroadcastUseDisplayName = getBoolean("settings.messages.afk-broadcast-use-display-name", afkBroadcastUseDisplayName); + afkTabListPrefix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix))); + afkTabListSuffix = MiniMessage.miniMessage().serialize(MiniMessage.miniMessage().deserialize(getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix))); + creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput); + demoCommandOutput = getString("settings.messages.demo-command-output", demoCommandOutput); + pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); + ramCommandOutput = getString("settings.messages.ram-command-output", ramCommandOutput); + rambarCommandOutput = getString("settings.messages.rambar-command-output", rambarCommandOutput); + tpsbarCommandOutput = getString("settings.messages.tpsbar-command-output", tpsbarCommandOutput); + dontRunWithScissors = getString("settings.messages.dont-run-with-scissors", dontRunWithScissors); + uptimeCommandOutput = getString("settings.messages.uptime-command-output", uptimeCommandOutput); + unverifiedUsername = getString("settings.messages.unverified-username", unverifiedUsername); + sleepSkippingNight = getString("settings.messages.sleep-skipping-night", sleepSkippingNight); + sleepingPlayersPercent = getString("settings.messages.sleeping-players-percent", sleepingPlayersPercent); + sleepNotPossible = getString("settings.messages.sleep-not-possible", sleepNotPossible); + } + + public static String deathMsgRunWithScissors = " slipped and fell on their shears"; + public static String deathMsgStonecutter = " has sawed themself in half"; + private static void deathMessages() { + deathMsgRunWithScissors = getString("settings.messages.death-message.run-with-scissors", deathMsgRunWithScissors); + deathMsgStonecutter = getString("settings.messages.death-message.stonecutter", deathMsgStonecutter); + } + + public static boolean advancementOnlyBroadcastToAffectedPlayer = false; + public static boolean deathMessageOnlyBroadcastToAffectedPlayer = false; + private static void broadcastSettings() { + if (version < 13) { + boolean oldValue = getBoolean("settings.advancement.only-broadcast-to-affected-player", false); + set("settings.broadcasts.advancement.only-broadcast-to-affected-player", oldValue); + set("settings.advancement.only-broadcast-to-affected-player", null); + } + advancementOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.advancement.only-broadcast-to-affected-player", advancementOnlyBroadcastToAffectedPlayer); + deathMessageOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.death.only-broadcast-to-affected-player", deathMessageOnlyBroadcastToAffectedPlayer); + } + + public static String serverModName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); + private static void serverModName() { + serverModName = getString("settings.server-mod-name", serverModName); + } + + public static double laggingThreshold = 19.0D; + private static void tickLoopSettings() { + laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold); + } + + public static boolean useAlternateKeepAlive = false; + private static void useAlternateKeepAlive() { + useAlternateKeepAlive = getBoolean("settings.use-alternate-keepalive", useAlternateKeepAlive); + } + + public static boolean disableGiveCommandDrops = false; + private static void disableGiveCommandDrops() { + disableGiveCommandDrops = getBoolean("settings.disable-give-dropping", disableGiveCommandDrops); + } + + public static String commandRamBarTitle = "Ram: / ()"; + public static BossBar.Overlay commandRamBarProgressOverlay = BossBar.Overlay.NOTCHED_20; + public static BossBar.Color commandRamBarProgressColorGood = BossBar.Color.GREEN; + public static BossBar.Color commandRamBarProgressColorMedium = BossBar.Color.YELLOW; + public static BossBar.Color commandRamBarProgressColorLow = BossBar.Color.RED; + public static String commandRamBarTextColorGood = ""; + public static String commandRamBarTextColorMedium = ""; + public static String commandRamBarTextColorLow = ""; + public static int commandRamBarTickInterval = 20; + public static String commandTPSBarTitle = "TPS: MSPT: Ping: ms"; + public static BossBar.Overlay commandTPSBarProgressOverlay = BossBar.Overlay.NOTCHED_20; + public static TPSBarTask.FillMode commandTPSBarProgressFillMode = TPSBarTask.FillMode.MSPT; + public static BossBar.Color commandTPSBarProgressColorGood = BossBar.Color.GREEN; + public static BossBar.Color commandTPSBarProgressColorMedium = BossBar.Color.YELLOW; + public static BossBar.Color commandTPSBarProgressColorLow = BossBar.Color.RED; + public static String commandTPSBarTextColorGood = ""; + public static String commandTPSBarTextColorMedium = ""; + public static String commandTPSBarTextColorLow = ""; + public static int commandTPSBarTickInterval = 20; + public static String commandCompassBarTitle = "S \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 W \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 N \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 E \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 S \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 W \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NW \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 N \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 NE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 E \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 SE \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 \u25C8 \u00B7 "; + public static BossBar.Overlay commandCompassBarProgressOverlay = BossBar.Overlay.PROGRESS; + public static BossBar.Color commandCompassBarProgressColor = BossBar.Color.BLUE; + public static float commandCompassBarProgressPercent = 1.0F; + public static int commandCompassBarTickInterval = 5; + public static boolean commandGamemodeRequiresPermission = false; + public static boolean hideHiddenPlayersFromEntitySelector = false; + public static String uptimeFormat = ""; + public static String uptimeDay = "%02d day, "; + public static String uptimeDays = "%02d days, "; + public static String uptimeHour = "%02d hour, "; + public static String uptimeHours = "%02d hours, "; + public static String uptimeMinute = "%02d minute, and "; + public static String uptimeMinutes = "%02d minutes, and "; + public static String uptimeSecond = "%02d second"; + public static String uptimeSeconds = "%02d seconds"; + private static void commandSettings() { + commandRamBarTitle = getString("settings.command.rambar.title", commandRamBarTitle); + commandRamBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.rambar.overlay", commandRamBarProgressOverlay.name())); + commandRamBarProgressColorGood = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.good", commandRamBarProgressColorGood.name())); + commandRamBarProgressColorMedium = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.medium", commandRamBarProgressColorMedium.name())); + commandRamBarProgressColorLow = BossBar.Color.valueOf(getString("settings.command.rambar.progress-color.low", commandRamBarProgressColorLow.name())); + commandRamBarTextColorGood = getString("settings.command.rambar.text-color.good", commandRamBarTextColorGood); + commandRamBarTextColorMedium = getString("settings.command.rambar.text-color.medium", commandRamBarTextColorMedium); + commandRamBarTextColorLow = getString("settings.command.rambar.text-color.low", commandRamBarTextColorLow); + commandRamBarTickInterval = getInt("settings.command.rambar.tick-interval", commandRamBarTickInterval); + + commandTPSBarTitle = getString("settings.command.tpsbar.title", commandTPSBarTitle); + commandTPSBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.tpsbar.overlay", commandTPSBarProgressOverlay.name())); + commandTPSBarProgressFillMode = TPSBarTask.FillMode.valueOf(getString("settings.command.tpsbar.fill-mode", commandTPSBarProgressFillMode.name())); + commandTPSBarProgressColorGood = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.good", commandTPSBarProgressColorGood.name())); + commandTPSBarProgressColorMedium = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.medium", commandTPSBarProgressColorMedium.name())); + commandTPSBarProgressColorLow = BossBar.Color.valueOf(getString("settings.command.tpsbar.progress-color.low", commandTPSBarProgressColorLow.name())); + commandTPSBarTextColorGood = getString("settings.command.tpsbar.text-color.good", commandTPSBarTextColorGood); + commandTPSBarTextColorMedium = getString("settings.command.tpsbar.text-color.medium", commandTPSBarTextColorMedium); + commandTPSBarTextColorLow = getString("settings.command.tpsbar.text-color.low", commandTPSBarTextColorLow); + commandTPSBarTickInterval = getInt("settings.command.tpsbar.tick-interval", commandTPSBarTickInterval); + + commandCompassBarTitle = getString("settings.command.compass.title", commandCompassBarTitle); + commandCompassBarProgressOverlay = BossBar.Overlay.valueOf(getString("settings.command.compass.overlay", commandCompassBarProgressOverlay.name())); + commandCompassBarProgressColor = BossBar.Color.valueOf(getString("settings.command.compass.progress-color", commandCompassBarProgressColor.name())); + commandCompassBarProgressPercent = (float) getDouble("settings.command.compass.percent", commandCompassBarProgressPercent); + commandCompassBarTickInterval = getInt("settings.command.compass.tick-interval", commandCompassBarTickInterval); + + commandGamemodeRequiresPermission = getBoolean("settings.command.gamemode.requires-specific-permission", commandGamemodeRequiresPermission); + hideHiddenPlayersFromEntitySelector = getBoolean("settings.command.hide-hidden-players-from-entity-selector", hideHiddenPlayersFromEntitySelector); + uptimeFormat = getString("settings.command.uptime.format", uptimeFormat); + uptimeDay = getString("settings.command.uptime.day", uptimeDay); + uptimeDays = getString("settings.command.uptime.days", uptimeDays); + uptimeHour = getString("settings.command.uptime.hour", uptimeHour); + uptimeHours = getString("settings.command.uptime.hours", uptimeHours); + uptimeMinute = getString("settings.command.uptime.minute", uptimeMinute); + uptimeMinutes = getString("settings.command.uptime.minutes", uptimeMinutes); + uptimeSecond = getString("settings.command.uptime.second", uptimeSecond); + uptimeSeconds = getString("settings.command.uptime.seconds", uptimeSeconds); + } + + public static int barrelRows = 3; + public static boolean enderChestSixRows = false; + public static boolean enderChestPermissionRows = false; + public static boolean cryingObsidianValidForPortalFrame = false; + public static int beeInsideBeeHive = 3; + public static boolean anvilCumulativeCost = true; + public static int lightningRodRange = 128; + public static Set grindstoneIgnoredEnchants = new HashSet<>(); + public static boolean grindstoneRemoveAttributes = false; + public static boolean grindstoneRemoveDisplay = false; + public static int caveVinesMaxGrowthAge = 25; + public static int kelpMaxGrowthAge = 25; + public static int twistingVinesMaxGrowthAge = 25; + public static int weepingVinesMaxGrowthAge = 25; + public static boolean magmaBlockReverseBubbleColumnFlow = false; + public static boolean soulSandBlockReverseBubbleColumnFlow = false; + private static void blockSettings() { + if (version < 3) { + boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); + set("settings.blocks.barrel.six-rows", oldValue); + set("settings.packed-barrels", null); + oldValue = getBoolean("settings.large-ender-chests", true); + set("settings.blocks.ender_chest.six-rows", oldValue); + set("settings.large-ender-chests", null); + } + if (version < 20) { + boolean oldValue = getBoolean("settings.blocks.barrel.six-rows", false); + set("settings.blocks.barrel.rows", oldValue ? 6 : 3); + set("settings.blocks.barrel.six-rows", null); + } + barrelRows = getInt("settings.blocks.barrel.rows", barrelRows); + if (barrelRows < 1 || barrelRows > 6) { + Bukkit.getLogger().severe("settings.blocks.barrel.rows must be 1-6, resetting to default"); + barrelRows = 3; + } + org.bukkit.event.inventory.InventoryType.BARREL.setDefaultSize(switch (barrelRows) { + case 6 -> 54; + case 5 -> 45; + case 4 -> 36; + case 2 -> 18; + case 1 -> 9; + default -> 27; + }); + enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows); + org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); + enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); + cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame); + beeInsideBeeHive = getInt("settings.blocks.beehive.max-bees-inside", beeInsideBeeHive); + anvilCumulativeCost = getBoolean("settings.blocks.anvil.cumulative-cost", anvilCumulativeCost); + lightningRodRange = getInt("settings.blocks.lightning_rod.range", lightningRodRange); + ArrayList defaultCurses = new ArrayList<>(){{ + add("minecraft:binding_curse"); + add("minecraft:vanishing_curse"); + }}; + if (version < 24 && !getBoolean("settings.blocks.grindstone.ignore-curses", true)) { + defaultCurses.clear(); + } + getList("settings.blocks.grindstone.ignored-enchants", defaultCurses).forEach(key -> { + Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.ENCHANTMENT); + Enchantment enchantment = registry.getValue(ResourceLocation.parse(key.toString())); + if (enchantment == null) return; + grindstoneIgnoredEnchants.add(enchantment); + }); + grindstoneRemoveAttributes = getBoolean("settings.blocks.grindstone.remove-attributes", grindstoneRemoveAttributes); + grindstoneRemoveDisplay = getBoolean("settings.blocks.grindstone.remove-name-and-lore", grindstoneRemoveDisplay); + caveVinesMaxGrowthAge = getInt("settings.blocks.cave_vines.max-growth-age", caveVinesMaxGrowthAge); + if (caveVinesMaxGrowthAge > 25) { + caveVinesMaxGrowthAge = 25; + log(Level.WARNING, "blocks.cave_vines.max-growth-age is set to above maximum allowed value of 25"); + log(Level.WARNING, "Using value of 25 to prevent issues"); + } + kelpMaxGrowthAge = getInt("settings.blocks.kelp.max-growth-age", kelpMaxGrowthAge); + if (kelpMaxGrowthAge > 25) { + kelpMaxGrowthAge = 25; + log(Level.WARNING, "blocks.kelp.max-growth-age is set to above maximum allowed value of 25"); + log(Level.WARNING, "Using value of 25 to prevent issues"); + } + twistingVinesMaxGrowthAge = getInt("settings.blocks.twisting_vines.max-growth-age", twistingVinesMaxGrowthAge); + if (twistingVinesMaxGrowthAge > 25) { + twistingVinesMaxGrowthAge = 25; + log(Level.WARNING, "blocks.twisting_vines.max-growth-age is set to above maximum allowed value of 25"); + log(Level.WARNING, "Using value of 25 to prevent issues"); + } + weepingVinesMaxGrowthAge = getInt("settings.blocks.weeping_vines.max-growth-age", weepingVinesMaxGrowthAge); + if (weepingVinesMaxGrowthAge > 25) { + weepingVinesMaxGrowthAge = 25; + log(Level.WARNING, "blocks.weeping_vines.max-growth-age is set to above maximum allowed value of 25"); + log(Level.WARNING, "Using value of 25 to prevent issues"); + } + magmaBlockReverseBubbleColumnFlow = getBoolean("settings.blocks.magma-block.reverse-bubble-column-flow", magmaBlockReverseBubbleColumnFlow); + soulSandBlockReverseBubbleColumnFlow = getBoolean("settings.blocks.soul-sand.reverse-bubble-column-flow", soulSandBlockReverseBubbleColumnFlow); + } + + public static boolean allowInapplicableEnchants = false; + public static boolean allowIncompatibleEnchants = false; + public static boolean allowHigherEnchantsLevels = false; + public static boolean allowUnsafeEnchantCommand = false; + public static boolean replaceIncompatibleEnchants = false; + public static boolean clampEnchantLevels = true; + private static void enchantmentSettings() { + if (version < 30) { + boolean oldValue = getBoolean("settings.enchantment.allow-unsafe-enchants", false); + set("settings.enchantment.anvil.allow-unsafe-enchants", oldValue); + set("settings.enchantment.anvil.allow-inapplicable-enchants", true); + set("settings.enchantment.anvil.allow-incompatible-enchants", true); + set("settings.enchantment.anvil.allow-higher-enchants-levels", true); + set("settings.enchantment.allow-unsafe-enchants", null); + } + if (version < 37) { + boolean allowUnsafeEnchants = getBoolean("settings.enchantment.anvil.allow-unsafe-enchants", false); + if (!allowUnsafeEnchants) { + set("settings.enchantment.anvil.allow-inapplicable-enchants", false); + set("settings.enchantment.anvil.allow-incompatible-enchants", false); + set("settings.enchantment.anvil.allow-higher-enchants-levels", false); + } + set("settings.enchantment.anvil.allow-unsafe-enchants", null); + } + allowInapplicableEnchants = getBoolean("settings.enchantment.anvil.allow-inapplicable-enchants", allowInapplicableEnchants); + allowIncompatibleEnchants = getBoolean("settings.enchantment.anvil.allow-incompatible-enchants", allowIncompatibleEnchants); + allowHigherEnchantsLevels = getBoolean("settings.enchantment.anvil.allow-higher-enchants-levels", allowHigherEnchantsLevels); + allowUnsafeEnchantCommand = getBoolean("settings.enchantment.allow-unsafe-enchant-command", allowUnsafeEnchantCommand); + replaceIncompatibleEnchants = getBoolean("settings.enchantment.anvil.replace-incompatible-enchants", replaceIncompatibleEnchants); + clampEnchantLevels = getBoolean("settings.enchantment.clamp-levels", clampEnchantLevels); + } + + public static boolean endermanShortHeight = false; + private static void entitySettings() { + endermanShortHeight = getBoolean("settings.entity.enderman.short-height", endermanShortHeight); + if (endermanShortHeight) EntityType.ENDERMAN.dimensions = EntityDimensions.scalable(0.6F, 1.9F); + } + + public static boolean allowWaterPlacementInTheEnd = true; + private static void allowWaterPlacementInEnd() { + allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd); + } + + public static boolean beeCountPayload = false; + private static void beeCountPayload() { + beeCountPayload = getBoolean("settings.bee-count-payload", beeCountPayload); + } + + public static boolean loggerSuppressInitLegacyMaterialError = false; + public static boolean loggerSuppressIgnoredAdvancementWarnings = false; + public static boolean loggerSuppressUnrecognizedRecipeErrors = false; + public static boolean loggerSuppressSetBlockFarChunk = false; + public static boolean loggerSuppressLibraryLoader = false; + private static void loggerSettings() { + loggerSuppressInitLegacyMaterialError = getBoolean("settings.logger.suppress-init-legacy-material-errors", loggerSuppressInitLegacyMaterialError); + loggerSuppressIgnoredAdvancementWarnings = getBoolean("settings.logger.suppress-ignored-advancement-warnings", loggerSuppressIgnoredAdvancementWarnings); + loggerSuppressUnrecognizedRecipeErrors = getBoolean("settings.logger.suppress-unrecognized-recipe-errors", loggerSuppressUnrecognizedRecipeErrors); + loggerSuppressSetBlockFarChunk = getBoolean("settings.logger.suppress-setblock-in-far-chunk-errors", loggerSuppressSetBlockFarChunk); + loggerSuppressLibraryLoader = getBoolean("settings.logger.suppress-library-loader", loggerSuppressLibraryLoader); + org.bukkit.plugin.java.JavaPluginLoader.SuppressLibraryLoaderLogger = loggerSuppressLibraryLoader; + } + + public static boolean tpsCatchup = true; + private static void tpsCatchup() { + tpsCatchup = getBoolean("settings.tps-catchup", tpsCatchup); + } + + public static boolean useUPnP = false; + public static boolean maxJoinsPerSecond = false; + public static boolean kickForOutOfOrderChat = true; + private static void networkSettings() { + useUPnP = getBoolean("settings.network.upnp-port-forwarding", useUPnP); + maxJoinsPerSecond = getBoolean("settings.network.max-joins-per-second", maxJoinsPerSecond); + kickForOutOfOrderChat = getBoolean("settings.network.kick-for-out-of-order-chat", kickForOutOfOrderChat); + } + + public static Pattern usernameValidCharactersPattern; + private static void usernameValidationSettings() { + String defaultPattern = "^[a-zA-Z0-9_.]*$"; + String setPattern = getString("settings.username-valid-characters", defaultPattern); + usernameValidCharactersPattern = Pattern.compile(setPattern == null || setPattern.isBlank() ? defaultPattern : setPattern); + } + + public static boolean fixProjectileLootingTransfer = false; + private static void fixProjectileLootingTransfer() { + fixProjectileLootingTransfer = getBoolean("settings.fix-projectile-looting-transfer", fixProjectileLootingTransfer); + } + + public static boolean clampAttributes = true; + private static void clampAttributes() { + clampAttributes = getBoolean("settings.clamp-attributes", clampAttributes); + } + + public static boolean limitArmor = true; + private static void limitArmor() { + limitArmor = getBoolean("settings.limit-armor", limitArmor); + } + + private static void blastResistanceSettings() { + getMap("settings.blast-resistance-overrides", Collections.emptyMap()).forEach((blockId, value) -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId)); + if (block == Blocks.AIR) { + log(Level.SEVERE, "Invalid block for `settings.blast-resistance-overrides`: " + blockId); + return; + } + if (!(value instanceof Number blastResistance)) { + log(Level.SEVERE, "Invalid blast resistance for `settings.blast-resistance-overrides." + blockId + "`: " + value); + return; + } + block.explosionResistance = blastResistance.floatValue(); + }); + } + private static void blockFallMultiplierSettings() { + getMap("settings.block-fall-multipliers", Map.ofEntries( + Map.entry("minecraft:hay_block", Map.of("damage", 0.2F)), + Map.entry("minecraft:white_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:light_gray_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:gray_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:black_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:brown_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:pink_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:red_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:orange_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:yellow_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:green_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:lime_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:cyan_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:light_blue_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:blue_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:purple_bed", Map.of("distance", 0.5F)), + Map.entry("minecraft:magenta_bed", Map.of("distance", 0.5F)) + )).forEach((blockId, value) -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId)); + if (block == Blocks.AIR) { + log(Level.SEVERE, "Invalid block for `settings.block-fall-multipliers`: " + blockId); + return; + } + if (!(value instanceof Map map)) { + log(Level.SEVERE, "Invalid fall multiplier for `settings.block-fall-multipliers." + blockId + "`: " + value + + ", expected a map with keys `damage` and `distance` to floats."); + return; + } + Object rawFallDamageMultiplier = map.get("damage"); + if (rawFallDamageMultiplier == null) rawFallDamageMultiplier = 1F; + if (!(rawFallDamageMultiplier instanceof Number fallDamageMultiplier)) { + log(Level.SEVERE, "Invalid multiplier for `settings.block-fall-multipliers." + blockId + ".damage`: " + map.get("damage")); + return; + } + Object rawFallDistanceMultiplier = map.get("distance"); + if (rawFallDistanceMultiplier == null) rawFallDistanceMultiplier = 1F; + if (!(rawFallDistanceMultiplier instanceof Number fallDistanceMultiplier)) { + log(Level.SEVERE, "Invalid multiplier for `settings.block-fall-multipliers." + blockId + ".distance`: " + map.get("distance")); + return; + } + block.fallDamageMultiplier = fallDamageMultiplier.floatValue(); + block.fallDistanceMultiplier = fallDistanceMultiplier.floatValue(); + }); + } + + public static boolean playerDeathsAlwaysShowItem = false; + private static void playerDeathsAlwaysShowItem() { + playerDeathsAlwaysShowItem = getBoolean("settings.player-deaths-always-show-item", playerDeathsAlwaysShowItem); + } + + public static boolean registerMinecraftDebugCommands = false; + private static void registerMinecraftDebugCommands() { + registerMinecraftDebugCommands = getBoolean("settings.register-minecraft-debug-commands", registerMinecraftDebugCommands); + } + + public static List startupCommands = new ArrayList<>(); + private static void startupCommands() { + startupCommands.clear(); + getList("settings.startup-commands", new ArrayList()).forEach(line -> { + String command = line.toString(); + if (command.startsWith("/")) { + command = command.substring(1); + } + startupCommands.add(command); + }); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/purpur-server/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java new file mode 100644 index 000000000..cfc0c0b2c --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java @@ -0,0 +1,3451 @@ +package org.purpurmc.purpur; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.function.Predicate; +import java.util.logging.Level; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.monster.Shulker; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.properties.Tilt; +import org.apache.commons.lang.BooleanUtils; +import org.bukkit.ChatColor; +import org.bukkit.World; +import org.bukkit.configuration.ConfigurationSection; +import java.util.List; +import java.util.Map; +import org.purpurmc.purpur.tool.Flattenable; +import org.purpurmc.purpur.tool.Strippable; +import org.purpurmc.purpur.tool.Tillable; +import org.purpurmc.purpur.tool.Waxable; +import org.purpurmc.purpur.tool.Weatherable; + +import static org.purpurmc.purpur.PurpurConfig.log; + +@SuppressWarnings("unused") +public class PurpurWorldConfig { + + private final String worldName; + private final World.Environment environment; + + public PurpurWorldConfig(String worldName, World.Environment environment) { + this.worldName = worldName; + this.environment = environment; + init(); + } + + public void init() { + log("-------- World Settings For [" + worldName + "] --------"); + PurpurConfig.readConfig(PurpurWorldConfig.class, this); + } + + private void set(String path, Object val) { + PurpurConfig.config.addDefault("world-settings.default." + path, val); + PurpurConfig.config.set("world-settings.default." + path, val); + if (PurpurConfig.config.get("world-settings." + worldName + "." + path) != null) { + PurpurConfig.config.addDefault("world-settings." + worldName + "." + path, val); + PurpurConfig.config.set("world-settings." + worldName + "." + path, val); + } + } + + private ConfigurationSection getConfigurationSection(String path) { + ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + "." + path); + return section != null ? section : PurpurConfig.config.getConfigurationSection("world-settings.default." + path); + } + + private String getString(String path, String def) { + PurpurConfig.config.addDefault("world-settings.default." + path, def); + return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); + } + + private boolean getBoolean(String path, boolean def) { + PurpurConfig.config.addDefault("world-settings.default." + path, def); + return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path)); + } + + private boolean getBoolean(String path, Predicate predicate) { + String val = getString(path, "default").toLowerCase(); + Boolean bool = BooleanUtils.toBooleanObject(val, "true", "false", "default"); + return predicate.test(bool); + } + + private double getDouble(String path, double def) { + PurpurConfig.config.addDefault("world-settings.default." + path, def); + return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path)); + } + + private int getInt(String path, int def) { + PurpurConfig.config.addDefault("world-settings.default." + path, def); + return PurpurConfig.config.getInt("world-settings." + worldName + "." + path, PurpurConfig.config.getInt("world-settings.default." + path)); + } + + private List getList(String path, T def) { + PurpurConfig.config.addDefault("world-settings.default." + path, def); + return PurpurConfig.config.getList("world-settings." + worldName + "." + path, PurpurConfig.config.getList("world-settings.default." + path)); + } + + private Map getMap(String path, Map def) { + final Map fallback = PurpurConfig.getMap("world-settings.default." + path, def); + final Map value = PurpurConfig.getMap("world-settings." + worldName + "." + path, null); + return value.isEmpty() ? fallback : value; + } + + public float armorstandStepHeight = 0.0F; + public boolean armorstandSetNameVisible = false; + public boolean armorstandFixNametags = false; + public boolean armorstandMovement = true; + public boolean armorstandWaterMovement = true; + public boolean armorstandWaterFence = true; + public boolean armorstandPlaceWithArms = false; + private void armorstandSettings() { + armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); + armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); + armorstandFixNametags = getBoolean("gameplay-mechanics.armorstand.fix-nametags", armorstandFixNametags); + armorstandMovement = getBoolean("gameplay-mechanics.armorstand.can-movement-tick", armorstandMovement); + armorstandWaterMovement = getBoolean("gameplay-mechanics.armorstand.can-move-in-water", armorstandWaterMovement); + armorstandWaterFence = getBoolean("gameplay-mechanics.armorstand.can-move-in-water-over-fence", armorstandWaterFence); + armorstandPlaceWithArms = getBoolean("gameplay-mechanics.armorstand.place-with-arms-visible", armorstandPlaceWithArms); + } + + public boolean arrowMovementResetsDespawnCounter = true; + private void arrowSettings() { + arrowMovementResetsDespawnCounter = getBoolean("gameplay-mechanics.arrow.movement-resets-despawn-counter", arrowMovementResetsDespawnCounter); + } + + public boolean useBetterMending = false; + public boolean alwaysTameInCreative = false; + public boolean boatEjectPlayersOnLand = false; + public boolean boatsDoFallDamage = false; + public boolean disableDropsOnCrammingDeath = false; + public boolean milkCuresBadOmen = true; + public double tridentLoyaltyVoidReturnHeight = 0.0D; + public boolean entitiesCanUsePortals = true; + public int raidCooldownSeconds = 0; + public int animalBreedingCooldownSeconds = 0; + public boolean persistentDroppableEntityDisplayNames = true; + public boolean entitiesPickUpLootBypassMobGriefing = false; + public boolean fireballsBypassMobGriefing = false; + public boolean projectilesBypassMobGriefing = false; + public boolean noteBlockIgnoreAbove = false; + public boolean imposeTeleportRestrictionsOnGateways = false; + public boolean imposeTeleportRestrictionsOnNetherPortals = false; + public boolean imposeTeleportRestrictionsOnEndPortals = false; + public boolean tickFluids = true; + public double mobsBlindnessMultiplier = 1; + public boolean mobsIgnoreRails = false; + public boolean rainStopsAfterSleep = true; + public boolean thunderStopsAfterSleep = true; + public boolean persistentTileEntityLore = false; + public boolean persistentTileEntityDisplayName = true; + public int mobLastHurtByPlayerTime = 100; + public boolean milkClearsBeneficialEffects = true; + public boolean disableOxidationProximityPenalty = false; + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); + boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); + boatsDoFallDamage = getBoolean("gameplay-mechanics.boat.do-fall-damage", boatsDoFallDamage); + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); + entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); + raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); + animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds); + persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); + entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); + fireballsBypassMobGriefing = getBoolean("gameplay-mechanics.fireballs-bypass-mob-griefing", fireballsBypassMobGriefing); + projectilesBypassMobGriefing = getBoolean("gameplay-mechanics.projectiles-bypass-mob-griefing", projectilesBypassMobGriefing); + noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove); + imposeTeleportRestrictionsOnGateways = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-gateways", imposeTeleportRestrictionsOnGateways); + imposeTeleportRestrictionsOnNetherPortals = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-nether-portals", imposeTeleportRestrictionsOnNetherPortals); + imposeTeleportRestrictionsOnEndPortals = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-end-portals", imposeTeleportRestrictionsOnEndPortals); + tickFluids = getBoolean("gameplay-mechanics.tick-fluids", tickFluids); + mobsBlindnessMultiplier = getDouble("gameplay-mechanics.entity-blindness-multiplier", mobsBlindnessMultiplier); + mobsIgnoreRails = getBoolean("gameplay-mechanics.mobs-ignore-rails", mobsIgnoreRails); + rainStopsAfterSleep = getBoolean("gameplay-mechanics.rain-stops-after-sleep", rainStopsAfterSleep); + thunderStopsAfterSleep = getBoolean("gameplay-mechanics.thunder-stops-after-sleep", thunderStopsAfterSleep); + if (PurpurConfig.version < 35) { + boolean oldVal = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityLore); + set("gameplay-mechanics.persistent-tileentity-display-names-and-lore", null); + set("gameplay-mechanics.persistent-tileentity-lore", oldVal); + set("gameplay-mechanics.persistent-tileentity-display-name", !oldVal); + } + persistentTileEntityLore = getBoolean("gameplay-mechanics.persistent-tileentity-lore", persistentTileEntityLore); + persistentTileEntityDisplayName = getBoolean("gameplay-mechanics.persistent-tileentity-display-name", persistentTileEntityDisplayName); + mobLastHurtByPlayerTime = getInt("gameplay-mechanics.mob-last-hurt-by-player-time", mobLastHurtByPlayerTime); + milkClearsBeneficialEffects = getBoolean("gameplay-mechanics.milk-clears-beneficial-effects", milkClearsBeneficialEffects); + disableOxidationProximityPenalty = getBoolean("gameplay-mechanics.disable-oxidation-proximity-penalty", disableOxidationProximityPenalty); + } + + public int daytimeTicks = 12000; + public int nighttimeTicks = 12000; + private void daytimeCycleSettings() { + daytimeTicks = getInt("gameplay-mechanics.daylight-cycle-ticks.daytime", daytimeTicks); + nighttimeTicks = getInt("gameplay-mechanics.daylight-cycle-ticks.nighttime", nighttimeTicks); + } + + public int drowningAirTicks = 300; + public int drowningDamageInterval = 20; + public double damageFromDrowning = 2.0F; + private void drowningSettings() { + drowningAirTicks = getInt("gameplay-mechanics.drowning.air-ticks", drowningAirTicks); + drowningDamageInterval = getInt("gameplay-mechanics.drowning.ticks-per-damage", drowningDamageInterval); + damageFromDrowning = getDouble("gameplay-mechanics.drowning.damage-from-drowning", damageFromDrowning); + } + + public int elytraDamagePerSecond = 1; + public double elytraDamageMultiplyBySpeed = 0; + public int elytraDamagePerFireworkBoost = 0; + public int elytraDamagePerTridentBoost = 0; + public boolean elytraKineticDamage = true; + private void elytraSettings() { + elytraDamagePerSecond = getInt("gameplay-mechanics.elytra.damage-per-second", elytraDamagePerSecond); + elytraDamageMultiplyBySpeed = getDouble("gameplay-mechanics.elytra.damage-multiplied-by-speed", elytraDamageMultiplyBySpeed); + elytraDamagePerFireworkBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.firework", elytraDamagePerFireworkBoost); + elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost); + elytraKineticDamage = getBoolean("gameplay-mechanics.elytra.kinetic-damage", elytraKineticDamage); + } + + public int entityLifeSpan = 0; + public float entityLeftHandedChance = 0.05f; + public boolean entitySharedRandom = true; + private void entitySettings() { + entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan); + entityLeftHandedChance = (float) getDouble("gameplay-mechanics.entity-left-handed-chance", entityLeftHandedChance); + entitySharedRandom = getBoolean("settings.entity.shared-random", entitySharedRandom); + } + + public boolean infinityWorksWithoutArrows = false; + private void infinityArrowsSettings() { + infinityWorksWithoutArrows = getBoolean("gameplay-mechanics.infinity-bow.works-without-arrows", infinityWorksWithoutArrows); + } + + public boolean explosionClampRadius = true; + private void explosionSettings() { + explosionClampRadius = getBoolean("gameplay-mechanics.clamp-explosion-radius", explosionClampRadius); + } + + public List itemImmuneToCactus = new ArrayList<>(); + public List itemImmuneToExplosion = new ArrayList<>(); + public List itemImmuneToFire = new ArrayList<>(); + public List itemImmuneToLightning = new ArrayList<>(); + public boolean dontRunWithScissors = false; + public ResourceLocation dontRunWithScissorsItemModelReference = ResourceLocation.parse("purpurmc:scissors"); + public boolean ignoreScissorsInWater = false; + public boolean ignoreScissorsInLava = false; + public double scissorsRunningDamage = 1D; + public float enderPearlDamage = 5.0F; + public int enderPearlCooldown = 20; + public int enderPearlCooldownCreative = 20; + public float enderPearlEndermiteChance = 0.05F; + public int glowBerriesEatGlowDuration = 0; + public boolean shulkerBoxItemDropContentsWhenDestroyed = true; + public boolean compassItemShowsBossBar = false; + public boolean snowballExtinguishesFire = false; + public boolean snowballExtinguishesCandles = false; + public boolean snowballExtinguishesCampfires = false; + public boolean bowUseBundleAsQuiver = false; + public boolean crossbowUseBundleAsQuiver = false; + private void itemSettings() { + itemImmuneToCactus.clear(); + getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { + if (key.toString().equals("*")) { + BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToCactus.add(item)); + return; + } + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString())); + if (item != Items.AIR) itemImmuneToCactus.add(item); + }); + itemImmuneToExplosion.clear(); + getList("gameplay-mechanics.item.immune.explosion", new ArrayList<>()).forEach(key -> { + if (key.toString().equals("*")) { + BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToExplosion.add(item)); + return; + } + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString())); + if (item != Items.AIR) itemImmuneToExplosion.add(item); + }); + itemImmuneToFire.clear(); + getList("gameplay-mechanics.item.immune.fire", new ArrayList<>()).forEach(key -> { + if (key.toString().equals("*")) { + BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToFire.add(item)); + return; + } + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString())); + if (item != Items.AIR) itemImmuneToFire.add(item); + }); + itemImmuneToLightning.clear(); + getList("gameplay-mechanics.item.immune.lightning", new ArrayList<>()).forEach(key -> { + if (key.toString().equals("*")) { + BuiltInRegistries.ITEM.stream().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToLightning.add(item)); + return; + } + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString())); + if (item != Items.AIR) itemImmuneToLightning.add(item); + }); + dontRunWithScissors = getBoolean("gameplay-mechanics.item.shears.damage-if-sprinting", dontRunWithScissors); + dontRunWithScissorsItemModelReference = ResourceLocation.parse(getString("gameplay-mechanics.item.shears.damage-if-sprinting-item-model", "purpurmc:scissors")); + ignoreScissorsInWater = getBoolean("gameplay-mechanics.item.shears.ignore-in-water", ignoreScissorsInWater); + ignoreScissorsInLava = getBoolean("gameplay-mechanics.item.shears.ignore-in-lava", ignoreScissorsInLava); + scissorsRunningDamage = getDouble("gameplay-mechanics.item.shears.sprinting-damage", scissorsRunningDamage); + enderPearlDamage = (float) getDouble("gameplay-mechanics.item.ender-pearl.damage", enderPearlDamage); + enderPearlCooldown = getInt("gameplay-mechanics.item.ender-pearl.cooldown", enderPearlCooldown); + enderPearlCooldownCreative = getInt("gameplay-mechanics.item.ender-pearl.creative-cooldown", enderPearlCooldownCreative); + enderPearlEndermiteChance = (float) getDouble("gameplay-mechanics.item.ender-pearl.endermite-spawn-chance", enderPearlEndermiteChance); + glowBerriesEatGlowDuration = getInt("gameplay-mechanics.item.glow_berries.eat-glow-duration", glowBerriesEatGlowDuration); + shulkerBoxItemDropContentsWhenDestroyed = getBoolean("gameplay-mechanics.item.shulker_box.drop-contents-when-destroyed", shulkerBoxItemDropContentsWhenDestroyed); + compassItemShowsBossBar = getBoolean("gameplay-mechanics.item.compass.holding-shows-bossbar", compassItemShowsBossBar); + snowballExtinguishesFire = getBoolean("gameplay-mechanics.item.snowball.extinguish.fire", snowballExtinguishesFire); + snowballExtinguishesCandles = getBoolean("gameplay-mechanics.item.snowball.extinguish.candles", snowballExtinguishesCandles); + snowballExtinguishesCampfires = getBoolean("gameplay-mechanics.item.snowball.extinguish.campfires", snowballExtinguishesCampfires); + bowUseBundleAsQuiver = getBoolean("gameplay-mechanics.item.bow.use-bundle-as-quiver", bowUseBundleAsQuiver); + crossbowUseBundleAsQuiver = getBoolean("gameplay-mechanics.item.crossbow.use-bundle-as-quiver", crossbowUseBundleAsQuiver); + } + + public double minecartMaxSpeed = 0.4D; + public boolean minecartPlaceAnywhere = false; + public boolean minecartControllable = false; + public float minecartControllableStepHeight = 1.0F; + public double minecartControllableHopBoost = 0.5D; + public boolean minecartControllableFallDamage = true; + public double minecartControllableBaseSpeed = 0.1D; + public Map minecartControllableBlockSpeeds = new HashMap<>(); + public double poweredRailBoostModifier = 0.06; + private void minecartSettings() { + if (PurpurConfig.version < 12) { + boolean oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.place-anywhere", minecartPlaceAnywhere); + set("gameplay-mechanics.controllable-minecarts.place-anywhere", null); + set("gameplay-mechanics.minecart.place-anywhere", oldBool); + oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.enabled", minecartControllable); + set("gameplay-mechanics.controllable-minecarts.enabled", null); + set("gameplay-mechanics.minecart.controllable.enabled", oldBool); + double oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.step-height", minecartControllableStepHeight); + set("gameplay-mechanics.controllable-minecarts.step-height", null); + set("gameplay-mechanics.minecart.controllable.step-height", oldDouble); + oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.hop-boost", minecartControllableHopBoost); + set("gameplay-mechanics.controllable-minecarts.hop-boost", null); + set("gameplay-mechanics.minecart.controllable.hop-boost", oldDouble); + oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.fall-damage", minecartControllableFallDamage); + set("gameplay-mechanics.controllable-minecarts.fall-damage", null); + set("gameplay-mechanics.minecart.controllable.fall-damage", oldBool); + oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.base-speed", minecartControllableBaseSpeed); + set("gameplay-mechanics.controllable-minecarts.base-speed", null); + set("gameplay-mechanics.minecart.controllable.base-speed", oldDouble); + ConfigurationSection section = getConfigurationSection("gameplay-mechanics.controllable-minecarts.block-speed"); + if (section != null) { + for (String key : section.getKeys(false)) { + if ("grass-block".equals(key)) key = "grass_block"; // oopsie + oldDouble = section.getDouble(key, minecartControllableBaseSpeed); + set("gameplay-mechanics.controllable-minecarts.block-speed." + key, null); + set("gameplay-mechanics.minecart.controllable.block-speed." + key, oldDouble); + } + set("gameplay-mechanics.controllable-minecarts.block-speed", null); + } + set("gameplay-mechanics.controllable-minecarts", null); + } + + minecartMaxSpeed = getDouble("gameplay-mechanics.minecart.max-speed", minecartMaxSpeed); + minecartPlaceAnywhere = getBoolean("gameplay-mechanics.minecart.place-anywhere", minecartPlaceAnywhere); + minecartControllable = getBoolean("gameplay-mechanics.minecart.controllable.enabled", minecartControllable); + minecartControllableStepHeight = (float) getDouble("gameplay-mechanics.minecart.controllable.step-height", minecartControllableStepHeight); + minecartControllableHopBoost = getDouble("gameplay-mechanics.minecart.controllable.hop-boost", minecartControllableHopBoost); + minecartControllableFallDamage = getBoolean("gameplay-mechanics.minecart.controllable.fall-damage", minecartControllableFallDamage); + minecartControllableBaseSpeed = getDouble("gameplay-mechanics.minecart.controllable.base-speed", minecartControllableBaseSpeed); + ConfigurationSection section = getConfigurationSection("gameplay-mechanics.minecart.controllable.block-speed"); + if (section != null) { + for (String key : section.getKeys(false)) { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(key)); + if (block != Blocks.AIR) { + minecartControllableBlockSpeeds.put(block, section.getDouble(key, minecartControllableBaseSpeed)); + } + } + } else { + set("gameplay-mechanics.minecart.controllable.block-speed.grass_block", 0.3D); + set("gameplay-mechanics.minecart.controllable.block-speed.stone", 0.5D); + } + poweredRailBoostModifier = getDouble("gameplay-mechanics.minecart.powered-rail.boost-modifier", poweredRailBoostModifier); + } + + public float entityHealthRegenAmount = 1.0F; + public float entityMinimalHealthPoison = 1.0F; + public float entityPoisonDegenerationAmount = 1.0F; + public float entityWitherDegenerationAmount = 1.0F; + public float humanHungerExhaustionAmount = 0.005F; + public float humanSaturationRegenAmount = 1.0F; + private void mobEffectSettings() { + entityHealthRegenAmount = (float) getDouble("gameplay-mechanics.mob-effects.health-regen-amount", entityHealthRegenAmount); + entityMinimalHealthPoison = (float) getDouble("gameplay-mechanics.mob-effects.minimal-health-poison-amount", entityMinimalHealthPoison); + entityPoisonDegenerationAmount = (float) getDouble("gameplay-mechanics.mob-effects.poison-degeneration-amount", entityPoisonDegenerationAmount); + entityWitherDegenerationAmount = (float) getDouble("gameplay-mechanics.mob-effects.wither-degeneration-amount", entityWitherDegenerationAmount); + humanHungerExhaustionAmount = (float) getDouble("gameplay-mechanics.mob-effects.hunger-exhaustion-amount", humanHungerExhaustionAmount); + humanSaturationRegenAmount = (float) getDouble("gameplay-mechanics.mob-effects.saturation-regen-amount", humanSaturationRegenAmount); + } + + public boolean catSpawning; + public boolean patrolSpawning; + public boolean phantomSpawning; + public boolean villagerTraderSpawning; + public boolean villageSiegeSpawning; + public boolean mobSpawningIgnoreCreativePlayers = false; + private void mobSpawnerSettings() { + // values of "default" or null will default to true only if the world environment is normal (aka overworld) + Predicate predicate = (bool) -> (bool != null && bool) || (bool == null && environment == World.Environment.NORMAL); + catSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-cats", predicate); + patrolSpawning = getBoolean("gameplay-mechanics.mob-spawning.raid-patrols", predicate); + phantomSpawning = getBoolean("gameplay-mechanics.mob-spawning.phantoms", predicate); + villagerTraderSpawning = getBoolean("gameplay-mechanics.mob-spawning.wandering-traders", predicate); + villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate); + mobSpawningIgnoreCreativePlayers = getBoolean("gameplay-mechanics.mob-spawning.ignore-creative-players", mobSpawningIgnoreCreativePlayers); + } + + public boolean disableObserverClocks = false; + private void observerSettings() { + disableObserverClocks = getBoolean("blocks.observer.disable-clock", disableObserverClocks); + } + + public int playerNetheriteFireResistanceDuration = 0; + public int playerNetheriteFireResistanceAmplifier = 0; + public boolean playerNetheriteFireResistanceAmbient = false; + public boolean playerNetheriteFireResistanceShowParticles = false; + public boolean playerNetheriteFireResistanceShowIcon = true; + private void playerNetheriteFireResistance() { + playerNetheriteFireResistanceDuration = getInt("gameplay-mechanics.player.netherite-fire-resistance.duration", playerNetheriteFireResistanceDuration); + playerNetheriteFireResistanceAmplifier = getInt("gameplay-mechanics.player.netherite-fire-resistance.amplifier", playerNetheriteFireResistanceAmplifier); + playerNetheriteFireResistanceAmbient = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.ambient", playerNetheriteFireResistanceAmbient); + playerNetheriteFireResistanceShowParticles = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.show-particles", playerNetheriteFireResistanceShowParticles); + playerNetheriteFireResistanceShowIcon = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.show-icon", playerNetheriteFireResistanceShowIcon); + } + + public boolean idleTimeoutKick = true; + public boolean idleTimeoutTickNearbyEntities = true; + public boolean idleTimeoutCountAsSleeping = false; + public boolean idleTimeoutUpdateTabList = false; + public boolean idleTimeoutTargetPlayer = true; + public String playerDeathExpDropEquation = "expLevel * 7"; + public int playerDeathExpDropMax = 100; + public boolean teleportIfOutsideBorder = false; + public boolean teleportOnNetherCeilingDamage = false; + public boolean totemOfUndyingWorksInInventory = false; + public boolean playerFixStuckPortal = false; + public boolean creativeOnePunch = false; + public boolean playerSleepNearMonsters = false; + public boolean playersSkipNight = true; + public double playerCriticalDamageMultiplier = 1.5D; + public int playerBurpDelay = 10; + public boolean playerBurpWhenFull = false; + public boolean playerRidableInWater = false; + public boolean playerRemoveBindingWithWeakness = false; + public int shiftRightClickRepairsMendingPoints = 0; + public int playerExpPickupDelay = 2; + public boolean playerVoidTrading = false; + private void playerSettings() { + if (PurpurConfig.version < 19) { + boolean oldVal = getBoolean("gameplay-mechanics.player.idle-timeout.mods-target", idleTimeoutTargetPlayer); + set("gameplay-mechanics.player.idle-timeout.mods-target", null); + set("gameplay-mechanics.player.idle-timeout.mobs-target", oldVal); + } + idleTimeoutKick = System.getenv("PURPUR_FORCE_IDLE_KICK") == null ? getBoolean("gameplay-mechanics.player.idle-timeout.kick-if-idle", idleTimeoutKick) : Boolean.parseBoolean(System.getenv("PURPUR_FORCE_IDLE_KICK")); + idleTimeoutTickNearbyEntities = getBoolean("gameplay-mechanics.player.idle-timeout.tick-nearby-entities", idleTimeoutTickNearbyEntities); + idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping); + idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + idleTimeoutTargetPlayer = getBoolean("gameplay-mechanics.player.idle-timeout.mobs-target", idleTimeoutTargetPlayer); + playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation); + playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax); + teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); + teleportOnNetherCeilingDamage = getBoolean("gameplay-mechanics.player.teleport-on-nether-ceiling-damage", teleportOnNetherCeilingDamage); + totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory); + playerFixStuckPortal = getBoolean("gameplay-mechanics.player.fix-stuck-in-portal", playerFixStuckPortal); + creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); + playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters); + playersSkipNight = getBoolean("gameplay-mechanics.player.can-skip-night", playersSkipNight); + playerCriticalDamageMultiplier = getDouble("gameplay-mechanics.player.critical-damage-multiplier", playerCriticalDamageMultiplier); + playerBurpDelay = getInt("gameplay-mechanics.player.burp-delay", playerBurpDelay); + playerBurpWhenFull = getBoolean("gameplay-mechanics.player.burp-when-full", playerBurpWhenFull); + playerRidableInWater = getBoolean("gameplay-mechanics.player.ridable-in-water", playerRidableInWater); + playerRemoveBindingWithWeakness = getBoolean("gameplay-mechanics.player.curse-of-binding.remove-with-weakness", playerRemoveBindingWithWeakness); + shiftRightClickRepairsMendingPoints = getInt("gameplay-mechanics.player.shift-right-click-repairs-mending-points", shiftRightClickRepairsMendingPoints); + playerExpPickupDelay = getInt("gameplay-mechanics.player.exp-pickup-delay-ticks", playerExpPickupDelay); + playerVoidTrading = getBoolean("gameplay-mechanics.player.allow-void-trading", playerVoidTrading); + } + + public boolean silkTouchEnabled = false; + public String silkTouchSpawnerName = "Monster Spawner"; + public List silkTouchSpawnerLore = new ArrayList<>(); + public List silkTouchTools = new ArrayList<>(); + public int minimumSilkTouchSpawnerRequire = 1; + private void silkTouchSettings() { + if (PurpurConfig.version < 21) { + String oldName = getString("gameplay-mechanics.silk-touch.spawner-name", silkTouchSpawnerName); + set("gameplay-mechanics.silk-touch.spawner-name", "" + ChatColor.toMM(oldName.replace("{mob}", ""))); + List list = new ArrayList<>(); + getList("gameplay-mechanics.silk-touch.spawner-lore", List.of("Spawns a ")) + .forEach(line -> list.add("" + ChatColor.toMM(line.toString().replace("{mob}", "")))); + set("gameplay-mechanics.silk-touch.spawner-lore", list); + } + silkTouchEnabled = getBoolean("gameplay-mechanics.silk-touch.enabled", silkTouchEnabled); + silkTouchSpawnerName = getString("gameplay-mechanics.silk-touch.spawner-name", silkTouchSpawnerName); + minimumSilkTouchSpawnerRequire = getInt("gameplay-mechanics.silk-touch.minimal-level", minimumSilkTouchSpawnerRequire); + silkTouchSpawnerLore.clear(); + getList("gameplay-mechanics.silk-touch.spawner-lore", List.of("Spawns a ")) + .forEach(line -> silkTouchSpawnerLore.add(line.toString())); + silkTouchTools.clear(); + getList("gameplay-mechanics.silk-touch.tools", List.of( + "minecraft:iron_pickaxe", + "minecraft:golden_pickaxe", + "minecraft:diamond_pickaxe", + "minecraft:netherite_pickaxe" + )).forEach(key -> { + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(key.toString())); + if (item != Items.AIR) silkTouchTools.add(item); + }); + } + + public double bowProjectileOffset = 1.0D; + public double crossbowProjectileOffset = 1.0D; + public double eggProjectileOffset = 1.0D; + public double enderPearlProjectileOffset = 1.0D; + public double throwablePotionProjectileOffset = 1.0D; + public double tridentProjectileOffset = 1.0D; + public double snowballProjectileOffset = 1.0D; + private void projectileOffsetSettings() { + bowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.bow", bowProjectileOffset); + crossbowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.crossbow", crossbowProjectileOffset); + eggProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.egg", eggProjectileOffset); + enderPearlProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.ender-pearl", enderPearlProjectileOffset); + throwablePotionProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.throwable-potion", throwablePotionProjectileOffset); + tridentProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.trident", tridentProjectileOffset); + snowballProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.snowball", snowballProjectileOffset); + } + + public int snowballDamage = -1; + private void snowballSettings() { + snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); + } + + public Map axeStrippables = new HashMap<>(); + public Map axeWaxables = new HashMap<>(); + public Map axeWeatherables = new HashMap<>(); + public Map hoeTillables = new HashMap<>(); + public Map shovelFlattenables = new HashMap<>(); + public boolean hoeReplantsCrops = false; + public boolean hoeReplantsNetherWarts = false; + private void toolSettings() { + axeStrippables.clear(); + axeWaxables.clear(); + axeWeatherables.clear(); + hoeTillables.clear(); + shovelFlattenables.clear(); + if (PurpurConfig.version < 18) { + ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + ".tools.hoe.tilling"); + if (section != null) { + PurpurConfig.config.set("world-settings." + worldName + ".tools.hoe.tillables", section); + PurpurConfig.config.set("world-settings." + worldName + ".tools.hoe.tilling", null); + } + section = PurpurConfig.config.getConfigurationSection("world-settings.default.tools.hoe.tilling"); + if (section != null) { + PurpurConfig.config.set("world-settings.default.tools.hoe.tillables", section); + PurpurConfig.config.set("world-settings.default.tools.hoe.tilling", null); + } + } + if (PurpurConfig.version < 29) { + PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:mangrove_log", Map.of("into", "minecraft:stripped_mangrove_log", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:mangrove_wood", Map.of("into", "minecraft:stripped_mangrove_wood", "drops", new HashMap())); + } + if (PurpurConfig.version < 32) { + PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:cherry_log", Map.of("into", "minecraft:stripped_cherry_log", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:cherry_wood", Map.of("into", "minecraft:stripped_cherry_wood", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:bamboo_block", Map.of("into", "minecraft:stripped_bamboo_block", "drops", new HashMap())); + } + if (PurpurConfig.version < 33) { + getList("gameplay-mechanics.shovel-turns-block-to-grass-path", new ArrayList(){{ + add("minecraft:coarse_dirt"); + add("minecraft:dirt"); + add("minecraft:grass_block"); + add("minecraft:mycelium"); + add("minecraft:podzol"); + add("minecraft:rooted_dirt"); + }}).forEach(key -> { + PurpurConfig.config.set("world-settings.default.tools.shovel.flattenables." + key.toString(), Map.of("into", "minecraft:dirt_path", "drops", new HashMap())); + }); + set("gameplay-mechanics.shovel-turns-block-to-grass-path", null); + } + if (PurpurConfig.version < 34) { + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_chiseled_copper", Map.of("into", "minecraft:oxidized_chiseled_copper", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_door", Map.of("into", "minecraft:oxidized_copper_door", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_trapdoor", Map.of("into", "minecraft:oxidized_copper_trapdoor", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_grate", Map.of("into", "minecraft:oxidized_copper_grate", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_exposed_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_weathered_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.waxables.minecraft:waxed_oxidized_copper_bulb", Map.of("into", "minecraft:oxidized_copper_bulb", "drops", new HashMap())); + + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:exposed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:weathered_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.weatherables.minecraft:oxidized_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap())); + } + if (PurpurConfig.version < 39) { + PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:pale_oak_wood", Map.of("into", "minecraft:stripped_pale_oak_wood", "drops", new HashMap())); + PurpurConfig.config.set("world-settings.default.tools.axe.strippables.minecraft:pale_oak_log", Map.of("into", "minecraft:stripped_pale_oak_log", "drops", new HashMap())); + } + getMap("tools.axe.strippables", Map.ofEntries( + Map.entry("minecraft:oak_wood", Map.of("into", "minecraft:stripped_oak_wood", "drops", new HashMap())), + Map.entry("minecraft:oak_log", Map.of("into", "minecraft:stripped_oak_log", "drops", new HashMap())), + Map.entry("minecraft:dark_oak_wood", Map.of("into", "minecraft:stripped_dark_oak_wood", "drops", new HashMap())), + Map.entry("minecraft:dark_oak_log", Map.of("into", "minecraft:stripped_dark_oak_log", "drops", new HashMap())), + Map.entry("minecraft:pale_oak_wood", Map.of("into", "minecraft:stripped_pale_oak_wood", "drops", new HashMap())), + Map.entry("minecraft:pale_oak_log", Map.of("into", "minecraft:stripped_pale_oak_log", "drops", new HashMap())), + Map.entry("minecraft:acacia_wood", Map.of("into", "minecraft:stripped_acacia_wood", "drops", new HashMap())), + Map.entry("minecraft:acacia_log", Map.of("into", "minecraft:stripped_acacia_log", "drops", new HashMap())), + Map.entry("minecraft:cherry_wood", Map.of("into", "minecraft:stripped_cherry_wood", "drops", new HashMap())), + Map.entry("minecraft:cherry_log", Map.of("into", "minecraft:stripped_cherry_log", "drops", new HashMap())), + Map.entry("minecraft:birch_wood", Map.of("into", "minecraft:stripped_birch_wood", "drops", new HashMap())), + Map.entry("minecraft:birch_log", Map.of("into", "minecraft:stripped_birch_log", "drops", new HashMap())), + Map.entry("minecraft:jungle_wood", Map.of("into", "minecraft:stripped_jungle_wood", "drops", new HashMap())), + Map.entry("minecraft:jungle_log", Map.of("into", "minecraft:stripped_jungle_log", "drops", new HashMap())), + Map.entry("minecraft:spruce_wood", Map.of("into", "minecraft:stripped_spruce_wood", "drops", new HashMap())), + Map.entry("minecraft:spruce_log", Map.of("into", "minecraft:stripped_spruce_log", "drops", new HashMap())), + Map.entry("minecraft:warped_stem", Map.of("into", "minecraft:stripped_warped_stem", "drops", new HashMap())), + Map.entry("minecraft:warped_hyphae", Map.of("into", "minecraft:stripped_warped_hyphae", "drops", new HashMap())), + Map.entry("minecraft:crimson_stem", Map.of("into", "minecraft:stripped_crimson_stem", "drops", new HashMap())), + Map.entry("minecraft:crimson_hyphae", Map.of("into", "minecraft:stripped_crimson_hyphae", "drops", new HashMap())), + Map.entry("minecraft:mangrove_wood", Map.of("into", "minecraft:stripped_mangrove_wood", "drops", new HashMap())), + Map.entry("minecraft:mangrove_log", Map.of("into", "minecraft:stripped_mangrove_log", "drops", new HashMap())), + Map.entry("minecraft:bamboo_block", Map.of("into", "minecraft:stripped_bamboo_block", "drops", new HashMap())) + ) + ).forEach((blockId, obj) -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId)); + if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.strippables`: " + blockId); return; } + if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.strippables." + blockId + "`"); return; } + String intoId = (String) map.get("into"); + Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId)); + if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.strippables." + blockId + ".into`: " + intoId); return; } + Object dropsObj = map.get("drops"); + if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.strippables." + blockId + ".drops`"); return; } + Map drops = new HashMap<>(); + dropsMap.forEach((itemId, chance) -> { + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString())); + if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.strippables." + blockId + ".drops`: " + itemId); return; } + drops.put(item, (double) chance); + }); + axeStrippables.put(block, new Strippable(into, drops)); + }); + getMap("tools.axe.waxables", Map.ofEntries( + Map.entry("minecraft:waxed_copper_block", Map.of("into", "minecraft:copper_block", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_copper", Map.of("into", "minecraft:exposed_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_copper", Map.of("into", "minecraft:weathered_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_copper", Map.of("into", "minecraft:oxidized_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_cut_copper", Map.of("into", "minecraft:cut_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_cut_copper", Map.of("into", "minecraft:exposed_cut_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_cut_copper", Map.of("into", "minecraft:weathered_cut_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_cut_copper", Map.of("into", "minecraft:oxidized_cut_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_cut_copper_slab", Map.of("into", "minecraft:cut_copper_slab", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_cut_copper_slab", Map.of("into", "minecraft:exposed_cut_copper_slab", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_cut_copper_slab", Map.of("into", "minecraft:weathered_cut_copper_slab", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_cut_copper_slab", Map.of("into", "minecraft:oxidized_cut_copper_slab", "drops", new HashMap())), + Map.entry("minecraft:waxed_cut_copper_stairs", Map.of("into", "minecraft:cut_copper_stairs", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_cut_copper_stairs", Map.of("into", "minecraft:exposed_cut_copper_stairs", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_cut_copper_stairs", Map.of("into", "minecraft:oxidized_cut_copper_stairs", "drops", new HashMap())), + Map.entry("minecraft:waxed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_chiseled_copper", Map.of("into", "minecraft:oxidized_chiseled_copper", "drops", new HashMap())), + Map.entry("minecraft:waxed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_copper_door", Map.of("into", "minecraft:oxidized_copper_door", "drops", new HashMap())), + Map.entry("minecraft:waxed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_copper_trapdoor", Map.of("into", "minecraft:oxidized_copper_trapdoor", "drops", new HashMap())), + Map.entry("minecraft:waxed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_copper_grate", Map.of("into", "minecraft:oxidized_copper_grate", "drops", new HashMap())), + Map.entry("minecraft:waxed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap())), + Map.entry("minecraft:waxed_exposed_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap())), + Map.entry("minecraft:waxed_weathered_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap())), + Map.entry("minecraft:waxed_oxidized_copper_bulb", Map.of("into", "minecraft:oxidized_copper_bulb", "drops", new HashMap()))) + ).forEach((blockId, obj) -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId)); + if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.waxables`: " + blockId); return; } + if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.waxables." + blockId + "`"); return; } + String intoId = (String) map.get("into"); + Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId)); + if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.waxables." + blockId + ".into`: " + intoId); return; } + Object dropsObj = map.get("drops"); + if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.waxables." + blockId + ".drops`"); return; } + Map drops = new HashMap<>(); + dropsMap.forEach((itemId, chance) -> { + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString())); + if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.waxables." + blockId + ".drops`: " + itemId); return; } + drops.put(item, (double) chance); + }); + axeWaxables.put(block, new Waxable(into, drops)); + }); + getMap("tools.axe.weatherables", Map.ofEntries( + Map.entry("minecraft:exposed_copper", Map.of("into", "minecraft:copper_block", "drops", new HashMap())), + Map.entry("minecraft:weathered_copper", Map.of("into", "minecraft:exposed_copper", "drops", new HashMap())), + Map.entry("minecraft:oxidized_copper", Map.of("into", "minecraft:weathered_copper", "drops", new HashMap())), + Map.entry("minecraft:exposed_cut_copper", Map.of("into", "minecraft:cut_copper", "drops", new HashMap())), + Map.entry("minecraft:weathered_cut_copper", Map.of("into", "minecraft:exposed_cut_copper", "drops", new HashMap())), + Map.entry("minecraft:oxidized_cut_copper", Map.of("into", "minecraft:weathered_cut_copper", "drops", new HashMap())), + Map.entry("minecraft:exposed_chiseled_copper", Map.of("into", "minecraft:chiseled_copper", "drops", new HashMap())), + Map.entry("minecraft:weathered_chiseled_copper", Map.of("into", "minecraft:exposed_chiseled_copper", "drops", new HashMap())), + Map.entry("minecraft:oxidized_chiseled_copper", Map.of("into", "minecraft:weathered_chiseled_copper", "drops", new HashMap())), + Map.entry("minecraft:exposed_cut_copper_slab", Map.of("into", "minecraft:cut_copper_slab", "drops", new HashMap())), + Map.entry("minecraft:weathered_cut_copper_slab", Map.of("into", "minecraft:exposed_cut_copper_slab", "drops", new HashMap())), + Map.entry("minecraft:oxidized_cut_copper_slab", Map.of("into", "minecraft:weathered_cut_copper_slab", "drops", new HashMap())), + Map.entry("minecraft:exposed_cut_copper_stairs", Map.of("into", "minecraft:cut_copper_stairs", "drops", new HashMap())), + Map.entry("minecraft:weathered_cut_copper_stairs", Map.of("into", "minecraft:exposed_cut_copper_stairs", "drops", new HashMap())), + Map.entry("minecraft:oxidized_cut_copper_stairs", Map.of("into", "minecraft:weathered_cut_copper_stairs", "drops", new HashMap())), + Map.entry("minecraft:exposed_copper_door", Map.of("into", "minecraft:copper_door", "drops", new HashMap())), + Map.entry("minecraft:weathered_copper_door", Map.of("into", "minecraft:exposed_copper_door", "drops", new HashMap())), + Map.entry("minecraft:oxidized_copper_door", Map.of("into", "minecraft:weathered_copper_door", "drops", new HashMap())), + Map.entry("minecraft:exposed_copper_trapdoor", Map.of("into", "minecraft:copper_trapdoor", "drops", new HashMap())), + Map.entry("minecraft:weathered_copper_trapdoor", Map.of("into", "minecraft:exposed_copper_trapdoor", "drops", new HashMap())), + Map.entry("minecraft:oxidized_copper_trapdoor", Map.of("into", "minecraft:weathered_copper_trapdoor", "drops", new HashMap())), + Map.entry("minecraft:exposed_copper_grate", Map.of("into", "minecraft:copper_grate", "drops", new HashMap())), + Map.entry("minecraft:weathered_copper_grate", Map.of("into", "minecraft:exposed_copper_grate", "drops", new HashMap())), + Map.entry("minecraft:oxidized_copper_grate", Map.of("into", "minecraft:weathered_copper_grate", "drops", new HashMap())), + Map.entry("minecraft:exposed_copper_bulb", Map.of("into", "minecraft:copper_bulb", "drops", new HashMap())), + Map.entry("minecraft:weathered_copper_bulb", Map.of("into", "minecraft:exposed_copper_bulb", "drops", new HashMap())), + Map.entry("minecraft:oxidized_copper_bulb", Map.of("into", "minecraft:weathered_copper_bulb", "drops", new HashMap()))) + ).forEach((blockId, obj) -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId)); + if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.weatherables`: " + blockId); return; } + if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.weatherables." + blockId + "`"); return; } + String intoId = (String) map.get("into"); + Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId)); + if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.axe.weatherables." + blockId + ".into`: " + intoId); return; } + Object dropsObj = map.get("drops"); + if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.axe.weatherables." + blockId + ".drops`"); return; } + Map drops = new HashMap<>(); + dropsMap.forEach((itemId, chance) -> { + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString())); + if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.axe.weatherables." + blockId + ".drops`: " + itemId); return; } + drops.put(item, (double) chance); + }); + axeWeatherables.put(block, new Weatherable(into, drops)); + }); + getMap("tools.hoe.tillables", Map.ofEntries( + Map.entry("minecraft:grass_block", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap())), + Map.entry("minecraft:dirt_path", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap())), + Map.entry("minecraft:dirt", Map.of("condition", "air_above", "into", "minecraft:farmland", "drops", new HashMap())), + Map.entry("minecraft:coarse_dirt", Map.of("condition", "air_above", "into", "minecraft:dirt", "drops", new HashMap())), + Map.entry("minecraft:rooted_dirt", Map.of("condition", "always", "into", "minecraft:dirt", "drops", Map.of("minecraft:hanging_roots", 1.0D)))) + ).forEach((blockId, obj) -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId)); + if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.hoe.tillables`: " + blockId); return; } + if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.hoe.tillables." + blockId + "`"); return; } + String conditionId = (String) map.get("condition"); + Tillable.Condition condition = Tillable.Condition.get(conditionId); + if (condition == null) { PurpurConfig.log(Level.SEVERE, "Invalid condition for `tools.hoe.tillables." + blockId + ".condition`: " + conditionId); return; } + String intoId = (String) map.get("into"); + Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId)); + if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.hoe.tillables." + blockId + ".into`: " + intoId); return; } + Object dropsObj = map.get("drops"); + if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.hoe.tillables." + blockId + ".drops`"); return; } + Map drops = new HashMap<>(); + dropsMap.forEach((itemId, chance) -> { + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString())); + if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.hoe.tillables." + blockId + ".drops`: " + itemId); return; } + drops.put(item, (double) chance); + }); + hoeTillables.put(block, new Tillable(condition, into, drops)); + }); + getMap("tools.shovel.flattenables", Map.ofEntries( + Map.entry("minecraft:grass_block", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), + Map.entry("minecraft:dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), + Map.entry("minecraft:podzol", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), + Map.entry("minecraft:coarse_dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), + Map.entry("minecraft:mycelium", Map.of("into", "minecraft:dirt_path", "drops", new HashMap())), + Map.entry("minecraft:rooted_dirt", Map.of("into", "minecraft:dirt_path", "drops", new HashMap()))) + ).forEach((blockId, obj) -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(blockId)); + if (block == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.shovel.flattenables`: " + blockId); return; } + if (!(obj instanceof Map map)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.shovel.flattenables." + blockId + "`"); return; } + String intoId = (String) map.get("into"); + Block into = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(intoId)); + if (into == Blocks.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid block for `tools.shovel.flattenables." + blockId + ".into`: " + intoId); return; } + Object dropsObj = map.get("drops"); + if (!(dropsObj instanceof Map dropsMap)) { PurpurConfig.log(Level.SEVERE, "Invalid yaml for `tools.shovel.flattenables." + blockId + ".drops`"); return; } + Map drops = new HashMap<>(); + dropsMap.forEach((itemId, chance) -> { + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(itemId.toString())); + if (item == Items.AIR) { PurpurConfig.log(Level.SEVERE, "Invalid item for `tools.shovel.flattenables." + blockId + ".drops`: " + itemId); return; } + drops.put(item, (double) chance); + }); + shovelFlattenables.put(block, new Flattenable(into, drops)); + }); + hoeReplantsCrops = getBoolean("tools.hoe.replant-crops", hoeReplantsCrops); + hoeReplantsNetherWarts = getBoolean("tools.hoe.replant-nether-warts", hoeReplantsNetherWarts); + } + + public boolean anvilAllowColors = false; + public boolean anvilColorsUseMiniMessage; + public int anvilRepairIngotsAmount = 0; + public int anvilDamageObsidianAmount = 0; + private void anvilSettings() { + anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors); + anvilColorsUseMiniMessage = getBoolean("blocks.anvil.use-mini-message", anvilColorsUseMiniMessage); + anvilRepairIngotsAmount = getInt("blocks.anvil.iron-ingots-used-for-repair", anvilRepairIngotsAmount); + anvilDamageObsidianAmount = getInt("blocks.anvil.obsidian-used-for-damage", anvilDamageObsidianAmount); + } + + public double azaleaGrowthChance = 0.0D; + private void azaleaSettings() { + azaleaGrowthChance = getDouble("blocks.azalea.growth-chance", azaleaGrowthChance); + } + + public int beaconLevelOne = 20; + public int beaconLevelTwo = 30; + public int beaconLevelThree = 40; + public int beaconLevelFour = 50; + public boolean beaconAllowEffectsWithTintedGlass = false; + private void beaconSettings() { + beaconLevelOne = getInt("blocks.beacon.effect-range.level-1", beaconLevelOne); + beaconLevelTwo = getInt("blocks.beacon.effect-range.level-2", beaconLevelTwo); + beaconLevelThree = getInt("blocks.beacon.effect-range.level-3", beaconLevelThree); + beaconLevelFour = getInt("blocks.beacon.effect-range.level-4", beaconLevelFour); + beaconAllowEffectsWithTintedGlass = getBoolean("blocks.beacon.allow-effects-with-tinted-glass", beaconAllowEffectsWithTintedGlass); + } + + public boolean bedExplode = true; + public boolean bedExplodeOnVillagerSleep = false; + public double bedExplosionPower = 5.0D; + public boolean bedExplosionFire = true; + public net.minecraft.world.level.Level.ExplosionInteraction bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; + private void bedSettings() { + if (PurpurConfig.version < 31) { + if ("DESTROY".equals(getString("blocks.bed.explosion-effect", bedExplosionEffect.name()))) { + set("blocks.bed.explosion-effect", "BLOCK"); + } + } + bedExplode = getBoolean("blocks.bed.explode", bedExplode); + bedExplodeOnVillagerSleep = getBoolean("blocks.bed.explode-on-villager-sleep", bedExplodeOnVillagerSleep); + bedExplosionPower = getDouble("blocks.bed.explosion-power", bedExplosionPower); + bedExplosionFire = getBoolean("blocks.bed.explosion-fire", bedExplosionFire); + try { + bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.bed.explosion-effect", bedExplosionEffect.name())); + } catch (IllegalArgumentException e) { + log(Level.SEVERE, "Unknown value for `blocks.bed.explosion-effect`! Using default of `BLOCK`"); + bedExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; + } + } + + public Map bigDripleafTiltDelay = new HashMap<>(); + private void bigDripleafSettings() { + bigDripleafTiltDelay.clear(); + getMap("blocks.big_dripleaf.tilt-delay", Map.ofEntries( + Map.entry("UNSTABLE", 10), + Map.entry("PARTIAL", 10), + Map.entry("FULL", 100)) + ).forEach((tilt, delay) -> { + try { + bigDripleafTiltDelay.put(Tilt.valueOf(tilt), (int) delay); + } catch (IllegalArgumentException e) { + PurpurConfig.log(Level.SEVERE, "Invalid big_dripleaf tilt key: " + tilt); + } + }); + } + + public boolean cactusBreaksFromSolidNeighbors = true; + public boolean cactusAffectedByBonemeal = false; + private void cactusSettings() { + cactusBreaksFromSolidNeighbors = getBoolean("blocks.cactus.breaks-from-solid-neighbors", cactusBreaksFromSolidNeighbors); + cactusAffectedByBonemeal = getBoolean("blocks.cactus.affected-by-bonemeal", cactusAffectedByBonemeal); + } + + public boolean sugarCanAffectedByBonemeal = false; + private void sugarCaneSettings() { + sugarCanAffectedByBonemeal = getBoolean("blocks.sugar_cane.affected-by-bonemeal", sugarCanAffectedByBonemeal); + } + + public boolean netherWartAffectedByBonemeal = false; + private void netherWartSettings() { + netherWartAffectedByBonemeal = getBoolean("blocks.nether_wart.affected-by-bonemeal", netherWartAffectedByBonemeal); + } + + public boolean campFireLitWhenPlaced = true; + private void campFireSettings() { + campFireLitWhenPlaced = getBoolean("blocks.campfire.lit-when-placed", campFireLitWhenPlaced); + } + + public boolean chestOpenWithBlockOnTop = false; + private void chestSettings() { + chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); + } + + public boolean composterBulkProcess = false; + private void composterSettings() { + composterBulkProcess = getBoolean("blocks.composter.sneak-to-bulk-process", composterBulkProcess); + } + + public boolean coralDieOutsideWater = true; + private void coralSettings() { + coralDieOutsideWater = getBoolean("blocks.coral.die-outside-water", coralDieOutsideWater); + } + + public boolean dispenserApplyCursedArmor = true; + public boolean dispenserPlaceAnvils = false; + private void dispenserSettings() { + dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor); + dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils); + } + + public List doorRequiresRedstone = new ArrayList<>(); + private void doorSettings() { + getList("blocks.door.requires-redstone", new ArrayList()).forEach(key -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(key.toString())); + if (!block.defaultBlockState().isAir()) { + doorRequiresRedstone.add(block); + } + }); + } + + public boolean dragonEggTeleport = true; + private void dragonEggSettings() { + dragonEggTeleport = getBoolean("blocks.dragon_egg.teleport", dragonEggTeleport); + } + + public boolean baselessEndCrystalExplode = true; + public double baselessEndCrystalExplosionPower = 6.0D; + public boolean baselessEndCrystalExplosionFire = false; + public net.minecraft.world.level.Level.ExplosionInteraction baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; + public boolean basedEndCrystalExplode = true; + public double basedEndCrystalExplosionPower = 6.0D; + public boolean basedEndCrystalExplosionFire = false; + public net.minecraft.world.level.Level.ExplosionInteraction basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; + public int endCrystalCramming = 0; + public boolean endCrystalPlaceAnywhere = false; + private void endCrystalSettings() { + if (PurpurConfig.version < 31) { + if ("DESTROY".equals(getString("blocks.end-crystal.baseless.explosion-effect", baselessEndCrystalExplosionEffect.name()))) { + set("blocks.end-crystal.baseless.explosion-effect", "BLOCK"); + } + if ("DESTROY".equals(getString("blocks.end-crystal.base.explosion-effect", basedEndCrystalExplosionEffect.name()))) { + set("blocks.end-crystal.base.explosion-effect", "BLOCK"); + } + } + baselessEndCrystalExplode = getBoolean("blocks.end-crystal.baseless.explode", baselessEndCrystalExplode); + baselessEndCrystalExplosionPower = getDouble("blocks.end-crystal.baseless.explosion-power", baselessEndCrystalExplosionPower); + baselessEndCrystalExplosionFire = getBoolean("blocks.end-crystal.baseless.explosion-fire", baselessEndCrystalExplosionFire); + try { + baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.end-crystal.baseless.explosion-effect", baselessEndCrystalExplosionEffect.name())); + } catch (IllegalArgumentException e) { + log(Level.SEVERE, "Unknown value for `blocks.end-crystal.baseless.explosion-effect`! Using default of `BLOCK`"); + baselessEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; + } + basedEndCrystalExplode = getBoolean("blocks.end-crystal.base.explode", basedEndCrystalExplode); + basedEndCrystalExplosionPower = getDouble("blocks.end-crystal.base.explosion-power", basedEndCrystalExplosionPower); + basedEndCrystalExplosionFire = getBoolean("blocks.end-crystal.base.explosion-fire", basedEndCrystalExplosionFire); + try { + basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.end-crystal.base.explosion-effect", basedEndCrystalExplosionEffect.name())); + } catch (IllegalArgumentException e) { + log(Level.SEVERE, "Unknown value for `blocks.end-crystal.base.explosion-effect`! Using default of `BLOCK`"); + basedEndCrystalExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; + } + endCrystalCramming = getInt("blocks.end-crystal.cramming-amount", endCrystalCramming); + endCrystalPlaceAnywhere = getBoolean("gameplay-mechanics.item.end-crystal.place-anywhere", endCrystalPlaceAnywhere); + } + + public boolean farmlandBypassMobGriefing = false; + public boolean farmlandGetsMoistFromBelow = false; + public boolean farmlandAlpha = false; + public boolean farmlandTramplingDisabled = false; + public boolean farmlandTramplingOnlyPlayers = false; + public boolean farmlandTramplingFeatherFalling = false; + public double farmlandTrampleHeight = -1D; + private void farmlandSettings() { + farmlandBypassMobGriefing = getBoolean("blocks.farmland.bypass-mob-griefing", farmlandBypassMobGriefing); + farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); + farmlandAlpha = getBoolean("blocks.farmland.use-alpha-farmland", farmlandAlpha); + farmlandTramplingDisabled = getBoolean("blocks.farmland.disable-trampling", farmlandTramplingDisabled); + farmlandTramplingOnlyPlayers = getBoolean("blocks.farmland.only-players-trample", farmlandTramplingOnlyPlayers); + farmlandTramplingFeatherFalling = getBoolean("blocks.farmland.feather-fall-distance-affects-trampling", farmlandTramplingFeatherFalling); + farmlandTrampleHeight = getDouble("blocks.farmland.trample-height", farmlandTrampleHeight); + } + + public double floweringAzaleaGrowthChance = 0.0D; + private void floweringAzaleaSettings() { + floweringAzaleaGrowthChance = getDouble("blocks.flowering_azalea.growth-chance", floweringAzaleaGrowthChance); + } + + public boolean furnaceUseLavaFromUnderneath = false; + private void furnaceSettings() { + if (PurpurConfig.version < 17) { + furnaceUseLavaFromUnderneath = getBoolean("blocks.furnace.infinite-fuel", furnaceUseLavaFromUnderneath); + boolean oldValue = getBoolean("blocks.furnace.infinite-fuel", furnaceUseLavaFromUnderneath); + set("blocks.furnace.infinite-fuel", null); + set("blocks.furnace.use-lava-from-underneath", oldValue); + } + furnaceUseLavaFromUnderneath = getBoolean("blocks.furnace.use-lava-from-underneath", furnaceUseLavaFromUnderneath); + } + + public boolean mobsSpawnOnPackedIce = true; + public boolean mobsSpawnOnBlueIce = true; + public boolean snowOnBlueIce = true; + private void iceSettings() { + mobsSpawnOnPackedIce = getBoolean("blocks.packed_ice.allow-mob-spawns", mobsSpawnOnPackedIce); + mobsSpawnOnBlueIce = getBoolean("blocks.blue_ice.allow-mob-spawns", mobsSpawnOnBlueIce); + snowOnBlueIce = getBoolean("blocks.blue_ice.allow-snow-formation", snowOnBlueIce); + } + + public int lavaInfiniteRequiredSources = 2; + public int lavaSpeedNether = 10; + public int lavaSpeedNotNether = 30; + private void lavaSettings() { + lavaInfiniteRequiredSources = getInt("blocks.lava.infinite-required-sources", lavaInfiniteRequiredSources); + lavaSpeedNether = getInt("blocks.lava.speed.nether", lavaSpeedNether); + lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether); + } + + public int pistonBlockPushLimit = 12; + private void pistonSettings() { + pistonBlockPushLimit = getInt("blocks.piston.block-push-limit", pistonBlockPushLimit); + } + + public boolean magmaBlockDamageWhenSneaking = false; + private void magmaBlockSettings() { + magmaBlockDamageWhenSneaking = getBoolean("blocks.magma-block.damage-when-sneaking", magmaBlockDamageWhenSneaking); + } + + public boolean powderSnowBypassMobGriefing = false; + private void powderSnowSettings() { + powderSnowBypassMobGriefing = getBoolean("blocks.powder_snow.bypass-mob-griefing", powderSnowBypassMobGriefing); + } + + public int railActivationRange = 8; + private void railSettings() { + railActivationRange = getInt("blocks.powered-rail.activation-range", railActivationRange); + } + + public boolean respawnAnchorExplode = true; + public double respawnAnchorExplosionPower = 5.0D; + public boolean respawnAnchorExplosionFire = true; + public net.minecraft.world.level.Level.ExplosionInteraction respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; + private void respawnAnchorSettings() { + if (PurpurConfig.version < 31) { + if ("DESTROY".equals(getString("blocks.respawn_anchor.explosion-effect", respawnAnchorExplosionEffect.name()))) { + set("blocks.respawn_anchor.explosion-effect", "BLOCK"); + } + } + respawnAnchorExplode = getBoolean("blocks.respawn_anchor.explode", respawnAnchorExplode); + respawnAnchorExplosionPower = getDouble("blocks.respawn_anchor.explosion-power", respawnAnchorExplosionPower); + respawnAnchorExplosionFire = getBoolean("blocks.respawn_anchor.explosion-fire", respawnAnchorExplosionFire); + try { + respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.valueOf(getString("blocks.respawn_anchor.explosion-effect", respawnAnchorExplosionEffect.name())); + } catch (IllegalArgumentException e) { + log(Level.SEVERE, "Unknown value for `blocks.respawn_anchor.explosion-effect`! Using default of `BLOCK`"); + respawnAnchorExplosionEffect = net.minecraft.world.level.Level.ExplosionInteraction.BLOCK; + } + } + + public boolean sculkShriekerCanSummonDefault = false; + private void sculkShriekerSettings() { + sculkShriekerCanSummonDefault = getBoolean("blocks.sculk_shrieker.can-summon-default", sculkShriekerCanSummonDefault); + } + + public boolean signAllowColors = false; + private void signSettings() { + signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors); + } + + public boolean slabHalfBreak = false; + private void slabSettings() { + slabHalfBreak = getBoolean("blocks.slab.break-individual-slabs-when-sneaking", slabHalfBreak); + } + + public boolean spawnerDeactivateByRedstone = false; + public boolean spawnerFixMC238526 = false; + private void spawnerSettings() { + spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); + spawnerFixMC238526 = getBoolean("blocks.spawner.fix-mc-238526", spawnerFixMC238526); + } + + public int spongeAbsorptionArea = 65; + public int spongeAbsorptionRadius = 6; + public boolean spongeAbsorbsLava = false; + public boolean spongeAbsorbsWaterFromMud = false; + private void spongeSettings() { + spongeAbsorptionArea = getInt("blocks.sponge.absorption.area", spongeAbsorptionArea); + spongeAbsorptionRadius = getInt("blocks.sponge.absorption.radius", spongeAbsorptionRadius); + spongeAbsorbsLava = getBoolean("blocks.sponge.absorbs-lava", spongeAbsorbsLava); + spongeAbsorbsWaterFromMud = getBoolean("blocks.sponge.absorbs-water-from-mud", spongeAbsorbsWaterFromMud); + } + + public float stonecutterDamage = 0.0F; + private void stonecutterSettings() { + stonecutterDamage = (float) getDouble("blocks.stonecutter.damage", stonecutterDamage); + } + + public boolean turtleEggsBreakFromExpOrbs = false; + public boolean turtleEggsBreakFromItems = false; + public boolean turtleEggsBreakFromMinecarts = false; + public boolean turtleEggsBypassMobGriefing = false; + public int turtleEggsRandomTickCrackChance = 500; + public boolean turtleEggsTramplingFeatherFalling = false; + private void turtleEggSettings() { + turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs); + turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems); + turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); + turtleEggsBypassMobGriefing = getBoolean("blocks.turtle_egg.bypass-mob-griefing", turtleEggsBypassMobGriefing); + turtleEggsRandomTickCrackChance = getInt("blocks.turtle_egg.random-tick-crack-chance", turtleEggsRandomTickCrackChance); + turtleEggsTramplingFeatherFalling = getBoolean("blocks.turtle_egg.feather-fall-distance-affects-trampling", turtleEggsTramplingFeatherFalling); + } + + public int waterInfiniteRequiredSources = 2; + private void waterSources() { + waterInfiniteRequiredSources = getInt("blocks.water.infinite-required-sources", waterInfiniteRequiredSources); + } + + public boolean babiesAreRidable = true; + public boolean untamedTamablesAreRidable = true; + public boolean useNightVisionWhenRiding = false; + public boolean useDismountsUnderwaterTag = true; + private void ridableSettings() { + babiesAreRidable = getBoolean("ridable-settings.babies-are-ridable", babiesAreRidable); + untamedTamablesAreRidable = getBoolean("ridable-settings.untamed-tamables-are-ridable", untamedTamablesAreRidable); + useNightVisionWhenRiding = getBoolean("ridable-settings.use-night-vision", useNightVisionWhenRiding); + useDismountsUnderwaterTag = getBoolean("ridable-settings.use-dismounts-underwater-tag", useDismountsUnderwaterTag); + } + + public boolean allayRidable = false; + public boolean allayRidableInWater = true; + public boolean allayControllable = true; + public double allayMaxHealth = 20.0D; + public double allayScale = 1.0D; + private void allaySettings() { + allayRidable = getBoolean("mobs.allay.ridable", allayRidable); + allayRidableInWater = getBoolean("mobs.allay.ridable-in-water", allayRidableInWater); + allayControllable = getBoolean("mobs.allay.controllable", allayControllable); + allayMaxHealth = getDouble("mobs.allay.attributes.max_health", allayMaxHealth); + allayScale = Mth.clamp(getDouble("mobs.allay.attributes.scale", allayScale), 0.0625D, 16.0D); + } + + public boolean armadilloRidable = false; + public boolean armadilloRidableInWater = true; + public boolean armadilloControllable = true; + public double armadilloMaxHealth = 12.0D; + public double armadilloScale = 1.0D; + public int armadilloBreedingTicks = 6000; + private void armadilloSettings() { + armadilloRidable = getBoolean("mobs.armadillo.ridable", armadilloRidable); + armadilloRidableInWater = getBoolean("mobs.armadillo.ridable-in-water", armadilloRidableInWater); + armadilloControllable = getBoolean("mobs.armadillo.controllable", armadilloControllable); + armadilloMaxHealth = getDouble("mobs.armadillo.attributes.max_health", armadilloMaxHealth); + armadilloScale = Mth.clamp(getDouble("mobs.armadillo.attributes.scale", armadilloScale), 0.0625D, 16.0D); + armadilloBreedingTicks = getInt("mobs.armadillo.breeding-delay-ticks", armadilloBreedingTicks); + } + + public boolean axolotlRidable = false; + public boolean axolotlControllable = true; + public double axolotlMaxHealth = 14.0D; + public double axolotlScale = 1.0D; + public int axolotlBreedingTicks = 6000; + public boolean axolotlTakeDamageFromWater = false; + public boolean axolotlAlwaysDropExp = false; + private void axolotlSettings() { + axolotlRidable = getBoolean("mobs.axolotl.ridable", axolotlRidable); + axolotlControllable = getBoolean("mobs.axolotl.controllable", axolotlControllable); + axolotlMaxHealth = getDouble("mobs.axolotl.attributes.max_health", axolotlMaxHealth); + axolotlScale = Mth.clamp(getDouble("mobs.axolotl.attributes.scale", axolotlScale), 0.0625D, 16.0D); + axolotlBreedingTicks = getInt("mobs.axolotl.breeding-delay-ticks", axolotlBreedingTicks); + axolotlTakeDamageFromWater = getBoolean("mobs.axolotl.takes-damage-from-water", axolotlTakeDamageFromWater); + axolotlAlwaysDropExp = getBoolean("mobs.axolotl.always-drop-exp", axolotlAlwaysDropExp); + } + + public boolean batRidable = false; + public boolean batRidableInWater = true; + public boolean batControllable = true; + public double batMaxY = 320D; + public double batMaxHealth = 6.0D; + public double batScale = 1.0D; + public double batFollowRange = 16.0D; + public double batKnockbackResistance = 0.0D; + public double batMovementSpeed = 0.6D; + public double batFlyingSpeed = 0.6D; + public double batArmor = 0.0D; + public double batArmorToughness = 0.0D; + public double batAttackKnockback = 0.0D; + public boolean batTakeDamageFromWater = false; + public boolean batAlwaysDropExp = false; + private void batSettings() { + batRidable = getBoolean("mobs.bat.ridable", batRidable); + batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater); + batControllable = getBoolean("mobs.bat.controllable", batControllable); + batMaxY = getDouble("mobs.bat.ridable-max-y", batMaxY); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.bat.attributes.max-health", batMaxHealth); + set("mobs.bat.attributes.max-health", null); + set("mobs.bat.attributes.max_health", oldValue); + } + batMaxHealth = getDouble("mobs.bat.attributes.max_health", batMaxHealth); + batScale = Mth.clamp(getDouble("mobs.bat.attributes.scale", batScale), 0.0625D, 16.0D); + batFollowRange = getDouble("mobs.bat.attributes.follow_range", batFollowRange); + batKnockbackResistance = getDouble("mobs.bat.attributes.knockback_resistance", batKnockbackResistance); + batMovementSpeed = getDouble("mobs.bat.attributes.movement_speed", batMovementSpeed); + batFlyingSpeed = getDouble("mobs.bat.attributes.flying_speed", batFlyingSpeed); + batArmor = getDouble("mobs.bat.attributes.armor", batArmor); + batArmorToughness = getDouble("mobs.bat.attributes.armor_toughness", batArmorToughness); + batAttackKnockback = getDouble("mobs.bat.attributes.attack_knockback", batAttackKnockback); + batTakeDamageFromWater = getBoolean("mobs.bat.takes-damage-from-water", batTakeDamageFromWater); + batAlwaysDropExp = getBoolean("mobs.bat.always-drop-exp", batAlwaysDropExp); + } + + public boolean beeRidable = false; + public boolean beeRidableInWater = true; + public boolean beeControllable = true; + public double beeMaxY = 320D; + public double beeMaxHealth = 10.0D; + public double beeScale = 1.0D; + public int beeBreedingTicks = 6000; + public boolean beeTakeDamageFromWater = true; + public boolean beeCanWorkAtNight = false; + public boolean beeCanWorkInRain = false; + public boolean beeAlwaysDropExp = false; + public boolean beeDiesAfterSting = true; + private void beeSettings() { + beeRidable = getBoolean("mobs.bee.ridable", beeRidable); + beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); + beeControllable = getBoolean("mobs.bee.controllable", beeControllable); + beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.bee.attributes.max-health", beeMaxHealth); + set("mobs.bee.attributes.max-health", null); + set("mobs.bee.attributes.max_health", oldValue); + } + beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth); + beeScale = Mth.clamp(getDouble("mobs.bee.attributes.scale", beeScale), 0.0625D, 16.0D); + beeBreedingTicks = getInt("mobs.bee.breeding-delay-ticks", beeBreedingTicks); + beeTakeDamageFromWater = getBoolean("mobs.bee.takes-damage-from-water", beeTakeDamageFromWater); + beeCanWorkAtNight = getBoolean("mobs.bee.can-work-at-night", beeCanWorkAtNight); + beeCanWorkInRain = getBoolean("mobs.bee.can-work-in-rain", beeCanWorkInRain); + beeAlwaysDropExp = getBoolean("mobs.bee.always-drop-exp", beeAlwaysDropExp); + beeDiesAfterSting = getBoolean("mobs.bee.dies-after-sting", beeDiesAfterSting); + } + + public boolean blazeRidable = false; + public boolean blazeRidableInWater = true; + public boolean blazeControllable = true; + public double blazeMaxY = 320D; + public double blazeMaxHealth = 20.0D; + public double blazeScale = 1.0D; + public boolean blazeTakeDamageFromWater = true; + public boolean blazeAlwaysDropExp = false; + private void blazeSettings() { + blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); + blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); + blazeControllable = getBoolean("mobs.blaze.controllable", blazeControllable); + blazeMaxY = getDouble("mobs.blaze.ridable-max-y", blazeMaxY); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.blaze.attributes.max-health", blazeMaxHealth); + set("mobs.blaze.attributes.max-health", null); + set("mobs.blaze.attributes.max_health", oldValue); + } + blazeMaxHealth = getDouble("mobs.blaze.attributes.max_health", blazeMaxHealth); + blazeScale = Mth.clamp(getDouble("mobs.blaze.attributes.scale", blazeScale), 0.0625D, 16.0D); + blazeTakeDamageFromWater = getBoolean("mobs.blaze.takes-damage-from-water", blazeTakeDamageFromWater); + blazeAlwaysDropExp = getBoolean("mobs.blaze.always-drop-exp", blazeAlwaysDropExp); + } + + public boolean boggedRidable = false; + public boolean boggedRidableInWater = true; + public boolean boggedControllable = true; + public double boggedMaxHealth = 16.0D; + public double boggedScale = 1.0D; + private void boggedSettings() { + boggedRidable = getBoolean("mobs.bogged.ridable", boggedRidable); + boggedRidableInWater = getBoolean("mobs.bogged.ridable-in-water", boggedRidableInWater); + boggedControllable = getBoolean("mobs.bogged.controllable", boggedControllable); + boggedMaxHealth = getDouble("mobs.bogged.attributes.max_health", boggedMaxHealth); + boggedScale = Mth.clamp(getDouble("mobs.bogged.attributes.scale", boggedScale), 0.0625D, 16.0D); + } + + public boolean camelRidableInWater = false; + public double camelMaxHealthMin = 32.0D; + public double camelMaxHealthMax = 32.0D; + public double camelJumpStrengthMin = 0.42D; + public double camelJumpStrengthMax = 0.42D; + public double camelMovementSpeedMin = 0.09D; + public double camelMovementSpeedMax = 0.09D; + public int camelBreedingTicks = 6000; + private void camelSettings() { + camelRidableInWater = getBoolean("mobs.camel.ridable-in-water", camelRidableInWater); + camelMaxHealthMin = getDouble("mobs.camel.attributes.max_health.min", camelMaxHealthMin); + camelMaxHealthMax = getDouble("mobs.camel.attributes.max_health.max", camelMaxHealthMax); + camelJumpStrengthMin = getDouble("mobs.camel.attributes.jump_strength.min", camelJumpStrengthMin); + camelJumpStrengthMax = getDouble("mobs.camel.attributes.jump_strength.max", camelJumpStrengthMax); + camelMovementSpeedMin = getDouble("mobs.camel.attributes.movement_speed.min", camelMovementSpeedMin); + camelMovementSpeedMax = getDouble("mobs.camel.attributes.movement_speed.max", camelMovementSpeedMax); + camelBreedingTicks = getInt("mobs.camel.breeding-delay-ticks", camelBreedingTicks); + } + + public boolean catRidable = false; + public boolean catRidableInWater = true; + public boolean catControllable = true; + public double catMaxHealth = 10.0D; + public double catScale = 1.0D; + public int catSpawnDelay = 1200; + public int catSpawnSwampHutScanRange = 16; + public int catSpawnVillageScanRange = 48; + public int catBreedingTicks = 6000; + public DyeColor catDefaultCollarColor = DyeColor.RED; + public boolean catTakeDamageFromWater = false; + public boolean catAlwaysDropExp = false; + private void catSettings() { + catRidable = getBoolean("mobs.cat.ridable", catRidable); + catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); + catControllable = getBoolean("mobs.cat.controllable", catControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.cat.attributes.max-health", catMaxHealth); + set("mobs.cat.attributes.max-health", null); + set("mobs.cat.attributes.max_health", oldValue); + } + catMaxHealth = getDouble("mobs.cat.attributes.max_health", catMaxHealth); + catScale = Mth.clamp(getDouble("mobs.cat.attributes.scale", catScale), 0.0625D, 16.0D); + catSpawnDelay = getInt("mobs.cat.spawn-delay", catSpawnDelay); + catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange); + catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange); + catBreedingTicks = getInt("mobs.cat.breeding-delay-ticks", catBreedingTicks); + try { + catDefaultCollarColor = DyeColor.valueOf(getString("mobs.cat.default-collar-color", catDefaultCollarColor.name())); + } catch (IllegalArgumentException ignore) { + catDefaultCollarColor = DyeColor.RED; + } + catTakeDamageFromWater = getBoolean("mobs.cat.takes-damage-from-water", catTakeDamageFromWater); + catAlwaysDropExp = getBoolean("mobs.cat.always-drop-exp", catAlwaysDropExp); + } + + public boolean caveSpiderRidable = false; + public boolean caveSpiderRidableInWater = true; + public boolean caveSpiderControllable = true; + public double caveSpiderMaxHealth = 12.0D; + public double caveSpiderScale = 1.0D; + public boolean caveSpiderTakeDamageFromWater = false; + public boolean caveSpiderAlwaysDropExp = false; + private void caveSpiderSettings() { + caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable); + caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater); + caveSpiderControllable = getBoolean("mobs.cave_spider.controllable", caveSpiderControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.cave_spider.attributes.max-health", caveSpiderMaxHealth); + set("mobs.cave_spider.attributes.max-health", null); + set("mobs.cave_spider.attributes.max_health", oldValue); + } + caveSpiderMaxHealth = getDouble("mobs.cave_spider.attributes.max_health", caveSpiderMaxHealth); + caveSpiderScale = Mth.clamp(getDouble("mobs.cave_spider.attributes.scale", caveSpiderScale), 0.0625D, 16.0D); + caveSpiderTakeDamageFromWater = getBoolean("mobs.cave_spider.takes-damage-from-water", caveSpiderTakeDamageFromWater); + caveSpiderAlwaysDropExp = getBoolean("mobs.cave_spider.always-drop-exp", caveSpiderAlwaysDropExp); + } + + public boolean chickenRidable = false; + public boolean chickenRidableInWater = false; + public boolean chickenControllable = true; + public double chickenMaxHealth = 4.0D; + public double chickenScale = 1.0D; + public boolean chickenRetaliate = false; + public int chickenBreedingTicks = 6000; + public boolean chickenTakeDamageFromWater = false; + public boolean chickenAlwaysDropExp = false; + private void chickenSettings() { + chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); + chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); + chickenControllable = getBoolean("mobs.chicken.controllable", chickenControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.chicken.attributes.max-health", chickenMaxHealth); + set("mobs.chicken.attributes.max-health", null); + set("mobs.chicken.attributes.max_health", oldValue); + } + chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth); + chickenScale = Mth.clamp(getDouble("mobs.chicken.attributes.scale", chickenScale), 0.0625D, 16.0D); + chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); + chickenBreedingTicks = getInt("mobs.chicken.breeding-delay-ticks", chickenBreedingTicks); + chickenTakeDamageFromWater = getBoolean("mobs.chicken.takes-damage-from-water", chickenTakeDamageFromWater); + chickenAlwaysDropExp = getBoolean("mobs.chicken.always-drop-exp", chickenAlwaysDropExp); + } + + public boolean codRidable = false; + public boolean codControllable = true; + public double codMaxHealth = 3.0D; + public double codScale = 1.0D; + public boolean codTakeDamageFromWater = false; + public boolean codAlwaysDropExp = false; + private void codSettings() { + codRidable = getBoolean("mobs.cod.ridable", codRidable); + codControllable = getBoolean("mobs.cod.controllable", codControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.cod.attributes.max-health", codMaxHealth); + set("mobs.cod.attributes.max-health", null); + set("mobs.cod.attributes.max_health", oldValue); + } + codMaxHealth = getDouble("mobs.cod.attributes.max_health", codMaxHealth); + codScale = Mth.clamp(getDouble("mobs.cod.attributes.scale", codScale), 0.0625D, 16.0D); + codTakeDamageFromWater = getBoolean("mobs.cod.takes-damage-from-water", codTakeDamageFromWater); + codAlwaysDropExp = getBoolean("mobs.cod.always-drop-exp", codAlwaysDropExp); + } + + public boolean cowRidable = false; + public boolean cowRidableInWater = true; + public boolean cowControllable = true; + public double cowMaxHealth = 10.0D; + public double cowScale = 1.0D; + public int cowFeedMushrooms = 0; + public int cowBreedingTicks = 6000; + public boolean cowTakeDamageFromWater = false; + public double cowNaturallyAggressiveToPlayersChance = 0.0D; + public double cowNaturallyAggressiveToPlayersDamage = 2.0D; + public boolean cowAlwaysDropExp = false; + private void cowSettings() { + if (PurpurConfig.version < 22) { + double oldValue = getDouble("mobs.cow.naturally-aggressive-to-players-chance", cowNaturallyAggressiveToPlayersChance); + set("mobs.cow.naturally-aggressive-to-players-chance", null); + set("mobs.cow.naturally-aggressive-to-players.chance", oldValue); + } + cowRidable = getBoolean("mobs.cow.ridable", cowRidable); + cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); + cowControllable = getBoolean("mobs.cow.controllable", cowControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.cow.attributes.max-health", cowMaxHealth); + set("mobs.cow.attributes.max-health", null); + set("mobs.cow.attributes.max_health", oldValue); + } + cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth); + cowScale = Mth.clamp(getDouble("mobs.cow.attributes.scale", cowScale), 0.0625D, 16.0D); + cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); + cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks); + cowTakeDamageFromWater = getBoolean("mobs.cow.takes-damage-from-water", cowTakeDamageFromWater); + cowNaturallyAggressiveToPlayersChance = getDouble("mobs.cow.naturally-aggressive-to-players.chance", cowNaturallyAggressiveToPlayersChance); + cowNaturallyAggressiveToPlayersDamage = getDouble("mobs.cow.naturally-aggressive-to-players.damage", cowNaturallyAggressiveToPlayersDamage); + cowAlwaysDropExp = getBoolean("mobs.cow.always-drop-exp", cowAlwaysDropExp); + } + + public boolean creakingRidable = false; + public boolean creakingRidableInWater = true; + public boolean creakingControllable = true; + public double creakingMaxHealth = 1.0D; + public double creakingScale = 1.0D; + private void creakingSettings() { + creakingRidable = getBoolean("mobs.creaking.ridable", creakingRidable); + creakingRidableInWater = getBoolean("mobs.creaking.ridable-in-water", creakingRidableInWater); + creakingControllable = getBoolean("mobs.creaking.controllable", creakingControllable); + creakingMaxHealth = getDouble("mobs.creaking.attributes.max_health", creakingMaxHealth); + creakingScale = Mth.clamp(getDouble("mobs.creaking.attributes.scale", creakingScale), 0.0625D, 16.0D); + } + + public boolean creeperRidable = false; + public boolean creeperRidableInWater = true; + public boolean creeperControllable = true; + public double creeperMaxHealth = 20.0D; + public double creeperScale = 1.0D; + public double creeperChargedChance = 0.0D; + public boolean creeperAllowGriefing = true; + public boolean creeperBypassMobGriefing = false; + public boolean creeperTakeDamageFromWater = false; + public boolean creeperExplodeWhenKilled = false; + public boolean creeperHealthRadius = false; + public boolean creeperAlwaysDropExp = false; + public double creeperHeadVisibilityPercent = 0.5D; + public boolean creeperEncircleTarget = false; + private void creeperSettings() { + creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); + creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); + creeperControllable = getBoolean("mobs.creeper.controllable", creeperControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.creeper.attributes.max-health", creeperMaxHealth); + set("mobs.creeper.attributes.max-health", null); + set("mobs.creeper.attributes.max_health", oldValue); + } + creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth); + creeperScale = Mth.clamp(getDouble("mobs.creeper.attributes.scale", creeperScale), 0.0625D, 16.0D); + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); + creeperBypassMobGriefing = getBoolean("mobs.creeper.bypass-mob-griefing", creeperBypassMobGriefing); + creeperTakeDamageFromWater = getBoolean("mobs.creeper.takes-damage-from-water", creeperTakeDamageFromWater); + creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled); + creeperHealthRadius = getBoolean("mobs.creeper.health-impacts-explosion", creeperHealthRadius); + creeperAlwaysDropExp = getBoolean("mobs.creeper.always-drop-exp", creeperAlwaysDropExp); + creeperHeadVisibilityPercent = getDouble("mobs.creeper.head-visibility-percent", creeperHeadVisibilityPercent); + creeperEncircleTarget = getBoolean("mobs.creeper.encircle-target", creeperEncircleTarget); + } + + public boolean dolphinRidable = false; + public boolean dolphinControllable = true; + public int dolphinSpitCooldown = 20; + public float dolphinSpitSpeed = 1.0F; + public float dolphinSpitDamage = 2.0F; + public double dolphinMaxHealth = 10.0D; + public double dolphinScale = 1.0D; + public boolean dolphinDisableTreasureSearching = false; + public boolean dolphinTakeDamageFromWater = false; + public double dolphinNaturallyAggressiveToPlayersChance = 0.0D; + public boolean dolphinAlwaysDropExp = false; + private void dolphinSettings() { + dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); + dolphinControllable = getBoolean("mobs.dolphin.controllable", dolphinControllable); + dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown); + dolphinSpitSpeed = (float) getDouble("mobs.dolphin.spit.speed", dolphinSpitSpeed); + dolphinSpitDamage = (float) getDouble("mobs.dolphin.spit.damage", dolphinSpitDamage); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.dolphin.attributes.max-health", dolphinMaxHealth); + set("mobs.dolphin.attributes.max-health", null); + set("mobs.dolphin.attributes.max_health", oldValue); + } + dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth); + dolphinScale = Mth.clamp(getDouble("mobs.dolphin.attributes.scale", dolphinScale), 0.0625D, 16.0D); + dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching); + dolphinTakeDamageFromWater = getBoolean("mobs.dolphin.takes-damage-from-water", dolphinTakeDamageFromWater); + dolphinNaturallyAggressiveToPlayersChance = getDouble("mobs.dolphin.naturally-aggressive-to-players-chance", dolphinNaturallyAggressiveToPlayersChance); + dolphinAlwaysDropExp = getBoolean("mobs.dolphin.always-drop-exp", dolphinAlwaysDropExp); + } + + public boolean donkeyRidableInWater = false; + public double donkeyMaxHealthMin = 15.0D; + public double donkeyMaxHealthMax = 30.0D; + public double donkeyJumpStrengthMin = 0.5D; + public double donkeyJumpStrengthMax = 0.5D; + public double donkeyMovementSpeedMin = 0.175D; + public double donkeyMovementSpeedMax = 0.175D; + public int donkeyBreedingTicks = 6000; + public boolean donkeyTakeDamageFromWater = false; + public boolean donkeyAlwaysDropExp = false; + private void donkeySettings() { + donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); + if (PurpurConfig.version < 10) { + double oldMin = getDouble("mobs.donkey.attributes.max-health.min", donkeyMaxHealthMin); + double oldMax = getDouble("mobs.donkey.attributes.max-health.max", donkeyMaxHealthMax); + set("mobs.donkey.attributes.max-health", null); + set("mobs.donkey.attributes.max_health.min", oldMin); + set("mobs.donkey.attributes.max_health.max", oldMax); + } + donkeyMaxHealthMin = getDouble("mobs.donkey.attributes.max_health.min", donkeyMaxHealthMin); + donkeyMaxHealthMax = getDouble("mobs.donkey.attributes.max_health.max", donkeyMaxHealthMax); + donkeyJumpStrengthMin = getDouble("mobs.donkey.attributes.jump_strength.min", donkeyJumpStrengthMin); + donkeyJumpStrengthMax = getDouble("mobs.donkey.attributes.jump_strength.max", donkeyJumpStrengthMax); + donkeyMovementSpeedMin = getDouble("mobs.donkey.attributes.movement_speed.min", donkeyMovementSpeedMin); + donkeyMovementSpeedMax = getDouble("mobs.donkey.attributes.movement_speed.max", donkeyMovementSpeedMax); + donkeyBreedingTicks = getInt("mobs.donkey.breeding-delay-ticks", donkeyBreedingTicks); + donkeyTakeDamageFromWater = getBoolean("mobs.donkey.takes-damage-from-water", donkeyTakeDamageFromWater); + donkeyAlwaysDropExp = getBoolean("mobs.donkey.always-drop-exp", donkeyAlwaysDropExp); + } + + public boolean drownedRidable = false; + public boolean drownedRidableInWater = true; + public boolean drownedControllable = true; + public double drownedMaxHealth = 20.0D; + public double drownedScale = 1.0D; + public double drownedSpawnReinforcements = 0.1D; + public boolean drownedJockeyOnlyBaby = true; + public double drownedJockeyChance = 0.05D; + public boolean drownedJockeyTryExistingChickens = true; + public boolean drownedTakeDamageFromWater = false; + public boolean drownedBreakDoors = false; + public boolean drownedAlwaysDropExp = false; + private void drownedSettings() { + drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); + drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); + drownedControllable = getBoolean("mobs.drowned.controllable", drownedControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.drowned.attributes.max-health", drownedMaxHealth); + set("mobs.drowned.attributes.max-health", null); + set("mobs.drowned.attributes.max_health", oldValue); + } + drownedMaxHealth = getDouble("mobs.drowned.attributes.max_health", drownedMaxHealth); + drownedScale = Mth.clamp(getDouble("mobs.drowned.attributes.scale", drownedScale), 0.0625D, 16.0D); + drownedSpawnReinforcements = getDouble("mobs.drowned.attributes.spawn_reinforcements", drownedSpawnReinforcements); + drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby); + drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance); + drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens); + drownedTakeDamageFromWater = getBoolean("mobs.drowned.takes-damage-from-water", drownedTakeDamageFromWater); + drownedBreakDoors = getBoolean("mobs.drowned.can-break-doors", drownedBreakDoors); + drownedAlwaysDropExp = getBoolean("mobs.drowned.always-drop-exp", drownedAlwaysDropExp); + } + + public boolean elderGuardianRidable = false; + public boolean elderGuardianControllable = true; + public double elderGuardianMaxHealth = 80.0D; + public double elderGuardianScale = 1.0D; + public boolean elderGuardianTakeDamageFromWater = false; + public boolean elderGuardianAlwaysDropExp = false; + private void elderGuardianSettings() { + elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable); + elderGuardianControllable = getBoolean("mobs.elder_guardian.controllable", elderGuardianControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.elder_guardian.attributes.max-health", elderGuardianMaxHealth); + set("mobs.elder_guardian.attributes.max-health", null); + set("mobs.elder_guardian.attributes.max_health", oldValue); + } + elderGuardianMaxHealth = getDouble("mobs.elder_guardian.attributes.max_health", elderGuardianMaxHealth); + elderGuardianScale = Mth.clamp(getDouble("mobs.elder_guardian.attributes.scale", elderGuardianScale), 0.0625D, 16.0D); + elderGuardianTakeDamageFromWater = getBoolean("mobs.elder_guardian.takes-damage-from-water", elderGuardianTakeDamageFromWater); + elderGuardianAlwaysDropExp = getBoolean("mobs.elder_guardian.always-drop-exp", elderGuardianAlwaysDropExp); + } + + public boolean enchantmentTableLapisPersists = false; + private void enchantmentTableSettings() { + enchantmentTableLapisPersists = getBoolean("blocks.enchantment-table.lapis-persists", enchantmentTableLapisPersists); + } + + public boolean enderDragonRidable = false; + public boolean enderDragonRidableInWater = true; + public boolean enderDragonControllable = true; + public double enderDragonMaxY = 320D; + public double enderDragonMaxHealth = 200.0D; + public boolean enderDragonAlwaysDropsFullExp = false; + public boolean enderDragonBypassMobGriefing = false; + public boolean enderDragonTakeDamageFromWater = false; + public boolean enderDragonCanRideVehicles = false; + private void enderDragonSettings() { + enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); + enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); + enderDragonControllable = getBoolean("mobs.ender_dragon.controllable", enderDragonControllable); + enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY); + if (PurpurConfig.version < 8) { + double oldValue = getDouble("mobs.ender_dragon.max-health", enderDragonMaxHealth); + set("mobs.ender_dragon.max-health", null); + set("mobs.ender_dragon.attributes.max_health", oldValue); + } else if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.ender_dragon.attributes.max-health", enderDragonMaxHealth); + set("mobs.ender_dragon.attributes.max-health", null); + set("mobs.ender_dragon.attributes.max_health", oldValue); + } + enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth); + enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); + enderDragonBypassMobGriefing = getBoolean("mobs.ender_dragon.bypass-mob-griefing", enderDragonBypassMobGriefing); + enderDragonTakeDamageFromWater = getBoolean("mobs.ender_dragon.takes-damage-from-water", enderDragonTakeDamageFromWater); + enderDragonCanRideVehicles = getBoolean("mobs.ender_dragon.can-ride-vehicles", enderDragonCanRideVehicles); + } + + public boolean endermanRidable = false; + public boolean endermanRidableInWater = true; + public boolean endermanControllable = true; + public double endermanMaxHealth = 40.0D; + public double endermanScale = 1.0D; + public boolean endermanAllowGriefing = true; + public boolean endermanDespawnEvenWithBlock = false; + public boolean endermanBypassMobGriefing = false; + public boolean endermanTakeDamageFromWater = true; + public boolean endermanAggroEndermites = true; + public boolean endermanAggroEndermitesOnlyIfPlayerSpawned = false; + public boolean endermanDisableStareAggro = false; + public boolean endermanIgnoreProjectiles = false; + public boolean endermanAlwaysDropExp = false; + private void endermanSettings() { + endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); + endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); + endermanControllable = getBoolean("mobs.enderman.controllable", endermanControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.enderman.attributes.max-health", endermanMaxHealth); + set("mobs.enderman.attributes.max-health", null); + set("mobs.enderman.attributes.max_health", oldValue); + } + if (PurpurConfig.version < 15) { + // remove old option + set("mobs.enderman.aggressive-towards-spawned-endermites", null); + } + endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); + endermanScale = Mth.clamp(getDouble("mobs.enderman.attributes.scale", endermanScale), 0.0625D, 16.0D); + endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); + endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock); + endermanBypassMobGriefing = getBoolean("mobs.enderman.bypass-mob-griefing", endermanBypassMobGriefing); + endermanTakeDamageFromWater = getBoolean("mobs.enderman.takes-damage-from-water", endermanTakeDamageFromWater); + endermanAggroEndermites = getBoolean("mobs.enderman.aggressive-towards-endermites", endermanAggroEndermites); + endermanAggroEndermitesOnlyIfPlayerSpawned = getBoolean("mobs.enderman.aggressive-towards-endermites-only-spawned-by-player-thrown-ender-pearls", endermanAggroEndermitesOnlyIfPlayerSpawned); + endermanDisableStareAggro = getBoolean("mobs.enderman.disable-player-stare-aggression", endermanDisableStareAggro); + endermanIgnoreProjectiles = getBoolean("mobs.enderman.ignore-projectiles", endermanIgnoreProjectiles); + endermanAlwaysDropExp = getBoolean("mobs.enderman.always-drop-exp", endermanAlwaysDropExp); + } + + public boolean endermiteRidable = false; + public boolean endermiteRidableInWater = true; + public boolean endermiteControllable = true; + public double endermiteMaxHealth = 8.0D; + public double endermiteScale = 1.0D; + public boolean endermiteTakeDamageFromWater = false; + public boolean endermiteAlwaysDropExp = false; + private void endermiteSettings() { + endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable); + endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater); + endermiteControllable = getBoolean("mobs.endermite.controllable", endermiteControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.endermite.attributes.max-health", endermiteMaxHealth); + set("mobs.endermite.attributes.max-health", null); + set("mobs.endermite.attributes.max_health", oldValue); + } + endermiteMaxHealth = getDouble("mobs.endermite.attributes.max_health", endermiteMaxHealth); + endermiteScale = Mth.clamp(getDouble("mobs.endermite.attributes.scale", endermiteScale), 0.0625D, 16.0D); + endermiteTakeDamageFromWater = getBoolean("mobs.endermite.takes-damage-from-water", endermiteTakeDamageFromWater); + endermiteAlwaysDropExp = getBoolean("mobs.endermite.always-drop-exp", endermiteAlwaysDropExp); + } + + public boolean evokerRidable = false; + public boolean evokerRidableInWater = true; + public boolean evokerControllable = true; + public double evokerMaxHealth = 24.0D; + public double evokerScale = 1.0D; + public boolean evokerBypassMobGriefing = false; + public boolean evokerTakeDamageFromWater = false; + public boolean evokerAlwaysDropExp = false; + private void evokerSettings() { + evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); + evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); + evokerControllable = getBoolean("mobs.evoker.controllable", evokerControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.evoker.attributes.max-health", evokerMaxHealth); + set("mobs.evoker.attributes.max-health", null); + set("mobs.evoker.attributes.max_health", oldValue); + } + evokerMaxHealth = getDouble("mobs.evoker.attributes.max_health", evokerMaxHealth); + evokerScale = Mth.clamp(getDouble("mobs.evoker.attributes.scale", evokerScale), 0.0625D, 16.0D); + evokerBypassMobGriefing = getBoolean("mobs.evoker.bypass-mob-griefing", evokerBypassMobGriefing); + evokerTakeDamageFromWater = getBoolean("mobs.evoker.takes-damage-from-water", evokerTakeDamageFromWater); + evokerAlwaysDropExp = getBoolean("mobs.evoker.always-drop-exp", evokerAlwaysDropExp); + } + + public boolean foxRidable = false; + public boolean foxRidableInWater = true; + public boolean foxControllable = true; + public double foxMaxHealth = 10.0D; + public double foxScale = 1.0D; + public boolean foxTypeChangesWithTulips = false; + public int foxBreedingTicks = 6000; + public boolean foxBypassMobGriefing = false; + public boolean foxTakeDamageFromWater = false; + public boolean foxAlwaysDropExp = false; + private void foxSettings() { + foxRidable = getBoolean("mobs.fox.ridable", foxRidable); + foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); + foxControllable = getBoolean("mobs.fox.controllable", foxControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.fox.attributes.max-health", foxMaxHealth); + set("mobs.fox.attributes.max-health", null); + set("mobs.fox.attributes.max_health", oldValue); + } + foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth); + foxScale = Mth.clamp(getDouble("mobs.fox.attributes.scale", foxScale), 0.0625D, 16.0D); + foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); + foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks); + foxBypassMobGriefing = getBoolean("mobs.fox.bypass-mob-griefing", foxBypassMobGriefing); + foxTakeDamageFromWater = getBoolean("mobs.fox.takes-damage-from-water", foxTakeDamageFromWater); + foxAlwaysDropExp = getBoolean("mobs.fox.always-drop-exp", foxAlwaysDropExp); + } + + public boolean frogRidable = false; + public boolean frogRidableInWater = true; + public boolean frogControllable = true; + public float frogRidableJumpHeight = 0.65F; + public int frogBreedingTicks = 6000; + private void frogSettings() { + frogRidable = getBoolean("mobs.frog.ridable", frogRidable); + frogRidableInWater = getBoolean("mobs.frog.ridable-in-water", frogRidableInWater); + frogControllable = getBoolean("mobs.frog.controllable", frogControllable); + frogRidableJumpHeight = (float) getDouble("mobs.frog.ridable-jump-height", frogRidableJumpHeight); + frogBreedingTicks = getInt("mobs.frog.breeding-delay-ticks", frogBreedingTicks); + } + + public boolean ghastRidable = false; + public boolean ghastRidableInWater = true; + public boolean ghastControllable = true; + public double ghastMaxY = 320D; + public double ghastMaxHealth = 10.0D; + public double ghastScale = 1.0D; + public boolean ghastTakeDamageFromWater = false; + public boolean ghastAlwaysDropExp = false; + private void ghastSettings() { + ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); + ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater); + ghastControllable = getBoolean("mobs.ghast.controllable", ghastControllable); + ghastMaxY = getDouble("mobs.ghast.ridable-max-y", ghastMaxY); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.ghast.attributes.max-health", ghastMaxHealth); + set("mobs.ghast.attributes.max-health", null); + set("mobs.ghast.attributes.max_health", oldValue); + } + ghastMaxHealth = getDouble("mobs.ghast.attributes.max_health", ghastMaxHealth); + ghastScale = Mth.clamp(getDouble("mobs.ghast.attributes.scale", ghastScale), 0.0625D, 16.0D); + ghastTakeDamageFromWater = getBoolean("mobs.ghast.takes-damage-from-water", ghastTakeDamageFromWater); + ghastAlwaysDropExp = getBoolean("mobs.ghast.always-drop-exp", ghastAlwaysDropExp); + } + + public boolean giantRidable = false; + public boolean giantRidableInWater = true; + public boolean giantControllable = true; + public double giantMovementSpeed = 0.5D; + public double giantAttackDamage = 50.0D; + public double giantMaxHealth = 100.0D; + public double giantScale = 1.0D; + public float giantStepHeight = 2.0F; + public float giantJumpHeight = 1.0F; + public boolean giantHaveAI = false; + public boolean giantHaveHostileAI = false; + public boolean giantTakeDamageFromWater = false; + public boolean giantAlwaysDropExp = false; + private void giantSettings() { + giantRidable = getBoolean("mobs.giant.ridable", giantRidable); + giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater); + giantControllable = getBoolean("mobs.giant.controllable", giantControllable); + giantMovementSpeed = getDouble("mobs.giant.movement-speed", giantMovementSpeed); + giantAttackDamage = getDouble("mobs.giant.attack-damage", giantAttackDamage); + if (PurpurConfig.version < 8) { + double oldValue = getDouble("mobs.giant.max-health", giantMaxHealth); + set("mobs.giant.max-health", null); + set("mobs.giant.attributes.max_health", oldValue); + } else if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.giant.attributes.max-health", giantMaxHealth); + set("mobs.giant.attributes.max-health", null); + set("mobs.giant.attributes.max_health", oldValue); + } + giantMaxHealth = getDouble("mobs.giant.attributes.max_health", giantMaxHealth); + giantScale = Mth.clamp(getDouble("mobs.giant.attributes.scale", giantScale), 0.0625D, 16.0D); + giantStepHeight = (float) getDouble("mobs.giant.step-height", giantStepHeight); + giantJumpHeight = (float) getDouble("mobs.giant.jump-height", giantJumpHeight); + giantHaveAI = getBoolean("mobs.giant.have-ai", giantHaveAI); + giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI); + giantTakeDamageFromWater = getBoolean("mobs.giant.takes-damage-from-water", giantTakeDamageFromWater); + giantAlwaysDropExp = getBoolean("mobs.giant.always-drop-exp", giantAlwaysDropExp); + } + + public boolean glowSquidRidable = false; + public boolean glowSquidControllable = true; + public double glowSquidMaxHealth = 10.0D; + public double glowSquidScale = 1.0D; + public boolean glowSquidsCanFly = false; + public boolean glowSquidTakeDamageFromWater = false; + public boolean glowSquidAlwaysDropExp = false; + private void glowSquidSettings() { + glowSquidRidable = getBoolean("mobs.glow_squid.ridable", glowSquidRidable); + glowSquidControllable = getBoolean("mobs.glow_squid.controllable", glowSquidControllable); + glowSquidMaxHealth = getDouble("mobs.glow_squid.attributes.max_health", glowSquidMaxHealth); + glowSquidScale = Mth.clamp(getDouble("mobs.glow_squid.attributes.scale", glowSquidScale), 0.0625D, 16.0D); + glowSquidsCanFly = getBoolean("mobs.glow_squid.can-fly", glowSquidsCanFly); + glowSquidTakeDamageFromWater = getBoolean("mobs.glow_squid.takes-damage-from-water", glowSquidTakeDamageFromWater); + glowSquidAlwaysDropExp = getBoolean("mobs.glow_squid.always-drop-exp", glowSquidAlwaysDropExp); + } + + public boolean goatRidable = false; + public boolean goatRidableInWater = true; + public boolean goatControllable = true; + public double goatMaxHealth = 10.0D; + public double goatScale = 1.0D; + public int goatBreedingTicks = 6000; + public boolean goatTakeDamageFromWater = false; + public boolean goatAlwaysDropExp = false; + private void goatSettings() { + goatRidable = getBoolean("mobs.goat.ridable", goatRidable); + goatRidableInWater = getBoolean("mobs.goat.ridable-in-water", goatRidableInWater); + goatControllable = getBoolean("mobs.goat.controllable", goatControllable); + goatMaxHealth = getDouble("mobs.goat.attributes.max_health", goatMaxHealth); + goatScale = Mth.clamp(getDouble("mobs.goat.attributes.scale", goatScale), 0.0625D, 16.0D); + goatBreedingTicks = getInt("mobs.goat.breeding-delay-ticks", goatBreedingTicks); + goatTakeDamageFromWater = getBoolean("mobs.goat.takes-damage-from-water", goatTakeDamageFromWater); + goatAlwaysDropExp = getBoolean("mobs.goat.always-drop-exp", goatAlwaysDropExp); + } + + public boolean guardianRidable = false; + public boolean guardianControllable = true; + public double guardianMaxHealth = 30.0D; + public double guardianScale = 1.0D; + public boolean guardianTakeDamageFromWater = false; + public boolean guardianAlwaysDropExp = false; + private void guardianSettings() { + guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable); + guardianControllable = getBoolean("mobs.guardian.controllable", guardianControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.guardian.attributes.max-health", guardianMaxHealth); + set("mobs.guardian.attributes.max-health", null); + set("mobs.guardian.attributes.max_health", oldValue); + } + guardianMaxHealth = getDouble("mobs.guardian.attributes.max_health", guardianMaxHealth); + guardianScale = Mth.clamp(getDouble("mobs.guardian.attributes.scale", guardianScale), 0.0625D, 16.0D); + guardianTakeDamageFromWater = getBoolean("mobs.guardian.takes-damage-from-water", guardianTakeDamageFromWater); + guardianAlwaysDropExp = getBoolean("mobs.guardian.always-drop-exp", guardianAlwaysDropExp); + } + + public boolean forceHalloweenSeason = false; + public float chanceHeadHalloweenOnEntity = 0.25F; + private void halloweenSetting() { + forceHalloweenSeason = getBoolean("gameplay-mechanics.halloween.force", forceHalloweenSeason); + chanceHeadHalloweenOnEntity = (float) getDouble("gameplay-mechanics.halloween.head-chance", chanceHeadHalloweenOnEntity); + } + + public boolean hoglinRidable = false; + public boolean hoglinRidableInWater = true; + public boolean hoglinControllable = true; + public double hoglinMaxHealth = 40.0D; + public double hoglinScale = 1.0D; + public int hoglinBreedingTicks = 6000; + public boolean hoglinTakeDamageFromWater = false; + public boolean hoglinAlwaysDropExp = false; + private void hoglinSettings() { + hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); + hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); + hoglinControllable = getBoolean("mobs.hoglin.controllable", hoglinControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.hoglin.attributes.max-health", hoglinMaxHealth); + set("mobs.hoglin.attributes.max-health", null); + set("mobs.hoglin.attributes.max_health", oldValue); + } + hoglinMaxHealth = getDouble("mobs.hoglin.attributes.max_health", hoglinMaxHealth); + hoglinScale = Mth.clamp(getDouble("mobs.hoglin.attributes.scale", hoglinScale), 0.0625D, 16.0D); + hoglinBreedingTicks = getInt("mobs.hoglin.breeding-delay-ticks", hoglinBreedingTicks); + hoglinTakeDamageFromWater = getBoolean("mobs.hoglin.takes-damage-from-water", hoglinTakeDamageFromWater); + hoglinAlwaysDropExp = getBoolean("mobs.hoglin.always-drop-exp", hoglinAlwaysDropExp); + } + + public boolean horseRidableInWater = false; + public double horseMaxHealthMin = 15.0D; + public double horseMaxHealthMax = 30.0D; + public double horseJumpStrengthMin = 0.4D; + public double horseJumpStrengthMax = 1.0D; + public double horseMovementSpeedMin = 0.1125D; + public double horseMovementSpeedMax = 0.3375D; + public int horseBreedingTicks = 6000; + public boolean horseTakeDamageFromWater = false; + public boolean horseAlwaysDropExp = false; + private void horseSettings() { + horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); + if (PurpurConfig.version < 10) { + double oldMin = getDouble("mobs.horse.attributes.max-health.min", horseMaxHealthMin); + double oldMax = getDouble("mobs.horse.attributes.max-health.max", horseMaxHealthMax); + set("mobs.horse.attributes.max-health", null); + set("mobs.horse.attributes.max_health.min", oldMin); + set("mobs.horse.attributes.max_health.max", oldMax); + } + horseMaxHealthMin = getDouble("mobs.horse.attributes.max_health.min", horseMaxHealthMin); + horseMaxHealthMax = getDouble("mobs.horse.attributes.max_health.max", horseMaxHealthMax); + horseJumpStrengthMin = getDouble("mobs.horse.attributes.jump_strength.min", horseJumpStrengthMin); + horseJumpStrengthMax = getDouble("mobs.horse.attributes.jump_strength.max", horseJumpStrengthMax); + horseMovementSpeedMin = getDouble("mobs.horse.attributes.movement_speed.min", horseMovementSpeedMin); + horseMovementSpeedMax = getDouble("mobs.horse.attributes.movement_speed.max", horseMovementSpeedMax); + horseBreedingTicks = getInt("mobs.horse.breeding-delay-ticks", horseBreedingTicks); + horseTakeDamageFromWater = getBoolean("mobs.horse.takes-damage-from-water", horseTakeDamageFromWater); + horseAlwaysDropExp = getBoolean("mobs.horse.always-drop-exp", horseAlwaysDropExp); + } + + public boolean huskRidable = false; + public boolean huskRidableInWater = true; + public boolean huskControllable = true; + public double huskMaxHealth = 20.0D; + public double huskScale = 1.0D; + public double huskSpawnReinforcements = 0.1D; + public boolean huskJockeyOnlyBaby = true; + public double huskJockeyChance = 0.05D; + public boolean huskJockeyTryExistingChickens = true; + public boolean huskTakeDamageFromWater = false; + public boolean huskAlwaysDropExp = false; + private void huskSettings() { + huskRidable = getBoolean("mobs.husk.ridable", huskRidable); + huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); + huskControllable = getBoolean("mobs.husk.controllable", huskControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.husk.attributes.max-health", huskMaxHealth); + set("mobs.husk.attributes.max-health", null); + set("mobs.husk.attributes.max_health", oldValue); + } + huskMaxHealth = getDouble("mobs.husk.attributes.max_health", huskMaxHealth); + huskScale = Mth.clamp(getDouble("mobs.husk.attributes.scale", huskScale), 0.0625D, 16.0D); + huskSpawnReinforcements = getDouble("mobs.husk.attributes.spawn_reinforcements", huskSpawnReinforcements); + huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby); + huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance); + huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens); + huskTakeDamageFromWater = getBoolean("mobs.husk.takes-damage-from-water", huskTakeDamageFromWater); + huskAlwaysDropExp = getBoolean("mobs.husk.always-drop-exp", huskAlwaysDropExp); + } + + public boolean illusionerRidable = false; + public boolean illusionerRidableInWater = true; + public boolean illusionerControllable = true; + public double illusionerMovementSpeed = 0.5D; + public double illusionerFollowRange = 18.0D; + public double illusionerMaxHealth = 32.0D; + public double illusionerScale = 1.0D; + public boolean illusionerTakeDamageFromWater = false; + public boolean illusionerAlwaysDropExp = false; + private void illusionerSettings() { + illusionerRidable = getBoolean("mobs.illusioner.ridable", illusionerRidable); + illusionerRidableInWater = getBoolean("mobs.illusioner.ridable-in-water", illusionerRidableInWater); + illusionerControllable = getBoolean("mobs.illusioner.controllable", illusionerControllable); + illusionerMovementSpeed = getDouble("mobs.illusioner.movement-speed", illusionerMovementSpeed); + illusionerFollowRange = getDouble("mobs.illusioner.follow-range", illusionerFollowRange); + if (PurpurConfig.version < 8) { + double oldValue = getDouble("mobs.illusioner.max-health", illusionerMaxHealth); + set("mobs.illusioner.max-health", null); + set("mobs.illusioner.attributes.max_health", oldValue); + } else if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth); + set("mobs.illusioner.attributes.max-health", null); + set("mobs.illusioner.attributes.max_health", oldValue); + } + illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max_health", illusionerMaxHealth); + illusionerScale = Mth.clamp(getDouble("mobs.illusioner.attributes.scale", illusionerScale), 0.0625D, 16.0D); + illusionerTakeDamageFromWater = getBoolean("mobs.illusioner.takes-damage-from-water", illusionerTakeDamageFromWater); + illusionerAlwaysDropExp = getBoolean("mobs.illusioner.always-drop-exp", illusionerAlwaysDropExp); + } + + public boolean ironGolemRidable = false; + public boolean ironGolemRidableInWater = true; + public boolean ironGolemControllable = true; + public boolean ironGolemCanSwim = false; + public double ironGolemMaxHealth = 100.0D; + public double ironGolemScale = 1.0D; + public boolean ironGolemTakeDamageFromWater = false; + public boolean ironGolemPoppyCalm = false; + public boolean ironGolemHealCalm = false; + public boolean ironGolemAlwaysDropExp = false; + private void ironGolemSettings() { + ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); + ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); + ironGolemControllable = getBoolean("mobs.iron_golem.controllable", ironGolemControllable); + ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.iron_golem.attributes.max-health", ironGolemMaxHealth); + set("mobs.iron_golem.attributes.max-health", null); + set("mobs.iron_golem.attributes.max_health", oldValue); + } + ironGolemMaxHealth = getDouble("mobs.iron_golem.attributes.max_health", ironGolemMaxHealth); + ironGolemScale = Mth.clamp(getDouble("mobs.iron_golem.attributes.scale", ironGolemScale), 0.0625D, 16.0D); + ironGolemTakeDamageFromWater = getBoolean("mobs.iron_golem.takes-damage-from-water", ironGolemTakeDamageFromWater); + ironGolemPoppyCalm = getBoolean("mobs.iron_golem.poppy-calms-anger", ironGolemPoppyCalm); + ironGolemHealCalm = getBoolean("mobs.iron_golem.healing-calms-anger", ironGolemHealCalm); + ironGolemAlwaysDropExp = getBoolean("mobs.iron_golem.always-drop-exp", ironGolemAlwaysDropExp); + } + + public boolean llamaRidable = false; + public boolean llamaRidableInWater = false; + public boolean llamaControllable = true; + public double llamaMaxHealthMin = 15.0D; + public double llamaMaxHealthMax = 30.0D; + public double llamaJumpStrengthMin = 0.5D; + public double llamaJumpStrengthMax = 0.5D; + public double llamaMovementSpeedMin = 0.175D; + public double llamaMovementSpeedMax = 0.175D; + public int llamaBreedingTicks = 6000; + public boolean llamaTakeDamageFromWater = false; + public boolean llamaJoinCaravans = true; + public boolean llamaAlwaysDropExp = false; + private void llamaSettings() { + llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); + llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); + llamaControllable = getBoolean("mobs.llama.controllable", llamaControllable); + if (PurpurConfig.version < 10) { + double oldMin = getDouble("mobs.llama.attributes.max-health.min", llamaMaxHealthMin); + double oldMax = getDouble("mobs.llama.attributes.max-health.max", llamaMaxHealthMax); + set("mobs.llama.attributes.max-health", null); + set("mobs.llama.attributes.max_health.min", oldMin); + set("mobs.llama.attributes.max_health.max", oldMax); + } + llamaMaxHealthMin = getDouble("mobs.llama.attributes.max_health.min", llamaMaxHealthMin); + llamaMaxHealthMax = getDouble("mobs.llama.attributes.max_health.max", llamaMaxHealthMax); + llamaJumpStrengthMin = getDouble("mobs.llama.attributes.jump_strength.min", llamaJumpStrengthMin); + llamaJumpStrengthMax = getDouble("mobs.llama.attributes.jump_strength.max", llamaJumpStrengthMax); + llamaMovementSpeedMin = getDouble("mobs.llama.attributes.movement_speed.min", llamaMovementSpeedMin); + llamaMovementSpeedMax = getDouble("mobs.llama.attributes.movement_speed.max", llamaMovementSpeedMax); + llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks); + llamaTakeDamageFromWater = getBoolean("mobs.llama.takes-damage-from-water", llamaTakeDamageFromWater); + llamaJoinCaravans = getBoolean("mobs.llama.join-caravans", llamaJoinCaravans); + llamaAlwaysDropExp = getBoolean("mobs.llama.always-drop-exp", llamaAlwaysDropExp); + } + + public boolean magmaCubeRidable = false; + public boolean magmaCubeRidableInWater = true; + public boolean magmaCubeControllable = true; + public String magmaCubeMaxHealth = "size * size"; + public String magmaCubeAttackDamage = "size"; + public Map magmaCubeMaxHealthCache = new HashMap<>(); + public Map magmaCubeAttackDamageCache = new HashMap<>(); + public boolean magmaCubeTakeDamageFromWater = false; + public boolean magmaCubeAlwaysDropExp = false; + private void magmaCubeSettings() { + magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable); + magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater); + magmaCubeControllable = getBoolean("mobs.magma_cube.controllable", magmaCubeControllable); + if (PurpurConfig.version < 10) { + String oldValue = getString("mobs.magma_cube.attributes.max-health", magmaCubeMaxHealth); + set("mobs.magma_cube.attributes.max-health", null); + set("mobs.magma_cube.attributes.max_health", oldValue); + } + magmaCubeMaxHealth = getString("mobs.magma_cube.attributes.max_health", magmaCubeMaxHealth); + magmaCubeAttackDamage = getString("mobs.magma_cube.attributes.attack_damage", magmaCubeAttackDamage); + magmaCubeMaxHealthCache.clear(); + magmaCubeAttackDamageCache.clear(); + magmaCubeTakeDamageFromWater = getBoolean("mobs.magma_cube.takes-damage-from-water", magmaCubeTakeDamageFromWater); + magmaCubeAlwaysDropExp = getBoolean("mobs.magma_cube.always-drop-exp", magmaCubeAlwaysDropExp); + } + + public boolean mooshroomRidable = false; + public boolean mooshroomRidableInWater = true; + public boolean mooshroomControllable = true; + public double mooshroomMaxHealth = 10.0D; + public double mooshroomScale = 1.0D; + public int mooshroomBreedingTicks = 6000; + public boolean mooshroomTakeDamageFromWater = false; + public boolean mooshroomAlwaysDropExp = false; + private void mooshroomSettings() { + mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); + mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); + mooshroomControllable = getBoolean("mobs.mooshroom.controllable", mooshroomControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.mooshroom.attributes.max-health", mooshroomMaxHealth); + set("mobs.mooshroom.attributes.max-health", null); + set("mobs.mooshroom.attributes.max_health", oldValue); + } + mooshroomMaxHealth = getDouble("mobs.mooshroom.attributes.max_health", mooshroomMaxHealth); + mooshroomScale = Mth.clamp(getDouble("mobs.mooshroom.attributes.scale", mooshroomScale), 0.0625D, 16.0D); + mooshroomBreedingTicks = getInt("mobs.mooshroom.breeding-delay-ticks", mooshroomBreedingTicks); + mooshroomTakeDamageFromWater = getBoolean("mobs.mooshroom.takes-damage-from-water", mooshroomTakeDamageFromWater); + mooshroomAlwaysDropExp = getBoolean("mobs.mooshroom.always-drop-exp", mooshroomAlwaysDropExp); + } + + public boolean muleRidableInWater = false; + public double muleMaxHealthMin = 15.0D; + public double muleMaxHealthMax = 30.0D; + public double muleJumpStrengthMin = 0.5D; + public double muleJumpStrengthMax = 0.5D; + public double muleMovementSpeedMin = 0.175D; + public double muleMovementSpeedMax = 0.175D; + public int muleBreedingTicks = 6000; + public boolean muleTakeDamageFromWater = false; + public boolean muleAlwaysDropExp = false; + private void muleSettings() { + muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); + if (PurpurConfig.version < 10) { + double oldMin = getDouble("mobs.mule.attributes.max-health.min", muleMaxHealthMin); + double oldMax = getDouble("mobs.mule.attributes.max-health.max", muleMaxHealthMax); + set("mobs.mule.attributes.max-health", null); + set("mobs.mule.attributes.max_health.min", oldMin); + set("mobs.mule.attributes.max_health.max", oldMax); + } + muleMaxHealthMin = getDouble("mobs.mule.attributes.max_health.min", muleMaxHealthMin); + muleMaxHealthMax = getDouble("mobs.mule.attributes.max_health.max", muleMaxHealthMax); + muleJumpStrengthMin = getDouble("mobs.mule.attributes.jump_strength.min", muleJumpStrengthMin); + muleJumpStrengthMax = getDouble("mobs.mule.attributes.jump_strength.max", muleJumpStrengthMax); + muleMovementSpeedMin = getDouble("mobs.mule.attributes.movement_speed.min", muleMovementSpeedMin); + muleMovementSpeedMax = getDouble("mobs.mule.attributes.movement_speed.max", muleMovementSpeedMax); + muleBreedingTicks = getInt("mobs.mule.breeding-delay-ticks", muleBreedingTicks); + muleTakeDamageFromWater = getBoolean("mobs.mule.takes-damage-from-water", muleTakeDamageFromWater); + muleAlwaysDropExp = getBoolean("mobs.mule.always-drop-exp", muleAlwaysDropExp); + } + + public boolean ocelotRidable = false; + public boolean ocelotRidableInWater = true; + public boolean ocelotControllable = true; + public double ocelotMaxHealth = 10.0D; + public double ocelotScale = 1.0D; + public int ocelotBreedingTicks = 6000; + public boolean ocelotTakeDamageFromWater = false; + public boolean ocelotAlwaysDropExp = false; + public boolean ocelotSpawnUnderSeaLevel = false; + private void ocelotSettings() { + ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); + ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); + ocelotControllable = getBoolean("mobs.ocelot.controllable", ocelotControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.ocelot.attributes.max-health", ocelotMaxHealth); + set("mobs.ocelot.attributes.max-health", null); + set("mobs.ocelot.attributes.max_health", oldValue); + } + ocelotMaxHealth = getDouble("mobs.ocelot.attributes.max_health", ocelotMaxHealth); + ocelotScale = Mth.clamp(getDouble("mobs.ocelot.attributes.scale", ocelotScale), 0.0625D, 16.0D); + ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks); + ocelotTakeDamageFromWater = getBoolean("mobs.ocelot.takes-damage-from-water", ocelotTakeDamageFromWater); + ocelotAlwaysDropExp = getBoolean("mobs.ocelot.always-drop-exp", ocelotAlwaysDropExp); + ocelotSpawnUnderSeaLevel = getBoolean("mobs.ocelot.spawn-below-sea-level", ocelotSpawnUnderSeaLevel); + } + + public boolean pandaRidable = false; + public boolean pandaRidableInWater = true; + public boolean pandaControllable = true; + public double pandaMaxHealth = 20.0D; + public double pandaScale = 1.0D; + public int pandaBreedingTicks = 6000; + public boolean pandaTakeDamageFromWater = false; + public boolean pandaAlwaysDropExp = false; + private void pandaSettings() { + pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); + pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); + pandaControllable = getBoolean("mobs.panda.controllable", pandaControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.panda.attributes.max-health", pandaMaxHealth); + set("mobs.panda.attributes.max-health", null); + set("mobs.panda.attributes.max_health", oldValue); + } + pandaMaxHealth = getDouble("mobs.panda.attributes.max_health", pandaMaxHealth); + pandaScale = Mth.clamp(getDouble("mobs.panda.attributes.scale", pandaScale), 0.0625D, 16.0D); + pandaBreedingTicks = getInt("mobs.panda.breeding-delay-ticks", pandaBreedingTicks); + pandaTakeDamageFromWater = getBoolean("mobs.panda.takes-damage-from-water", pandaTakeDamageFromWater); + pandaAlwaysDropExp = getBoolean("mobs.panda.always-drop-exp", pandaAlwaysDropExp); + } + + public boolean parrotRidable = false; + public boolean parrotRidableInWater = true; + public boolean parrotControllable = true; + public double parrotMaxY = 320D; + public double parrotMaxHealth = 6.0D; + public double parrotScale = 1.0D; + public boolean parrotTakeDamageFromWater = false; + public boolean parrotBreedable = false; + public boolean parrotAlwaysDropExp = false; + private void parrotSettings() { + parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); + parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); + parrotControllable = getBoolean("mobs.parrot.controllable", parrotControllable); + parrotMaxY = getDouble("mobs.parrot.ridable-max-y", parrotMaxY); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.parrot.attributes.max-health", parrotMaxHealth); + set("mobs.parrot.attributes.max-health", null); + set("mobs.parrot.attributes.max_health", oldValue); + } + parrotMaxHealth = getDouble("mobs.parrot.attributes.max_health", parrotMaxHealth); + parrotScale = Mth.clamp(getDouble("mobs.parrot.attributes.scale", parrotScale), 0.0625D, 16.0D); + parrotTakeDamageFromWater = getBoolean("mobs.parrot.takes-damage-from-water", parrotTakeDamageFromWater); + parrotBreedable = getBoolean("mobs.parrot.can-breed", parrotBreedable); + parrotAlwaysDropExp = getBoolean("mobs.parrot.always-drop-exp", parrotAlwaysDropExp); + } + + public boolean phantomRidable = false; + public boolean phantomRidableInWater = true; + public boolean phantomControllable = true; + public double phantomMaxY = 320D; + public float phantomFlameDamage = 1.0F; + public int phantomFlameFireTime = 8; + public boolean phantomAllowGriefing = false; + public String phantomMaxHealth = "20.0"; + public String phantomAttackDamage = "6 + size"; + public Map phantomMaxHealthCache = new HashMap<>(); + public Map phantomAttackDamageCache = new HashMap<>(); + public double phantomAttackedByCrystalRadius = 0.0D; + public float phantomAttackedByCrystalDamage = 1.0F; + public double phantomOrbitCrystalRadius = 0.0D; + public int phantomSpawnMinSkyDarkness = 5; + public boolean phantomSpawnOnlyAboveSeaLevel = true; + public boolean phantomSpawnOnlyWithVisibleSky = true; + public double phantomSpawnLocalDifficultyChance = 3.0D; + public int phantomSpawnMinPerAttempt = 1; + public int phantomSpawnMaxPerAttempt = -1; + public int phantomBurnInLight = 0; + public boolean phantomIgnorePlayersWithTorch = false; + public boolean phantomBurnInDaylight = true; + public boolean phantomFlamesOnSwoop = false; + public boolean phantomTakeDamageFromWater = false; + public boolean phantomAlwaysDropExp = false; + public int phantomMinSize = 0; + public int phantomMaxSize = 0; + private void phantomSettings() { + phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); + phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); + phantomControllable = getBoolean("mobs.phantom.controllable", phantomControllable); + phantomMaxY = getDouble("mobs.phantom.ridable-max-y", phantomMaxY); + phantomFlameDamage = (float) getDouble("mobs.phantom.flames.damage", phantomFlameDamage); + phantomFlameFireTime = getInt("mobs.phantom.flames.fire-time", phantomFlameFireTime); + phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.phantom.attributes.max-health", Double.parseDouble(phantomMaxHealth)); + set("mobs.phantom.attributes.max-health", null); + set("mobs.phantom.attributes.max_health", String.valueOf(oldValue)); + } + if (PurpurConfig.version < 25) { + double oldValue = getDouble("mobs.phantom.attributes.max_health", Double.parseDouble(phantomMaxHealth)); + set("mobs.phantom.attributes.max_health", String.valueOf(oldValue)); + } + phantomMaxHealth = getString("mobs.phantom.attributes.max_health", phantomMaxHealth); + phantomAttackDamage = getString("mobs.phantom.attributes.attack_damage", phantomAttackDamage); + phantomMaxHealthCache.clear(); + phantomAttackDamageCache.clear(); + phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius); + phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage); + phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius); + phantomSpawnMinSkyDarkness = getInt("mobs.phantom.spawn.min-sky-darkness", phantomSpawnMinSkyDarkness); + phantomSpawnOnlyAboveSeaLevel = getBoolean("mobs.phantom.spawn.only-above-sea-level", phantomSpawnOnlyAboveSeaLevel); + phantomSpawnOnlyWithVisibleSky = getBoolean("mobs.phantom.spawn.only-with-visible-sky", phantomSpawnOnlyWithVisibleSky); + phantomSpawnLocalDifficultyChance = getDouble("mobs.phantom.spawn.local-difficulty-chance", phantomSpawnLocalDifficultyChance); + phantomSpawnMinPerAttempt = getInt("mobs.phantom.spawn.per-attempt.min", phantomSpawnMinPerAttempt); + phantomSpawnMaxPerAttempt = getInt("mobs.phantom.spawn.per-attempt.max", phantomSpawnMaxPerAttempt); + phantomBurnInLight = getInt("mobs.phantom.burn-in-light", phantomBurnInLight); + phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight); + phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); + phantomFlamesOnSwoop = getBoolean("mobs.phantom.flames-on-swoop", phantomFlamesOnSwoop); + phantomTakeDamageFromWater = getBoolean("mobs.phantom.takes-damage-from-water", phantomTakeDamageFromWater); + phantomAlwaysDropExp = getBoolean("mobs.phantom.always-drop-exp", phantomAlwaysDropExp); + phantomMinSize = Mth.clamp(getInt("mobs.phantom.size.min", phantomMinSize), 0, 64); + phantomMaxSize = Mth.clamp(getInt("mobs.phantom.size.max", phantomMaxSize), 0, 64); + if (phantomMinSize > phantomMaxSize) { + phantomMinSize = phantomMinSize ^ phantomMaxSize; + phantomMaxSize = phantomMinSize ^ phantomMaxSize; + phantomMinSize = phantomMinSize ^ phantomMaxSize; + } + } + + public boolean pigRidable = false; + public boolean pigRidableInWater = false; + public boolean pigControllable = true; + public double pigMaxHealth = 10.0D; + public double pigScale = 1.0D; + public boolean pigGiveSaddleBack = false; + public int pigBreedingTicks = 6000; + public boolean pigTakeDamageFromWater = false; + public boolean pigAlwaysDropExp = false; + private void pigSettings() { + pigRidable = getBoolean("mobs.pig.ridable", pigRidable); + pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); + pigControllable = getBoolean("mobs.pig.controllable", pigControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.pig.attributes.max-health", pigMaxHealth); + set("mobs.pig.attributes.max-health", null); + set("mobs.pig.attributes.max_health", oldValue); + } + pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth); + pigScale = Mth.clamp(getDouble("mobs.pig.attributes.scale", pigScale), 0.0625D, 16.0D); + pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); + pigBreedingTicks = getInt("mobs.pig.breeding-delay-ticks", pigBreedingTicks); + pigTakeDamageFromWater = getBoolean("mobs.pig.takes-damage-from-water", pigTakeDamageFromWater); + pigAlwaysDropExp = getBoolean("mobs.pig.always-drop-exp", pigAlwaysDropExp); + } + + public boolean piglinRidable = false; + public boolean piglinRidableInWater = true; + public boolean piglinControllable = true; + public double piglinMaxHealth = 16.0D; + public double piglinScale = 1.0D; + public boolean piglinBypassMobGriefing = false; + public boolean piglinTakeDamageFromWater = false; + public int piglinPortalSpawnModifier = 2000; + public boolean piglinAlwaysDropExp = false; + public double piglinHeadVisibilityPercent = 0.5D; + public boolean piglinIgnoresArmorWithGoldTrim = false; + private void piglinSettings() { + piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); + piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); + piglinControllable = getBoolean("mobs.piglin.controllable", piglinControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.piglin.attributes.max-health", piglinMaxHealth); + set("mobs.piglin.attributes.max-health", null); + set("mobs.piglin.attributes.max_health", oldValue); + } + piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth); + piglinScale = Mth.clamp(getDouble("mobs.piglin.attributes.scale", piglinScale), 0.0625D, 16.0D); + piglinBypassMobGriefing = getBoolean("mobs.piglin.bypass-mob-griefing", piglinBypassMobGriefing); + piglinTakeDamageFromWater = getBoolean("mobs.piglin.takes-damage-from-water", piglinTakeDamageFromWater); + piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier); + piglinAlwaysDropExp = getBoolean("mobs.piglin.always-drop-exp", piglinAlwaysDropExp); + piglinHeadVisibilityPercent = getDouble("mobs.piglin.head-visibility-percent", piglinHeadVisibilityPercent); + piglinIgnoresArmorWithGoldTrim = getBoolean("mobs.piglin.ignores-armor-with-gold-trim", piglinIgnoresArmorWithGoldTrim); + } + + public boolean piglinBruteRidable = false; + public boolean piglinBruteRidableInWater = true; + public boolean piglinBruteControllable = true; + public double piglinBruteMaxHealth = 50.0D; + public double piglinBruteScale = 1.0D; + public boolean piglinBruteTakeDamageFromWater = false; + public boolean piglinBruteAlwaysDropExp = false; + private void piglinBruteSettings() { + piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable); + piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater); + piglinBruteControllable = getBoolean("mobs.piglin_brute.controllable", piglinBruteControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.piglin_brute.attributes.max-health", piglinBruteMaxHealth); + set("mobs.piglin_brute.attributes.max-health", null); + set("mobs.piglin_brute.attributes.max_health", oldValue); + } + piglinBruteMaxHealth = getDouble("mobs.piglin_brute.attributes.max_health", piglinBruteMaxHealth); + piglinBruteScale = Mth.clamp(getDouble("mobs.piglin_brute.attributes.scale", piglinBruteScale), 0.0625D, 16.0D); + piglinBruteTakeDamageFromWater = getBoolean("mobs.piglin_brute.takes-damage-from-water", piglinBruteTakeDamageFromWater); + piglinBruteAlwaysDropExp = getBoolean("mobs.piglin_brute.always-drop-exp", piglinBruteAlwaysDropExp); + } + + public boolean pillagerRidable = false; + public boolean pillagerRidableInWater = true; + public boolean pillagerControllable = true; + public double pillagerMaxHealth = 24.0D; + public double pillagerScale = 1.0D; + public boolean pillagerBypassMobGriefing = false; + public boolean pillagerTakeDamageFromWater = false; + public boolean pillagerAlwaysDropExp = false; + private void pillagerSettings() { + pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); + pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); + pillagerControllable = getBoolean("mobs.pillager.controllable", pillagerControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.pillager.attributes.max-health", pillagerMaxHealth); + set("mobs.pillager.attributes.max-health", null); + set("mobs.pillager.attributes.max_health", oldValue); + } + pillagerMaxHealth = getDouble("mobs.pillager.attributes.max_health", pillagerMaxHealth); + pillagerScale = Mth.clamp(getDouble("mobs.pillager.attributes.scale", pillagerScale), 0.0625D, 16.0D); + pillagerBypassMobGriefing = getBoolean("mobs.pillager.bypass-mob-griefing", pillagerBypassMobGriefing); + pillagerTakeDamageFromWater = getBoolean("mobs.pillager.takes-damage-from-water", pillagerTakeDamageFromWater); + pillagerAlwaysDropExp = getBoolean("mobs.pillager.always-drop-exp", pillagerAlwaysDropExp); + } + + public boolean polarBearRidable = false; + public boolean polarBearRidableInWater = true; + public boolean polarBearControllable = true; + public double polarBearMaxHealth = 30.0D; + public double polarBearScale = 1.0D; + public String polarBearBreedableItemString = ""; + public Item polarBearBreedableItem = null; + public int polarBearBreedingTicks = 6000; + public boolean polarBearTakeDamageFromWater = false; + public boolean polarBearAlwaysDropExp = false; + private void polarBearSettings() { + polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); + polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); + polarBearControllable = getBoolean("mobs.polar_bear.controllable", polarBearControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.polar_bear.attributes.max-health", polarBearMaxHealth); + set("mobs.polar_bear.attributes.max-health", null); + set("mobs.polar_bear.attributes.max_health", oldValue); + } + polarBearMaxHealth = getDouble("mobs.polar_bear.attributes.max_health", polarBearMaxHealth); + polarBearScale = Mth.clamp(getDouble("mobs.polar_bear.attributes.scale", polarBearScale), 0.0625D, 16.0D); + polarBearBreedableItemString = getString("mobs.polar_bear.breedable-item", polarBearBreedableItemString); + Item item = BuiltInRegistries.ITEM.getValue(ResourceLocation.parse(polarBearBreedableItemString)); + if (item != Items.AIR) polarBearBreedableItem = item; + polarBearBreedingTicks = getInt("mobs.polar_bear.breeding-delay-ticks", polarBearBreedingTicks); + polarBearTakeDamageFromWater = getBoolean("mobs.polar_bear.takes-damage-from-water", polarBearTakeDamageFromWater); + polarBearAlwaysDropExp = getBoolean("mobs.polar_bear.always-drop-exp", polarBearAlwaysDropExp); + } + + public boolean pufferfishRidable = false; + public boolean pufferfishControllable = true; + public double pufferfishMaxHealth = 3.0D; + public double pufferfishScale = 1.0D; + public boolean pufferfishTakeDamageFromWater = false; + public boolean pufferfishAlwaysDropExp = false; + private void pufferfishSettings() { + pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable); + pufferfishControllable = getBoolean("mobs.pufferfish.controllable", pufferfishControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.pufferfish.attributes.max-health", pufferfishMaxHealth); + set("mobs.pufferfish.attributes.max-health", null); + set("mobs.pufferfish.attributes.max_health", oldValue); + } + pufferfishMaxHealth = getDouble("mobs.pufferfish.attributes.max_health", pufferfishMaxHealth); + pufferfishScale = Mth.clamp(getDouble("mobs.pufferfish.attributes.scale", pufferfishScale), 0.0625D, 16.0D); + pufferfishTakeDamageFromWater = getBoolean("mobs.pufferfish.takes-damage-from-water", pufferfishTakeDamageFromWater); + pufferfishAlwaysDropExp = getBoolean("mobs.pufferfish.always-drop-exp", pufferfishAlwaysDropExp); + } + + public boolean rabbitRidable = false; + public boolean rabbitRidableInWater = true; + public boolean rabbitControllable = true; + public double rabbitMaxHealth = 3.0D; + public double rabbitScale = 1.0D; + public double rabbitNaturalToast = 0.0D; + public double rabbitNaturalKiller = 0.0D; + public int rabbitBreedingTicks = 6000; + public boolean rabbitBypassMobGriefing = false; + public boolean rabbitTakeDamageFromWater = false; + public boolean rabbitAlwaysDropExp = false; + private void rabbitSettings() { + rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); + rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); + rabbitControllable = getBoolean("mobs.rabbit.controllable", rabbitControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.rabbit.attributes.max-health", rabbitMaxHealth); + set("mobs.rabbit.attributes.max-health", null); + set("mobs.rabbit.attributes.max_health", oldValue); + } + rabbitMaxHealth = getDouble("mobs.rabbit.attributes.max_health", rabbitMaxHealth); + rabbitScale = Mth.clamp(getDouble("mobs.rabbit.attributes.scale", rabbitScale), 0.0625D, 16.0D); + rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); + rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); + rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks); + rabbitBypassMobGriefing = getBoolean("mobs.rabbit.bypass-mob-griefing", rabbitBypassMobGriefing); + rabbitTakeDamageFromWater = getBoolean("mobs.rabbit.takes-damage-from-water", rabbitTakeDamageFromWater); + rabbitAlwaysDropExp = getBoolean("mobs.rabbit.always-drop-exp", rabbitAlwaysDropExp); + } + + public boolean ravagerRidable = false; + public boolean ravagerRidableInWater = false; + public boolean ravagerControllable = true; + public double ravagerMaxHealth = 100.0D; + public double ravagerScale = 1.0D; + public boolean ravagerBypassMobGriefing = false; + public boolean ravagerTakeDamageFromWater = false; + public List ravagerGriefableBlocks = new ArrayList<>(); + public boolean ravagerAlwaysDropExp = false; + public boolean ravagerAvoidRabbits = false; + private void ravagerSettings() { + ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); + ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); + ravagerControllable = getBoolean("mobs.ravager.controllable", ravagerControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.ravager.attributes.max-health", ravagerMaxHealth); + set("mobs.ravager.attributes.max-health", null); + set("mobs.ravager.attributes.max_health", oldValue); + } + ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth); + ravagerScale = Mth.clamp(getDouble("mobs.ravager.attributes.scale", ravagerScale), 0.0625D, 16.0D); + ravagerBypassMobGriefing = getBoolean("mobs.ravager.bypass-mob-griefing", ravagerBypassMobGriefing); + ravagerTakeDamageFromWater = getBoolean("mobs.ravager.takes-damage-from-water", ravagerTakeDamageFromWater); + getList("mobs.ravager.griefable-blocks", new ArrayList(){{ + add("minecraft:oak_leaves"); + add("minecraft:spruce_leaves"); + add("minecraft:birch_leaves"); + add("minecraft:jungle_leaves"); + add("minecraft:acacia_leaves"); + add("minecraft:dark_oak_leaves"); + add("minecraft:beetroots"); + add("minecraft:carrots"); + add("minecraft:potatoes"); + add("minecraft:wheat"); + }}).forEach(key -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(key.toString())); + if (!block.defaultBlockState().isAir()) { + ravagerGriefableBlocks.add(block); + } + }); + ravagerAlwaysDropExp = getBoolean("mobs.ravager.always-drop-exp", ravagerAlwaysDropExp); + ravagerAvoidRabbits = getBoolean("mobs.ravager.avoid-rabbits", ravagerAvoidRabbits); + } + + public boolean salmonRidable = false; + public boolean salmonControllable = true; + public double salmonMaxHealth = 3.0D; + public double salmonScale = 1.0D; + public boolean salmonTakeDamageFromWater = false; + public boolean salmonAlwaysDropExp = false; + private void salmonSettings() { + salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable); + salmonControllable = getBoolean("mobs.salmon.controllable", salmonControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.salmon.attributes.max-health", salmonMaxHealth); + set("mobs.salmon.attributes.max-health", null); + set("mobs.salmon.attributes.max_health", oldValue); + } + salmonMaxHealth = getDouble("mobs.salmon.attributes.max_health", salmonMaxHealth); + salmonScale = Mth.clamp(getDouble("mobs.salmon.attributes.scale", salmonScale), 0.0625D, 16.0D); + salmonTakeDamageFromWater = getBoolean("mobs.salmon.takes-damage-from-water", salmonTakeDamageFromWater); + salmonAlwaysDropExp = getBoolean("mobs.salmon.always-drop-exp", salmonAlwaysDropExp); + } + + public boolean sheepRidable = false; + public boolean sheepRidableInWater = true; + public boolean sheepControllable = true; + public double sheepMaxHealth = 8.0D; + public double sheepScale = 1.0D; + public int sheepBreedingTicks = 6000; + public boolean sheepBypassMobGriefing = false; + public boolean sheepTakeDamageFromWater = false; + public boolean sheepAlwaysDropExp = false; + private void sheepSettings() { + sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); + sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); + sheepControllable = getBoolean("mobs.sheep.controllable", sheepControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.sheep.attributes.max-health", sheepMaxHealth); + set("mobs.sheep.attributes.max-health", null); + set("mobs.sheep.attributes.max_health", oldValue); + } + sheepMaxHealth = getDouble("mobs.sheep.attributes.max_health", sheepMaxHealth); + sheepScale = Mth.clamp(getDouble("mobs.sheep.attributes.scale", sheepScale), 0.0625D, 16.0D); + sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks); + sheepBypassMobGriefing = getBoolean("mobs.sheep.bypass-mob-griefing", sheepBypassMobGriefing); + sheepTakeDamageFromWater = getBoolean("mobs.sheep.takes-damage-from-water", sheepTakeDamageFromWater); + sheepAlwaysDropExp = getBoolean("mobs.sheep.always-drop-exp", sheepAlwaysDropExp); + } + + public boolean shulkerRidable = false; + public boolean shulkerRidableInWater = true; + public boolean shulkerControllable = true; + public double shulkerMaxHealth = 30.0D; + public double shulkerScale = 1.0D; + public boolean shulkerTakeDamageFromWater = false; + public float shulkerSpawnFromBulletBaseChance = 1.0F; + public boolean shulkerSpawnFromBulletRequireOpenLid = true; + public double shulkerSpawnFromBulletNearbyRange = 8.0D; + public String shulkerSpawnFromBulletNearbyEquation = "(nearby - 1) / 5.0"; + public boolean shulkerSpawnFromBulletRandomColor = false; + public boolean shulkerChangeColorWithDye = false; + public boolean shulkerAlwaysDropExp = false; + private void shulkerSettings() { + shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); + shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); + shulkerControllable = getBoolean("mobs.shulker.controllable", shulkerControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.shulker.attributes.max-health", shulkerMaxHealth); + set("mobs.shulker.attributes.max-health", null); + set("mobs.shulker.attributes.max_health", oldValue); + } + shulkerMaxHealth = getDouble("mobs.shulker.attributes.max_health", shulkerMaxHealth); + shulkerScale = Mth.clamp(getDouble("mobs.shulker.attributes.scale", shulkerScale), 0.0625D, Shulker.MAX_SCALE); + shulkerTakeDamageFromWater = getBoolean("mobs.shulker.takes-damage-from-water", shulkerTakeDamageFromWater); + shulkerSpawnFromBulletBaseChance = (float) getDouble("mobs.shulker.spawn-from-bullet.base-chance", shulkerSpawnFromBulletBaseChance); + shulkerSpawnFromBulletRequireOpenLid = getBoolean("mobs.shulker.spawn-from-bullet.require-open-lid", shulkerSpawnFromBulletRequireOpenLid); + shulkerSpawnFromBulletNearbyRange = getDouble("mobs.shulker.spawn-from-bullet.nearby-range", shulkerSpawnFromBulletNearbyRange); + shulkerSpawnFromBulletNearbyEquation = getString("mobs.shulker.spawn-from-bullet.nearby-equation", shulkerSpawnFromBulletNearbyEquation); + shulkerSpawnFromBulletRandomColor = getBoolean("mobs.shulker.spawn-from-bullet.random-color", shulkerSpawnFromBulletRandomColor); + shulkerChangeColorWithDye = getBoolean("mobs.shulker.change-color-with-dye", shulkerChangeColorWithDye); + shulkerAlwaysDropExp = getBoolean("mobs.shulker.always-drop-exp", shulkerAlwaysDropExp); + } + + public boolean silverfishRidable = false; + public boolean silverfishRidableInWater = true; + public boolean silverfishControllable = true; + public double silverfishMaxHealth = 8.0D; + public double silverfishScale = 1.0D; + public double silverfishMovementSpeed = 0.25D; + public double silverfishAttackDamage = 1.0D; + public boolean silverfishBypassMobGriefing = false; + public boolean silverfishTakeDamageFromWater = false; + public boolean silverfishAlwaysDropExp = false; + private void silverfishSettings() { + silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); + silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); + silverfishControllable = getBoolean("mobs.silverfish.controllable", silverfishControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.silverfish.attributes.max-health", silverfishMaxHealth); + set("mobs.silverfish.attributes.max-health", null); + set("mobs.silverfish.attributes.max_health", oldValue); + } + silverfishMaxHealth = getDouble("mobs.silverfish.attributes.max_health", silverfishMaxHealth); + silverfishScale = Mth.clamp(getDouble("mobs.silverfish.attributes.scale", silverfishScale), 0.0625D, 16.0D); + silverfishMovementSpeed = getDouble("mobs.silverfish.attributes.movement_speed", silverfishMovementSpeed); + silverfishAttackDamage = getDouble("mobs.silverfish.attributes.attack_damage", silverfishAttackDamage); + silverfishBypassMobGriefing = getBoolean("mobs.silverfish.bypass-mob-griefing", silverfishBypassMobGriefing); + silverfishTakeDamageFromWater = getBoolean("mobs.silverfish.takes-damage-from-water", silverfishTakeDamageFromWater); + silverfishAlwaysDropExp = getBoolean("mobs.silverfish.always-drop-exp", silverfishAlwaysDropExp); + } + + public boolean skeletonRidable = false; + public boolean skeletonRidableInWater = true; + public boolean skeletonControllable = true; + public double skeletonMaxHealth = 20.0D; + public double skeletonScale = 1.0D; + public boolean skeletonTakeDamageFromWater = false; + public boolean skeletonAlwaysDropExp = false; + public double skeletonHeadVisibilityPercent = 0.5D; + public int skeletonFeedWitherRoses = 0; + public String skeletonBowAccuracy = "14 - difficulty * 4"; + public Map skeletonBowAccuracyMap = new HashMap<>(); + private void skeletonSettings() { + skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); + skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); + skeletonControllable = getBoolean("mobs.skeleton.controllable", skeletonControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.skeleton.attributes.max-health", skeletonMaxHealth); + set("mobs.skeleton.attributes.max-health", null); + set("mobs.skeleton.attributes.max_health", oldValue); + } + skeletonMaxHealth = getDouble("mobs.skeleton.attributes.max_health", skeletonMaxHealth); + skeletonScale = Mth.clamp(getDouble("mobs.skeleton.attributes.scale", skeletonScale), 0.0625D, 16.0D); + skeletonTakeDamageFromWater = getBoolean("mobs.skeleton.takes-damage-from-water", skeletonTakeDamageFromWater); + skeletonAlwaysDropExp = getBoolean("mobs.skeleton.always-drop-exp", skeletonAlwaysDropExp); + skeletonHeadVisibilityPercent = getDouble("mobs.skeleton.head-visibility-percent", skeletonHeadVisibilityPercent); + skeletonFeedWitherRoses = getInt("mobs.skeleton.feed-wither-roses", skeletonFeedWitherRoses); + final String defaultSkeletonBowAccuracy = skeletonBowAccuracy; + skeletonBowAccuracy = getString("mobs.skeleton.bow-accuracy", skeletonBowAccuracy); + for (int i = 1; i < 4; i++) { + final float divergence; + try { + divergence = ((Number) Entity.scriptEngine.eval("let difficulty = " + i + "; " + skeletonBowAccuracy)).floatValue(); + } catch (javax.script.ScriptException e) { + e.printStackTrace(); + break; + } + skeletonBowAccuracyMap.put(i, divergence); + } + } + + public boolean skeletonHorseRidable = false; + public boolean skeletonHorseRidableInWater = true; + public boolean skeletonHorseCanSwim = false; + public double skeletonHorseMaxHealthMin = 15.0D; + public double skeletonHorseMaxHealthMax = 15.0D; + public double skeletonHorseJumpStrengthMin = 0.4D; + public double skeletonHorseJumpStrengthMax = 1.0D; + public double skeletonHorseMovementSpeedMin = 0.2D; + public double skeletonHorseMovementSpeedMax = 0.2D; + public boolean skeletonHorseTakeDamageFromWater = false; + public boolean skeletonHorseAlwaysDropExp = false; + private void skeletonHorseSettings() { + skeletonHorseRidable = getBoolean("mobs.skeleton_horse.ridable", skeletonHorseRidable); + skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater); + skeletonHorseCanSwim = getBoolean("mobs.skeleton_horse.can-swim", skeletonHorseCanSwim); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.skeleton_horse.attributes.max-health", skeletonHorseMaxHealthMin); + set("mobs.skeleton_horse.attributes.max-health", null); + set("mobs.skeleton_horse.attributes.max_health.min", oldValue); + set("mobs.skeleton_horse.attributes.max_health.max", oldValue); + } + skeletonHorseMaxHealthMin = getDouble("mobs.skeleton_horse.attributes.max_health.min", skeletonHorseMaxHealthMin); + skeletonHorseMaxHealthMax = getDouble("mobs.skeleton_horse.attributes.max_health.max", skeletonHorseMaxHealthMax); + skeletonHorseJumpStrengthMin = getDouble("mobs.skeleton_horse.attributes.jump_strength.min", skeletonHorseJumpStrengthMin); + skeletonHorseJumpStrengthMax = getDouble("mobs.skeleton_horse.attributes.jump_strength.max", skeletonHorseJumpStrengthMax); + skeletonHorseMovementSpeedMin = getDouble("mobs.skeleton_horse.attributes.movement_speed.min", skeletonHorseMovementSpeedMin); + skeletonHorseMovementSpeedMax = getDouble("mobs.skeleton_horse.attributes.movement_speed.max", skeletonHorseMovementSpeedMax); + skeletonHorseTakeDamageFromWater = getBoolean("mobs.skeleton_horse.takes-damage-from-water", skeletonHorseTakeDamageFromWater); + skeletonHorseAlwaysDropExp = getBoolean("mobs.skeleton_horse.always-drop-exp", skeletonHorseAlwaysDropExp); + } + + public boolean slimeRidable = false; + public boolean slimeRidableInWater = true; + public boolean slimeControllable = true; + public String slimeMaxHealth = "size * size"; + public String slimeAttackDamage = "size"; + public Map slimeMaxHealthCache = new HashMap<>(); + public Map slimeAttackDamageCache = new HashMap<>(); + public boolean slimeTakeDamageFromWater = false; + public boolean slimeAlwaysDropExp = false; + private void slimeSettings() { + slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable); + slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater); + slimeControllable = getBoolean("mobs.slime.controllable", slimeControllable); + if (PurpurConfig.version < 10) { + String oldValue = getString("mobs.slime.attributes.max-health", slimeMaxHealth); + set("mobs.slime.attributes.max-health", null); + set("mobs.slime.attributes.max_health", oldValue); + } + slimeMaxHealth = getString("mobs.slime.attributes.max_health", slimeMaxHealth); + slimeAttackDamage = getString("mobs.slime.attributes.attack_damage", slimeAttackDamage); + slimeMaxHealthCache.clear(); + slimeAttackDamageCache.clear(); + slimeTakeDamageFromWater = getBoolean("mobs.slime.takes-damage-from-water", slimeTakeDamageFromWater); + slimeAlwaysDropExp = getBoolean("mobs.slime.always-drop-exp", slimeAlwaysDropExp); + } + + public boolean snowGolemRidable = false; + public boolean snowGolemRidableInWater = true; + public boolean snowGolemControllable = true; + public boolean snowGolemLeaveTrailWhenRidden = false; + public double snowGolemMaxHealth = 4.0D; + public double snowGolemScale = 1.0D; + public boolean snowGolemPutPumpkinBack = false; + public int snowGolemSnowBallMin = 20; + public int snowGolemSnowBallMax = 20; + public float snowGolemSnowBallModifier = 10.0F; + public double snowGolemAttackDistance = 1.25D; + public boolean snowGolemBypassMobGriefing = false; + public boolean snowGolemTakeDamageFromWater = true; + public boolean snowGolemAlwaysDropExp = false; + private void snowGolemSettings() { + snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); + snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); + snowGolemControllable = getBoolean("mobs.snow_golem.controllable", snowGolemControllable); + snowGolemLeaveTrailWhenRidden = getBoolean("mobs.snow_golem.leave-trail-when-ridden", snowGolemLeaveTrailWhenRidden); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.snow_golem.attributes.max-health", snowGolemMaxHealth); + set("mobs.snow_golem.attributes.max-health", null); + set("mobs.snow_golem.attributes.max_health", oldValue); + } + snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth); + snowGolemScale = Mth.clamp(getDouble("mobs.snow_golem.attributes.scale", snowGolemScale), 0.0625D, 16.0D); + snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack); + snowGolemSnowBallMin = getInt("mobs.snow_golem.min-shoot-interval-ticks", snowGolemSnowBallMin); + snowGolemSnowBallMax = getInt("mobs.snow_golem.max-shoot-interval-ticks", snowGolemSnowBallMax); + snowGolemSnowBallModifier = (float) getDouble("mobs.snow_golem.snow-ball-modifier", snowGolemSnowBallModifier); + snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance); + snowGolemBypassMobGriefing = getBoolean("mobs.snow_golem.bypass-mob-griefing", snowGolemBypassMobGriefing); + snowGolemTakeDamageFromWater = getBoolean("mobs.snow_golem.takes-damage-from-water", snowGolemTakeDamageFromWater); + snowGolemAlwaysDropExp = getBoolean("mobs.snow_golem.always-drop-exp", snowGolemAlwaysDropExp); + } + + public boolean snifferRidable = false; + public boolean snifferRidableInWater = true; + public boolean snifferControllable = true; + public double snifferMaxHealth = 14.0D; + public double snifferScale = 1.0D; + public int snifferBreedingTicks = 6000; + private void snifferSettings() { + snifferRidable = getBoolean("mobs.sniffer.ridable", snifferRidable); + snifferRidableInWater = getBoolean("mobs.sniffer.ridable-in-water", snifferRidableInWater); + snifferControllable = getBoolean("mobs.sniffer.controllable", snifferControllable); + snifferMaxHealth = getDouble("mobs.sniffer.attributes.max_health", snifferMaxHealth); + snifferScale = Mth.clamp(getDouble("mobs.sniffer.attributes.scale", snifferScale), 0.0625D, 16.0D); + snifferBreedingTicks = getInt("mobs.sniffer.breeding-delay-ticks", snifferBreedingTicks); + } + + public boolean squidRidable = false; + public boolean squidControllable = true; + public double squidMaxHealth = 10.0D; + public double squidScale = 1.0D; + public boolean squidImmuneToEAR = true; + public double squidOffsetWaterCheck = 0.0D; + public boolean squidsCanFly = false; + public boolean squidTakeDamageFromWater = false; + public boolean squidAlwaysDropExp = false; + private void squidSettings() { + squidRidable = getBoolean("mobs.squid.ridable", squidRidable); + squidControllable = getBoolean("mobs.squid.controllable", squidControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.squid.attributes.max-health", squidMaxHealth); + set("mobs.squid.attributes.max-health", null); + set("mobs.squid.attributes.max_health", oldValue); + } + squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth); + squidScale = Mth.clamp(getDouble("mobs.squid.attributes.scale", squidScale), 0.0625D, 16.0D); + squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); + squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); + squidsCanFly = getBoolean("mobs.squid.can-fly", squidsCanFly); + squidTakeDamageFromWater = getBoolean("mobs.squid.takes-damage-from-water", squidTakeDamageFromWater); + squidAlwaysDropExp = getBoolean("mobs.squid.always-drop-exp", squidAlwaysDropExp); + } + + public boolean spiderRidable = false; + public boolean spiderRidableInWater = false; + public boolean spiderControllable = true; + public double spiderMaxHealth = 16.0D; + public double spiderScale = 1.0D; + public boolean spiderTakeDamageFromWater = false; + public boolean spiderAlwaysDropExp = false; + private void spiderSettings() { + spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable); + spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater); + spiderControllable = getBoolean("mobs.spider.controllable", spiderControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.spider.attributes.max-health", spiderMaxHealth); + set("mobs.spider.attributes.max-health", null); + set("mobs.spider.attributes.max_health", oldValue); + } + spiderMaxHealth = getDouble("mobs.spider.attributes.max_health", spiderMaxHealth); + spiderScale = Mth.clamp(getDouble("mobs.spider.attributes.scale", spiderScale), 0.0625D, 16.0D); + spiderTakeDamageFromWater = getBoolean("mobs.spider.takes-damage-from-water", spiderTakeDamageFromWater); + spiderAlwaysDropExp = getBoolean("mobs.spider.always-drop-exp", spiderAlwaysDropExp); + } + + public boolean strayRidable = false; + public boolean strayRidableInWater = true; + public boolean strayControllable = true; + public double strayMaxHealth = 20.0D; + public double strayScale = 1.0D; + public boolean strayTakeDamageFromWater = false; + public boolean strayAlwaysDropExp = false; + private void straySettings() { + strayRidable = getBoolean("mobs.stray.ridable", strayRidable); + strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater); + strayControllable = getBoolean("mobs.stray.controllable", strayControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.stray.attributes.max-health", strayMaxHealth); + set("mobs.stray.attributes.max-health", null); + set("mobs.stray.attributes.max_health", oldValue); + } + strayMaxHealth = getDouble("mobs.stray.attributes.max_health", strayMaxHealth); + strayScale = Mth.clamp(getDouble("mobs.stray.attributes.scale", strayScale), 0.0625D, 16.0D); + strayTakeDamageFromWater = getBoolean("mobs.stray.takes-damage-from-water", strayTakeDamageFromWater); + strayAlwaysDropExp = getBoolean("mobs.stray.always-drop-exp", strayAlwaysDropExp); + } + + public boolean striderRidable = false; + public boolean striderRidableInWater = false; + public boolean striderControllable = true; + public double striderMaxHealth = 20.0D; + public double striderScale = 1.0D; + public int striderBreedingTicks = 6000; + public boolean striderGiveSaddleBack = false; + public boolean striderTakeDamageFromWater = true; + public boolean striderAlwaysDropExp = false; + private void striderSettings() { + striderRidable = getBoolean("mobs.strider.ridable", striderRidable); + striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); + striderControllable = getBoolean("mobs.strider.controllable", striderControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.strider.attributes.max-health", striderMaxHealth); + set("mobs.strider.attributes.max-health", null); + set("mobs.strider.attributes.max_health", oldValue); + } + striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth); + striderScale = Mth.clamp(getDouble("mobs.strider.attributes.scale", striderScale), 0.0625D, 16.0D); + striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks); + striderGiveSaddleBack = getBoolean("mobs.strider.give-saddle-back", striderGiveSaddleBack); + striderTakeDamageFromWater = getBoolean("mobs.strider.takes-damage-from-water", striderTakeDamageFromWater); + striderAlwaysDropExp = getBoolean("mobs.strider.always-drop-exp", striderAlwaysDropExp); + } + + public boolean tadpoleRidable = false; + public boolean tadpoleRidableInWater = true; + public boolean tadpoleControllable = true; + private void tadpoleSettings() { + tadpoleRidable = getBoolean("mobs.tadpole.ridable", tadpoleRidable); + tadpoleRidableInWater = getBoolean("mobs.tadpole.ridable-in-water", tadpoleRidableInWater); + tadpoleControllable = getBoolean("mobs.tadpole.controllable", tadpoleControllable); + } + + public boolean traderLlamaRidable = false; + public boolean traderLlamaRidableInWater = false; + public boolean traderLlamaControllable = true; + public double traderLlamaMaxHealthMin = 15.0D; + public double traderLlamaMaxHealthMax = 30.0D; + public double traderLlamaJumpStrengthMin = 0.5D; + public double traderLlamaJumpStrengthMax = 0.5D; + public double traderLlamaMovementSpeedMin = 0.175D; + public double traderLlamaMovementSpeedMax = 0.175D; + public int traderLlamaBreedingTicks = 6000; + public boolean traderLlamaTakeDamageFromWater = false; + public boolean traderLlamaAlwaysDropExp = false; + private void traderLlamaSettings() { + traderLlamaRidable = getBoolean("mobs.trader_llama.ridable", traderLlamaRidable); + traderLlamaRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", traderLlamaRidableInWater); + traderLlamaControllable = getBoolean("mobs.trader_llama.controllable", traderLlamaControllable); + if (PurpurConfig.version < 10) { + double oldMin = getDouble("mobs.trader_llama.attributes.max-health.min", traderLlamaMaxHealthMin); + double oldMax = getDouble("mobs.trader_llama.attributes.max-health.max", traderLlamaMaxHealthMax); + set("mobs.trader_llama.attributes.max-health", null); + set("mobs.trader_llama.attributes.max_health.min", oldMin); + set("mobs.trader_llama.attributes.max_health.max", oldMax); + } + traderLlamaMaxHealthMin = getDouble("mobs.trader_llama.attributes.max_health.min", traderLlamaMaxHealthMin); + traderLlamaMaxHealthMax = getDouble("mobs.trader_llama.attributes.max_health.max", traderLlamaMaxHealthMax); + traderLlamaJumpStrengthMin = getDouble("mobs.trader_llama.attributes.jump_strength.min", traderLlamaJumpStrengthMin); + traderLlamaJumpStrengthMax = getDouble("mobs.trader_llama.attributes.jump_strength.max", traderLlamaJumpStrengthMax); + traderLlamaMovementSpeedMin = getDouble("mobs.trader_llama.attributes.movement_speed.min", traderLlamaMovementSpeedMin); + traderLlamaMovementSpeedMax = getDouble("mobs.trader_llama.attributes.movement_speed.max", traderLlamaMovementSpeedMax); + traderLlamaBreedingTicks = getInt("mobs.trader_llama.breeding-delay-ticks", traderLlamaBreedingTicks); + traderLlamaTakeDamageFromWater = getBoolean("mobs.trader_llama.takes-damage-from-water", traderLlamaTakeDamageFromWater); + traderLlamaAlwaysDropExp = getBoolean("mobs.trader_llama.always-drop-exp", traderLlamaAlwaysDropExp); + } + + public boolean tropicalFishRidable = false; + public boolean tropicalFishControllable = true; + public double tropicalFishMaxHealth = 3.0D; + public double tropicalFishScale = 1.0D; + public boolean tropicalFishTakeDamageFromWater = false; + public boolean tropicalFishAlwaysDropExp = false; + private void tropicalFishSettings() { + tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable); + tropicalFishControllable = getBoolean("mobs.tropical_fish.controllable", tropicalFishControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.tropical_fish.attributes.max-health", tropicalFishMaxHealth); + set("mobs.tropical_fish.attributes.max-health", null); + set("mobs.tropical_fish.attributes.max_health", oldValue); + } + tropicalFishMaxHealth = getDouble("mobs.tropical_fish.attributes.max_health", tropicalFishMaxHealth); + tropicalFishScale = Mth.clamp(getDouble("mobs.tropical_fish.attributes.scale", tropicalFishScale), 0.0625D, 16.0D); + tropicalFishTakeDamageFromWater = getBoolean("mobs.tropical_fish.takes-damage-from-water", tropicalFishTakeDamageFromWater); + tropicalFishAlwaysDropExp = getBoolean("mobs.tropical_fish.always-drop-exp", tropicalFishAlwaysDropExp); + } + + public boolean turtleRidable = false; + public boolean turtleRidableInWater = true; + public boolean turtleControllable = true; + public double turtleMaxHealth = 30.0D; + public double turtleScale = 1.0D; + public int turtleBreedingTicks = 6000; + public boolean turtleTakeDamageFromWater = false; + public boolean turtleAlwaysDropExp = false; + private void turtleSettings() { + turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); + turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); + turtleControllable = getBoolean("mobs.turtle.controllable", turtleControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.turtle.attributes.max-health", turtleMaxHealth); + set("mobs.turtle.attributes.max-health", null); + set("mobs.turtle.attributes.max_health", oldValue); + } + turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth); + turtleScale = Mth.clamp(getDouble("mobs.turtle.attributes.scale", turtleScale), 0.0625D, 16.0D); + turtleBreedingTicks = getInt("mobs.turtle.breeding-delay-ticks", turtleBreedingTicks); + turtleTakeDamageFromWater = getBoolean("mobs.turtle.takes-damage-from-water", turtleTakeDamageFromWater); + turtleAlwaysDropExp = getBoolean("mobs.turtle.always-drop-exp", turtleAlwaysDropExp); + } + + public boolean vexRidable = false; + public boolean vexRidableInWater = true; + public boolean vexControllable = true; + public double vexMaxY = 320D; + public double vexMaxHealth = 14.0D; + public double vexScale = 1.0D; + public boolean vexTakeDamageFromWater = false; + public boolean vexAlwaysDropExp = false; + private void vexSettings() { + vexRidable = getBoolean("mobs.vex.ridable", vexRidable); + vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater); + vexControllable = getBoolean("mobs.vex.controllable", vexControllable); + vexMaxY = getDouble("mobs.vex.ridable-max-y", vexMaxY); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.vex.attributes.max-health", vexMaxHealth); + set("mobs.vex.attributes.max-health", null); + set("mobs.vex.attributes.max_health", oldValue); + } + vexMaxHealth = getDouble("mobs.vex.attributes.max_health", vexMaxHealth); + vexScale = Mth.clamp(getDouble("mobs.vex.attributes.scale", vexScale), 0.0625D, 16.0D); + vexTakeDamageFromWater = getBoolean("mobs.vex.takes-damage-from-water", vexTakeDamageFromWater); + vexAlwaysDropExp = getBoolean("mobs.vex.always-drop-exp", vexAlwaysDropExp); + } + + public boolean villagerRidable = false; + public boolean villagerRidableInWater = true; + public boolean villagerControllable = true; + public double villagerMaxHealth = 20.0D; + public double villagerScale = 1.0D; + public boolean villagerFollowEmeraldBlock = false; + public double villagerTemptRange = 10.0D; + public boolean villagerCanBeLeashed = false; + public boolean villagerCanBreed = true; + public int villagerBreedingTicks = 6000; + public boolean villagerClericsFarmWarts = false; + public boolean villagerClericFarmersThrowWarts = true; + public boolean villagerBypassMobGriefing = false; + public boolean villagerTakeDamageFromWater = false; + public boolean villagerAllowTrading = true; + public boolean villagerAlwaysDropExp = false; + public int villagerMinimumDemand = 0; + public boolean villagerLobotomizeEnabled = false; + public int villagerLobotomizeCheckInterval = 100; + public boolean villagerLobotomizeWaitUntilTradeLocked = false; + public boolean villagerDisplayTradeItem = true; + public int villagerSpawnIronGolemRadius = 0; + public int villagerSpawnIronGolemLimit = 0; + public int villagerAcquirePoiSearchRadius = 48; + public int villagerNearestBedSensorSearchRadius = 48; + private void villagerSettings() { + villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); + villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); + villagerControllable = getBoolean("mobs.villager.controllable", villagerControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.villager.attributes.max-health", villagerMaxHealth); + set("mobs.villager.attributes.max-health", null); + set("mobs.villager.attributes.max_health", oldValue); + } + villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth); + villagerScale = Mth.clamp(getDouble("mobs.villager.attributes.scale", villagerScale), 0.0625D, 16.0D); + villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); + villagerTemptRange = getDouble("mobs.villager.attributes.tempt_range", villagerTemptRange); + villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed); + villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed); + villagerBreedingTicks = getInt("mobs.villager.breeding-delay-ticks", villagerBreedingTicks); + villagerClericsFarmWarts = getBoolean("mobs.villager.clerics-farm-warts", villagerClericsFarmWarts); + villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts); + villagerBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerBypassMobGriefing); + villagerTakeDamageFromWater = getBoolean("mobs.villager.takes-damage-from-water", villagerTakeDamageFromWater); + villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading); + villagerAlwaysDropExp = getBoolean("mobs.villager.always-drop-exp", villagerAlwaysDropExp); + villagerMinimumDemand = getInt("mobs.villager.minimum-demand", villagerMinimumDemand); + if (PurpurConfig.version < 9) { + boolean oldValue = getBoolean("mobs.villager.lobotomize-1x1", villagerLobotomizeEnabled); + set("mobs.villager.lobotomize.enabled", oldValue); + set("mobs.villager.lobotomize-1x1", null); + } + if (PurpurConfig.version < 27) { + int oldValue = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval); + set("mobs.villager.lobotomize.check-interval", oldValue == 60 ? 100 : oldValue); + } + villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled); + villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval); + villagerLobotomizeWaitUntilTradeLocked = getBoolean("mobs.villager.lobotomize.wait-until-trade-locked", villagerLobotomizeWaitUntilTradeLocked); + villagerDisplayTradeItem = getBoolean("mobs.villager.display-trade-item", villagerDisplayTradeItem); + villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius); + villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit); + villagerAcquirePoiSearchRadius = getInt("mobs.villager.search-radius.acquire-poi", villagerAcquirePoiSearchRadius); + villagerNearestBedSensorSearchRadius = getInt("mobs.villager.search-radius.nearest-bed-sensor", villagerNearestBedSensorSearchRadius); + } + + public boolean vindicatorRidable = false; + public boolean vindicatorRidableInWater = true; + public boolean vindicatorControllable = true; + public double vindicatorMaxHealth = 24.0D; + public double vindicatorScale = 1.0D; + public double vindicatorJohnnySpawnChance = 0D; + public boolean vindicatorTakeDamageFromWater = false; + public boolean vindicatorAlwaysDropExp = false; + private void vindicatorSettings() { + vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); + vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); + vindicatorControllable = getBoolean("mobs.vindicator.controllable", vindicatorControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.vindicator.attributes.max-health", vindicatorMaxHealth); + set("mobs.vindicator.attributes.max-health", null); + set("mobs.vindicator.attributes.max_health", oldValue); + } + vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth); + vindicatorScale = Mth.clamp(getDouble("mobs.vindicator.attributes.scale", vindicatorScale), 0.0625D, 16.0D); + vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance); + vindicatorTakeDamageFromWater = getBoolean("mobs.vindicator.takes-damage-from-water", vindicatorTakeDamageFromWater); + vindicatorAlwaysDropExp = getBoolean("mobs.vindicator.always-drop-exp", vindicatorAlwaysDropExp); + } + + public boolean wanderingTraderRidable = false; + public boolean wanderingTraderRidableInWater = true; + public boolean wanderingTraderControllable = true; + public double wanderingTraderMaxHealth = 20.0D; + public double wanderingTraderScale = 1.0D; + public boolean wanderingTraderFollowEmeraldBlock = false; + public double wanderingTraderTemptRange = 10.0D; + public boolean wanderingTraderCanBeLeashed = false; + public boolean wanderingTraderTakeDamageFromWater = false; + public boolean wanderingTraderAllowTrading = true; + public boolean wanderingTraderAlwaysDropExp = false; + private void wanderingTraderSettings() { + wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); + wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); + wanderingTraderControllable = getBoolean("mobs.wandering_trader.controllable", wanderingTraderControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.wandering_trader.attributes.max-health", wanderingTraderMaxHealth); + set("mobs.wandering_trader.attributes.max-health", null); + set("mobs.wandering_trader.attributes.max_health", oldValue); + } + wanderingTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", wanderingTraderMaxHealth); + wanderingTraderScale = Mth.clamp(getDouble("mobs.wandering_trader.attributes.scale", wanderingTraderScale), 0.0625D, 16.0D); + wanderingTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", wanderingTraderFollowEmeraldBlock); + wanderingTraderTemptRange = getDouble("mobs.wandering_trader.attributes.tempt_range", wanderingTraderTemptRange); + wanderingTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", wanderingTraderCanBeLeashed); + wanderingTraderTakeDamageFromWater = getBoolean("mobs.wandering_trader.takes-damage-from-water", wanderingTraderTakeDamageFromWater); + wanderingTraderAllowTrading = getBoolean("mobs.wandering_trader.allow-trading", wanderingTraderAllowTrading); + wanderingTraderAlwaysDropExp = getBoolean("mobs.wandering_trader.always-drop-exp", wanderingTraderAlwaysDropExp); + } + + public boolean wardenRidable = false; + public boolean wardenRidableInWater = true; + public boolean wardenControllable = true; + private void wardenSettings() { + wardenRidable = getBoolean("mobs.warden.ridable", wardenRidable); + wardenRidableInWater = getBoolean("mobs.warden.ridable-in-water", wardenRidableInWater); + wardenControllable = getBoolean("mobs.warden.controllable", wardenControllable); + } + + public boolean witchRidable = false; + public boolean witchRidableInWater = true; + public boolean witchControllable = true; + public double witchMaxHealth = 26.0D; + public double witchScale = 1.0D; + public boolean witchTakeDamageFromWater = false; + public boolean witchAlwaysDropExp = false; + private void witchSettings() { + witchRidable = getBoolean("mobs.witch.ridable", witchRidable); + witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater); + witchControllable = getBoolean("mobs.witch.controllable", witchControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.witch.attributes.max-health", witchMaxHealth); + set("mobs.witch.attributes.max-health", null); + set("mobs.witch.attributes.max_health", oldValue); + } + witchMaxHealth = getDouble("mobs.witch.attributes.max_health", witchMaxHealth); + witchScale = Mth.clamp(getDouble("mobs.witch.attributes.scale", witchScale), 0.0625D, 16.0D); + witchTakeDamageFromWater = getBoolean("mobs.witch.takes-damage-from-water", witchTakeDamageFromWater); + witchAlwaysDropExp = getBoolean("mobs.witch.always-drop-exp", witchAlwaysDropExp); + } + + public boolean witherRidable = false; + public boolean witherRidableInWater = true; + public boolean witherControllable = true; + public double witherMaxY = 320D; + public double witherMaxHealth = 300.0D; + public double witherScale = 1.0D; + public float witherHealthRegenAmount = 1.0f; + public int witherHealthRegenDelay = 20; + public boolean witherBypassMobGriefing = false; + public boolean witherTakeDamageFromWater = false; + public boolean witherCanRideVehicles = false; + public float witherExplosionRadius = 1.0F; + public boolean witherPlaySpawnSound = true; + public boolean witherAlwaysDropExp = false; + private void witherSettings() { + witherRidable = getBoolean("mobs.wither.ridable", witherRidable); + witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); + witherControllable = getBoolean("mobs.wither.controllable", witherControllable); + witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); + if (PurpurConfig.version < 8) { + double oldValue = getDouble("mobs.wither.max-health", witherMaxHealth); + set("mobs.wither.max_health", null); + set("mobs.wither.attributes.max-health", oldValue); + } else if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.wither.attributes.max-health", witherMaxHealth); + set("mobs.wither.attributes.max-health", null); + set("mobs.wither.attributes.max_health", oldValue); + } + witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth); + witherScale = Mth.clamp(getDouble("mobs.wither.attributes.scale", witherScale), 0.0625D, 16.0D); + witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount); + witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); + witherBypassMobGriefing = getBoolean("mobs.wither.bypass-mob-griefing", witherBypassMobGriefing); + witherTakeDamageFromWater = getBoolean("mobs.wither.takes-damage-from-water", witherTakeDamageFromWater); + witherCanRideVehicles = getBoolean("mobs.wither.can-ride-vehicles", witherCanRideVehicles); + witherExplosionRadius = (float) getDouble("mobs.wither.explosion-radius", witherExplosionRadius); + witherPlaySpawnSound = getBoolean("mobs.wither.play-spawn-sound", witherPlaySpawnSound); + witherAlwaysDropExp = getBoolean("mobs.wither.always-drop-exp", witherAlwaysDropExp); + } + + public boolean witherSkeletonRidable = false; + public boolean witherSkeletonRidableInWater = true; + public boolean witherSkeletonControllable = true; + public double witherSkeletonMaxHealth = 20.0D; + public double witherSkeletonScale = 1.0D; + public boolean witherSkeletonTakeDamageFromWater = false; + public boolean witherSkeletonAlwaysDropExp = false; + private void witherSkeletonSettings() { + witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable); + witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater); + witherSkeletonControllable = getBoolean("mobs.wither_skeleton.controllable", witherSkeletonControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.wither_skeleton.attributes.max-health", witherSkeletonMaxHealth); + set("mobs.wither_skeleton.attributes.max-health", null); + set("mobs.wither_skeleton.attributes.max_health", oldValue); + } + witherSkeletonMaxHealth = getDouble("mobs.wither_skeleton.attributes.max_health", witherSkeletonMaxHealth); + witherSkeletonScale = Mth.clamp(getDouble("mobs.wither_skeleton.attributes.scale", witherSkeletonScale), 0.0625D, 16.0D); + witherSkeletonTakeDamageFromWater = getBoolean("mobs.wither_skeleton.takes-damage-from-water", witherSkeletonTakeDamageFromWater); + witherSkeletonAlwaysDropExp = getBoolean("mobs.wither_skeleton.always-drop-exp", witherSkeletonAlwaysDropExp); + } + + public boolean wolfRidable = false; + public boolean wolfRidableInWater = true; + public boolean wolfControllable = true; + public double wolfMaxHealth = 8.0D; + public double wolfScale = 1.0D; + public DyeColor wolfDefaultCollarColor = DyeColor.RED; + public boolean wolfMilkCuresRabies = true; + public double wolfNaturalRabid = 0.0D; + public int wolfBreedingTicks = 6000; + public boolean wolfTakeDamageFromWater = false; + public boolean wolfAlwaysDropExp = false; + private void wolfSettings() { + wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); + wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); + wolfControllable = getBoolean("mobs.wolf.controllable", wolfControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.wolf.attributes.max-health", wolfMaxHealth); + set("mobs.wolf.attributes.max-health", null); + set("mobs.wolf.attributes.max_health", oldValue); + } + wolfMaxHealth = getDouble("mobs.wolf.attributes.max_health", wolfMaxHealth); + wolfScale = Mth.clamp(getDouble("mobs.wolf.attributes.scale", wolfScale), 0.0625D, 16.0D); + try { + wolfDefaultCollarColor = DyeColor.valueOf(getString("mobs.wolf.default-collar-color", wolfDefaultCollarColor.name())); + } catch (IllegalArgumentException ignore) { + wolfDefaultCollarColor = DyeColor.RED; + } + wolfMilkCuresRabies = getBoolean("mobs.wolf.milk-cures-rabid-wolves", wolfMilkCuresRabies); + wolfNaturalRabid = getDouble("mobs.wolf.spawn-rabid-chance", wolfNaturalRabid); + wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks); + wolfTakeDamageFromWater = getBoolean("mobs.wolf.takes-damage-from-water", wolfTakeDamageFromWater); + wolfAlwaysDropExp = getBoolean("mobs.wolf.always-drop-exp", wolfAlwaysDropExp); + } + + public boolean zoglinRidable = false; + public boolean zoglinRidableInWater = true; + public boolean zoglinControllable = true; + public double zoglinMaxHealth = 40.0D; + public double zoglinScale = 1.0D; + public boolean zoglinTakeDamageFromWater = false; + public boolean zoglinAlwaysDropExp = false; + private void zoglinSettings() { + zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable); + zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater); + zoglinControllable = getBoolean("mobs.zoglin.controllable", zoglinControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.zoglin.attributes.max-health", zoglinMaxHealth); + set("mobs.zoglin.attributes.max-health", null); + set("mobs.zoglin.attributes.max_health", oldValue); + } + zoglinMaxHealth = getDouble("mobs.zoglin.attributes.max_health", zoglinMaxHealth); + zoglinScale = Mth.clamp(getDouble("mobs.zoglin.attributes.scale", zoglinScale), 0.0625D, 16.0D); + zoglinTakeDamageFromWater = getBoolean("mobs.zoglin.takes-damage-from-water", zoglinTakeDamageFromWater); + zoglinAlwaysDropExp = getBoolean("mobs.zoglin.always-drop-exp", zoglinAlwaysDropExp); + } + + public boolean zombieRidable = false; + public boolean zombieRidableInWater = true; + public boolean zombieControllable = true; + public double zombieMaxHealth = 20.0D; + public double zombieScale = 1.0D; + public double zombieSpawnReinforcements = 0.1D; + public boolean zombieJockeyOnlyBaby = true; + public double zombieJockeyChance = 0.05D; + public boolean zombieJockeyTryExistingChickens = true; + public boolean zombieAggressiveTowardsVillagerWhenLagging = true; + public boolean zombieBypassMobGriefing = false; + public boolean zombieTakeDamageFromWater = false; + public boolean zombieAlwaysDropExp = false; + public double zombieHeadVisibilityPercent = 0.5D; + private void zombieSettings() { + zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); + zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); + zombieControllable = getBoolean("mobs.zombie.controllable", zombieControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.zombie.attributes.max-health", zombieMaxHealth); + set("mobs.zombie.attributes.max-health", null); + set("mobs.zombie.attributes.max_health", oldValue); + } + zombieMaxHealth = getDouble("mobs.zombie.attributes.max_health", zombieMaxHealth); + zombieScale = Mth.clamp(getDouble("mobs.zombie.attributes.scale", zombieScale), 0.0625D, 16.0D); + zombieSpawnReinforcements = getDouble("mobs.zombie.attributes.spawn_reinforcements", zombieSpawnReinforcements); + zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby); + zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); + zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); + zombieAggressiveTowardsVillagerWhenLagging = getBoolean("mobs.zombie.aggressive-towards-villager-when-lagging", zombieAggressiveTowardsVillagerWhenLagging); + zombieBypassMobGriefing = getBoolean("mobs.zombie.bypass-mob-griefing", zombieBypassMobGriefing); + zombieTakeDamageFromWater = getBoolean("mobs.zombie.takes-damage-from-water", zombieTakeDamageFromWater); + zombieAlwaysDropExp = getBoolean("mobs.zombie.always-drop-exp", zombieAlwaysDropExp); + zombieHeadVisibilityPercent = getDouble("mobs.zombie.head-visibility-percent", zombieHeadVisibilityPercent); + } + + public boolean zombieHorseRidable = false; + public boolean zombieHorseRidableInWater = false; + public boolean zombieHorseCanSwim = false; + public double zombieHorseMaxHealthMin = 15.0D; + public double zombieHorseMaxHealthMax = 15.0D; + public double zombieHorseJumpStrengthMin = 0.4D; + public double zombieHorseJumpStrengthMax = 1.0D; + public double zombieHorseMovementSpeedMin = 0.2D; + public double zombieHorseMovementSpeedMax = 0.2D; + public double zombieHorseSpawnChance = 0.0D; + public boolean zombieHorseTakeDamageFromWater = false; + public boolean zombieHorseAlwaysDropExp = false; + private void zombieHorseSettings() { + zombieHorseRidable = getBoolean("mobs.zombie_horse.ridable", zombieHorseRidable); + zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); + zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.zombie_horse.attributes.max-health", zombieHorseMaxHealthMin); + set("mobs.zombie_horse.attributes.max-health", null); + set("mobs.zombie_horse.attributes.max_health.min", oldValue); + set("mobs.zombie_horse.attributes.max_health.max", oldValue); + } + zombieHorseMaxHealthMin = getDouble("mobs.zombie_horse.attributes.max_health.min", zombieHorseMaxHealthMin); + zombieHorseMaxHealthMax = getDouble("mobs.zombie_horse.attributes.max_health.max", zombieHorseMaxHealthMax); + zombieHorseJumpStrengthMin = getDouble("mobs.zombie_horse.attributes.jump_strength.min", zombieHorseJumpStrengthMin); + zombieHorseJumpStrengthMax = getDouble("mobs.zombie_horse.attributes.jump_strength.max", zombieHorseJumpStrengthMax); + zombieHorseMovementSpeedMin = getDouble("mobs.zombie_horse.attributes.movement_speed.min", zombieHorseMovementSpeedMin); + zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax); + zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); + zombieHorseTakeDamageFromWater = getBoolean("mobs.zombie_horse.takes-damage-from-water", zombieHorseTakeDamageFromWater); + zombieHorseAlwaysDropExp = getBoolean("mobs.zombie_horse.always-drop-exp", zombieHorseAlwaysDropExp); + } + + public boolean zombieVillagerRidable = false; + public boolean zombieVillagerRidableInWater = true; + public boolean zombieVillagerControllable = true; + public double zombieVillagerMaxHealth = 20.0D; + public double zombieVillagerScale = 1.0D; + public double zombieVillagerSpawnReinforcements = 0.1D; + public boolean zombieVillagerJockeyOnlyBaby = true; + public double zombieVillagerJockeyChance = 0.05D; + public boolean zombieVillagerJockeyTryExistingChickens = true; + public boolean zombieVillagerTakeDamageFromWater = false; + public int zombieVillagerCuringTimeMin = 3600; + public int zombieVillagerCuringTimeMax = 6000; + public boolean zombieVillagerCureEnabled = true; + public boolean zombieVillagerAlwaysDropExp = false; + private void zombieVillagerSettings() { + zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); + zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); + zombieVillagerControllable = getBoolean("mobs.zombie_villager.controllable", zombieVillagerControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.zombie_villager.attributes.max-health", zombieVillagerMaxHealth); + set("mobs.zombie_villager.attributes.max-health", null); + set("mobs.zombie_villager.attributes.max_health", oldValue); + } + zombieVillagerMaxHealth = getDouble("mobs.zombie_villager.attributes.max_health", zombieVillagerMaxHealth); + zombieVillagerScale = Mth.clamp(getDouble("mobs.zombie_villager.attributes.scale", zombieVillagerScale), 0.0625D, 16.0D); + zombieVillagerSpawnReinforcements = getDouble("mobs.zombie_villager.attributes.spawn_reinforcements", zombieVillagerSpawnReinforcements); + zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby); + zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance); + zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens); + zombieVillagerTakeDamageFromWater = getBoolean("mobs.zombie_villager.takes-damage-from-water", zombieVillagerTakeDamageFromWater); + zombieVillagerCuringTimeMin = getInt("mobs.zombie_villager.curing_time.min", zombieVillagerCuringTimeMin); + zombieVillagerCuringTimeMax = getInt("mobs.zombie_villager.curing_time.max", zombieVillagerCuringTimeMax); + zombieVillagerCureEnabled = getBoolean("mobs.zombie_villager.cure.enabled", zombieVillagerCureEnabled); + zombieVillagerAlwaysDropExp = getBoolean("mobs.zombie_villager.always-drop-exp", zombieVillagerAlwaysDropExp); + } + + public boolean zombifiedPiglinRidable = false; + public boolean zombifiedPiglinRidableInWater = true; + public boolean zombifiedPiglinControllable = true; + public double zombifiedPiglinMaxHealth = 20.0D; + public double zombifiedPiglinScale = 1.0D; + public double zombifiedPiglinSpawnReinforcements = 0.0D; + public boolean zombifiedPiglinJockeyOnlyBaby = true; + public double zombifiedPiglinJockeyChance = 0.05D; + public boolean zombifiedPiglinJockeyTryExistingChickens = true; + public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = true; + public boolean zombifiedPiglinTakeDamageFromWater = false; + public boolean zombifiedPiglinAlwaysDropExp = false; + private void zombifiedPiglinSettings() { + zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); + zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); + zombifiedPiglinControllable = getBoolean("mobs.zombified_piglin.controllable", zombifiedPiglinControllable); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.zombified_piglin.attributes.max-health", zombifiedPiglinMaxHealth); + set("mobs.zombified_piglin.attributes.max-health", null); + set("mobs.zombified_piglin.attributes.max_health", oldValue); + } + zombifiedPiglinMaxHealth = getDouble("mobs.zombified_piglin.attributes.max_health", zombifiedPiglinMaxHealth); + zombifiedPiglinScale = Mth.clamp(getDouble("mobs.zombified_piglin.attributes.scale", zombifiedPiglinScale), 0.0625D, 16.0D); + zombifiedPiglinSpawnReinforcements = getDouble("mobs.zombified_piglin.attributes.spawn_reinforcements", zombifiedPiglinSpawnReinforcements); + zombifiedPiglinJockeyOnlyBaby = getBoolean("mobs.zombified_piglin.jockey.only-babies", zombifiedPiglinJockeyOnlyBaby); + zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance); + zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); + zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry); + zombifiedPiglinTakeDamageFromWater = getBoolean("mobs.zombified_piglin.takes-damage-from-water", zombifiedPiglinTakeDamageFromWater); + zombifiedPiglinAlwaysDropExp = getBoolean("mobs.zombified_piglin.always-drop-exp", zombifiedPiglinAlwaysDropExp); + } + + public float hungerStarvationDamage = 1.0F; + private void hungerSettings() { + hungerStarvationDamage = (float) getDouble("hunger.starvation-damage", hungerStarvationDamage); + } + + public int conduitDistance = 16; + public double conduitDamageDistance = 8; + public float conduitDamageAmount = 4; + public Block[] conduitBlocks; + private void conduitSettings() { + conduitDistance = getInt("blocks.conduit.effect-distance", conduitDistance); + conduitDamageDistance = getDouble("blocks.conduit.mob-damage.distance", conduitDamageDistance); + conduitDamageAmount = (float) getDouble("blocks.conduit.mob-damage.damage-amount", conduitDamageAmount); + List conduitBlockList = new ArrayList<>(); + getList("blocks.conduit.valid-ring-blocks", new ArrayList(){{ + add("minecraft:prismarine"); + add("minecraft:prismarine_bricks"); + add("minecraft:sea_lantern"); + add("minecraft:dark_prismarine"); + }}).forEach(key -> { + Block block = BuiltInRegistries.BLOCK.getValue(ResourceLocation.parse(key.toString())); + if (!block.defaultBlockState().isAir()) { + conduitBlockList.add(block); + } + }); + conduitBlocks = conduitBlockList.toArray(Block[]::new); + } + + public float cauldronRainChance = 0.05F; + public float cauldronPowderSnowChance = 0.1F; + public float cauldronDripstoneWaterFillChance = 0.17578125F; + public float cauldronDripstoneLavaFillChance = 0.05859375F; + private void cauldronSettings() { + cauldronRainChance = (float) getDouble("blocks.cauldron.fill-chances.rain", cauldronRainChance); + cauldronPowderSnowChance = (float) getDouble("blocks.cauldron.fill-chances.powder-snow", cauldronPowderSnowChance); + cauldronDripstoneWaterFillChance = (float) getDouble("blocks.cauldron.fill-chances.dripstone-water", cauldronDripstoneWaterFillChance); + cauldronDripstoneLavaFillChance = (float) getDouble("blocks.cauldron.fill-chances.dripstone-lava", cauldronDripstoneLavaFillChance); + } + + public float shearsCanDefuseTntChance = 0.00F; + public boolean shearsCanDefuseTnt = false; + private void shearsCanDefuseTntSettings() { + shearsCanDefuseTntChance = (float) getDouble("gameplay-mechanics.item.shears.defuse-tnt-chance", 0.00D); + shearsCanDefuseTnt = shearsCanDefuseTntChance > 0.00F; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/CompassCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/CompassCommand.java new file mode 100644 index 000000000..79b849083 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/CompassCommand.java @@ -0,0 +1,27 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.server.level.ServerPlayer; +import org.purpurmc.purpur.task.CompassTask; + +public class CompassCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("compass") + .requires(listener -> listener.hasPermission(2, "bukkit.command.compass")) + .executes(context -> { + ServerPlayer player = context.getSource().getPlayerOrException(); + CompassTask task = CompassTask.instance(); + if (player.compassBar()) { + task.removePlayer(player.getBukkitEntity()); + player.compassBar(false); + } else { + task.addPlayer(player.getBukkitEntity()); + player.compassBar(true); + } + return 1; + }) + ); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java new file mode 100644 index 000000000..40d2fab4a --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/CreditsCommand.java @@ -0,0 +1,35 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.network.protocol.game.ClientboundGameEventPacket; +import net.minecraft.server.level.ServerPlayer; +import org.purpurmc.purpur.PurpurConfig; + +import java.util.Collection; +import java.util.Collections; + +public class CreditsCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("credits") + .requires((listener) -> listener.hasPermission(2, "bukkit.command.credits")) + .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) + .then(Commands.argument("targets", EntityArgument.players()) + .requires(listener -> listener.hasPermission(2, "bukkit.command.credits.other")) + .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) + ) + ); + } + + private static int execute(CommandSourceStack sender, Collection targets) { + for (ServerPlayer player : targets) { + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1F); + player.connection.send(packet); + String output = String.format(PurpurConfig.creditsCommandOutput, player.getGameProfile().getName()); + sender.sendSuccess(output, false); + } + return targets.size(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/DemoCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/DemoCommand.java new file mode 100644 index 000000000..235f3cd89 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/DemoCommand.java @@ -0,0 +1,35 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.network.protocol.game.ClientboundGameEventPacket; +import net.minecraft.server.level.ServerPlayer; +import org.purpurmc.purpur.PurpurConfig; + +import java.util.Collection; +import java.util.Collections; + +public class DemoCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("demo") + .requires((listener) -> listener.hasPermission(2, "bukkit.command.demo")) + .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) + .then(Commands.argument("targets", EntityArgument.players()) + .requires(listener -> listener.hasPermission(2, "bukkit.command.demo.other")) + .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) + ) + ); + } + + private static int execute(CommandSourceStack sender, Collection targets) { + for (ServerPlayer player : targets) { + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.DEMO_EVENT, 0); + player.connection.send(packet); + String output = String.format(PurpurConfig.demoCommandOutput, player.getGameProfile().getName()); + sender.sendSuccess(output, false); + } + return targets.size(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/PingCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/PingCommand.java new file mode 100644 index 000000000..74a602c33 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/PingCommand.java @@ -0,0 +1,32 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.server.level.ServerPlayer; +import org.purpurmc.purpur.PurpurConfig; + +import java.util.Collection; +import java.util.Collections; + +public class PingCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("ping") + .requires((listener) -> listener.hasPermission(2, "bukkit.command.ping")) + .executes((context) -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) + .then(Commands.argument("targets", EntityArgument.players()) + .requires(listener -> listener.hasPermission(2, "bukkit.command.ping.other")) + .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) + ) + ); + } + + private static int execute(CommandSourceStack sender, Collection targets) { + for (ServerPlayer player : targets) { + String output = String.format(PurpurConfig.pingCommandOutput, player.getGameProfile().getName(), player.connection.latency()); + sender.sendSuccess(output, false); + } + return targets.size(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java new file mode 100644 index 000000000..7163c8247 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/PurpurCommand.java @@ -0,0 +1,66 @@ +package org.purpurmc.purpur.command; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import org.purpurmc.purpur.PurpurConfig; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +import java.io.File; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class PurpurCommand extends Command { + public PurpurCommand(String name) { + super(name); + this.description = "Purpur related commands"; + this.usageMessage = "/purpur [reload | version]"; + this.setPermission("bukkit.command.purpur"); + } + + @Override + public List tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { + if (args.length == 1) { + return Stream.of("reload", "version") + .filter(arg -> arg.startsWith(args[0].toLowerCase())) + .collect(Collectors.toList()); + } + return Collections.emptyList(); + } + + @Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + if (!testPermission(sender)) return true; + + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + if (args[0].equalsIgnoreCase("reload")) { + Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues."); + Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server."); + + MinecraftServer console = MinecraftServer.getServer(); + PurpurConfig.init((File) console.options.valueOf("purpur-settings")); + for (ServerLevel level : console.getAllLevels()) { + level.purpurConfig.init(); + level.resetBreedingCooldowns(); // Purpur - Add adjustable breeding cooldown to config + } + console.server.reloadCount++; + + Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Purpur config reload complete."); + } else if (args[0].equalsIgnoreCase("version")) { + Command verCmd = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version"); + if (verCmd != null) { + return verCmd.execute(sender, commandLabel, new String[0]); + } + } + + return true; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/RamBarCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/RamBarCommand.java new file mode 100644 index 000000000..2852c07ad --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/RamBarCommand.java @@ -0,0 +1,44 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.server.level.ServerPlayer; +import org.purpurmc.purpur.PurpurConfig; +import org.purpurmc.purpur.task.RamBarTask; + +import java.util.Collection; +import java.util.Collections; + +public class RamBarCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("rambar") + .requires(listener -> listener.hasPermission(2, "bukkit.command.rambar")) + .executes(context -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) + .then(Commands.argument("targets", EntityArgument.players()) + .requires(listener -> listener.hasPermission(2, "bukkit.command.rambar.other")) + .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) + ) + ); + } + + private static int execute(CommandSourceStack sender, Collection targets) { + for (ServerPlayer player : targets) { + boolean result = RamBarTask.instance().togglePlayer(player.getBukkitEntity()); + player.ramBar(result); + + Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.rambarCommandOutput, + Placeholder.component("onoff", Component.translatable(result ? "options.on" : "options.off") + .color(result ? NamedTextColor.GREEN : NamedTextColor.RED)), + Placeholder.parsed("target", player.getGameProfile().getName())); + + sender.sendSuccess(output, false); + } + return targets.size(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/RamCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/RamCommand.java new file mode 100644 index 000000000..992f8dfc6 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/RamCommand.java @@ -0,0 +1,30 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import io.papermc.paper.adventure.PaperAdventure; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import org.purpurmc.purpur.PurpurConfig; +import org.purpurmc.purpur.task.RamBarTask; + +public class RamCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("ram") + .requires(listener -> listener.hasPermission(2, "bukkit.command.ram")) + .executes(context -> { + CommandSourceStack sender = context.getSource(); + RamBarTask ramBar = RamBarTask.instance(); + sender.sendSuccess(() -> PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(PurpurConfig.ramCommandOutput, + Placeholder.component("allocated", ramBar.format(ramBar.getAllocated())), + Placeholder.component("used", ramBar.format(ramBar.getUsed())), + Placeholder.component("xmx", ramBar.format(ramBar.getXmx())), + Placeholder.component("xms", ramBar.format(ramBar.getXms())), + Placeholder.unparsed("percent", ((int) (ramBar.getPercent() * 100)) + "%") + )), false); + return 1; + }) + ); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java new file mode 100644 index 000000000..d8f9b0441 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/TPSBarCommand.java @@ -0,0 +1,44 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.server.level.ServerPlayer; +import org.purpurmc.purpur.PurpurConfig; +import org.purpurmc.purpur.task.TPSBarTask; + +import java.util.Collection; +import java.util.Collections; + +public class TPSBarCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("tpsbar") + .requires(listener -> listener.hasPermission(2, "bukkit.command.tpsbar")) + .executes(context -> execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException()))) + .then(Commands.argument("targets", EntityArgument.players()) + .requires(listener -> listener.hasPermission(2, "bukkit.command.tpsbar.other")) + .executes((context) -> execute(context.getSource(), EntityArgument.getPlayers(context, "targets"))) + ) + ); + } + + private static int execute(CommandSourceStack sender, Collection targets) { + for (ServerPlayer player : targets) { + boolean result = TPSBarTask.instance().togglePlayer(player.getBukkitEntity()); + player.tpsBar(result); + + Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.tpsbarCommandOutput, + Placeholder.component("onoff", Component.translatable(result ? "options.on" : "options.off") + .color(result ? NamedTextColor.GREEN : NamedTextColor.RED)), + Placeholder.parsed("target", player.getGameProfile().getName())); + + sender.sendSuccess(output, false); + } + return targets.size(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java b/purpur-server/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java new file mode 100644 index 000000000..4bb475099 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/command/UptimeCommand.java @@ -0,0 +1,55 @@ +package org.purpurmc.purpur.command; + +import com.mojang.brigadier.CommandDispatcher; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.server.MinecraftServer; +import org.purpurmc.purpur.PurpurConfig; + +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +public class UptimeCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("uptime") + .requires((listener) -> listener.hasPermission(2, "bukkit.command.uptime")) + .executes((context) -> execute(context.getSource())) + ); + } + + private static int execute(CommandSourceStack sender) { + Data data = new Data(); + + data.format = PurpurConfig.uptimeFormat; + data.hide = true; + data.millis = System.currentTimeMillis() - MinecraftServer.startTimeMillis; + + process(data, "", PurpurConfig.uptimeDay, PurpurConfig.uptimeDays, TimeUnit.DAYS, TimeUnit.MILLISECONDS::toDays); + process(data, "", PurpurConfig.uptimeHour, PurpurConfig.uptimeHours, TimeUnit.HOURS, TimeUnit.MILLISECONDS::toHours); + process(data, "", PurpurConfig.uptimeMinute, PurpurConfig.uptimeMinutes, TimeUnit.MINUTES, TimeUnit.MILLISECONDS::toMinutes); + data.hide = false; // never hide seconds + process(data, "", PurpurConfig.uptimeSecond, PurpurConfig.uptimeSeconds, TimeUnit.SECONDS, TimeUnit.MILLISECONDS::toSeconds); + + Component output = MiniMessage.miniMessage().deserialize(PurpurConfig.uptimeCommandOutput, Placeholder.unparsed("uptime", data.format)); + sender.sendSuccess(output, false); + return 1; + } + + private static void process(Data data, String replace, String singular, String plural, TimeUnit unit, Function func) { + if (data.format.contains(replace)) { + long val = func.apply(data.millis); + if (data.hide) data.hide = val == 0; + if (!data.hide) data.millis -= unit.toMillis(val); + data.format = data.format.replace(replace, data.hide ? "" : String.format(val == 1 ? singular : plural, val)); + } + } + + private static class Data { + String format; + boolean hide; + long millis; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java b/purpur-server/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java new file mode 100644 index 000000000..940bcc6f7 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/controller/FlyingMoveControllerWASD.java @@ -0,0 +1,74 @@ +package org.purpurmc.purpur.controller; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Input; +import net.minecraft.world.entity.player.Player; + +public class FlyingMoveControllerWASD extends MoveControllerWASD { + protected final float groundSpeedModifier; + protected final float flyingSpeedModifier; + protected int tooHighCooldown = 0; + protected boolean setNoGravityFlag; + + public FlyingMoveControllerWASD(Mob entity) { + this(entity, 1.0F); + } + + public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier) { + this(entity, groundSpeedModifier, 1.0F, true); + } + + public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier, float flyingSpeedModifier) { + this(entity, groundSpeedModifier, flyingSpeedModifier, true); + } + + public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier, float flyingSpeedModifier, boolean setNoGravityFlag) { + super(entity); + this.groundSpeedModifier = groundSpeedModifier; + this.flyingSpeedModifier = flyingSpeedModifier; + this.setNoGravityFlag = setNoGravityFlag; + } + + @Override + public void purpurTick(Player rider) { + Input lastClientInput = ((ServerPlayer) rider).getLastClientInput(); + float forward = lastClientInput.forward() == lastClientInput.backward() ? 0.0F : lastClientInput.forward() ? 1.0F : 0.0F; + float vertical = forward == 0.0F ? 0.0F : -(rider.xRotO / 45.0F); + float strafe = (lastClientInput.left() == lastClientInput.right() ? 0.0F : lastClientInput.left() ? 1.0F : -1.0F); + + if (lastClientInput.jump() && spacebarEvent(entity)) { + entity.onSpacebar(); + } + + if (entity.getY() >= entity.getMaxY() || --tooHighCooldown > 0) { + if (tooHighCooldown <= 0) { + tooHighCooldown = 20; + } + entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, -0.05D, 0.0D)); + vertical = 0.0F; + } + + setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED)); + float speed = (float) getSpeedModifier(); + + if (entity.onGround) { + speed *= groundSpeedModifier; // TODO = fix this! + } else { + speed *= flyingSpeedModifier; + } + + if (setNoGravityFlag) { + entity.setNoGravity(forward > 0); + } + + entity.setSpeed(speed); + entity.setVerticalMot(vertical); + entity.setStrafeMot(strafe); + entity.setForwardMot(forward); + + setForward(entity.getForwardMot()); + setStrafe(entity.getStrafeMot()); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java b/purpur-server/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java new file mode 100644 index 000000000..e0bbaec05 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java @@ -0,0 +1,66 @@ +package org.purpurmc.purpur.controller; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Input; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +public class FlyingWithSpacebarMoveControllerWASD extends FlyingMoveControllerWASD { + public FlyingWithSpacebarMoveControllerWASD(Mob entity) { + super(entity); + } + + public FlyingWithSpacebarMoveControllerWASD(Mob entity, float groundSpeedModifier) { + super(entity, groundSpeedModifier); + } + + @Override + public void purpurTick(Player rider) { + Input lastClientInput = ((ServerPlayer) rider).getLastClientInput(); + float forward = (lastClientInput.forward() == lastClientInput.backward() ? 0.0F : lastClientInput.forward() ? 1.0F : -1.0F); + float strafe = (lastClientInput.left() == lastClientInput.right() ? 0.0F : lastClientInput.left() ? 1.0F : -1.0F) * 0.5F; + float vertical = 0; + + if (forward < 0.0F) { + forward *= 0.5F; + strafe *= 0.5F; + } + + float speed = (float) entity.getAttributeValue(Attributes.MOVEMENT_SPEED); + + if (entity.onGround) { + speed *= groundSpeedModifier; + } + + if (lastClientInput.jump() && spacebarEvent(entity) && !entity.onSpacebar()) { + entity.setNoGravity(true); + vertical = 1.0F; + } else { + entity.setNoGravity(false); + } + + if (entity.getY() >= entity.getMaxY() || --tooHighCooldown > 0) { + if (tooHighCooldown <= 0) { + tooHighCooldown = 20; + } + entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, -0.2D, 0.0D)); + vertical = 0.0F; + } + + setSpeedModifier(speed); + entity.setSpeed((float) getSpeedModifier()); + entity.setVerticalMot(vertical); + entity.setStrafeMot(strafe); + entity.setForwardMot(forward); + + setForward(entity.getForwardMot()); + setStrafe(entity.getStrafeMot()); + + Vec3 mot = entity.getDeltaMovement(); + if (mot.y > 0.2D) { + entity.setDeltaMovement(mot.x, 0.2D, mot.z); + } + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java b/purpur-server/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java new file mode 100644 index 000000000..dd2195181 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/controller/LookControllerWASD.java @@ -0,0 +1,79 @@ +package org.purpurmc.purpur.controller; + + +import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.control.LookControl; +import net.minecraft.world.entity.player.Player; + +public class LookControllerWASD extends LookControl { + protected final Mob entity; + private float yOffset = 0; + private float xOffset = 0; + + public LookControllerWASD(Mob entity) { + super(entity); + this.entity = entity; + } + + // tick + @Override + public void tick() { + if (entity.getRider() != null && entity.isControllable()) { + purpurTick(entity.getRider()); + } else { + vanillaTick(); + } + } + + protected void purpurTick(Player rider) { + setYawPitch(rider.getYRot(), rider.getXRot()); + } + + public void vanillaTick() { + super.tick(); + } + + public void setYawPitch(float yRot, float xRot) { + entity.setXRot(normalizePitch(xRot + xOffset)); + entity.setYRot(normalizeYaw(yRot + yOffset)); + entity.setYHeadRot(entity.getYRot()); + entity.xRotO = entity.getXRot(); + entity.yRotO = entity.getYRot(); + + ClientboundMoveEntityPacket.PosRot entityPacket = new ClientboundMoveEntityPacket.PosRot( + entity.getId(), + (short) 0, (short) 0, (short) 0, + (byte) Mth.floor(entity.getYRot() * 256.0F / 360.0F), + (byte) Mth.floor(entity.getXRot() * 256.0F / 360.0F), + entity.onGround + ); + ((ServerLevel) entity.level()).getChunkSource().broadcast(entity, entityPacket); + } + + public void setOffsets(float yaw, float pitch) { + yOffset = yaw; + xOffset = pitch; + } + + public float normalizeYaw(float yaw) { + yaw %= 360.0f; + if (yaw >= 180.0f) { + yaw -= 360.0f; + } else if (yaw < -180.0f) { + yaw += 360.0f; + } + return yaw; + } + + public float normalizePitch(float pitch) { + if (pitch > 90.0f) { + pitch = 90.0f; + } else if (pitch < -90.0f) { + pitch = -90.0f; + } + return pitch; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java b/purpur-server/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java new file mode 100644 index 000000000..34f3c43fa --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/controller/MoveControllerWASD.java @@ -0,0 +1,92 @@ +package org.purpurmc.purpur.controller; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.ai.control.MoveControl; +import net.minecraft.world.entity.player.Input; +import net.minecraft.world.entity.player.Player; +import org.purpurmc.purpur.event.entity.RidableSpacebarEvent; + +public class MoveControllerWASD extends MoveControl { + protected final Mob entity; + private final double speedModifier; + + public MoveControllerWASD(Mob entity) { + this(entity, 1.0D); + } + + public MoveControllerWASD(Mob entity, double speedModifier) { + super(entity); + this.entity = entity; + this.speedModifier = speedModifier; + } + + @Override + public boolean hasWanted() { + return entity.getRider() != null ? strafeForwards != 0 || strafeRight != 0 : super.hasWanted(); + } + + @Override + public void tick() { + if (entity.getRider() != null && entity.isControllable()) { + purpurTick(entity.getRider()); + } else { + vanillaTick(); + } + } + + public void vanillaTick() { + super.tick(); + } + + public void purpurTick(Player rider) { + Input lastClientInput = ((ServerPlayer) rider).getLastClientInput(); + float forward = (lastClientInput.forward() == lastClientInput.backward() ? 0.0F : lastClientInput.forward() ? 1.0F : -1.0F) * 0.5F; + float strafe = (lastClientInput.left() == lastClientInput.right() ? 0.0F : lastClientInput.left() ? 1.0F : -1.0F) * 0.25F; + + if (forward <= 0.0F) { + forward *= 0.5F; + } + + float yawOffset = 0; + if (strafe != 0) { + if (forward == 0) { + yawOffset += strafe > 0 ? -90 : 90; + forward = Math.abs(strafe * 2); + } else { + yawOffset += strafe > 0 ? -30 : 30; + strafe /= 2; + if (forward < 0) { + yawOffset += strafe > 0 ? -110 : 110; + forward *= -1; + } + } + } else if (forward < 0) { + yawOffset -= 180; + forward *= -1; + } + + ((LookControllerWASD) entity.getLookControl()).setOffsets(yawOffset, 0); + + if (lastClientInput.jump() && spacebarEvent(entity) && !entity.onSpacebar() && entity.onGround) { + entity.jumpFromGround(); + } + + setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED) * speedModifier); + + entity.setSpeed((float) getSpeedModifier()); + entity.setForwardMot(forward); + + setForward(entity.getForwardMot()); + setStrafe(entity.getStrafeMot()); + } + + public static boolean spacebarEvent(Mob entity) { + if (RidableSpacebarEvent.getHandlerList().getRegisteredListeners().length > 0) { + return new RidableSpacebarEvent(entity.getBukkitEntity()).callEvent(); + } else { + return true; + } + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java b/purpur-server/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java new file mode 100644 index 000000000..922e48799 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/controller/WaterMoveControllerWASD.java @@ -0,0 +1,53 @@ +package org.purpurmc.purpur.controller; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Input; +import net.minecraft.world.entity.player.Player; + +public class WaterMoveControllerWASD extends MoveControllerWASD { + private final double speedModifier; + + public WaterMoveControllerWASD(Mob entity) { + this(entity, 1.0D); + } + + public WaterMoveControllerWASD(Mob entity, double speedModifier) { + super(entity); + this.speedModifier = speedModifier; + } + + @Override + public void purpurTick(Player rider) { + Input lastClientInput = ((ServerPlayer) rider).getLastClientInput(); + float forward = (lastClientInput.forward() == lastClientInput.backward() ? 0.0F : lastClientInput.forward() ? 1.0F : -1.0F); + float strafe = (lastClientInput.left() == lastClientInput.right() ? 0.0F : lastClientInput.left() ? 1.0F : -1.0F) * 0.5F; // strafe slower by default + float vertical = -(rider.xRotO / 90); + + if (forward == 0.0F) { + // strafe slower if not moving forward + strafe *= 0.5F; + // do not move vertically if not moving forward + vertical = 0.0F; + } else if (forward < 0.0F) { + // water animals can't swim backwards + forward = 0.0F; + vertical = 0.0F; + } + + if (rider.jumping && spacebarEvent(entity)) { + entity.onSpacebar(); + } + + setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED) * speedModifier); + entity.setSpeed((float) getSpeedModifier() * 0.1F); + + entity.setForwardMot(forward * (float) speedModifier); + entity.setStrafeMot(strafe * (float) speedModifier); + entity.setVerticalMot(vertical * (float) speedModifier); + + setForward(entity.getForwardMot()); + setStrafe(entity.getStrafeMot()); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java b/purpur-server/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java new file mode 100644 index 000000000..7608bf098 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/entity/PurpurStoredBee.java @@ -0,0 +1,106 @@ +package org.purpurmc.purpur.entity; + +import io.papermc.paper.adventure.PaperAdventure; +import net.kyori.adventure.text.Component; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.block.entity.BeehiveBlockEntity; +import org.bukkit.block.EntityBlockStorage; +import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; +import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry; +import org.bukkit.entity.Bee; +import org.bukkit.entity.EntityType; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Locale; + +public class PurpurStoredBee implements StoredEntity { + private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); + + private final EntityBlockStorage blockStorage; + private final BeehiveBlockEntity.BeeData handle; + private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(PurpurStoredBee.DATA_TYPE_REGISTRY); + + private Component customName; + + public PurpurStoredBee(BeehiveBlockEntity.BeeData data, EntityBlockStorage blockStorage) { + this.handle = data; + this.blockStorage = blockStorage; + + CompoundTag customData = handle.occupant.entityData().copyTag(); + this.customName = customData.contains("CustomName") + ? PaperAdventure.asAdventure(net.minecraft.network.chat.Component.Serializer.fromJson(customData.getString("CustomName"), MinecraftServer.getDefaultRegistryAccess())) + : null; + + if(customData.contains("BukkitValues", Tag.TAG_COMPOUND)) { + this.persistentDataContainer.putAll(customData.getCompound("BukkitValues")); + } + } + + public BeehiveBlockEntity.BeeData getHandle() { + return handle; + } + + @Override + public @Nullable Component customName() { + return customName; + } + + @Override + public void customName(@Nullable Component customName) { + this.customName = customName; + } + + @Override + public @Nullable String getCustomName() { + return PaperAdventure.asPlain(customName, Locale.US); + } + + @Override + public void setCustomName(@Nullable String name) { + customName(name != null ? Component.text(name) : null); + } + + @Override + public @NotNull PersistentDataContainer getPersistentDataContainer() { + return persistentDataContainer; + } + + @Override + public boolean hasBeenReleased() { + return !blockStorage.getEntities().contains(this); + } + + @Override + public @Nullable Bee release() { + return blockStorage.releaseEntity(this); + } + + @Override + public @Nullable EntityBlockStorage getBlockStorage() { + if(hasBeenReleased()) { + return null; + } + + return blockStorage; + } + + @Override + public @NotNull EntityType getType() { + return EntityType.BEE; + } + + @Override + public void update() { + handle.occupant.entityData().copyTag().put("BukkitValues", this.persistentDataContainer.toTagCompound()); + if(customName == null) { + handle.occupant.entityData().copyTag().remove("CustomName"); + } else { + handle.occupant.entityData().copyTag().putString("CustomName", net.minecraft.network.chat.Component.Serializer.toJson(PaperAdventure.asVanilla(customName), MinecraftServer.getDefaultRegistryAccess())); + } + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java b/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java new file mode 100644 index 000000000..8babdaddd --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/HasRider.java @@ -0,0 +1,20 @@ +package org.purpurmc.purpur.entity.ai; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.goal.Goal; + +import java.util.EnumSet; + +public class HasRider extends Goal { + public final Mob entity; + + public HasRider(Mob entity) { + this.entity = entity; + setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK, Flag.TARGET, Flag.UNKNOWN_BEHAVIOR)); + } + + @Override + public boolean canUse() { + return entity.getRider() != null && entity.isControllable(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java b/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java new file mode 100644 index 000000000..432f4f3d8 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/HorseHasRider.java @@ -0,0 +1,17 @@ +package org.purpurmc.purpur.entity.ai; + +import net.minecraft.world.entity.animal.horse.AbstractHorse; + +public class HorseHasRider extends HasRider { + public final AbstractHorse horse; + + public HorseHasRider(AbstractHorse entity) { + super(entity); + this.horse = entity; + } + + @Override + public boolean canUse() { + return super.canUse() && horse.isSaddled(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java b/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java new file mode 100644 index 000000000..18a95e043 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/LlamaHasRider.java @@ -0,0 +1,17 @@ +package org.purpurmc.purpur.entity.ai; + +import net.minecraft.world.entity.animal.horse.Llama; + +public class LlamaHasRider extends HasRider { + public final Llama llama; + + public LlamaHasRider(Llama entity) { + super(entity); + this.llama = entity; + } + + @Override + public boolean canUse() { + return super.canUse() && llama.isSaddled() && llama.isControllable(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java b/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java new file mode 100644 index 000000000..9660716f4 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/entity/ai/ReceiveFlower.java @@ -0,0 +1,91 @@ +package org.purpurmc.purpur.entity.ai; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ai.goal.Goal; +import net.minecraft.world.entity.animal.IronGolem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Blocks; + +import java.util.EnumSet; +import java.util.UUID; + +public class ReceiveFlower extends Goal { + private final IronGolem irongolem; + private ServerPlayer target; + private int cooldown; + + public ReceiveFlower(IronGolem entity) { + this.irongolem = entity; + setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK)); + } + + @Override + public boolean canUse() { + if (this.irongolem.getOfferFlowerTick() > 0) { + return false; + } + if (!this.irongolem.isAngry()) { + return false; + } + UUID uuid = this.irongolem.getPersistentAngerTarget(); + if (uuid == null) { + return false; + } + Entity target = ((ServerLevel) this.irongolem.level()).getEntity(uuid); + if (!(target instanceof ServerPlayer player)) { + return false; + } + InteractionHand hand = getPoppyHand(player); + if (hand == null) { + return false; + } + removeFlower(player, hand); + this.target = player; + return true; + } + + @Override + public boolean canContinueToUse() { + return this.cooldown > 0; + } + + @Override + public void start() { + this.cooldown = 100; + this.irongolem.stopBeingAngry(); + this.irongolem.offerFlower(true); + } + + @Override + public void stop() { + this.irongolem.offerFlower(false); + this.target = null; + } + + @Override + public void tick() { + this.irongolem.getLookControl().setLookAt(this.target, 30.0F, 30.0F); + --this.cooldown; + } + + private InteractionHand getPoppyHand(ServerPlayer player) { + if (isPoppy(player.getMainHandItem())) { + return InteractionHand.MAIN_HAND; + } + if (isPoppy(player.getOffhandItem())) { + return InteractionHand.OFF_HAND; + } + return null; + } + + private void removeFlower(ServerPlayer player, InteractionHand hand) { + player.setItemInHand(hand, ItemStack.EMPTY); + } + + private boolean isPoppy(ItemStack item) { + return item.getItem() == Blocks.POPPY.asItem(); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/entity/projectile/DolphinSpit.java b/purpur-server/src/main/java/org/purpurmc/purpur/entity/projectile/DolphinSpit.java new file mode 100644 index 000000000..8ffacde04 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/entity/projectile/DolphinSpit.java @@ -0,0 +1,105 @@ +package org.purpurmc.purpur.entity.projectile; + +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.animal.Dolphin; +import net.minecraft.world.entity.projectile.LlamaSpit; +import net.minecraft.world.entity.projectile.ProjectileUtil; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import org.bukkit.event.entity.EntityRemoveEvent; + +public class DolphinSpit extends LlamaSpit { + public LivingEntity dolphin; + public int ticksLived; + + public DolphinSpit(EntityType type, Level world) { + super(type, world); + } + + public DolphinSpit(Level world, Dolphin dolphin) { + this(EntityType.LLAMA_SPIT, world); + this.setOwner(dolphin.getRider() != null ? dolphin.getRider() : dolphin); + this.dolphin = dolphin; + this.setPos( + dolphin.getX() - (double) (dolphin.getBbWidth() + 1.0F) * 0.5 * (double) Mth.sin(dolphin.yBodyRot * (float) (Math.PI / 180.0)), + dolphin.getEyeY() - 0.1F, + dolphin.getZ() + (double) (dolphin.getBbWidth() + 1.0F) * 0.5 * (double) Mth.cos(dolphin.yBodyRot * (float) (Math.PI / 180.0))); + } + + @Override + public boolean canSaveToDisk() { + return false; + } + + public void tick() { + projectileTick(); + + Vec3 mot = this.getDeltaMovement(); + HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); + + this.preHitTargetOrDeflectSelf(hitResult); + + double x = this.getX() + mot.x; + double y = this.getY() + mot.y; + double z = this.getZ() + mot.z; + + this.updateRotation(); + + Vec3 motDouble = mot.scale(2.0); + for (int i = 0; i < 5; i++) { + ((ServerLevel) level()).sendParticlesSource(null, ParticleTypes.BUBBLE, + false, true, + getX() + random.nextFloat() / 2 - 0.25F, + getY() + random.nextFloat() / 2 - 0.25F, + getZ() + random.nextFloat() / 2 - 0.25F, + 0, motDouble.x(), motDouble.y(), motDouble.z(), 0.1D); + } + + if (++ticksLived > 20) { + this.discard(EntityRemoveEvent.Cause.DISCARD); + } else { + this.setDeltaMovement(mot.scale(0.99D)); + if (!this.isNoGravity()) { + this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.06D, 0.0D)); + } + + this.setPos(x, y, z); + } + } + + @Override + public void shoot(double x, double y, double z, float speed, float inaccuracy) { + setDeltaMovement(new Vec3(x, y, z).normalize().add( + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) + .scale(speed)); + } + + @Override + protected void onHitEntity(EntityHitResult entityHitResult) { + Entity shooter = this.getOwner(); + if (shooter instanceof LivingEntity) { + entityHitResult.getEntity().hurt(entityHitResult.getEntity().damageSources().mobProjectile(this, (LivingEntity) shooter), level().purpurConfig.dolphinSpitDamage); + } + } + + @Override + protected void onHitBlock(BlockHitResult blockHitResult) { + if (this.hitCancelled) { + return; + } + BlockState state = this.level().getBlockState(blockHitResult.getBlockPos()); + state.onProjectileHit(this.level(), state, blockHitResult, this); + this.discard(EntityRemoveEvent.Cause.DISCARD); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/entity/projectile/PhantomFlames.java b/purpur-server/src/main/java/org/purpurmc/purpur/entity/projectile/PhantomFlames.java new file mode 100644 index 000000000..580d8dc55 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/entity/projectile/PhantomFlames.java @@ -0,0 +1,127 @@ +package org.purpurmc.purpur.entity.projectile; + +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.monster.Phantom; +import net.minecraft.world.entity.projectile.LlamaSpit; +import net.minecraft.world.entity.projectile.ProjectileUtil; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class PhantomFlames extends LlamaSpit { + public Phantom phantom; + public int ticksLived; + public boolean canGrief = false; + + public PhantomFlames(EntityType type, Level world) { + super(type, world); + } + + public PhantomFlames(Level world, Phantom phantom) { + this(EntityType.LLAMA_SPIT, world); + setOwner(phantom.getRider() != null ? phantom.getRider() : phantom); + this.phantom = phantom; + this.setPos( + phantom.getX() - (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(phantom.yBodyRot * (float) (Math.PI / 180.0)), + phantom.getEyeY() - 0.10000000149011612D, + phantom.getZ() + (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(phantom.yBodyRot * (float) (Math.PI / 180.0))); + } + + @Override + public boolean canSaveToDisk() { + return false; + } + + public void tick() { + projectileTick(); + + Vec3 mot = this.getDeltaMovement(); + HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); + + this.preHitTargetOrDeflectSelf(hitResult); + + double x = this.getX() + mot.x; + double y = this.getY() + mot.y; + double z = this.getZ() + mot.z; + + this.updateRotation(); + + Vec3 motDouble = mot.scale(2.0); + for (int i = 0; i < 5; i++) { + ((ServerLevel) level()).sendParticlesSource(null, ParticleTypes.FLAME, + false, true, + getX() + random.nextFloat() / 2 - 0.25F, + getY() + random.nextFloat() / 2 - 0.25F, + getZ() + random.nextFloat() / 2 - 0.25F, + 0, motDouble.x(), motDouble.y(), motDouble.z(), 0.1D); + } + + if (++ticksLived > 20) { + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + } else if (this.level().getBlockStates(this.getBoundingBox()).noneMatch(BlockBehaviour.BlockStateBase::isAir)) { + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + } else if (this.isInWaterOrBubble()) { + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + } else { + this.setDeltaMovement(mot.scale(0.99D)); + if (!this.isNoGravity()) { + this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.06D, 0.0D)); + } + + this.setPos(x, y, z); + } + } + + @Override + public void shoot(double x, double y, double z, float speed, float inaccuracy) { + setDeltaMovement(new Vec3(x, y, z).normalize().add( + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) + .scale(speed)); + } + + @Override + protected void onHitEntity(EntityHitResult entityHitResult) { + Level world = this.level(); + + if (world instanceof ServerLevel worldserver) { + Entity shooter = this.getOwner(); + if (shooter instanceof LivingEntity) { + Entity target = entityHitResult.getEntity(); + if (canGrief || (target instanceof LivingEntity && !(target instanceof ArmorStand))) { + boolean hurt = target.hurtServer(worldserver, target.damageSources().mobProjectile(this, (LivingEntity) shooter), worldserver.purpurConfig.phantomFlameDamage); + if (hurt && worldserver.purpurConfig.phantomFlameFireTime > 0) { + target.igniteForSeconds(worldserver.purpurConfig.phantomFlameFireTime); + } + } + } + } + } + + @Override + protected void onHitBlock(BlockHitResult blockHitResult) { + Level world = this.level(); + + if (world instanceof ServerLevel worldserver) { + if (this.hitCancelled) { + return; + } + if (this.canGrief) { + BlockState state = worldserver.getBlockState(blockHitResult.getBlockPos()); + state.onProjectileHit(worldserver, state, blockHitResult, this); + } + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + } + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/gui/GUIColor.java b/purpur-server/src/main/java/org/purpurmc/purpur/gui/GUIColor.java new file mode 100644 index 000000000..550222758 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/gui/GUIColor.java @@ -0,0 +1,58 @@ +package org.purpurmc.purpur.gui; + +import net.md_5.bungee.api.ChatColor; + +import java.awt.Color; +import java.util.HashMap; +import java.util.Map; + +public enum GUIColor { + BLACK(ChatColor.BLACK, new Color(0x000000)), + DARK_BLUE(ChatColor.DARK_BLUE, new Color(0x0000AA)), + DARK_GREEN(ChatColor.DARK_GREEN, new Color(0x00AA00)), + DARK_AQUA(ChatColor.DARK_AQUA, new Color(0x009999)), + DARK_RED(ChatColor.DARK_RED, new Color(0xAA0000)), + DARK_PURPLE(ChatColor.DARK_PURPLE, new Color(0xAA00AA)), + GOLD(ChatColor.GOLD, new Color(0xBB8800)), + GRAY(ChatColor.GRAY, new Color(0x888888)), + DARK_GRAY(ChatColor.DARK_GRAY, new Color(0x444444)), + BLUE(ChatColor.BLUE, new Color(0x5555FF)), + GREEN(ChatColor.GREEN, new Color(0x55FF55)), + AQUA(ChatColor.AQUA, new Color(0x55DDDD)), + RED(ChatColor.RED, new Color(0xFF5555)), + LIGHT_PURPLE(ChatColor.LIGHT_PURPLE, new Color(0xFF55FF)), + YELLOW(ChatColor.YELLOW, new Color(0xFFBB00)), + WHITE(ChatColor.WHITE, new Color(0xBBBBBB)); + + private final ChatColor chat; + private final Color color; + + private static final Map BY_CHAT = new HashMap<>(); + + GUIColor(ChatColor chat, Color color) { + this.chat = chat; + this.color = color; + } + + public Color getColor() { + return color; + } + + public ChatColor getChatColor() { + return chat; + } + + public String getCode() { + return chat.toString(); + } + + public static GUIColor getColor(ChatColor chat) { + return BY_CHAT.get(chat); + } + + static { + for (GUIColor color : values()) { + BY_CHAT.put(color.chat, color); + } + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java b/purpur-server/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java new file mode 100644 index 000000000..d75fb5e77 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/gui/JColorTextPane.java @@ -0,0 +1,83 @@ +package org.purpurmc.purpur.gui; + +import com.google.common.collect.Sets; +import javax.swing.UIManager; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; + +import javax.swing.JTextPane; +import javax.swing.Timer; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import java.util.Set; + +public class JColorTextPane extends JTextPane { + private static final GUIColor DEFAULT_COLOR; + static { + DEFAULT_COLOR = UIManager.getSystemLookAndFeelClassName().equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel") + ? GUIColor.WHITE : GUIColor.BLACK; + } + + + public void append(String msg) { + // TODO: update to use adventure instead + BaseComponent[] components = TextComponent.fromLegacyText(DEFAULT_COLOR.getCode() + msg, DEFAULT_COLOR.getChatColor()); + for (BaseComponent component : components) { + String text = component.toPlainText(); + if (text == null || text.isEmpty()) { + continue; + } + + GUIColor guiColor = GUIColor.getColor(component.getColor()); + + StyleContext context = StyleContext.getDefaultStyleContext(); + AttributeSet attr = context.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, guiColor.getColor()); + attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Bold, component.isBold() || guiColor != DEFAULT_COLOR); + attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Italic, component.isItalic()); + attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Underline, component.isUnderlined()); + attr = context.addAttribute(attr, StyleConstants.CharacterConstants.StrikeThrough, component.isStrikethrough()); + //attr = context.addAttribute(attr, StyleConstants.CharacterConstants.Blink, component.isObfuscated()); // no such thing as Blink, sadly + + try { + int pos = getDocument().getLength(); + getDocument().insertString(pos, text, attr); + + if (component.isObfuscated()) { + // dirty hack to blink some text + Blink blink = new Blink(pos, text.length(), attr, context.addAttribute(attr, StyleConstants.Foreground, getBackground())); + BLINKS.add(blink); + } + } catch (BadLocationException ignore) { + } + } + } + + private static final Set BLINKS = Sets.newHashSet(); + private static boolean SYNC_BLINK; + + static { + new Timer(500, e -> { + SYNC_BLINK = !SYNC_BLINK; + BLINKS.forEach(Blink::blink); + }).start(); + } + + public class Blink { + private final int start, length; + private final AttributeSet attr1, attr2; + + private Blink(int start, int length, AttributeSet attr1, AttributeSet attr2) { + this.start = start; + this.length = length; + this.attr1 = attr1; + this.attr2 = attr2; + } + + private void blink() { + getStyledDocument().setCharacterAttributes(start, length, SYNC_BLINK ? attr1 : attr2, true); + } + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java b/purpur-server/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java new file mode 100644 index 000000000..b257f35ca --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/item/GlowBerryItem.java @@ -0,0 +1,26 @@ +package org.purpurmc.purpur.item; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import org.bukkit.event.entity.EntityPotionEffectEvent; + +public class GlowBerryItem extends BlockItem { + public GlowBerryItem(Block block, Properties settings) { + super(block, settings); + } + + @Override + public ItemStack finishUsingItem(ItemStack stack, Level world, LivingEntity user) { + ItemStack result = super.finishUsingItem(stack, world, user); + if (world.purpurConfig.glowBerriesEatGlowDuration > 0 && user instanceof ServerPlayer player) { + player.addEffect(new MobEffectInstance(MobEffects.GLOWING, world.purpurConfig.glowBerriesEatGlowDuration), EntityPotionEffectEvent.Cause.FOOD); + } + return result; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java b/purpur-server/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java new file mode 100644 index 000000000..ed50cb211 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/item/SpawnerItem.java @@ -0,0 +1,40 @@ +package org.purpurmc.purpur.item; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +public class SpawnerItem extends BlockItem { + + public SpawnerItem(Block block, Properties settings) { + super(block, settings); + } + + @Override + protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, Player player, ItemStack stack, BlockState state) { + boolean handled = super.updateCustomBlockEntityTag(pos, level, player, stack, state); + if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.place.spawners")) { + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity instanceof SpawnerBlockEntity spawner) { + CompoundTag customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + if (customData.contains("Purpur.mob_type")) { + EntityType.byString(customData.getString("Purpur.mob_type")).ifPresent(type -> spawner.getSpawner().setEntityId(type, level, level.random, pos)); + } else if (customData.contains("Purpur.SpawnData")) { + net.minecraft.world.level.SpawnData.CODEC.parse(net.minecraft.nbt.NbtOps.INSTANCE, customData.getCompound("Purpur.SpawnData")).result() + .ifPresent(spawnData -> spawner.getSpawner().nextSpawnData = spawnData); + } + } + } + return handled; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java b/purpur-server/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java new file mode 100644 index 000000000..793a3ea45 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/network/ClientboundBeehivePayload.java @@ -0,0 +1,27 @@ +package org.purpurmc.purpur.network; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +public record ClientboundBeehivePayload(BlockPos pos, int numOfBees) implements CustomPacketPayload { + public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ClientboundBeehivePayload::write, ClientboundBeehivePayload::new); + public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("purpur", "beehive_s2c")); + + public ClientboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) { + this(friendlyByteBuf.readBlockPos(), friendlyByteBuf.readInt()); + } + + private void write(FriendlyByteBuf friendlyByteBuf) { + friendlyByteBuf.writeBlockPos(this.pos); + friendlyByteBuf.writeInt(this.numOfBees); + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java b/purpur-server/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java new file mode 100644 index 000000000..fa72769e0 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/network/ServerboundBeehivePayload.java @@ -0,0 +1,26 @@ +package org.purpurmc.purpur.network; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +public record ServerboundBeehivePayload(BlockPos pos) implements CustomPacketPayload { + public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ServerboundBeehivePayload::write, ServerboundBeehivePayload::new); + public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("purpur", "beehive_c2s")); + + public ServerboundBeehivePayload(FriendlyByteBuf friendlyByteBuf) { + this(friendlyByteBuf.readBlockPos()); + } + + private void write(FriendlyByteBuf friendlyByteBuf) { + friendlyByteBuf.writeBlockPos(this.pos); + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java b/purpur-server/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java new file mode 100644 index 000000000..664f9d5e1 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/task/BeehiveTask.java @@ -0,0 +1,67 @@ +package org.purpurmc.purpur.task; + +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.block.entity.BeehiveBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginBase; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; +import org.purpurmc.purpur.network.ClientboundBeehivePayload; +import org.purpurmc.purpur.network.ServerboundBeehivePayload; +import org.purpurmc.purpur.util.MinecraftInternalPlugin; + +public class BeehiveTask implements PluginMessageListener { + + private static BeehiveTask instance; + + public static BeehiveTask instance() { + if (instance == null) { + instance = new BeehiveTask(); + } + return instance; + } + + private final PluginBase plugin = new MinecraftInternalPlugin(); + + private BeehiveTask() { + } + + public void register() { + Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString()); + Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString(), this); + } + + public void unregister() { + Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, ClientboundBeehivePayload.TYPE.id().toString()); + Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, ServerboundBeehivePayload.TYPE.id().toString()); + } + + @Override + public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] bytes) { + FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.copiedBuffer(bytes)); + ServerboundBeehivePayload payload = ServerboundBeehivePayload.STREAM_CODEC.decode(byteBuf); + + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + + // targeted block info max range specified in client at net.minecraft.client.gui.hud.DebugHud#render + if (!payload.pos().getCenter().closerThan(serverPlayer.position(), 20)) return; // Targeted Block info max range is 20 + if (serverPlayer.level().getChunkIfLoaded(payload.pos()) == null) return; + + BlockEntity blockEntity = serverPlayer.level().getBlockEntity(payload.pos()); + if (!(blockEntity instanceof BeehiveBlockEntity beehive)) { + return; + } + + ClientboundBeehivePayload customPacketPayload = new ClientboundBeehivePayload(payload.pos(), beehive.getOccupantCount()); + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); + ClientboundBeehivePayload.STREAM_CODEC.encode(friendlyByteBuf, customPacketPayload); + byte[] byteArray = new byte[friendlyByteBuf.readableBytes()]; + friendlyByteBuf.readBytes(byteArray); + player.sendPluginMessage(this.plugin, customPacketPayload.type().id().toString(), byteArray); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/task/BossBarTask.java b/purpur-server/src/main/java/org/purpurmc/purpur/task/BossBarTask.java new file mode 100644 index 000000000..3c3d4cd52 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/task/BossBarTask.java @@ -0,0 +1,121 @@ +package org.purpurmc.purpur.task; + +import net.kyori.adventure.bossbar.BossBar; +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; +import org.purpurmc.purpur.util.MinecraftInternalPlugin; + +public abstract class BossBarTask extends BukkitRunnable { + private final Map bossbars = new HashMap<>(); + private boolean started; + + abstract BossBar createBossBar(); + + abstract void updateBossBar(BossBar bossbar, Player player); + + @Override + public void run() { + Iterator> iter = bossbars.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + Player player = Bukkit.getPlayer(entry.getKey()); + if (player == null) { + iter.remove(); + continue; + } + updateBossBar(entry.getValue(), player); + } + } + + @Override + public void cancel() { + super.cancel(); + new HashSet<>(this.bossbars.keySet()).forEach(uuid -> { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + removePlayer(player); + } + }); + this.bossbars.clear(); + } + + public boolean removePlayer(Player player) { + BossBar bossbar = this.bossbars.remove(player.getUniqueId()); + if (bossbar != null) { + player.hideBossBar(bossbar); + return true; + } + return false; + } + + public void addPlayer(Player player) { + removePlayer(player); + BossBar bossbar = createBossBar(); + this.bossbars.put(player.getUniqueId(), bossbar); + this.updateBossBar(bossbar, player); + player.showBossBar(bossbar); + } + + public boolean hasPlayer(UUID uuid) { + return this.bossbars.containsKey(uuid); + } + + public boolean togglePlayer(Player player) { + if (removePlayer(player)) { + return false; + } + addPlayer(player); + return true; + } + + public void start() { + stop(); + this.runTaskTimerAsynchronously(new MinecraftInternalPlugin(), 1, 1); + started = true; + } + + public void stop() { + if (started) { + cancel(); + } + } + + public static void startAll() { + RamBarTask.instance().start(); + TPSBarTask.instance().start(); + CompassTask.instance().start(); + } + + public static void stopAll() { + RamBarTask.instance().stop(); + TPSBarTask.instance().stop(); + CompassTask.instance().stop(); + } + + public static void addToAll(ServerPlayer player) { + Player bukkit = player.getBukkitEntity(); + if (player.ramBar()) { + RamBarTask.instance().addPlayer(bukkit); + } + if (player.tpsBar()) { + TPSBarTask.instance().addPlayer(bukkit); + } + if (player.compassBar()) { + CompassTask.instance().addPlayer(bukkit); + } + } + + public static void removeFromAll(Player player) { + RamBarTask.instance().removePlayer(player); + TPSBarTask.instance().removePlayer(player); + CompassTask.instance().removePlayer(player); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/task/CompassTask.java b/purpur-server/src/main/java/org/purpurmc/purpur/task/CompassTask.java new file mode 100644 index 000000000..bece7eefc --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/task/CompassTask.java @@ -0,0 +1,68 @@ +package org.purpurmc.purpur.task; + +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.item.Items; +import org.bukkit.entity.Player; +import org.purpurmc.purpur.PurpurConfig; + +public class CompassTask extends BossBarTask { + private static CompassTask instance; + + private int tick = 0; + + public static CompassTask instance() { + if (instance == null) { + instance = new CompassTask(); + } + return instance; + } + + @Override + public void run() { + if (++tick < PurpurConfig.commandCompassBarTickInterval) { + return; + } + tick = 0; + + MinecraftServer.getServer().getAllLevels().forEach((level) -> { + if (level.purpurConfig.compassItemShowsBossBar) { + level.players().forEach(player -> { + if (!player.compassBar()) { + if (player.getMainHandItem().getItem() != Items.COMPASS && player.getOffhandItem().getItem() != Items.COMPASS) { + removePlayer(player.getBukkitEntity()); + } else if (!hasPlayer(player.getUUID())) { + addPlayer(player.getBukkitEntity()); + } + } + }); + } + }); + + super.run(); + } + + @Override + BossBar createBossBar() { + return BossBar.bossBar(Component.text(""), PurpurConfig.commandCompassBarProgressPercent, PurpurConfig.commandCompassBarProgressColor, PurpurConfig.commandCompassBarProgressOverlay); + } + + @Override + void updateBossBar(BossBar bossbar, Player player) { + float yaw = player.getLocation().getYaw(); + int length = PurpurConfig.commandCompassBarTitle.length(); + int pos = (int) ((normalize(yaw) * (length / 720F)) + (length / 2F)); + bossbar.name(Component.text(PurpurConfig.commandCompassBarTitle.substring(pos - 25, pos + 25))); + } + + private float normalize(float yaw) { + while (yaw < -180.0F) { + yaw += 360.0F; + } + while (yaw > 180.0F) { + yaw -= 360.0F; + } + return yaw; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/task/RamBarTask.java b/purpur-server/src/main/java/org/purpurmc/purpur/task/RamBarTask.java new file mode 100644 index 000000000..8e98c0ae7 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/task/RamBarTask.java @@ -0,0 +1,117 @@ +package org.purpurmc.purpur.task; + +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.bukkit.entity.Player; +import org.purpurmc.purpur.PurpurConfig; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; + +public class RamBarTask extends BossBarTask { + private static RamBarTask instance; + private long allocated = 0L; + private long used = 0L; + private long xmx = 0L; + private long xms = 0L; + private float percent = 0F; + private int tick = 0; + + public static RamBarTask instance() { + if (instance == null) { + instance = new RamBarTask(); + } + return instance; + } + + @Override + BossBar createBossBar() { + return BossBar.bossBar(Component.text(""), 0.0F, instance().getBossBarColor(), PurpurConfig.commandRamBarProgressOverlay); + } + + @Override + void updateBossBar(BossBar bossbar, Player player) { + bossbar.progress(getBossBarProgress()); + bossbar.color(getBossBarColor()); + bossbar.name(MiniMessage.miniMessage().deserialize(PurpurConfig.commandRamBarTitle, + Placeholder.component("allocated", format(this.allocated)), + Placeholder.component("used", format(this.used)), + Placeholder.component("xmx", format(this.xmx)), + Placeholder.component("xms", format(this.xms)), + Placeholder.unparsed("percent", ((int) (this.percent * 100)) + "%") + )); + } + + @Override + public void run() { + if (++this.tick < PurpurConfig.commandRamBarTickInterval) { + return; + } + this.tick = 0; + + MemoryUsage heap = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + + this.allocated = heap.getCommitted(); + this.used = heap.getUsed(); + this.xmx = heap.getMax(); + this.xms = heap.getInit(); + this.percent = Math.max(Math.min((float) this.used / this.xmx, 1.0F), 0.0F); + + super.run(); + } + + private float getBossBarProgress() { + return this.percent; + } + + private BossBar.Color getBossBarColor() { + if (this.percent < 0.5F) { + return PurpurConfig.commandRamBarProgressColorGood; + } else if (this.percent < 0.75F) { + return PurpurConfig.commandRamBarProgressColorMedium; + } else { + return PurpurConfig.commandRamBarProgressColorLow; + } + } + + public Component format(long v) { + String color; + if (this.percent < 0.60F) { + color = PurpurConfig.commandRamBarTextColorGood; + } else if (this.percent < 0.85F) { + color = PurpurConfig.commandRamBarTextColorMedium; + } else { + color = PurpurConfig.commandRamBarTextColorLow; + } + String value; + if (v < 1024) { + value = v + "B"; + } else { + int z = (63 - Long.numberOfLeadingZeros(v)) / 10; + value = String.format("%.1f%s", (double) v / (1L << (z * 10)), "BKMGTPE".charAt(z)); + } + return MiniMessage.miniMessage().deserialize(color, Placeholder.unparsed("text", value)); + } + + public long getAllocated() { + return this.allocated; + } + + public long getUsed() { + return this.used; + } + + public long getXmx() { + return this.xmx; + } + + public long getXms() { + return this.xms; + } + + public float getPercent() { + return this.percent; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java b/purpur-server/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java new file mode 100644 index 000000000..8769993e7 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/task/TPSBarTask.java @@ -0,0 +1,142 @@ +package org.purpurmc.purpur.task; + +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.purpurmc.purpur.PurpurConfig; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public class TPSBarTask extends BossBarTask { + private static TPSBarTask instance; + private double tps = 20.0D; + private double mspt = 0.0D; + private int tick = 0; + + public static TPSBarTask instance() { + if (instance == null) { + instance = new TPSBarTask(); + } + return instance; + } + + @Override + BossBar createBossBar() { + return BossBar.bossBar(Component.text(""), 0.0F, instance().getBossBarColor(), PurpurConfig.commandTPSBarProgressOverlay); + } + + @Override + void updateBossBar(BossBar bossbar, Player player) { + bossbar.progress(getBossBarProgress()); + bossbar.color(getBossBarColor()); + bossbar.name(MiniMessage.miniMessage().deserialize(PurpurConfig.commandTPSBarTitle, + Placeholder.component("tps", getTPSColor()), + Placeholder.component("mspt", getMSPTColor()), + Placeholder.component("ping", getPingColor(player.getPing())) + )); + } + + @Override + public void run() { + if (++tick < PurpurConfig.commandTPSBarTickInterval) { + return; + } + tick = 0; + + this.tps = Math.max(Math.min(Bukkit.getTPS()[0], 20.0D), 0.0D); + this.mspt = Bukkit.getAverageTickTime(); + + super.run(); + } + + private float getBossBarProgress() { + if (PurpurConfig.commandTPSBarProgressFillMode == FillMode.MSPT) { + return Math.max(Math.min((float) mspt / 50.0F, 1.0F), 0.0F); + } else { + return Math.max(Math.min((float) tps / 20.0F, 1.0F), 0.0F); + } + } + + private BossBar.Color getBossBarColor() { + if (isGood(PurpurConfig.commandTPSBarProgressFillMode)) { + return PurpurConfig.commandTPSBarProgressColorGood; + } else if (isMedium(PurpurConfig.commandTPSBarProgressFillMode)) { + return PurpurConfig.commandTPSBarProgressColorMedium; + } else { + return PurpurConfig.commandTPSBarProgressColorLow; + } + } + + private boolean isGood(FillMode mode) { + return isGood(mode, 0); + } + + private boolean isGood(FillMode mode, int ping) { + if (mode == FillMode.MSPT) { + return mspt < 40; + } else if (mode == FillMode.TPS) { + return tps >= 19; + } else if (mode == FillMode.PING) { + return ping < 100; + } else { + return false; + } + } + + private boolean isMedium(FillMode mode) { + return isMedium(mode, 0); + } + + private boolean isMedium(FillMode mode, int ping) { + if (mode == FillMode.MSPT) { + return mspt < 50; + } else if (mode == FillMode.TPS) { + return tps >= 15; + } else if (mode == FillMode.PING) { + return ping < 200; + } else { + return false; + } + } + + private Component getTPSColor() { + String color; + if (isGood(FillMode.TPS)) { + color = PurpurConfig.commandTPSBarTextColorGood; + } else if (isMedium(FillMode.TPS)) { + color = PurpurConfig.commandTPSBarTextColorMedium; + } else { + color = PurpurConfig.commandTPSBarTextColorLow; + } + return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%.2f", tps))); + } + + private Component getMSPTColor() { + String color; + if (isGood(FillMode.MSPT)) { + color = PurpurConfig.commandTPSBarTextColorGood; + } else if (isMedium(FillMode.MSPT)) { + color = PurpurConfig.commandTPSBarTextColorMedium; + } else { + color = PurpurConfig.commandTPSBarTextColorLow; + } + return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%.2f", mspt))); + } + + private Component getPingColor(int ping) { + String color; + if (isGood(FillMode.PING, ping)) { + color = PurpurConfig.commandTPSBarTextColorGood; + } else if (isMedium(FillMode.PING, ping)) { + color = PurpurConfig.commandTPSBarTextColorMedium; + } else { + color = PurpurConfig.commandTPSBarTextColorLow; + } + return MiniMessage.miniMessage().deserialize(color, Placeholder.parsed("text", String.format("%s", ping))); + } + + public enum FillMode { + TPS, MSPT, PING + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/tool/Actionable.java b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Actionable.java new file mode 100644 index 000000000..e18c37f06 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Actionable.java @@ -0,0 +1,24 @@ +package org.purpurmc.purpur.tool; + +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +import java.util.Map; + +public abstract class Actionable { + private final Block into; + private final Map drops; + + public Actionable(Block into, Map drops) { + this.into = into; + this.drops = drops; + } + + public Block into() { + return into; + } + + public Map drops() { + return drops; + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/tool/Flattenable.java b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Flattenable.java new file mode 100644 index 000000000..345d4ee4f --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Flattenable.java @@ -0,0 +1,12 @@ +package org.purpurmc.purpur.tool; + +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +import java.util.Map; + +public class Flattenable extends Actionable { + public Flattenable(Block into, Map drops) { + super(into, drops); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/tool/Strippable.java b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Strippable.java new file mode 100644 index 000000000..bf5402214 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Strippable.java @@ -0,0 +1,12 @@ +package org.purpurmc.purpur.tool; + +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +import java.util.Map; + +public class Strippable extends Actionable { + public Strippable(Block into, Map drops) { + super(into, drops); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/tool/Tillable.java b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Tillable.java new file mode 100644 index 000000000..715f6dd44 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Tillable.java @@ -0,0 +1,50 @@ +package org.purpurmc.purpur.tool; + +import net.minecraft.world.item.HoeItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.block.Block; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Predicate; + +public class Tillable extends Actionable { + private final Condition condition; + + public Tillable(Condition condition, Block into, Map drops) { + super(into, drops); + this.condition = condition; + } + + public Condition condition() { + return condition; + } + + public enum Condition { + AIR_ABOVE(HoeItem::onlyIfAirAbove), + ALWAYS((useOnContext) -> true); + + private final Predicate predicate; + + Condition(Predicate predicate) { + this.predicate = predicate; + } + + public Predicate predicate() { + return predicate; + } + + private static final Map BY_NAME = new HashMap<>(); + + static { + for (Condition condition : values()) { + BY_NAME.put(condition.name(), condition); + } + } + + public static Condition get(String name) { + return BY_NAME.get(name.toUpperCase(java.util.Locale.ROOT)); + } + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/tool/Waxable.java b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Waxable.java new file mode 100644 index 000000000..64adb13b2 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Waxable.java @@ -0,0 +1,12 @@ +package org.purpurmc.purpur.tool; + +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +import java.util.Map; + +public class Waxable extends Actionable { + public Waxable(Block into, Map drops) { + super(into, drops); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/tool/Weatherable.java b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Weatherable.java new file mode 100644 index 000000000..b7586f494 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/tool/Weatherable.java @@ -0,0 +1,12 @@ +package org.purpurmc.purpur.tool; + +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +import java.util.Map; + +public class Weatherable extends Actionable { + public Weatherable(Block into, Map drops) { + super(into, drops); + } +} diff --git a/purpur-server/src/main/java/org/purpurmc/purpur/util/MinecraftInternalPlugin.java b/purpur-server/src/main/java/org/purpurmc/purpur/util/MinecraftInternalPlugin.java new file mode 100644 index 000000000..77a18f304 --- /dev/null +++ b/purpur-server/src/main/java/org/purpurmc/purpur/util/MinecraftInternalPlugin.java @@ -0,0 +1,149 @@ +package org.purpurmc.purpur.util; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginBase; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.PluginLoader; +import org.bukkit.plugin.PluginLogger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.io.File; +import java.io.InputStream; +import java.util.List; + +public class MinecraftInternalPlugin extends PluginBase { + private boolean enabled = true; + + private final String pluginName; + private PluginDescriptionFile pdf; + + public MinecraftInternalPlugin() { + this.pluginName = "Minecraft"; + pdf = new PluginDescriptionFile(pluginName, "1.0", "nms"); + } + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public File getDataFolder() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public PluginDescriptionFile getDescription() { + return pdf; + } + + @Override + public io.papermc.paper.plugin.configuration.PluginMeta getPluginMeta() { + return pdf; + } + + @Override + public FileConfiguration getConfig() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public InputStream getResource(String filename) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void saveConfig() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void saveDefaultConfig() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void saveResource(String resourcePath, boolean replace) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void reloadConfig() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public PluginLogger getLogger() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public PluginLoader getPluginLoader() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public Server getServer() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void onDisable() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void onLoad() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void onEnable() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public boolean isNaggable() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void setNaggable(boolean canNag) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public @Nullable BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public @NotNull LifecycleEventManager getLifecycleManager() { + throw new UnsupportedOperationException("Not supported."); + } +} diff --git a/scripts/upstreamCommit.sh b/scripts/upstreamCommit.sh index 0883dfb06..c272a2dba 100755 --- a/scripts/upstreamCommit.sh +++ b/scripts/upstreamCommit.sh @@ -7,7 +7,7 @@ # flag: --pufferfish HASH - the commit hash to use for comparing commits between pufferfish (pufferfish-gg/Pufferfish/compare/HASH...HEAD) function getCommits() { - curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/"$1"/compare/"$2"..."$3" | jq -r '.commits[] | "'"$1"'@\(.sha[:7]) \(.commit.message | split("\r\n")[0] | split("\n")[0])"' + curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/"$1"/compare/"$2"..."$3" | jq -r '.commits[] | "'"$1"'@\(.sha[:8]) \(.commit.message | split("\r\n")[0] | split("\n")[0])" | sub("\\[ci( |-)skip]"; "[ci/skip]")' } ( diff --git a/settings.gradle.kts b/settings.gradle.kts index 0ff9678cd..11c5dd958 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,7 +8,7 @@ pluginManagement { } plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" + id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" } if (!file(".git").exists()) { @@ -32,7 +32,7 @@ if (!file(".git").exists()) { } rootProject.name = "purpur" -for (name in listOf("Purpur-API", "Purpur-Server", "paper-api-generator")) { +for (name in listOf("purpur-api", "purpur-server")) { val projName = name.lowercase(Locale.ENGLISH) include(projName) findProject(":$projName")!!.projectDir = file(name) diff --git a/test-plugin/src/main/resources/paper-plugin.yml b/test-plugin/src/main/resources/paper-plugin.yml index 3418d110e..4357c79e2 100644 --- a/test-plugin/src/main/resources/paper-plugin.yml +++ b/test-plugin/src/main/resources/paper-plugin.yml @@ -5,8 +5,8 @@ description: Purpur Test Plugin author: PurpurMC api-version: ${apiversion} load: STARTUP -bootstrapper: org.purpurmc.testplugin.TestPluginBootstrap -loader: org.purpurmc.testplugin.TestPluginLoader +#bootstrapper: org.purpurmc.testplugin.TestPluginBootstrap +#loader: org.purpurmc.testplugin.TestPluginLoader defaultPerm: FALSE permissions: dependencies: