hardfork from paper 😊

This commit is contained in:
granny
2025-03-31 23:15:31 -07:00
parent aa0bf38f14
commit 73f443461b
197 changed files with 108 additions and 1256 deletions

View File

@@ -45,25 +45,16 @@ javac 21.0.5
## Understanding Patches
Unlike the Purpur API and its implementation, modifications to Paper and Minecraft source files
Unlike the Purpur API and its implementation, modifications to the Minecraft source files
are done through patches. These patches/extensions are split into three different sets of two
categories, which are formatted like so:
Under `purpur-api`:
- `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:
@@ -72,16 +63,14 @@ 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 applyAllPatches` in a terminal to apply the patches to both paper and minecraft classes.
2. Type `./gradlew applyPatches` in a terminal to apply the patches to 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.
3. cd into `purpur-server` for server changes, `purpur-api` for API changes.
`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.
by the individual feature-patch commits.
## Understanding the Gradle Tasks
@@ -98,12 +87,12 @@ Each "project" that includes a local git repository has the following available
Some additional useful tasks are listed below:
- `./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 applyAllPatches` - Applies all patches defined in the paperweight-patcher project and the server project. (equivalent to running `applyPatches` 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`)
- `./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`
- `./gradlew rebuildSingleFilePatches` - Fixups and rebuilds all single-file patches. This is how you'd make changes to the `build.gradle.kts` files located under `purpur-api` and `purpur-server`
## Modifying (per-file) patches
@@ -229,7 +218,7 @@ when making and submitting changes.
## Formatting
All modifications to Minecraft files and Paper files should be marked. For historical reasons,
All modifications to Minecraft files should be marked. For historical reasons,
API and API-implementation contain a lot of these too, but they are no longer
required.
@@ -273,7 +262,7 @@ into most IDEs and formatters by default. There are a few notes, however:
hard to parse generics in a case where the base type itself is already obvious.
### Imports
When adding new imports to a Minecraft or Paper class, use the fully qualified class name
When adding new imports to a Minecraft 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 it's only used a couple of times, the FQN is preferred to prevent future
patch conflicts in the import section of the file.

View File

@@ -15,7 +15,7 @@
[![Forks](https://img.shields.io/github/forks/PurpurMC/Purpur?label=forks&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/n4Ax9dyyerighsAAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfmCBMVNCYN3/YeAAAA/UlEQVQ4y7WTQUoDQRBFf01czlJcxUyOINGjjAvFHMFzZGdygOwDwTtk6UZcqLlAxCAuMigug89FamIzdAIN+qGhq/6v6qrqbumvAJwBj8AHMAQs4DJgBHy65jSW4Bl4AaZsUAbcufumrnmquSzIcSzpTtLA7XbA1fuBa9qxCob8YgUUAdcFqoC/iSXIgLELOhG+49w4nM+2BTP7ljR3M4/MufbNzYxdN1E0Sm2ialZnsVIllZKOJF24eyLpXdKtmS1S3sYMmO3THOwJziUdbrbkZvaVcnILeAh6vweylAQ9D7z2BXCS0sJS0lrSpdtrSW+pn6sPLIFX4Er/hR9C0wl1FTBzNwAAAABJRU5ErkJggg==)](https://github.com/PurpurMC/Purpur/network/members)
[![Watchers](https://img.shields.io/github/watchers/PurpurMC/Purpur?label=watchers&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/n4Ax9dyyerighsAAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfmCBMVNw4TRw0nAAAA3UlEQVQ4y83SP04CURAG8I0lewHOwAFUaiwkdmAlp8CL4FHopfIvtOIJWE3opIBK489mQPKy6xYWOskkL9/MN/PNzMuyf2fIcYkZVuGzwPI68gle8Yl7jMIfAntBp4o8wAeecFgSP8I8cgZp8DwC12j8oLCBCd7R34ItbHCzT8ZZSC7QTYrcYo1WhjGWaCbdCt+2SGLN4IwPfnu07QjrkhG6oWKB0+TMd7sRAuzHYuqWmO8tsVd1xjmOS8htPEfORVWHTmweHnEVPg2sqPxIicxhFFjhLd7D2q/8J/YFHSJt9VSqQ08AAAAASUVORK5CYII=)](https://github.com/PurpurMC/Purpur/watchers)
Purpur is a drop-in replacement for [Paper](https://github.com/PaperMC/Paper) servers designed for configurability, new fun and exciting gameplay features, and performance built on top of [Paper](https://github.com/PaperMC/Paper/).
Purpur is a drop-in replacement for [Spigot](https://github.com/SpigotMC/Spigot) servers designed for configurability, new fun and exciting gameplay features, and performance built on top of [Spigot](https://github.com/SpigotMC/Spigot).
</div>
@@ -44,7 +44,7 @@ All patches are licensed under the MIT license, unless otherwise noted in the pa
[![MIT License](https://img.shields.io/github/license/PurpurMC/Purpur?&logo=github)](LICENSE)
See [PaperMC/Paper](https://github.com/PaperMC/Paper), and [PaperMC/Paperweight](https://github.com/PaperMC/paperweight) for the license of material used by this project.
See [SpigotMC/Spigot](https://github.com/SpigotMC/Spigot), and [PaperMC/Paperweight](https://github.com/PaperMC/paperweight) for the license of material used by this project.
## bStats
@@ -84,7 +84,7 @@ dependencies {
}
```
Yes, this also includes all API provided by Paper, Spigot, and Bukkit.
Yes, this also includes all API provided by Spigot and Bukkit.
## Building and setting up

View File

@@ -6,27 +6,27 @@ plugins {
id("io.papermc.paperweight.patcher") version "2.0.0-beta.16"
}
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
val spigotMavenPublicUrl = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/"
paperweight {
upstreams.paper {
ref = providers.gradleProperty("paperCommit")
upstreams.spigot {
ref = providers.gradleProperty("spigotCommit")
patchFile {
path = "paper-server/build.gradle.kts"
path = "spigot-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"
path = "spigot-api/build.gradle.kts"
outputFile = file("purpur-api/build.gradle.kts")
patchFile = file("purpur-api/build.gradle.kts.patch")
}
patchDir("paperApi") {
upstreamPath = "paper-api"
patchDir("spigotApi") {
upstreamPath = "spigot-api"
excludes = setOf("build.gradle.kts")
patchesDir = file("purpur-api/paper-patches")
outputDir = file("paper-api")
patchesDir = file("purpur-api/spigot-patches")
outputDir = file("spigot-api")
}
}
}
@@ -66,7 +66,7 @@ subprojects {
repositories {
mavenCentral()
maven(paperMavenPublicUrl)
maven(spigotMavenPublicUrl)
maven("https://jitpack.io")
}

View File

@@ -1,42 +1,18 @@
--- a/paper-api/build.gradle.kts
+++ b/paper-api/build.gradle.kts
--- a/spigot-api/build.gradle.kts
+++ b/spigot-api/build.gradle.kts
@@ -93,7 +_,7 @@
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
-val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("src/generated/java").asFile.toPath()
+val generatedDir: java.nio.file.Path = rootProject.layout.projectDirectory.dir("paper-api/src/generated/java").asFile.toPath()
idea {
module {
generatedSourceDirs.add(generatedDir.toFile())
@@ -103,6 +_,18 @@
main {
java {
srcDir(generatedDir)
+ 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<Services>()
tasks.withType<Javadoc> {
+ //(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
+ (options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet") // Purpur - silence Spigot'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.overview = "../spigot-api/src/main/javadoc/overview.html"
options.use()
options.isDocFilesSubDirs = true
options.links(
@@ -45,12 +21,12 @@
// 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")
+ inputs.dir("../spigot-api/src/main/javadoc").withPropertyName("javadoc-sourceset")
val fsOps = services.fileSystemOperations
doLast {
fsOps.copy {
- from("src/main/javadoc") {
+ from("../paper-api/src/main/javadoc") {
+ from("../spigot-api/src/main/javadoc") {
include("**/doc-files/**")
}
into("build/docs/javadoc")

View File

@@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: granny <granny@purpurmc.org>
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}.
*

View File

@@ -1,29 +0,0 @@
--- 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> ZOMBIE_ATTACK_TURTLE_EGG = create("zombie_attack_turtle_egg", Zombie.class);
+ // Purpur start - Ridables
+ GoalKey<Mob> MOB_HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider"));
+ GoalKey<AbstractHorse> HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider"));
+ GoalKey<Llama> 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<Phantom> FIND_CRYSTAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal"));
+ GoalKey<Phantom> 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> DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager"));
+ GoalKey<Zombie> 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<Wolf> 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<IronGolem> RECEIVE_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("receive_flower"));
+ // Purpur end - Iron golem poppy calms anger
+
private static <T extends Mob> GoalKey<T> create(final String key, final Class<T> type) {
return GoalKey.of(type, NamespacedKey.minecraft(key));
}

View File

@@ -1,15 +0,0 @@
--- 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 {

View File

@@ -1,26 +0,0 @@
--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
@@ -213,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));
@@ -254,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("<grey>Current Purpur Version: %s%s*", distance == 0 ? "<green>" : distance > 0 ? "<yellow>" : "<red>", Bukkit.getVersion()),
+ // Purpur end
msg
);
this.versionMessage = Component.text()

View File

@@ -9,8 +9,8 @@ index 53ad1696d02afbebf27663dd753fa93e41cfeb4e..cec387842895d617b0dcf9158f080fe0
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2369,6 +2369,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
throw new UnsupportedOperationException("Not supported yet.");
}
// Paper end
+ // Purpur start
+ @NotNull

View File

@@ -4,7 +4,7 @@
* @return Timing
*/
@NotNull
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
+ @org.purpurmc.purpur.annotation.DoNotUse // Purpur - Remove Timings
Timing startTiming();
/**
@@ -12,7 +12,7 @@
*
* Will automatically be called when this Timing is used with try-with-resources
*/
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
+ @org.purpurmc.purpur.annotation.DoNotUse // Purpur - Remove Timings
void stopTiming();
/**
@@ -20,7 +20,7 @@
* @return Timing
*/
@NotNull
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
+ @org.purpurmc.purpur.annotation.DoNotUse // Purpur - Remove Timings
Timing startTimingIfSync();
/**
@@ -28,14 +28,14 @@
*
* But only if we are on the primary thread.
*/
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
+ @org.purpurmc.purpur.annotation.DoNotUse // Purpur - Remove Timings
void stopTimingIfSync();
/**
* @deprecated Doesn't do anything - Removed
*/
@Deprecated
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
+ @org.purpurmc.purpur.annotation.DoNotUse // Purpur - Remove Timings
void abort();
/**
@@ -43,6 +43,6 @@
TimingHandler getTimingHandler();
@Override
+ @io.papermc.paper.annotation.DoNotUse // Purpur - Remove Timings
+ @org.purpurmc.purpur.annotation.DoNotUse // Purpur - Remove Timings
void close();
}

View File

@@ -1,9 +1,6 @@
--- a/src/main/java/org/bukkit/Material.java
+++ b/src/main/java/org/bukkit/Material.java
@@ -3616,4 +_,40 @@
return this.asItemType().getDefaultDataTypes();
}
// Paper end - data component API
+
+ // Purpur start - ItemStack convenience methods
+ public boolean isArmor() {

View File

@@ -1,9 +1,6 @@
--- a/src/main/java/org/bukkit/OfflinePlayer.java
+++ b/src/main/java/org/bukkit/OfflinePlayer.java
@@ -570,4 +_,104 @@
@Override
io.papermc.paper.persistence.PersistentDataContainerView getPersistentDataContainer();
// Paper end - add pdc to offline player
+
+ // Purpur start - OfflinePlayer API
+ /**

View File

@@ -1,9 +1,6 @@
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2705,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
+ /**

View File

@@ -17,20 +17,16 @@
+ 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
- try (co.aikar.timings.Timing ignored = target.timings.startTiming()) {
+ //try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // 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.timings.stopTiming(); // Spigot
+ target.execute(sender, sentCommandLabel, parsedArgs); // Purpur - ExecuteCommandEvent
+ //} // target.timings.stopTiming(); // Spigot // Paper // Purpur - Remove Timings
+ //} // target.timings.stopTiming(); // Spigot // 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
target.timings.stopTiming(); // Spigot

View File

@@ -28,5 +28,4 @@
*/
- @Deprecated(since = "1.17", forRemoval = true)
void setPlayerSpawned(boolean playerSpawned);
// Paper start
/**

View File

@@ -1,9 +1,6 @@
--- a/src/main/java/org/bukkit/entity/Entity.java
+++ b/src/main/java/org/bukkit/entity/Entity.java
@@ -1214,4 +_,59 @@
*/
void broadcastHurtAnimation(@NotNull java.util.Collection<Player> players);
// Paper end - broadcast hurt animation
+
+ // Purpur start - Ridables
+ /**

View File

@@ -2,8 +2,6 @@
+++ b/src/main/java/org/bukkit/entity/Item.java
@@ -153,4 +_,62 @@
*/
public void setHealth(int health);
// Paper end
+
+ // Purpur start
+ /**

View File

@@ -2,8 +2,6 @@
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -1452,4 +_,20 @@
*/
boolean canUseEquipmentSlot(org.bukkit.inventory.@NotNull EquipmentSlot slot);
// Paper end - Expose canUseSlot
+
+ // Purpur start - API for any mob to burn daylight
+ /**

View File

@@ -1,9 +1,6 @@
--- 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
+ /**

View File

@@ -1,9 +1,7 @@
--- 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
+ /**

View File

@@ -15,9 +15,6 @@
/**
* Represents a stack of items.
@@ -1371,4 +_,482 @@
return this.craftDelegate.matchesWithoutData(item, excludeTypes, ignoreCount);
}
// Paper end - data component API
+
+ // Purpur start - ItemStack convenience methods
+ /**

View File

@@ -1,9 +1,7 @@
--- 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
+ /**

View File

@@ -9,13 +9,11 @@
}
});
@@ -88,6 +_,7 @@
// Paper end - plugin loader api
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
@@ -140,6 +_,7 @@
}
@@ -23,4 +21,3 @@
+ 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

View File

@@ -1,16 +1,14 @@
--- a/paper-server/build.gradle.kts
+++ b/paper-server/build.gradle.kts
--- a/spigot-server/build.gradle.kts
+++ b/spigot-server/build.gradle.kts
@@ -28,6 +_,18 @@
// oldPaperCommit = "f4f275519f7c1fbe9db173b7144a4fe81440e365"
//}
+ // Purpur start - Rebrand
+ val purpur = forks.register("purpur") {
+ upstream.patchDir("paperServer") {
+ upstreamPath = "paper-server"
+ upstream.patchDir("spigotServer") {
+ upstreamPath = "spigot-server"
+ excludes = setOf("src/minecraft", "patches", "build.gradle.kts")
+ patchesDir = rootDirectory.dir("purpur-server/paper-patches")
+ outputDir = rootDirectory.dir("paper-server")
+ patchesDir = rootDirectory.dir("purpur-server/spigot-patches")
+ outputDir = rootDirectory.dir("spigot-server")
+ }
+ }
+ activeFork = purpur
@@ -27,16 +25,16 @@
+// Purpur start - Rebrand
+sourceSets {
+ main {
+ java { srcDir("../paper-server/src/main/java") }
+ resources { srcDir("../paper-server/src/main/resources") }
+ java { srcDir("../spigot-server/src/main/java") }
+ resources { srcDir("../spigot-server/src/main/resources") }
+ }
+ test {
+ java { srcDir("../paper-server/src/test/java") }
+ resources { srcDir("../paper-server/src/test/resources") }
+ java { srcDir("../spigot-server/src/test/java") }
+ resources { srcDir("../spigot-server/src/test/resources") }
+ }
+}
+val log4jPlugins = sourceSets.create("log4jPlugins") {
+ java { srcDir("../paper-server/src/log4jPlugins/java") }
+ java { srcDir("../spigot-server/src/log4jPlugins/java") }
+}
+// Purpur end - Rebrand
configurations.named(log4jPlugins.compileClasspathConfigurationName) {
@@ -46,7 +44,7 @@
}
dependencies {
- implementation(project(":paper-api"))
- implementation(project(":spigot-api"))
+ implementation(project(":purpur-api")) // Purpur
implementation("ca.spottedleaf:concurrentutil:0.0.3")
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
@@ -66,16 +64,16 @@
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 "Spigot",
+ "Implementation-Title" to "Purpur", // Purpur
"Implementation-Version" to implementationVersion,
"Implementation-Vendor" to date,
- "Specification-Title" to "Paper",
- "Specification-Title" to "Spigot",
+ "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 "Spigot Team",
- "Brand-Id" to "spigotmc:spigot",
- "Brand-Name" to "Spigot",
+ "Specification-Vendor" to "Purpur Team", // Purpur
+ "Brand-Id" to "purpurmc:purpur", // Purpur
+ "Brand-Name" to "Purpur", // Purpur
@@ -86,8 +84,3 @@
jvmArgumentProviders.add(provider)
}
-val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("src/generated/java").asFile.toPath()
+val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("../paper-server/src/generated/java").asFile.toPath()
idea {
module {
generatedSourceDirs.add(generatedDir.toFile())

View File

@@ -22,9 +22,6 @@ index f34bc75f324454bf48f0ebf79111706bb027a54b..6ad266592c16bdeccfb689fb2ef2ee37
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1634,6 +1634,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
serverLevel.updateLagCompensationTick(); // Paper - lag compensation
+ serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables
profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location());
/* Drop global time updates
@@ -35,8 +32,6 @@ index 0e7405a480bffa81493ef2f2078c36ccda542cde..bc5c30430e79e2feb69c165d9e3e9b6a
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -212,6 +212,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public final java.util.UUID uuid;
public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
+ public boolean hasRidableMoveEvent = false; // Purpur - Ridables
@Override
@@ -73,7 +68,6 @@ index 63e01ec7e4ab04bb7d389bff485dfedca344bfa2..84b1570d0d88f57f33ff8179f0a78d37
+
// Entity in bucket - SPIGOT-4048 and SPIGOT-6859a
if ((target instanceof net.minecraft.world.entity.animal.Bucketable && target instanceof LivingEntity && origItem != null && origItem == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelectedItem().isEmpty() || !ServerGamePacketListenerImpl.this.player.getInventory().getSelectedItem().is(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 d1899b2411e90b4641dcbc58760e4a19b62846c5..1335a04edd053c06e290c070e3c03d02598d97e7 100644
--- a/net/minecraft/world/entity/Entity.java
@@ -110,7 +104,6 @@ index d1899b2411e90b4641dcbc58760e4a19b62846c5..1335a04edd053c06e290c070e3c03d02
@@ -4823,4 +4838,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;
@@ -213,7 +206,6 @@ index a077e2f518be39bbdba4919ed7161bb28547e56b..a4a19d962bc4665e9368b97cae4b2534
@@ -3577,8 +3578,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
@@ -222,8 +214,7 @@ index a077e2f518be39bbdba4919ed7161bb28547e56b..a4a19d962bc4665e9368b97cae4b2534
+ // 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());
@@ -3588,6 +3591,21 @@ public abstract class LivingEntity extends Entity implements Attackable {
@@ -3588,6 +3591,21 @@ public abstract class LivingEntity extends Entity implements Attackable {
this.absSnapTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch());
}
}
@@ -243,7 +234,6 @@ index a077e2f518be39bbdba4919ed7161bb28547e56b..a4a19d962bc4665e9368b97cae4b2534
+ }
+ // Purpur end - Ridables
}
// Paper end - Add EntityMoveEvent
if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterOrRain()) {
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
index e3b804f2d612ed7971db450aeea6768109b63470..ca1d0164c90e695731f05de39c1d2fff947ecfc1 100644
@@ -534,7 +524,6 @@ index 4e81bc7215c845b316bcd46ce29f49af7f986088..61e7300bbf272398b2faebf5e537d9c2
// CraftBukkit start - Got milk?
org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(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
}
@@ -604,7 +593,6 @@ index 585131365c40136cf8a8a715b077982091ee38d5..65ee07e09bb9bafb60abeec4916fdbb0
public Bee(EntityType<? extends Bee> 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) {
@@ -157,11 +158,24 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
@@ -631,7 +619,6 @@ index 585131365c40136cf8a8a715b077982091ee38d5..65ee07e09bb9bafb60abeec4916fdbb0
+ // Purpur end - Ridables
}
this.moveControl = new BeeFlyingMoveControl(this, 20, true);
// Paper end - Fix MC-167279
@@ -173,6 +187,40 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
this.setPathfindingMalus(PathType.FENCE, -1.0F);
}
@@ -1167,7 +1154,6 @@ index 0931bab3f52ccc4e405be22559323df90bcc065e..f04342dd4addb2be47533f12a2a475f1
- 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 48c8fdfea8687f37187b6092c285275c12963ea0..b8780911350ac5f4f10acdbed2b13523c8692344 100644
@@ -1727,7 +1713,6 @@ index 67c8f1e82c775818f906eeaa639e55d7c02834c6..aca62391131333d604d21c9aaf2bcea6
+ return tryRide(player, hand); // Purpur - Ridables
}
drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
// Paper end - custom shear drops
@@ -175,7 +195,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM
return InteractionResult.SUCCESS;
// Purpur end - Snowman drop and put back pumpkin
@@ -2180,7 +2165,6 @@ index ebdfd3fb6c0de48982d392bb2aa415f3676c6056..4db2d63fbc021f28b8ad8d20cc1cc1bb
@@ -64,13 +64,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<? extends AbstractFish> entityType, Level level) {
@@ -2350,7 +2334,6 @@ index d4467235e8dc9d10c61dfb6fd9dc32386903dd09..b60fa4cb07d8dc6b52e76b5e9f596baf
@@ -83,7 +83,51 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob {
super(entityType, level);
this.getNavigation().setRequiredPathLength(40.0F);
this.maxDomestication = 30; // Paper - Missing entity API; configure max temper instead of a hardcoded value
+ // Purpur start - Ridables
+ this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this) {
+ @Override
@@ -2652,9 +2635,7 @@ index ea9d27a3205b3699b9577f42bb04254bd76e700e..a414934ae4332cc6cf622d4bb19c5937
--- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
@@ -91,6 +91,7 @@ public class EnderDragon extends Mob implements Enemy {
private final net.minecraft.world.level.Explosion explosionSource; // Paper - reusable source for CraftTNTPrimed.getSource()
@Nullable private BlockPos podium;
// Paper end
+ private boolean hadRider; // Purpur - Ridables
public EnderDragon(EntityType<? extends EnderDragon> entityType, Level level) {
@@ -2662,7 +2643,6 @@ index ea9d27a3205b3699b9577f42bb04254bd76e700e..a414934ae4332cc6cf622d4bb19c5937
@@ -107,6 +108,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) {
@@ -2813,7 +2793,6 @@ index 2f7da367b58fd9c06c4e012e8eb7f59e5a7f9b6d..15e2c0d566256c4ba175e991d6d7fd4f
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
@@ -79,9 +80,23 @@ public class WitherBoss extends Monster implements RangedAttackMob {
@@ -3252,7 +3231,6 @@ index c2327306f093c834da9574f9466236fbec572aec..562641cdb76e7a50706459bee8a2dcdf
this.targetSelector.addGoal(2, new HurtByTargetGoal(this));
}
@@ -310,6 +387,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
@@ -3891,7 +3869,6 @@ index 73edb1a4e5daee16fa518c05de24e413847ab65d..2653cf2c353d7ae360201e74c4860a47
@@ -148,6 +209,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);
}
@@ -4155,7 +4132,6 @@ index 6a8a5a76400beeaf69a17d53105a7a522ec5791e..9127e99d632bcd01c2f042c33dc87dd4
@@ -58,6 +58,7 @@ public class Slime extends Mob implements Enemy {
public float oSquish;
private boolean wasOnGround = false;
private boolean canWander = true; // Paper - Slime pathfinder events
+ protected boolean actualJump; // Purpur - Ridables
public Slime(EntityType<? extends Slime> entityType, Level level) {
@@ -4666,7 +4642,6 @@ index e15df574282e0f5ba5791435020bc6ac96860d15..f9233f0689b26a8c65d60ab9421c1216
@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
@@ -4990,7 +4965,6 @@ index 49d43837b88d8f278baa5062aed83a297fe20ed8..15669f9157dc3d3d5e3fb76a668c7e3b
// 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
@@ -418,7 +440,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler

View File

@@ -11,7 +11,6 @@ index ccea424d813a4c137fa15612b7bcf4fdb5c9a811..a1304bc3b1ebb9fa246004ae418481d4
@@ -1029,6 +1029,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) {
@@ -41,7 +40,6 @@ index 2417c26a03decf756ad93cd54265277c95c653ca..87c8bc6f9128d2fcb19628bc3ef354e5
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -212,6 +212,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
@@ -120,7 +118,6 @@ index 5077a9ff7b78801bdc53536a37aee07b8d86ee4d..72794e204f7fcc31ece94913b7fd9f36
+ (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<EnderChestBlockEntity> i
}

View File

@@ -32,7 +32,6 @@ index 99617c08cbd989092ba357d8df928786fd04c89a..9d88b260528c3cea2c5fe8e2760094b0
+ 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
@@ -111,8 +115,13 @@ public abstract class AbstractMinecart extends VehicleEntity {

View File

@@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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 6ad266592c16bdeccfb689fb2ef2ee37e79a7b41..e950e74d7c14d2e180e5ca879eb1048866d85051 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1140,6 +1140,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
// Purpur end - config for startup commands
+ // Purpur start - Configurable void damage height and damage
+ if (org.purpurmc.purpur.configuration.transformation.VoidDamageHeightMigration.HAS_BEEN_REGISTERED) {
+ try {
+ org.purpurmc.purpur.PurpurConfig.config.save((java.io.File) this.options.valueOf("purpur-settings"));
+ } catch (IOException ex) {
+ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Could not save " + this.options.valueOf("purpur-settings"), ex);
+ }
+ }
+ // Purpur end - Configurable void damage height and damage
+
while (this.running) {
long l;
if (!this.isPaused() && this.tickRateManager.isSprinting() && this.tickRateManager.checkShouldSprintThisTick()) {
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 19bb96242fed268c23381a6f3eaef21e723666c5..127935326dbfa0aa454dc12d52dcef328fcf2771 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -168,6 +168,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
org.spigotmc.SpigotConfig.registerCommands();
// Spigot end
io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc.
+ // Purpur start - 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 - Configurable void damage height and damage
// Paper start - initialize global and world-defaults configuration
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());

View File

@@ -33,7 +33,6 @@ index 18d63d2da49451a2d5e1da7bf0c00e05e2f192bc..1f081e098ce3bec61b7f374e9b737838
--- a/net/minecraft/world/item/FireworkRocketItem.java
+++ b/net/minecraft/world/item/FireworkRocketItem.java
@@ -62,6 +62,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
+
@@ -57,7 +56,6 @@ index 8c9f64140f016edfadeeb75463655cc2f3fafc0c..84e7f1b119ccfdabf48ccac51278e197
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -725,6 +725,14 @@ public final class ItemStack implements DataComponentHolder {
org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent(serverPlayer, this); // Paper - Add EntityDamageItemEvent
}
// CraftBukkit end
+

View File

@@ -11,7 +11,6 @@ index 57f9f705c62706902efe9a7873f0e3866820f7d9..90ac1e4bdca5b6233eeae9bc84549770
@@ -26,6 +26,12 @@ public class EndCrystal extends Entity {
private static final boolean DEFAULT_SHOW_BOTTOM = true;
public int time;
public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals
+ // Purpur start - Phantoms attracted to crystals and crystals shoot phantoms
+ private net.minecraft.world.entity.monster.Phantom targetPhantom;
+ private int phantomBeamTicks = 0;
@@ -22,7 +21,6 @@ index 57f9f705c62706902efe9a7873f0e3866820f7d9..90ac1e4bdca5b6233eeae9bc84549770
public EndCrystal(EntityType<? extends EndCrystal> 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 - Phantoms attracted to crystals and crystals shoot phantoms
@@ -80,7 +78,6 @@ index 2f14561a3722f8175a234ad656ef64d4c58e3b96..6c41a2cc9a772c216abfc2b241429ec7
public BlockPos anchorPoint;
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;
@@ -119,6 +120,25 @@ public class Phantom extends FlyingMob implements Enemy {

View File

@@ -11,7 +11,6 @@ index 6c41a2cc9a772c216abfc2b241429ec712119bb4..eaa5f2db1bc6b01ef6a508cc5a60ff1e
@@ -54,6 +54,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<? extends Phantom> entityType, Level level) {
@@ -20,11 +19,9 @@ index 6c41a2cc9a772c216abfc2b241429ec712119bb4..eaa5f2db1bc6b01ef6a508cc5a60ff1e
@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);

View File

@@ -36,7 +36,6 @@ index 2ce0099460c14a6dd8b128f268ee915ea4be5183..1cae770340e969ec4f037b9121142878
@@ -283,8 +284,10 @@ public abstract class Animal extends AgeableMob {
player.awardStat(Stats.ANIMALS_BRED);
CriteriaTriggers.BRED_ANIMALS.trigger(player, this, animal, baby);
} // Paper - Call EntityBreedEvent
- this.setAge(6000);
- animal.setAge(6000);
+ // Purpur start - Make entity breeding times configurable

View File

@@ -11,12 +11,9 @@ index fb3b4e57e98b45adb3a908ddbc2d4ac066e22034..e0489ff30373c214927f34d78787fb85
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
@@ -492,6 +492,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 f9a97000b75db7999b1cbe1f72d680d4d7b803b7..9dfadb5639e840e69274b35f3366322141527104 100644
--- a/net/minecraft/world/entity/decoration/ItemFrame.java

View File

@@ -45,7 +45,6 @@ index de89e45ecd4ac4c6db8b74bbe3dd6b4a7cf21671..f15e4cfd8c0ac5e08779dbe6b9aa40bf
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
}

View File

@@ -11,7 +11,6 @@ index bdae20191d2e5765761442eb06924968e710b189..476b570ffe9d2df173bd57b57fe65372
@@ -1904,7 +1904,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();
@@ -62,10 +61,6 @@ index 7a75415a469bc99f45a5cfaab038181717903f1d..fc244a1fbd401f6ea92e7428b9738939
+++ 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_EDIBLE.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);
}
@@ -73,8 +68,6 @@ index 7a75415a469bc99f45a5cfaab038181717903f1d..fc244a1fbd401f6ea92e7428b9738939
} 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);
}
@@ -221,9 +214,6 @@ index c200d57841304ba0d7a76fdd9a440fe9f2b25136..ff3761507f2025fd1e652afee03a18de
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
@@ -301,8 +291,6 @@ index e81ae747fe95c22321fc69791a6509d601826fd6..77bb3aa7ff042aab6464aac55c846cb9
}
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()) {
@@ -313,8 +301,7 @@ index b370b955ac8636275dfada4f38a7ca10297f7dac..275eabf64977cdf262de55124c3e5f88
@@ -169,7 +169,7 @@ public class CropBlock extends VegetationBlock implements BonemealableBlock {
@Override
protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier) {
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 (!new - 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);
}

View File

@@ -21,9 +21,7 @@ index 68914268ca9350a6c1d794e011e1f9a8aecd609c..8e53b45dbf740de6c6fe499ef424d11b
--- a/net/minecraft/world/level/block/EndGatewayBlock.java
+++ b/net/minecraft/world/level/block/EndGatewayBlock.java
@@ -99,6 +99,13 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal {
org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level), 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()) {
@@ -40,8 +38,7 @@ index cf2b105c98a3b22b9bea59cbafcd598657dc92b5..65d3477ed32c3f0db58aab6ab87d8f17
+++ b/net/minecraft/world/level/block/EndPortalBlock.java
@@ -59,6 +59,13 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal {
protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier) {
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)) {
if (!new 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()) {
@@ -50,7 +47,6 @@ index cf2b105c98a3b22b9bea59cbafcd598657dc92b5..65d3477ed32c3f0db58aab6ab87d8f17
+ }
+ // Purpur end - Add EntityTeleportHinderedEvent
// CraftBukkit start - Entity in portal
org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level), 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 fa0d6baa40c6052c993d870d124af911e8621f0a..1c58af94050b75cd8f405a201448c822792e594a 100644
@@ -58,8 +54,7 @@ index fa0d6baa40c6052c993d870d124af911e8621f0a..1c58af94050b75cd8f405a201448c822
+++ b/net/minecraft/world/level/block/NetherPortalBlock.java
@@ -118,6 +118,13 @@ public class NetherPortalBlock extends Block implements Portal {
protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier) {
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)) {
if (!new 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()) {
@@ -68,5 +63,4 @@ index fa0d6baa40c6052c993d870d124af911e8621f0a..1c58af94050b75cd8f405a201448c822
+ }
+ // Purpur end - Add EntityTeleportHinderedEvent
// CraftBukkit start - Entity in portal
org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level), org.bukkit.PortalType.NETHER); // Paper - add portal type
level.getCraftServer().getPluginManager().callEvent(event);

View File

@@ -45,7 +45,6 @@ index afe7fd92348e6a2a26f8f258373b0c57bb5f4f3f..8da974e98f2207d76e8962eda54c75d0
--- a/net/minecraft/world/entity/animal/Bee.java
+++ b/net/minecraft/world/entity/animal/Bee.java
@@ -181,7 +181,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);
- if (this.level().purpurConfig.beeCanInstantlyStartDrowning) this.setPathfindingMalus(PathType.WATER, -1.0F); // Purpur - bee can instantly start drowning in water option

View File

@@ -39,9 +39,6 @@ index 476b570ffe9d2df173bd57b57fe65372cb35fa1d..4586d7afb4f0a27c7d61abb80af24205
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -273,6 +273,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
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
public int shieldBlockingDelay = this.level().paperConfig().misc.shieldBlockingDelay; // Paper - Make shield blocking delay configurable
+ 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
// CraftBukkit end
@@ -55,7 +52,6 @@ index 476b570ffe9d2df173bd57b57fe65372cb35fa1d..4586d7afb4f0a27c7d61abb80af24205
this.lastHurtByPlayer.store(compound, "last_hurt_by_player");
compound.putInt("last_hurt_by_player_memory_time", this.lastHurtByPlayerMemoryTime);
@@ -891,6 +893,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
} // Paper - The sleeping pos will always also set the actual pos, so a desync suggests something is wrong
}, this::clearSleepingPos);
compound.getCompound("Brain").ifPresent(compoundTag -> this.brain = this.makeBrain(new Dynamic<>(NbtOps.INSTANCE, compoundTag)));
+ this.shouldBurnInDay = compound.getBooleanOr("Purpur.ShouldBurnInDay", false); // Purpur - API for any mob to burn daylight
@@ -69,7 +65,6 @@ index 476b570ffe9d2df173bd57b57fe65372cb35fa1d..4586d7afb4f0a27c7d61abb80af24205
+
+ // 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()) {
@@ -129,8 +124,6 @@ index 0a5de00d41c59528e9f85a7cf82363c45e24d2bc..185edd9878f5193c44b75a126e8182ca
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<? extends AbstractSkeleton> entityType, Level level) {
super(entityType, level);
@@ -143,7 +136,6 @@ index 0a5de00d41c59528e9f85a7cf82363c45e24d2bc..185edd9878f5193c44b75a126e8182ca
@Override
public void aiStep() {
- boolean isSunBurnTick = this.shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API
- if (isSunBurnTick) {
- ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD);
- if (!itemBySlot.isEmpty()) {
@@ -172,19 +164,8 @@ index 0a5de00d41c59528e9f85a7cf82363c45e24d2bc..185edd9878f5193c44b75a126e8182ca
public void readAdditionalSaveData(CompoundTag compound) {
super.readAdditionalSaveData(compound);
this.reassessWeaponGoal();
- this.shouldBurnInDay = compound.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - shouldBurnInDay API
+ //this.shouldBurnInDay = compound.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - shouldBurnInDay API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
}
// Paper start - shouldBurnInDay API
@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 9baec22561093d64157d93449e84c23b3f238b39..3f331215ef49c52fa3a53bcf744159d2221111f5 100644
--- a/net/minecraft/world/entity/monster/Husk.java
@@ -242,7 +223,6 @@ index 409e98d0981aa8be0d35bc5c93f7130a9ce16860..c2bc638b0029ac46cf388187ca745450
- // 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);
@@ -252,24 +232,6 @@ index 409e98d0981aa8be0d35bc5c93f7130a9ce16860..c2bc638b0029ac46cf388187ca745450
super.aiStep();
}
@@ -294,7 +297,7 @@ public class Phantom extends FlyingMob implements Enemy {
this.setPhantomSize(compound.getIntOr("size", 0));
// Paper start
this.spawningEntity = compound.read("Paper.SpawningEntity", net.minecraft.core.UUIDUtil.CODEC).orElse(null);
- this.shouldBurnInDay = compound.getBooleanOr("Paper.ShouldBurnInDay", true);
+ //this.shouldBurnInDay = compound.getBooleanOr("Paper.ShouldBurnInDay", true); // Purpur - implemented in LivingEntity - API for any mob to burn daylight
// Paper end
}
@@ -305,7 +308,7 @@ public class Phantom extends FlyingMob implements Enemy {
compound.putInt("size", this.getPhantomSize());
// Paper start
compound.storeNullable("Paper.SpawningEntity", net.minecraft.core.UUIDUtil.CODEC, 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 7f9ee637f443f55ae901d1a0aebedd8f7411996d..aed6db357f5b4550407a424a5b83c590044568ee 100644
--- a/net/minecraft/world/entity/monster/Zombie.java
@@ -278,12 +240,9 @@ index 7f9ee637f443f55ae901d1a0aebedd8f7411996d..aed6db357f5b4550407a424a5b83c590
private boolean canBreakDoors = false;
private int inWaterTime = 0;
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<? extends Zombie> 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
}
@@ -325,14 +284,11 @@ index 7f9ee637f443f55ae901d1a0aebedd8f7411996d..aed6db357f5b4550407a424a5b83c590
+ 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
}
@@ -512,7 +492,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
@@ -340,8 +296,6 @@ index 7f9ee637f443f55ae901d1a0aebedd8f7411996d..aed6db357f5b4550407a424a5b83c590
} else {
this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, false);
}
- this.shouldBurnInDay = compound.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - Add more Zombie API
+ //this.shouldBurnInDay = compound.getBooleanOr("Paper.ShouldBurnInDay", true); // Paper - Add more Zombie API // Purpur - implemented in LivingEntity - API for any mob to burn daylight
}
@Override

View File

@@ -1,19 +0,0 @@
--- 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;

View File

@@ -4,10 +4,9 @@
private boolean trackingStackTrace = true;
private StackTraceElement[] uncategorizedStackTrace = new StackTraceElement[0];
private final SystemReport systemReport = new SystemReport();
+ private List<String> extraInfo = List.of("", "DO NOT REPORT THIS TO PAPER! REPORT TO PURPUR INSTEAD!", ""); // Purpur - Rebrand
+ private List<String> extraInfo = List.of("", "DO NOT REPORT THIS TO SPIGOT! REPORT TO PURPUR INSTEAD!", ""); // Purpur - Rebrand
public CrashReport(String title, Throwable exception) {
io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper
@@ -130,7 +_,7 @@
}

View File

@@ -11,7 +11,7 @@
+ }
+ 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("<permission>").replacement(bukkitPermission).build())));
+ sendFailure(org.purpurmc.purpur.adventure.PurpurAdventure.asVanilla(permissionMessage.replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("<permission>").replacement(bukkitPermission).build())));
+ }
+ return false;
+ }
@@ -45,7 +45,7 @@
+ if (message == null) {
+ return;
+ }
+ sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(message), broadcastToOps);
+ sendSuccess(() -> org.purpurmc.purpur.adventure.PurpurAdventure.asVanilla(message), broadcastToOps);
+ }
+ // Purpur end - Purpur config files

View File

@@ -26,8 +26,6 @@
if (selection.includeIntegrated) {
@@ -502,6 +_,7 @@
private void runSync(ServerPlayer player, java.util.Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootCommandNode) {
// Paper end - Perf: Async command map building
new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(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);

View File

@@ -1,8 +1,6 @@
--- 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) {

View File

@@ -6,6 +6,5 @@
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();

View File

@@ -1,23 +0,0 @@
--- 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

View File

@@ -7,5 +7,4 @@
- } 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 {

View File

@@ -5,11 +5,10 @@
}
+ // 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.bukkit.configuration.file.YamlConfiguration purpurConfiguration = org.purpurmc.purpur.configuration.PurpurConfigurations.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();

View File

@@ -3,24 +3,15 @@
@@ -283,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<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
public int autosavePeriod;
// Paper - don't store the vanilla dispatcher
@@ -293,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,6 +_,8 @@
public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
+ public boolean lagging = false; // Purpur - Lagging threshold
+ protected boolean upnp = false; // Purpur - UPnP Port Forwarding
@@ -29,7 +20,6 @@
@@ -917,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)) {
@@ -41,7 +31,6 @@
+ // Purpur end - UPnP Port Forwarding
// CraftBukkit start
if (this.server != null) {
this.server.spark.disable(); // Paper - spark
@@ -1011,6 +_,8 @@
this.safeShutdown(waitForServer, false);
}
@@ -49,9 +38,7 @@
+ 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
@@ -1030,6 +_,7 @@
if (isDebugging()) @@ -1030,6 +_,7 @@
private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L;
private long lastTick = 0;
private long catchupTime = 0;
@@ -61,7 +48,6 @@
public final RollingAverage tps15 = new RollingAverage(60 * 15);
@@ -1115,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()) {
@@ -98,7 +84,6 @@
+ lagging = recentTps[0] < org.purpurmc.purpur.PurpurConfig.laggingThreshold; // Purpur - Lagging threshold
tickSection = currentTime;
}
// Paper end - further improve server tick loop
@@ -1171,6 +_,12 @@
profilerFiller.popPush("nextTickWait");
this.mayHaveDelayedTasks = true;
@@ -125,8 +110,6 @@
@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) {

View File

@@ -8,11 +8,3 @@
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
}

View File

@@ -3,15 +3,10 @@
@@ -105,6 +_,7 @@
public void run() {
if (!org.bukkit.craftbukkit.Main.useConsole) return; // CraftBukkit
// 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();
/*
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
@@ -183,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"));
@@ -21,11 +16,9 @@
+ }
+ 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);
@@ -230,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

View File

@@ -24,7 +24,6 @@
@@ -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 {
@@ -95,7 +94,6 @@
@@ -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()) {
@@ -131,5 +129,4 @@
+ }
+ // Purpur end - GUI Improvements
// Paper start - Add onboarding message for initial server start
private JComponent buildOnboardingPanel() {

View File

@@ -6,6 +6,5 @@
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();

View File

@@ -42,14 +42,12 @@
+ this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle
}
// Paper start
@@ -477,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(
@@ -594,6 +_,13 @@
@@ -90,7 +88,6 @@
public void tickCustomSpawners(boolean spawnEnemies, boolean spawnFriendlies) {
for (CustomSpawner customSpawner : this.customSpawners) {
@@ -678,9 +_,17 @@
&& 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) {
- SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(this, EntitySpawnReason.EVENT);
@@ -127,8 +124,7 @@
+ 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
+ component = + } else
+ // Purpur end - Customizable sleeping actionbar messages
component = Component.translatable("sleep.skipping_night");
} else {
@@ -137,8 +133,7 @@
+ 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())),
+ component = + 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
@@ -150,7 +145,6 @@
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....
@@ -928,6 +_,7 @@
@@ -158,15 +152,12 @@
}
// 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.
@@ -2331,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

View File

@@ -1,9 +1,6 @@
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -422,6 +_,10 @@
public @Nullable com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent
public @Nullable String clientBrandName = null; // Paper - Brand support
public @Nullable 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
@@ -52,7 +49,6 @@
+ }
+ // 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))
@@ -1360,6 +_,7 @@
serverLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
@@ -81,8 +77,7 @@
+ 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 = + } else {
+ clientMessage = Component.translatable("sleep.not_possible");
+ }
+ if (clientMessage != null) {
@@ -113,8 +108,7 @@
+
+ public void sendActionBarMessage(@Nullable net.kyori.adventure.text.Component message) {
+ if (message != null) {
+ sendActionBarMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message));
+ }
+ sendActionBarMessage(+ }
+ }
+
+ public void sendActionBarMessage(@Nullable Component message) {
@@ -140,8 +134,7 @@
+
+ public void sendMessage(@Nullable net.kyori.adventure.text.Component message) {
+ if (message != null) {
+ this.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message));
+ }
+ this.sendSystemMessage(+ }
+ }
+ // Purpur end - Component related conveniences
+

View File

@@ -3,7 +3,6 @@
@@ -284,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(

View File

@@ -9,9 +9,6 @@
private volatile boolean suspendFlushingOnServerThread = false;
// CraftBukkit start
@@ -51,6 +_,7 @@
public final java.util.Map<java.util.UUID, net.kyori.adventure.resource.ResourcePackCallback> 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
@@ -47,7 +44,6 @@
this.player.clientBrandName = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.wrappedBuffer(data)).readUtf(256);
}
@@ -242,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;
+

View File

@@ -1,8 +1,7 @@
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -321,6 +_,20 @@
this.tickEndEvent = new io.papermc.paper.event.packet.ClientTickEndEvent(player.getBukkitEntity()); // Paper - add client tick end event
}
this.tickEndEvent = new }
+ // Purpur start - AFK API
+ private final com.google.common.cache.LoadingCache<org.bukkit.craftbukkit.entity.CraftPlayer, Boolean> kickPermissionCache = com.google.common.cache.CacheBuilder.newBuilder()
@@ -24,7 +23,6 @@
@@ -379,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()))) {
@@ -32,7 +30,6 @@
+ }
+ // 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
}
@@ -615,6 +_,8 @@
this.lastYaw = to.getYaw();
@@ -48,13 +45,11 @@
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;
}
@@ -1199,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;
final double multiplier = Math.clamp( 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;
@@ -69,7 +64,6 @@
- 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;
}
@@ -1242,31 +_,45 @@
@@ -103,7 +97,6 @@
- List<Filterable<String>> list = pages.stream().map(this::filterableFromOutgoing).toList();
+ List<Filterable<String>> 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)
}
}
@@ -128,7 +121,7 @@
+ // 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);
+ return hasPerm ? PurpurAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize(str)) : Component.literal(str);
+ }
+
+ private String color(String str, boolean hasPerm) {
@@ -153,16 +146,13 @@
+ 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();
@@ -1496,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
}
@@ -1552,6 +_,8 @@
@@ -217,8 +207,7 @@
@@ -2672,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
if (this.player.canInteractWithEntity(boundingBox, + 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

View File

@@ -5,7 +5,6 @@
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);
+ ServerLoginPacketListenerImpl.this.disconnect(org.purpurmc.purpur.PurpurConfig.unverifiedUsername.equals("default") ? Component.translatable("multiplayer.disconnect.unverified_username") : ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", string1);
}
} catch (AuthenticationUnavailableException var4) {

View File

@@ -3,8 +3,6 @@
@@ -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
}
}

View File

@@ -3,15 +3,12 @@
@@ -400,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()) {
@@ -504,6 +_,7 @@
}
public @Nullable 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);
@@ -22,7 +19,6 @@
// : 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
}
}
@@ -920,6 +_,20 @@
@@ -38,8 +34,7 @@
+
+ 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);
+ }
+ this.broadcastSystemMessage(+ }
+ }
+ // Purpur end - Component related conveniences
+

View File

@@ -2,7 +2,6 @@
+++ 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) {

View File

@@ -62,11 +62,9 @@
+
+ // 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 name = + 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);
+ }
+ return + }
+ // Purpur end - Component related conveniences
public String getMsgId() {

View File

@@ -14,8 +14,6 @@
public double zOld;
+ public float maxUpStep; // Purpur - Add option to set armorstand step height
public boolean noPhysics;
- 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;
@@ -28,8 +26,7 @@
+ protected UUID uuid; // Purpur - Add toggle for RNG manipulation
+ protected String stringUUID; // Purpur - Add toggle for RNG manipulation
private boolean hasGlowingTag;
private final Set<String> 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};
private final Set<String> tags = new private final double[] pistonDeltas = new double[]{0.0, 0.0, 0.0};
@@ -394,6 +_,7 @@
public long activatedTick = Integer.MIN_VALUE;
public boolean isTemporarilyActive;
@@ -40,7 +37,6 @@
}
@@ -406,10 +_,21 @@
}
// Paper end
+ // Purpur start - Add canSaveToDisk to Entity
+ public boolean canSaveToDisk() {
@@ -61,9 +57,7 @@
this.blockPosition = BlockPos.ZERO;
this.chunkPosition = ChunkPos.ZERO;
@@ -779,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(org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.level.getSharedSpawnPos(), this.level)); else // Purpur - Add option to teleport to spawn on nether ceiling damage
this.onBelowWorld();
}
@@ -87,9 +81,7 @@
this.wasTouchingWater = false;
} else if (this.updateFluidHeightAndDoFluidPushing(FluidTags.WATER, 0.014)) {
@@ -2364,6 +_,13 @@
compound.putBoolean("Paper.FreezeLock", true);
}
// Paper end
+
+ // Purpur start - Fire immune API
+ if (immuneToFire != null) {
@@ -101,9 +93,7 @@
} catch (Throwable var8) {
CrashReport crashReport = CrashReport.forThrowable(var8, "Saving entity NBT");
@@ -2481,6 +_,13 @@
freezeLocked = compound.getBooleanOr("Paper.FreezeLock", false);
}
// Paper end
+
+ // Purpur start - Fire immune API
+ if (compound.contains("Purpur.FireImmune")) {
@@ -120,7 +110,6 @@
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());
@@ -2936,15 +_,18 @@
return Vec3.directionFromRotation(this.getRotationVector());

View File

@@ -3,9 +3,7 @@
@@ -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<Player> notAfk = (player) -> !player.isAfk(); // Purpur - AFK API
+
// Paper start - Affects Spawning API
public static final Predicate<Entity> PLAYER_AFFECTS_SPAWNING = (entity) -> {
return !entity.isSpectator() && entity.isAlive() && entity instanceof Player player && player.affectsSpawning;

View File

@@ -37,7 +37,6 @@
@@ -1384,7 +_,11 @@
entity.load(tag);
},
// Paper end - Don't fire sync event during generation
- () -> LOGGER.warn("Skipping Entity with id {}", tag.getStringOr("id", "[invalid]"))
+ // Purpur start - log skipped entity's position
+ () -> {LOGGER.warn("Skipping Entity with id {}", tag.getStringOr("id", "[invalid]"));

View File

@@ -3,7 +3,6 @@
@@ -328,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 = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(entity, 2, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2;
+ entity.takeXpDelay = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(entity, this.level().purpurConfig.playerExpPickupDelay, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; // Purpur - Configurable player pickup exp delay
entity.take(this, 1);

View File

@@ -138,16 +138,12 @@
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;
@@ -1883,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
@@ -3057,6 +_,7 @@
float f = (float)(d * 10.0 - 3.0);
if (f > 0.0F) {

View File

@@ -6,9 +6,7 @@
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);

View File

@@ -1,7 +1,6 @@
--- a/net/minecraft/world/entity/animal/Bee.java
+++ b/net/minecraft/world/entity/animal/Bee.java
@@ -167,7 +_,7 @@
// Paper end - Fix MC-167279
this.lookControl = new Bee.BeeLookControl(this);
this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
- this.setPathfindingMalus(PathType.WATER, -1.0F);

View File

@@ -23,7 +23,6 @@
@@ -705,6 +_,29 @@
return slot == EquipmentSlot.MAINHAND;
}
// Paper end
+
+ // Purpur start - Tulips change fox type
+ @Override
@@ -49,4 +48,3 @@
+ // Purpur end - Tulips change fox type
@Override
// Paper start - Cancellable death event

View File

@@ -11,6 +11,5 @@
+ cow.yRotO = this.yRotO;
+ cow.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));

View File

@@ -4,8 +4,6 @@
public Squid(EntityType<? extends Squid> 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;
}

View File

@@ -1,9 +1,6 @@
--- a/net/minecraft/world/entity/animal/WaterAnimal.java
+++ b/net/minecraft/world/entity/animal/WaterAnimal.java
@@ -76,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

View File

@@ -2,7 +2,6 @@
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
@@ -395,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<Goat> brain = this.getBrain();

View File

@@ -3,7 +3,6 @@
@@ -77,6 +_,7 @@
private Llama caravanHead;
@Nullable
public Llama caravanTail; // Paper
+ public boolean shouldJoinCaravan = true; // Purpur - Llama API
public Llama(EntityType<? extends Llama> entityType, Level level) {

View File

@@ -28,7 +28,6 @@
@@ -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
+
}
@@ -47,10 +46,8 @@
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

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